浮点模数运算

时间:2012-02-29 19:38:13

标签: c assembly binary floating-point modulo

我正在尝试实现三角法的范围缩小操作。但相反,我认为对输入数据执行模数pi / 2操作可能会更好。我想知道什么算法存在并且对于32位IEEE 754浮点的操作有效?

我必须在汇编中实现它,因此只有一条指令我无法使用fmod,除法,乘法等。我的处理器使用16位字,我实现了32位浮点加法,减法,乘法,除法,平方根,余弦和正弦。我只需要范围缩减(模数)来输入余弦和正弦值。

4 个答案:

答案 0 :(得分:16)

我认为标准库的fmod()将是大多数情况下的最佳选择。这是关于几个简单算法的讨论的link

在我的计算机上,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)进行计算。

答案 1 :(得分:14)

也许我在这里忽略了这一点,但是 你有什么反对简单地使用fmod吗?

double theta = 10.4;
const double HALF_PI = 2 * atan(1);
double result = fmod(theta, HALF_PI);

答案 2 :(得分:8)

您想要的算法,将浮点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

答案 3 :(得分:0)

精确db.collection("drivers").aggregate([ { $project: { _id: { $toString: "$_id", }, agent_email: "$agent_email" }, }, { $lookup: { from: "reviews", localField: "_id", foreignField: "driver_id", as: "driver_info", }, }, // Makes the driver info flat with other information { "$unwind": "$driver_info" }, { // Now you can group them $group: { _id: "$_id", // Calculates avg on rating field avg: { "$avg": "$driver_info.rating" }, // To make email field appear in next pipeline. // You can do it for other fields too like Name, etc agent_email: { $first: "$agent_email" } } }, { $project: { // select the fields you want to display agent_email: 1, avg: 1 }, }, ]) 是用长除法实现的。确切的余数始终可以表示,因为被除数和除数共享相同的格式。您可以研究glibc和musl等开源实现。我也在metallic中取得了一个。 (无耻的插头)

Payne–Hanek范围缩小适用于π等常数除数,我们预先存储了其倒数。因此,此处不适用。