我正在尝试实现三角函数的范围缩减操作。但我认为,直接对输入数据执行模pi/2操作可能更好。我想知道是否有算法适用于32位 IEEE 754浮点数,并且效率高。
由于我必须在汇编中实现这个操作,所以fmod、除法、乘法等都不能只使用一个指令。我的处理器使用16位字,我已经实现了32位浮点加法、减法、乘法、除法、平方根、余弦和正弦。我只需要对输入值进行范围缩减(取模),然后将其输入到余弦和正弦函数中。
我正在尝试实现三角函数的范围缩减操作。但我认为,直接对输入数据执行模pi/2操作可能更好。我想知道是否有算法适用于32位 IEEE 754浮点数,并且效率高。
由于我必须在汇编中实现这个操作,所以fmod、除法、乘法等都不能只使用一个指令。我的处理器使用16位字,我已经实现了32位浮点加法、减法、乘法、除法、平方根、余弦和正弦。我只需要对输入值进行范围缩减(取模),然后将其输入到余弦和正弦函数中。
fmod()
在大多数情况下是最好的选择。这里有一个链接,讨论了几种简单的算法。fmod()
使用优化的内联汇编代码(/usr/include/bits/mathinline.h
):#if defined __FAST_MATH__ && !__GNUC_PREREQ (3, 5)
__inline_mathcodeNP2 (fmod, __x, __y, \
register long double __value; \
__asm __volatile__ \
("1: fprem\n\t" \
"fnstsw %%ax\n\t" \
"sahf\n\t" \
"jp 1b" \
: "=t" (__value) : "0" (__x), "u" (__y) : "ax", "cc"); \
return __value)
#endif
也许我在这里错过了什么,但是你有反对直接使用fmod吗?
double theta = 10.4;
const double HALF_PI = 2 * atan(1);
double result = fmod(theta, HALF_PI);
fmod
就可以使用。 - Gunther Piez你想要的算法是,将一个浮点数value
限制在0
和某个模数n
之间:
Double fmod(Double value, Double modulus)
{
return value - Trunc(value/modulus)*modulus;
}
例如 pi mod e
(3.14159265358979 mod 2.718281828459045)
3.14159265358979 / 2.718281828459045
= 1.1557273497909217179
Trunc(1.1557273497909217179)
= 1
1.1557273497909217179 - 1
= 0.1557273497909217179
0.1557273497909217179 * e
= 0.1557273497909217179 * 2.718281828459045
= 0.42331082513074800
pi mod e = 0.42331082513074800
value
来说可能非常不准确。有更复杂的算法。但如果在数值上可以接受,这通常会相当快速,因此如果适用于您的用例,则是一个不错的选择。 - Peter Cordesfmod
函数是用长除法实现的。确切的余数总是可以表示为被除数和除数具有相同格式。您可以查看开源实现,如glibc和musl。我还在metallic中制作了一个(厚颜无耻地推广)。
Payne-Hanek范围缩减适用于像π这样的常量除数,我们提前存储其倒数。因此,它在这里不适用。
remainder()
类似于fmod()
,但采用IEEE标准的四舍五入方式。 - Peter Cordes