如何:x86中的pow(real,real)

如何:x86中的pow(real,real),x86,assembly,pow,X86,Assembly,Pow,我正在寻找在x86汇编中实现pow(real,real)。我还想了解算法是如何工作的。只需将其计算为2^(y*log2(x)) 有一条x86指令FYL2X计算y*log2(x),还有一条x86指令F2XM1进行求幂。F2XM1需要一个[-1,1]范围内的参数,因此您必须在这两者之间添加一些代码来提取整数部分和余数,对余数进行幂运算,使用FSCALE将结果按适当的2次方进行缩放。只需将其计算为2^(y*log2(x)) 有一条x86指令FYL2X计算y*log2(x),还有一条x86指令F2XM1

我正在寻找在x86汇编中实现
pow(real,real)
。我还想了解算法是如何工作的。

只需将其计算为
2^(y*log2(x))


有一条x86指令FYL2X计算y*log2(x),还有一条x86指令F2XM1进行求幂。F2XM1需要一个[-1,1]范围内的参数,因此您必须在这两者之间添加一些代码来提取整数部分和余数,对余数进行幂运算,使用FSCALE将结果按适当的2次方进行缩放。

只需将其计算为
2^(y*log2(x))


有一条x86指令FYL2X计算y*log2(x),还有一条x86指令F2XM1进行求幂。F2XM1需要一个[-1,1]范围内的参数,因此您必须在这两者之间添加一些代码来提取整数部分和余数,对余数进行幂运算,使用FSCALE将结果按2的适当幂进行缩放。

好的,我实现了
幂(双a,双b,双*结果)在x86中,正如您建议的那样

代码:


好的,我实现了
power(双a,双b,双*结果)在x86中,正如您建议的那样

代码:


这是我的函数,它使用了Svin的主算法。我用uuu fastcall和uuu declspec(裸体)装饰将其包装起来,并添加了代码以确保base/x为正。如果x为负值,FPU将完全失效。你需要检查“X”符号位,再考虑“Y”的奇数/偶数位,并在完成后应用符号。让我知道你对任何读者的想法。如果可能的话,寻找使用x87 FPU代码的更好版本。它使用Microsoft VC++2005进行编译/工作。出于各种原因,我一直坚持使用它

兼容性。ANSI pow(x,y):非常好!更快、可预测的结果,负值得到处理,只是对无效输入没有错误反馈。但是,如果您知道“y”可以始终是INT/LONG,请不要使用此版本;我发布了Agner Fog的版本,其中有一些调整,避免了非常缓慢的FSCALE,搜索我的个人资料!在这些有限的环境下,His是最快的x87/FPU方式

extern double\uu快速调用fs\u电源(双x,双y);
//主要来源:Svin
//功率(x,y)等于exp(y*ln(x))
//版本:1.00
__declspec(裸)双快速调用fs_Power(双x,双y){uu asm{
leaeax[ESP+12];//在EAX中保存“y”索引
FLD QWORD PTR[EAX];//加载“y”(指数)(工作为正或负!)
First DWORD PTR[EAX];//将“y”取回INT形式以测试奇偶位
MOVZX-EAX,单词PTR[EAX-1];//获取x的左符号位和y的右奇偶位!
FLD QWORD PTR[ESP+4];//加载“x”(基本)(下一步为正值!)
FABS;//“x”必须为正,但请在退出前检查符号/奇数位!
和AX,0180h;//和关闭除右'y'奇数位和左'x'符号位之外的所有位!
FYL2X;//'y'*log2'x'-(ST(0)=ST(1)*log2 ST(0)),pop
FLD1;//加载1.0f:2次使用,尾数提取,添加1.0返回到F2XM1后
FLD ST(1);//重复当前结果
FPREM1;//使用80387+IEEE cmd通过部分ST0/ST1余数提取尾数
F2XM1;//计算(2^ST(0)-1)
FADDP ST(1),ST;//向后添加1.0f!我们想要的是(2^X),而不是(2^X-1)!
FSCALE;//ST(0)=ST(0)*2^ST(1)(按2的系数进行缩放)
FFREE ST(1);//保持FPU堆栈平衡
;//最后一个任务,如果需要,将结果设为负数!
CMP AX,0180h;//组合测试:是否设置了“y”奇数位和“x”符号位?
JNE EXIT_RETURN;//如果为正,则退出;如果为非正,则添加“-”号!
FCHS;//'x'为负,'y'为奇数,最终结果=负!:)
退出/返回:
;//对于uuu fastcall/uuuu declspec(裸体),必须清理这里的堆栈(2 x 8字节双倍)!
RET 16;//返回并弹出堆栈中的16字节
}}
好的,为了结束这个实验,我使用RDTSC CPU时间戳/时钟计数器指令运行了一个基准测试。我遵循了同样使用“SetPriorityClass(GetCurrentProcess(),High_priority_CLASS)”将进程设置为高优先级的建议,并关闭了所有其他应用程序

结果:我们的retro x87 FPU数学函数“fs_Power(x,y)”比MSCRT2005 pow(x,y)版本快50-60%,该版本使用了一个相当长的SSE分支代码,标记为“_pow_pentium4:”,如果它检测到64位>奔腾4+CPU。是啊!!:-)

注:(1)CRT pow()有一个约33微秒的初始化分支,它显示在本测试中为46000。在1200到3000次循环后,它以正常平均值运行。我们手工制作的x87 FPU beauty运行一致,第一次呼叫时没有初始惩罚

(2) 虽然CRT pow()每次测试都失败,但它确实在一个方面赢了:如果您输入了大量超出范围/溢出的值,它会很快返回一个错误。由于大多数应用程序在典型/正常使用时不需要进行错误检查,因此与此无关

第二次测试(我必须再次运行它,以便在图像捕捉后复制/粘贴文本):

有真实世界的应用程序吗?对Pow(x,y)大量用于帮助将CD的波形格式编码/解码为OGG,反之亦然!当您对整整60分钟的WAVE数据进行编码时,节省时间的回报将非常显著!OGG/libvorbis中使用了许多数学函数,如acos()、cos()、sin()、atan()、sqrt()、ldexp()(非常重要)等。因此,像这样的微调版本不需要进行错误检查,可以节省大量时间

我的实验是为NSIS安装程序系统构建OGG解码器的结果,这导致我将算法所需的所有数学“C”库函数替换为您上面看到的。嗯,差不多了,我需要x86中的acos(),但我仍然找不到任何相关内容


问候,希望这对喜欢修补的人有用

这是我的函数,它使用“Svin”的主算法。我用uuu fastcall和uuu declspec(裸体)装饰将它包装起来,并添加了代码以确保base/x是正的
%define a               QWORD [ebp+8]
%define b               QWORD [ebp+16]
%define result          DWORD [ebp+24]
%define ctrlWord            WORD [ebp-2]
%define tmp             DWORD [ebp-6]

segment .text
    global power

power:
    push ebp
    mov ebp, esp
    sub esp, 6
    push ebx

    fstcw ctrlWord
    or ctrlWord, 110000000000b
    fldcw ctrlWord

    fld b
    fld a
    fyl2x

    fist tmp

    fild tmp
    fsub
    f2xm1
    fld1
    fadd
    fild tmp
    fxch
    fscale

    mov ebx, result
    fst QWORD [ebx]

    pop ebx
    mov esp, ebp
    pop ebp
    ret
 x86 fs_Power(2, 32): CPU Cycles (RDTSC): 1248
MSCRT SSE pow(2, 32): CPU Cycles (RDTSC): 50112

 x86 fs_Power(-5, 256): CPU Cycles (RDTSC): 1120
MSCRT SSE pow(-5, 256): CPU Cycles (RDTSC): 2560

 x86 fs_Power(-35, 24): CPU Cycles (RDTSC): 1120
MSCRT SSE pow(-35, 24): CPU Cycles (RDTSC): 2528

 x86 fs_Power(64, -9): CPU Cycles (RDTSC): 1120
MSCRT SSE pow(64, -9): CPU Cycles (RDTSC): 1280

 x86 fs_Power(-45.5, 7): CPU Cycles (RDTSC): 1312
MSCRT SSE pow(-45.5, 7): CPU Cycles (RDTSC): 1632

 x86 fs_Power(72, -16): CPU Cycles (RDTSC): 1120
MSCRT SSE pow(72, -16): CPU Cycles (RDTSC): 1632

 x86 fs_Power(7, 127): CPU Cycles (RDTSC): 1056
MSCRT SSE pow(7, 127): CPU Cycles (RDTSC): 2016

 x86 fs_Power(6, 38): CPU Cycles (RDTSC): 1024
MSCRT SSE pow(6, 38): CPU Cycles (RDTSC): 2048

 x86 fs_Power(9, 200): CPU Cycles (RDTSC): 1152
MSCRT SSE pow(9, 200): CPU Cycles (RDTSC): 7168

 x86 fs_Power(3, 100): CPU Cycles (RDTSC): 1984
MSCRT SSE pow(3, 100): CPU Cycles (RDTSC): 2784