double trouble

J

John Doe

I have a not-so-large double in the range 1-1000, but with fractional
part. I only do ++my_double to increment it, however sometimes it
happens that after incrementing

int(old_double) == int(new_double)

why? Again the doubles are not large at all, their exponents cannot be
so high to shift out the 1 I add out when incrementing and we have 64
bits to use here.
 
P

Puppet_Sock

I have a not-so-large double in the range 1-1000, but with fractional
part. I only do ++my_double to increment it, however sometimes it
happens that after incrementing

int(old_double) == int(new_double)

why? Again the doubles are not large at all, their exponents cannot be
so high to shift out the 1 I add out when incrementing and we have 64
bits to use here.

It's kind of hard to know without some code sample
that shows the behaviour. But it's just possible that
the ++ operation took you from <number that is so close
to integer N that it is indistinguishable to the int()>
to <number that is very close to N+1, but just enough
smaller that it is distinguishable to int()>.

I'm guessing that you are working with numbers that are
quite close to integer values.

Don't forget that doubles are stored in a floating point
format. It may be that you have found one of those spots
where you can't perfectly represent a real number as a
floating point. You may think you've got a slightly
smaller number for the old than you really do, and
you may think you've got a slightly larger value for
the new than you really do.

Generally speaking, you should be doing a different kind
of compare, if you really must compare floating point
values. You should be defining some kind of tolerance
for equality, then checking if the difference is less
than this tolerance. And you should be aware of such
issues as loss of accuracy due to subtracting numbers
that are very close to eachother.
Socks
 
V

Victor Bazarov

John said:
I have a not-so-large double in the range 1-1000, but with fractional
part. I only do ++my_double to increment it, however sometimes it
happens that after incrementing

int(old_double) == int(new_double)

why? Again the doubles are not large at all, their exponents cannot be
so high to shift out the 1 I add out when incrementing and we have 64
bits to use here.

First of all, a nit pick: you most likely only have 53 bits, not 64.
Second, can you provide a concrete example? And how do you know that
int(before) == int(after)? By looking at it in the debugger? The
only case I know where it would be true if the double in on (-1,0) to
begin with.

V
 
J

Jacek Dziedzic

John said:
I have a not-so-large double in the range 1-1000, but with fractional
part. I only do ++my_double to increment it, however sometimes it
happens that after incrementing

int(old_double) == int(new_double)

why? Again the doubles are not large at all, their exponents cannot be
so high to shift out the 1 I add out when incrementing and we have 64
bits to use here.

Casting to int truncates the fractional part. Some values do
not have a finite representation in binary format and so cannot
be stored in a double with infinite accuracy. I imagine the
scenario is something like (though not for number 42):

double x=42; // actually becomes x=42.00000000000001
int y=(int)x; // the fractional part is truncated, y becomes 42.
x++; // actually becomes x=42.99999999999999
int z=(int)x; // the fractional part is truncated, z becomes 42.
z==y; // true

... but this is just guessing.

HTH,
- J.
 
V

Victor Bazarov

Jacek said:
Casting to int truncates the fractional part. Some values do
not have a finite representation in binary format and so cannot
be stored in a double with infinite accuracy. I imagine the
scenario is something like (though not for number 42):

double x=42; // actually becomes x=42.00000000000001

That is very unlikely. Integers of this magnitude are represented
precisely in IEEE floats. It could be after some kind of imprecise
calcuation, of course.
int y=(int)x; // the fractional part is truncated, y becomes 42.
x++; // actually becomes x=42.99999999999999

That is not possible. How can adding 1 screw up the mantissa so
badly? See my analysis below.
int z=(int)x; // the fractional part is truncated, z becomes 42.
z==y; // true

... but this is just guessing.

Yep.

What's going on with the number when you add 1?

Before adding the FP number can be written (in binary form) as

1bbbbbb.bbbbbbbbbbbbbB (total of N binary digits)
^^^^^^^
K digits before binary point. 'B' is the last binary digit
in the representation.

After adding 1 we could have either

10000000.bbbbbbbbbbbbbb (total of N binary digits)
^^^^^^^
K zeros

which would mean the last digit ('B') is lost or rounded to make
the fraction slightly different. If it's rounded "down", it is
the same as throwing it out. If it's rounded up, you can end up
with a fraction that when rounded eventually turns into another 1
and is added to the integral part (for that you need the fractional
part full of 1s). In either case adding 1 cannot mean retaining
the integral part (it either grows by 1 or by 2).

We could have (after adding 1)

1bbbbbb.bbbbbbbbbbbbbB (total of N binary digits)
^^^^^^^
K (slightly different) digits before binary point. 'B' is
still the last binary digit, in which case the fraction does not
change at all, and simply cannot contribute to changing the
integral part.

V
 
J

John Doe

You were right c++ wizards:

x started low ~-1e-14, adding 1 to this produced, 0.something very close
to 1, but int(old_double) == int(new_double). Then there was additional
trouble: adding 1 to this repeatedly was producing numbers very close to
round(x) integers and then suddenly adding 1 rounded a
number_close_to_an_integer upwards and 1 integer was skipped by int(x),
say if you had

511.99999999999999999999

int() would produce 511, but if you'd add 1 to this and hence shifted it
right sufficient places, you might produce 513, instead of
512.99999999999999999999.

Anyway, std::round(x) solved my problem, thank you.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top