Re: Convert float to double - weird failure



tugboat90 said:

<snips>

Thank you for the responses, but I understand how the numbers are
represented inside of a computer. I think I phrased my question
wrong.

You seem to have misunderstood the answers, too, because the answer to your
question is indeed to do with how numbers are represented inside a
computer. BUT if you meant to ask why std::cout didn't interpret the
number in the way you expected, see the end of this article.

When I converted from a float to a double, why did it add random junk
at the end of the number instead of making it zeros? If the random
junk is there, how do I get rid of it?

Here's your original code:

Example:
// Define a float
float f = 1.20000;

// Cast into a double - after the cast, the value of "d" is
// is "1.20000498297"
double d = static_cast<double> (f);

Firstly, let's get rid of the idea that it's the cast that's the problem.
(You have to promise not to laugh at my C++, though. I'm not a great fan
of iostreams, and it probably shows.)

#include <iostream>
#include <iomanip>

int main()
{
float f = 1.20000;
double d = static_cast<double> (f);

std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint)
<< std::setprecision(16)
<< "double d has the value "
<< d
<< std::endl;
std::cout << "float f has the value " << f << std::endl;
return 0;
}

The output from this program is:
double d has the value 1.2000000476837158
float f has the value 1.2000000476837158

So it isn't the cast, okay? The float has the same problem.

But why? Let's see.

We know that we can represent 1 exactly, so let's reduce the problem to
that of representing 0.2 (that is, one fifth) exactly. To try to do this,
we'll use binary representation, with each column to the right of the
radix point having half the value of the column to its left. So 0.1 means
a half, 0.01 means a quarter, 0.001 means an eighth, and so on.

Now let's use a binary search technique to narrow quickly onto the exact
representation of one fifth. We'll get as close as we can with one bit,
then with two, and so on.

0.1 = 1/2 = 0.5 - too large
0.01 = 1/4 = 0.25 - too large
0.001 = 1/8 = 0.125 - too small
0.0011 = 3/16 = 0.1875 - too small
0.00111 = 7/32 = 0.21875 - too large
0.001101 = 13/64 = 0.203125 - too large
0.0011001 = 25/128 = 0.1953125 - too small
0.00110011 = 51/256 = 0.19921875 - too small
0.001100111 = 103/512 = 0.201171875 - too large
0.0011001101 = 205/1024 = 0.2001953125 - too large
0.00110011001 = 409/2048 = 0.19970703125 - too small
0.001100110011 = 819/4096 = 0.199951171875 - too small
0.0011001100111 = 1639/8192 = 0.2000732421875 - too large
0.00110011001101 = 3277/16384 = 0.20001220703125 - too large
0.001100110011001 = 6553/32768 = 0.199981689453125 - too small
0.0011001100110011 = 13107/65536 = 0.1999969482421875 - too small

The pattern is clear. You need an infinite number of 0011 repeats if you
want to get exactly one fifth. Computers don't have infinite storage, so
the computer has to use the best approximation it can.

Now, if your question is "why didn't std::cout round my result?", the
answer is simple: std::cout is not a mind-reader. If you want it to
display a round number, you're going to have to tell it how to do the
rounding. Look up <iomanip> in your C++ reference book.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
.



Relevant Pages

  • Re: Convert float to double - weird failure
    ... bill robertson wrote: ... Float 1.2 is uninterpreted hex 0x3f99999a ... It's converting the float representation of 1.2 which is 0x3f99999a to a double representation which is not even 0x3f99999a00000000. ... unsigned int mantissa:23; ...
    (comp.programming)
  • Re: strong/weak typing and pointers
    ... unintentionally got people upset before. ... your float struct doesn't have get_sign, ... ;) You're still dealing with the same representation, ... If the top 2 or 4 bytes can specify multiple interpretations ...
    (comp.lang.python)
  • Re: float -> double
    ... Let us take a float with the hexadecimal representation 0x3f800001. ... When converting to double, we get another 29 bits of precision, which means we can theoretically convert this number to any one of 536,870,912 possible representable numbers in the range. ... The exact value could be printed if you really wanted to, but there's no real point since the implicit error in the number dwarfs most of the latter digits. ...
    (comp.lang.java.programmer)
  • Re: floating-point float
    ... > Why are float in C code different from fixed-point float? ... difference is that reals are the sum of an integer and a fractional part. ... use our representation consistently and it poses no fundamental roadblocks ...
    (comp.lang.c)
  • Re: Question
    ... Is that just a historial reason? ... There is no "default real number representation". ... The REAL type in Lisp is a super-type of RATIONAL and FLOAT. ...
    (comp.lang.lisp)