0

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 :

  • I though I could be due to d not being able to store a number as big as needed. This is why I used a long double

    • I tried different types of variables but I always end up with the same result.
STF
  • 1,485
  • 3
  • 19
  • 36
M-Gregoire
  • 808
  • 9
  • 22
  • 2
    It is not correct to compare floating point numbers like this. I suggest you read about floating point numbers and look at these questions: [q1](http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison) or [q2](http://stackoverflow.com/questions/588004/is-floating-point-math-broken?rq=1). – Elad Joseph May 25 '16 at 07:33
  • I get different outputs in visual studio and on Ideone(c++14). – Gaurav Sehgal May 25 '16 at 07:39
  • Counts the number of digits in what? The number of binary digits in a `double` is fixed at 53, and the number of decimal digits is indeterminate. Your purpose remains obscure and probably unimplementable. – user207421 May 25 '16 at 07:54

1 Answers1

3

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.

TrueY
  • 7,360
  • 1
  • 41
  • 46
  • I used this function `bool areSame(double a, double b) { return fabs(a - b) < std::numeric_limits::epsilon() ; }` to compare my double and It now works ! I've always learned at school that you can compare double as I did ! Thanks for the explanation – M-Gregoire May 25 '16 at 07:41
  • Would It be a bad idea to surcharge the operator== for double to use this function instead of the standard one ? – M-Gregoire May 25 '16 at 07:44
  • downvoted the answer since the precision is usually much worse than 1e-20 – user31264 May 25 '16 at 07:45
  • The number presented on the output and the number stored internally can be different, maybe in the 1e-20 magnitude. So to compare not integer data better to use the method shown above. – TrueY May 25 '16 at 07:47
  • @user31264 You are right! The number depends on the type of the real number. M-Gregoire's comment about using `std::numeric_limits::epsilon()` sounds good... – TrueY May 25 '16 at 07:49