比较int和double时出错

Error while comparing a int and a double

本文关键字:出错 double int 比较      更新时间:2023-10-16

我正在尝试制作一个计算位数的简单函数。我写了一些功能,可以完美地工作,但我被这个卡住了:

// The number I want to count the digits after the decimal
long double d=33.56;
// Going to modify d but I wan't to keep the original value
long double dTemp=d;
// v to store the part after the decimal and e the part before
long double v, e;
v=modfl(dTemp,&e);
// j is the number of digit after the decimal
int j=0;
while(dTemp!=e)
{
j++;
dTemp*=10;
v=modfl(dTemp,&e);
std::cout<<"D = "<<dTemp<<" e = "<<e<<" v = "<<v<<std::endl;
}
std::cout<<"J = "<<j<<std::endl;

输出为:

D = 335.6 e = 335 v = 0.6
D = 3356 e = 3356 v = 2.27374e-13
D = 33560 e = 33560 v = 2.27374e-12
D = 335600 e = 335600 v = 2.27374e-11
D = 3.356e+06 e = 3.356e+06 v = 2.27374e-10
D = 3.356e+07 e = 3.356e+07 v = 2.27374e-09
D = 3.356e+08 e = 3.356e+08 v = 2.27301e-08
D = 3.356e+09 e = 3.356e+09 v = 2.27243e-07
D = 3.356e+10 e = 3.356e+10 v = 2.27243e-06
D = 3.356e+11 e = 3.356e+11 v = 2.27094e-05
D = 3.356e+12 e = 3.356e+12 v = 0.000226974
D = 3.356e+13 e = 3.356e+13 v = 0.00226974
D = 3.356e+14 e = 3.356e+14 v = 0.0227051
D = 3.356e+15 e = 3.356e+15 v = 0.227051
D = 3.356e+16 e = 3.356e+16 v = 0.269531
D = 3.356e+17 e = 3.356e+17 v = 0.6875
D = 3.356e+18 e = 3.356e+18 v = 0
J = 17

但是,如果你看看输出的第2行,你会发现:

D=3356 e=3356 v=2.27374e-1

因此,dTemp等于e,while循环仍在继续。

我尝试了什么:

  • 我想我可能是因为d无法存储所需的大数字。这就是我使用长双的原因

    • 我尝试了不同类型的变量,但最终总是得到相同的结果

直接检查浮点数/双数/长双数的等式/非等式不是一个好的做法。所以我建议使用类似的东西

不相等:

while (abs(dTemp - e) > 1e-12) { ... }

相等:

while (abs(dTemp - e) < 1e-12) { ... }

"微小"数字取决于非整数的类型(浮点或固定精度实数)。M-Gregoire关于使用std::numeric_limits<double>::epsilon()的评论听起来不错,但人们可能会再次面临问题。由于33.56不能计算为2的正和/或负幂的有限和,因此不能存储!总是有细微的差别。在内部,它是这样存储的:33.56000000000000227373675443232059478759766(我在perl中打印,但在c++中您会得到类似的结果)。因此,您可以将这个"微小"的差值设置为一个"适当"的值,这个值足够高,可以禁用这个内部浮点格式问题。

您可以使用另一种方法。std::ostringstream可以与操纵器setprecision一起使用,将精度设置为"正确"数字,将数字转换为字符串,然后计算字符串中的数字。但这也不是那么简单。

我也检查了c++中的值"33.56"。参见示例代码:

#include <iostream>
#include <iomanip>
int main() {
float df = 33.56;
double dd = 33.56;
long double dld = 33.56;
std::cout << std::setprecision(50) << df << std::endl;
std::cout << std::setprecision(50) << dd << std::endl;
std::cout << std::setprecision(50) << dld << std::endl;
}

输出为:

33.560001373291015625
33.56000000000000227373675443232059478759766
33.56000000000000227373675443232059478759766

因此,在浮动1e-5可以用于间隙值的情况下,对于双1e-14,在这种情况下似乎是正确的值。