Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.191.228.88] |
|
Страницы: (3) 1 2 [3] все ( Перейти к последнему сообщению ) |
Сообщ.
#31
,
|
|
|
Цитата leo @ Это понятно, только ты из 2N не сможешь вычесть единицу, если N > 63 (для 80-битных чисел) или > 52 (для double), или > 23 (для single/float). А поскольку точность была настроена на double, то вычесть из 263 единицу не получалось, и в unsigned __int64 преобразовывалось не _I64_MAX, а _I64_MAX+1, и возникало исключение. Учти, что вычисляется степень двойки, а двоичная мантисса любого числа 2N строго равна 1 и представляется абсолютно точно в любом вещественном формате. Добавлено И надо сказать, что это значительно быстрее, чем через fyl2x/f2xm1/fscale. Иногда в 2 раза, а иногда раз в 5-6 (при малых степенях). Специально мерил... Но там есть косяк (в Delphi): он не может вычислять степень > MaxInt (по модулю) из отрицательных чисел. Возникает исключение. Что в Delphi 7, что в Berlin. Т.е. если число > MaxInt или нецелое, он выполняет вычисление через fyl2x/f2xm1/fscale (и вылетает на fyl2x, соответственно). Добавлено Если кому надо – вот рабочая функция вычисления степени любого числа из любого. Вариант без IntPower (есть ещё и с IntPower). ;############################################## ;## ## ;## -= FPU POWER FUNCTION =- ## ;## ФУНКЦИЯ ВОЗВЕДЕНИЯ В СТЕПЕНЬ ## ;## [ v1.00 ] ## ;## MASM/TASM (16/32) ## ;## ## ;## (c) 2017 by Jin X (jin.x@sources.ru) ## ;## http://xk7.ru/p/a/i ## ;## ## ;############################################## ;-- FPPower: функция возведения X в степень Y -------------------------------------------------------------------------- ; Входные данные: st(0) = основание X, st(1) = показатель степени Y ; Результат: st(0) = st(0)^st(1) = X^Y (или 0 при ошибке), st(1) пуст; CF=NC=0 - успешный результат, CF=CY=1 - ошибка (при X<0 и нецелом Y) ; Функция изменяет AX, DX и флаги FPPower proc ; Сравнение X с нулём ftst ; st(0)=X=0 ? fstsw ax mov dl,ah ; dl and 1=1, если X<0 (используется в чистом FPU-расчёте и при проверке ошибки), иначе dl and 1=0 sahf jz short @@Zero ; если X=0, результат=st(0)=0 (записываем чистый ноль - если допустим ноль со знаком, можно сделать прыжок на @@Free1AndExit); st(1)=Y; CF=NC=0 ; Проверка Y на целое fld st(1) ; st(0)=Y, st(1)=X, st(2)=Y frndint ; st(0)=Round(st(0))=Round(Y), st(1)=X, st(2)=Y fcomp st(2) ; сравнение st(0) и st(2): Round(Y) и Y; st(0)=X, st(1)=Y, st(2) пуст fstsw ax sahf jne short @@ErrChk ; прыгаем, если Y нецелое ; Степень Y - целое число, проверяем знак X shr dl,1 ; проверяем знак X (dl and 1) jnc short @@PosX ; прыгаем, если X>0 (dl=0) ; Проверка чётности целого Y (при X<0) fld1 ; st(0)=1, st(1)=X, st(2)=Y fld1 ; st(0)=st(1)=1, st(2)=X, st(3)=Y faddp ; st(0)=2.0, st(1)=X, st(2)=Y fld st(2) ; st(0)=Y, st(1)=2.0, st(2)=X, st(3)=Y fabs ; st(0)=|Y|, st(1)=2.0, st(2)=X, st(3)=Y fprem ; st(0)=|Y| mod 2.0 (если Y не чересчур большой, иначе st(0) будет содержать неверное значение, и тогда мы будем считать, что число чётное), st(1)=2.0, st(2)=X, st(3)=Y fld1 ; st(0)=1, st(1)=Y mod 2.0, st(2)=2.0, st(3)=X, st(4)=Y fcompp ; сравнение st(0) и st(1): 1 и (Y mod 2.0) с удалением этих чисел; st(0)=2.0, st(1)=X, st(2)=Y, st(3) и st(4) пусты fstsw ax shr ah,6 ; CF=ZF (т.к. нам надо получить CF=нечётный Y) sahf ; CF=NC=0, если Y чётное; CF=CY=1, если Y нечётное fstp st ; удаляем 2.0; st(0)=X, st(1)=Y, st(2) пуст fabs ; st(0)=|X|, st(1)=Y @@PosX: ; CF=NC=0, если dl and 1=0 (т.е. X>0, сюда был прыжок) или Y чётное fyl2x ; st(0)=Y*log2(|X|)=Z, st(1) пуст[st(0)=st(1)*log2(st(0))] fld st ; st(0)=Z, st(1)=Z frndint ; st(0)=Round(Z), st(1)=Z fxch ; st(0)=Z, st(1)=Round(Z) fsub st,st(1) ; st(0)=Z-Round(Z), st(1)=Round(Z) f2xm1 ; st(0)=2^(E-Round(Z))-1, st(1)=Round(Z) fld1 ; st(0)=1, st(1)=2^(E-Round(Z))-1, st(2)=Round(Z) faddp st(1),st ; st(0)=st(0)+1 = 2^(E-Round(Z)), st(1)=Round(Z), st(2) пуст fscale ; st(0)=2^(E-Round(Z))*2^Round(Z)=2^Z, st(1)=Round(Z) [st(0)=st(0)*2^RoundTowardZero(st(1))] ; st(0)=результат=X^Y jnc short @@Free1AndExit ; прыгаем, если X>0, либо Y чётное fchs ; иначе меняем знак результата clc ; ошибок нет, CF=NC=0 @@Free1AndExit: ffree st(1) ; удаляем лишнее значение st(1)=Round(Z) или st(1)=X; st(0)=результат ret ; Проверка ошибки (Y нецелое!) @@ErrChk: shr dl,1 ; проверяем знак X (dl and 1) jnc short @@PosX ; прыгаем, если X>0 (dl=0; CF=NC=0) ; иначе ошибка (dl=1: X<0 и Y нецелое); CF=CY=1 @@Zero: fldz ; st(0)=0, st(1)=X, st(2)=Y ffree st(2) ; удаляем лишнее значение st(2)=Y jmp short @@Free1AndExit FPPower endp |