c - fmod 十进制数的最佳方法是什么?

标签 c math floating-point double

我的问题是从模计算中获得最准确的结果,我得到余数答案以进行另一次舍入计算,因此我确实需要一个准确的结果。

double a = 0.12345678...(可能有很多数字);

double b = fmod(a, 0.01);

结果 b 可能不准确处理二进制存储问题。

我是否必须考虑使用 float 来提高准确性。 或者我只是将数字从小数点移动到整数

双 a = 12345678.0;

谢谢

最佳答案

首先,任何严格的 fmod 实现都会以单精度/ double /任何精度回答最接近余数的 float ,就好像以无限精度执行除法一样。 (注意:感谢@EricPostpischil 改写)

不过,那已经太晚了。 0.01 的二进制浮点内部表示并不完全像您已经知道的那样表示 1/100。

让我们检查错误是如何累积的。

你想知道除法的余数,比如 a % b = c .

您有不精确的表示 a1 和 b1,并且您知道这些表示的错误界限:a1=a+ea1 , abs(ea1) < ea , b1=b+eb1 , abs(eb1) < eb .

关于 a1 % b1 = c1,你有什么想说的吗? (确切的操作),c1=c+ec1那是关于错误界限abs(ec1) < ec

a = q * b + c.
a1 = q1 * b1 + c1.
a+ea1 = (q+eq1)*(b+eb1) + (c+ec1).
ea1 = eq1*(b+eb1) + q*eb1 + ec1.
ec1 = ea1 - q*eb1 - eq1*(b+eb1).
ec >= max( ea , abs(q)*eb , eq*abs(b) , eq*eb).
ec <= ea + abs(q)*eb + eq*abs(b) + eq*eb.

你可以控制eaabs(q)*eb通过提高表示精度(单倍、双倍、扩展、四倍、任意精度...)。

但是这个等式中的重要术语是 eq*abs(b) ,因为如果商可以减一,那么误差范围是 ec > b !

当然,商可以减一,这种情况非常容易构造。 取c=0a1表示关闭 a默认情况下 ( ea1<0 ) 或 b1表示关闭 b超出(eb1>0),你就完成了,你得到了eq1 = -1即使是小商和准确的精度。

不要认为仔细控制舍入模式,例如获得 ea1 > 0 (多余)和eb1 <= 0 (默认)会在所有情况下保护你,因为我们可以构造相反的情况

b - smallValue < c < b

不要尝试 remainder fmod 的变体舍入商而不是截断,这只会使问题接近完美平局(当精确除法 a/b 是 1/2 的倍数时)。

通过对误差范围的仔 segmentation 析,您可以得出 ec 的估计值。并确定商 q 可能不正确四舍五入的不良情况(当 a1/b1 接近整数时),或 abs(q)*eb达到 1,或 ea>=b .

在糟糕的情况下,您可以安排引发异常,然后重新开始生产 a1b1精度更高,但在边缘情况下c=0 , 即使精度任意,也不能保证收敛。

关于c - fmod 十进制数的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17539549/

相关文章:

c - 用于在 c 中创建螺旋形状图案的嵌套循环

c - 我什么时候可以在 C 中省略大括号?

python - 查找不能被 x 到 y 整除的 a 到 b 的数字

c++ - visual studio 2010 在 float /双增量上显示奇怪的行为

c - Windows Shell:通过C代码更改Shell颜色

c - 指向结构体的指针,这还是指向结构体的指针吗?

math - 判断点是否在三角形内

javascript - 使用正则表达式转换 JS 中的多项式字符串表示形式

sql - 如何从 SQLite 数据库中选择浮点无限文字?

python - 使用 F-string 显示 float