与双打的fmod问题

时间:2018-01-10 00:28:15

标签: c++ double fmod math.h

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

运行代码时得到的输出是这样的:

C:\Users\Marius>H:\Liquibase\Liquibase \
--driver=com.microsoft.sqlserver.jdbc.SQLServerDriver \
--classpath="C:\\Program Files\\Microsoft JDBC Driver 6.2 for SQL Server\\sqljdbc_6.2\\enu\\mssql-jdbc-6.2.2.jre7.jar" \
--url="jdbc:sqlserver://localhost:3306; databaseName=Test" \
--changeLogFile="H:\Liquibase\dbchangelog.xml" \
--username=liquibase \
--password=liquibase \
Update

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

1 个答案:

答案 0 :(得分:1)

问题不在于fmod,它可以提供最高精度的结果。问题是cout精度不像你期望的那样,加上“舍入”,因为double不能准确地存储0.1来表示cout认为16的精度。

此代码演示了此问题。当您将123.1分配给double时,实际上会发生舍入,但是由于左边的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

进一步阅读对您问题的评论: Is floating point math broken?

此外,对于绝大多数场景来说,双倍都不错。对于准确的,递归数学,你需要考虑一个重型数学库,甚至是数学专业语言。

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