-2
d = 92.345; //it is of double type
scnt = 92; //it is of int type
//cout<<scnt;
int d1 =  (d-scnt)*10;
int d2 =  ((d-scnt)*100)-(d1*10);
int d3 =  ((d-scnt)*1000) - ((d1*100)+d2*10);//same equation if we print in cout gives actual answer
bool f1, f2;
cout<<"original value : "<<((d-scnt)*1000) - ((d1*100)+d2*10)<<endl;
cout<<"d3 : "<<d3<<endl;

if you try to run the above code snippet, you'll notice that value storing in d3 variable is one less than the actual answer. I am expecting the value stored in d3 should be 5 but it is 4. If I take data type as double for d3, then it is working fine. But further code requires the data type for d3 as int , so I can't change it. Is it safe if I simply increment d3 by 1 after calculating it on line 6?

SABER
  • 373
  • 6
  • 17
  • Please [edit] your question and make clear what output you get and what output you expect. Also confirm that `d` is double and `scnt` is `int`. – Jabberwocky Apr 18 '18 at 04:50
  • I guess: `d3` is `int` type. When you assign a floating point number to an integer type variable, the floating point number would be truncated into an integer. For example, a floating point number `2.9` becomes `2`, which is an integer. – R zu Apr 18 '18 at 04:50
  • 2
    Do all your calculations as double and then truncate to an int only for the final result to avoid cumulative rounding errors. – Jonathan Potter Apr 18 '18 at 04:51
  • Nah. The difference between `d3` and the correct floating point value may be any number between 0 and 1 for different `d`. So if you try to "fix" this by adding 1, it would be wrong in many cases. For example, I can set `d` to a different number in first line of your program, then you can't fix `d3` by the same way. By the way, are you supposed to get an integer answer? If that is the case, do you want round up or round down? What is the program supposed to do? – R zu Apr 18 '18 at 04:55
  • yeah i thought so, fixing it by adding 1 is really bad idea... @Rzu – SABER Apr 18 '18 at 04:59
  • d = 92.345, i want d1 = 3, d2 = 4, and d3 = 5(decimal values upto 3 decimals) @Rzu – SABER Apr 18 '18 at 05:03
  • 1
    Tell us what the program is supposed to do. Very clearly. No ambiguity. Otherwise, we don't know what to do... Like: "The input the total value of coin put into the machine as an integer and in unit of cents. The output is the total value of coin returned to the customer, after he buys a soda. The program calculates the output by the following formula..." Don't just list the possible combinations of coins that you can put into a vending machine... – R zu Apr 18 '18 at 05:05
  • Hmm, Let me try to put it in this way... I am giving you a double value for e.g 22.345162734968(it can be anything) , now the only thing I care about is first 3 decimal digits and i want to store them in int variable d1, d2 and d3 having values 3, 4, 5 respectively in this example. But I am getting problem while calculating d3 value cause the value I'm getting here is one lesser than the actual value i.e 5 – SABER Apr 18 '18 at 05:18
  • You should [edit] your question to make it clear. Consider reading [ask] and [mcve] again. Anyhow, your misconception is that a double has decimal digits. It has binary digits, so conversions between the two may involve rounding. – Ulrich Eckhardt Apr 18 '18 at 05:28
  • Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – 1201ProgramAlarm Apr 18 '18 at 05:41
  • @1201ProgramAlarm and why is that duplicate? – SABER Apr 18 '18 at 05:49

2 Answers2

0

I guess that you are trying to get each decimal in a int variable from a double number. If you see the results by this code shown step by step:

double d = 92.345;
int scnt = 92;
int d1 =  (d-scnt)*10;
cout << d1 << endl;
cout << (d-scnt)*10 << endl;
int d2 =  ((d-scnt)*100)-(d1*10);
cout << d2 << endl;
cout << ((d-scnt)*100)-(d1*10) << endl;
int d3 =  ((d-scnt)*1000) - ((d1*100)+d2*10);
cout << d3 << endl;
cout << ((d-scnt)*1000) - ((d1*100)+d2*10) << endl;

So the printed results are:

d1 = 3
calculated d1 = 3.45
d2 = 4
calculated d2 = 4.5
d3 = 4
calculated d3 = 5

So, the fact that you are getting a 4 in the int and in cout a 5 is because, 92.345 is not a double valid representable number, in fact is a 92.344999999999999 so, by each integer multiplication you loose precision, but cout treats those numbers as a double, so cout roundes up those nines.

At low level all the operations are exactly the same, except for the storing or showing part, thats the only difference.

  mov DWORD PTR [rbp-24], eax //Int saving

  mov edi, OFFSET FLAT:std::cout //Cout displaying
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(double)
  mov esi, OFFSET FLAT:std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
  mov rdi, rax
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))

For more, if you do this:

if (((d - scnt) * 1000) - ((d1 * 100) + d2 * 10) == ((d - scnt) * 100) - (d1 * 10)) {
        cout << "lol" << endl;
    }

The "lol" won't be printed. Hope it helped.

petacreepers23
  • 164
  • 1
  • 9
0

The cause of your problem is a fundamental property of floating point types. Have a look here for more information.

In your specific case, the value of 92.345 cannot be represented exactly in a floating point type. A fraction 1/3 cannot be represented in a finite number of decimal (base 10) places (infinitely recurring term). The same effect occurs with floating point, except that floating point values are in binary (base 2). Trying to represent 0.345 in binary (i.e. as a sum of negative powers of two) requires an infinite number of binary digits.

A consequence of this is that the literal 92.345, when stored in any floating point variable (of type float, double, long double) ete, will have a value that is not exactly equal to 92.345.

The actual value depends on how floating point variables are represented on your system but, presumably, on your system the actual value is slightly less than 92.345.

This will affect your calculations (assuming d is of a floating point type).

int d1 =  (d-scnt)*10;        
int d2 =  ((d-scnt)*100)-(d1*10);
int d3 =  ((d-scnt)*1000) - ((d1*100)+d2*10);

will be subject to rounding errors, for the floating point calculations. The calculation (d-scnt)*10 will produce a value slightly less than 3.45, which means d1 will have a value 3. Similarly, d2 will get a value of 4. The problem (in this example) comes in computing d3, since (d-scnt)*1000 will give a floating point value slightly less than 345, and subtracting ((d1*100)+d2*10) will give a floating point value that is slightly less than 5. Conversion to int rounds towards zero, so d3 will end up with a value of 4, as you describe.

Incrementing d3 to "fix" the problem is a really bad idea, since floating point rounding can go either way. You will find other values of d for which rounding cuts the other way (the value as a double is slightly greater than you expect). There are also values for which your code will produce the behaviour you expect, without modification.

There are various ways to deal with the problem.

One way is to print the value to a string with the required number of digits. This can be done readily using std::ostringstream (from standard header <sstream>). This will convert 92.345 to the string "92.345". From there, you can extract the digits from the string.

Another way - which I would prefer - is to write your calculations to properly account for floating point rounding. In C++11 and later, you can use round() from <cmath> as follows.

int d1 =  round((d-scnt)*10);
int d2 =  round((d-scnt)*100)-(d1*10);
int d3 =  round((d-scnt)*1000) - ((d1*100)+d2*10);

or (to be really explicit about where conversions from double to int are occurring)

int d1 =  static_cast<int>(round((d-scnt)*10));
int d2 =  static_cast<int>(round((d-scnt)*100)) -(d1*10);
int d3 =  static_cast<int>(round((d-scnt)*1000)) - ((d1*100)+d2*10);

Before C++11 (which did not supply round()), the effects of round(x) can be roughly emulated as floor(x + 0.5)

Peter
  • 35,646
  • 4
  • 32
  • 74