M-Gregoire
M-Gregoire

Reputation: 818

Error while comparing a int and a double

I'm trying to make a simple function that count the number of digits. I have some written some function that work perfectly but I'm stuck on this one :

// 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;

The output is :

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

But, if you look at line 2 of the output, you have :

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

So, dTemp is equal to e and the while loop still continues.

What I tried :

Upvotes: 0

Views: 109

Answers (1)

TrueY
TrueY

Reputation: 7610

It is not a good practice to check equation/not equation of float/double/long double numbers directly. So I suggest to use something like this

Not equal:

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

Equal:

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

The "tiny" number depends on the type of the not-integer number (floating point or fixed precision real). M-Gregoire's comment about using std::numeric_limits<double>::epsilon() may sound good, but one may face to a problem again. As 33.56 cannot be calculated as a finite sum of positive and/or negative powers of 2, so it cannot be stored! Always there are itsy-bitsy differences. Internally it is stored like this: 33.56000000000000227373675443232059478759766 (I printed in , but in you get similar result). So you may set this "tiny" difference value to a "proper" value, which is high enough to disable this internal float format problem.

You may use another approach. An std::ostringstream could be used with manipulator setprecision setting the precision to a "proper" number to convert the number to string and then count the digits in the string. But it as also not that simple.

I checked the value '33.56' in as well. See the example code:

#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;
}

The output is:

33.560001373291015625
33.56000000000000227373675443232059478759766
33.56000000000000227373675443232059478759766

So in case of float 1e-5 could be used for the gap value, for double 1e-14 seems to be the right value in this case.

Upvotes: 3

Related Questions