[英]Floating Point Modulo Operation
我正在尝试实现三角函数的范围缩减操作。 但相反,我认为对传入数据执行模 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
所以它实际上使用了专用的 CPU 指令(fprem)进行计算。
也许我在这里错过了重点,但是您是否反对简单地使用fmod ?
double theta = 10.4;
const double HALF_PI = 2 * atan(1);
double result = fmod(theta, HALF_PI);
您想要的算法将浮点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
圆周率模式 e = 0.42331082513074800
精确的fmod
是用长除法实现的。 确切的余数总是可以表示为被除数和除数共享相同的格式。 您可以查看 glibc 和 musl 等开源实现。 我也做了一个金属的。 (无耻的插头)
Payne-Hanek 范围缩减适用于像 π 这样的常数除数,我们预先存储了它的倒数。 因此,这里不适用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.