鉴于以下双打,fmod
是否会返回正确的值?
double x = .090;
double y = .003;
double r = fmod(x, y);
// r = 0.0029999999999999949
为什么没有r = 0?
答案 0 :(得分:5)
因为,与大多数小数部分一样,这些数字不能用二进制浮点格式精确表示。要查看实际使用的值:
#include <cstdio>
int main() {
printf("%.20f %.20f\n", .090, .003);
}
Output: 0.08999999999999999667 0.00300000000000000006
这些小的舍入误差意味着第一个值略小于第二个值的精确倍数,因此您看到了结果。
您可能希望对错误允许小容差:
if (r > y - some_small_value) {
r = 0;
}
答案 1 :(得分:3)
这类问题可以通过阅读题为What Every Computer Scientist Should Know About Floating-Point Arithmetic。
的论文来解决您的机器使用二进制表示形式表示浮点数,这些数字不能完全代表有理数3/1000 = 0.003。
当然,机器可以将其近似值0.003打印为"0.003"
,但这是由printf
内的格式化打印代码完成的,当它将值四舍五入到给定的小数位数时
浮点值的打印十进制版本与其实际内部值之间的差异可能会给程序员或不了解问题的用户带来问题。