双打的 fmod 问题

Issue with fmod with doubles

本文关键字:问题 fmod      更新时间:2023-10-16

似乎fmod(x,1)x是双精度给出错误的结果,如行输出:

std::cout << fmod(min, 1) << "|" << fmod(max, 1) << std::endl;

我忘记了你所说的名称,但这是说明我的问题所需的最少代码:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <math.h>
const int deviation = 3;
void weightedRandomNumber(double min, double max);
int main() {
srand(time(nullptr));
std::cout.precision(16);
std::cout << 123.1 << "|" << 2789.3234 << std::endl;
weightedRandomNumber(123.1, 2789.3234);
system("pause");
return 0;
}
void weightedRandomNumber(double min, double max) {//inclusive
int multiplier = 1;
std::cout << min << "|" << max << std::endl;
while (fmod(min, 1) > 0 || fmod(max, 1) > 0) {
std::cout << min << "|" << max << std::endl;
std::cout << fmod(min, 1) << "|" << fmod(max, 1) << std::endl;
min *= 10;
max *= 10;
multiplier++;
}
std::cout << min << "|" << max << std::endl;
std::cout << multiplier << std::endl;
}

运行代码时得到的输出如下:

123.1|2789.3234
123.1|2789.3234
123.1|2789.3234
0.09999999999999432|0.3234000000002197
1231|27893.234
0|0.2340000000040163
12310|278932.34
0|0.3400000000256114
123100|2789323.4
0|0.400000000372529
1231000|27893234
0|3.725290298461914e-09
12310000|278932340.0000001
0|5.960464477539063e-08
123100000|2789323400
0|4.76837158203125e-07
1231000000|27893234000
0|3.814697265625e-06
12310000000|278932340000.0001
0|6.103515625e-05
123100000000|2789323400000
0|0.00048828125
1231000000000|27893234000000
0|0.00390625
12310000000000|278932340000000
0|0.03125
123100000000000|2789323400000001
0|0.5
1231000000000000|2.7893234e+16
14

除此之外,我不太知道该说什么,如果我错过了任何必要的内容,请发表评论,以便我可以修改我的问题。

问题不在于fmod,它提供了最高精度的结果。 问题在于 cout 精度的行为不像您预期的那样,再加上"舍入",因为双精度无法足够准确地存储0.1来表示cout认为的精度为 16。

此代码演示了该问题。 当您将123.1分配给双精度时,实际上会发生舍入,但由于左侧的 3 位数字在变为较小的数字之前不可见。

int main() {
std::cout.precision(16);
std::cout << (123.1L - 123L);
}

输出:

0.09999999999999432

实际上。。。。这更简洁地说明了这个问题:

int main() {
std::cout.precision(20);
std::cout << 123.1;
}

123.09999999999999432

进一步阅读有关您问题的评论: 浮点数学坏了吗?

此外,对于绝大多数情况,双精度值绰绰有余。 对于准确的递归数学,您需要考虑使用重型数学库,甚至是数学专用语言。

进一步阅读: http://www.boost.org/doc/libs/1_62_0/libs/math/doc/html/math_toolkit/high_precision/why_high_precision.html