# Help w/ Floats needed!

Discussion in 'C++' started by Somebody, May 18, 2008.

1. ### SomebodyGuest

Hi guys... quick question about floats...

I have a point "int x", and a width "int cx". In order to support scaling, I
store this as "double ratio = x / cx" which invariably led to round off
errors when I tried to re-calculate the new position from the ratio as in:

x = ratio * cx;

I tried to solve this by multiplying the numerator by 10,000 to gain more
precision... recent testing showed that I had not solved the problem in all
cases. Thinking about it, no matter how many times I multiply the numerator
of a fraction, I'll never be able to recover 100 from 1/3 (0.333333....) for
example.

I came up with this idea: instead of storing "double ratio = x / cx", I will
store int numerator=x, int denominator = cx;

That way, in my case off 1/3, I'll be able to fully recover the original
value. Ie...:

original pos = 33
original width = 100

num = 33;
denom = 100;

new width = num * 100 / denom = 33;

Does this sound like a reasonable solution (with ABSOLUTELY ZERO LOSS OF
PRECISION)? Or is there a better way?

Thanks!

Somebody, May 18, 2008

2. ### Jim LangstonGuest

Somebody wrote:
> Hi guys... quick question about floats...
>
> I have a point "int x", and a width "int cx". In order to support
> scaling, I store this as "double ratio = x / cx" which invariably led

This might be your problem right here.

double ratio = x / cx;
is going to do interger math because x is an interger and cx is an integer.

Proof of this is in a small test program which outputs
0

#include <iostream>

int main()
{
int x = 1;
int y = 3;
double z = x / y;

std::cout << z << "\n";
}

So, what to do? Cast x to a double.
Change the line in the program to:
double z = static_cast<double>( x ) / y;
and the output is
0.333333

> to round off errors when I tried to re-calculate the new position
> from the ratio as in:
> x = ratio * cx;

[SNIP]

--
Jim Langston

Jim Langston, May 18, 2008

3. ### James KanzeGuest

On 18 mai, 06:43, "Somebody" <> wrote:
> I have a point "int x", and a width "int cx". In order to
> support scaling, I store this as "double ratio = x / cx" which
> invariably led to round off errors when I tried to
> re-calculate the new position from the ratio as in:

> x = ratio * cx;

> I tried to solve this by multiplying the numerator by 10,000
> to gain more precision... recent testing showed that I had not
> solved the problem in all cases. Thinking about it, no matter
> how many times I multiply the numerator of a fraction, I'll
> never be able to recover 100 from 1/3 (0.333333....) for
> example.

No.

> I came up with this idea: instead of storing "double ratio = x
> / cx", I will store int numerator=x, int denominator = cx;

> That way, in my case off 1/3, I'll be able to fully recover the original
> value. Ie...:

Not unless your doubles use a base 3, or a power of 3.

> original pos = 33
> original width = 100

> num = 33;
> denom = 100;

> new width = num * 100 / denom = 33;

> Does this sound like a reasonable solution (with ABSOLUTELY
> ZERO LOSS OF PRECISION)?

You haven't really specified the problem. Zero loss of
precision isn't possible with a finite representation, so you

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze, May 18, 2008
4. ### Kai-Uwe BuxGuest

James Kanze wrote:

> On 18 mai, 06:43, "Somebody" <> wrote:
>> I have a point "int x", and a width "int cx". In order to
>> support scaling, I store this as "double ratio = x / cx" which
>> invariably led to round off errors when I tried to
>> re-calculate the new position from the ratio as in:

>
>> x = ratio * cx;

>
>> I tried to solve this by multiplying the numerator by 10,000
>> to gain more precision... recent testing showed that I had not
>> solved the problem in all cases. Thinking about it, no matter
>> how many times I multiply the numerator of a fraction, I'll
>> never be able to recover 100 from 1/3 (0.333333....) for
>> example.

>
> No.
>
>> I came up with this idea: instead of storing "double ratio = x
>> / cx", I will store int numerator=x, int denominator = cx;

>
>> That way, in my case off 1/3, I'll be able to fully recover the original
>> value. Ie...:

>
> Not unless your doubles use a base 3, or a power of 3.
>
>> original pos = 33
>> original width = 100

>
>> num = 33;
>> denom = 100;

>
>> new width = num * 100 / denom = 33;

>
>> Does this sound like a reasonable solution (with ABSOLUTELY
>> ZERO LOSS OF PRECISION)?

>
> You haven't really specified the problem. Zero loss of
> precision isn't possible with a finite representation, so you

Well, the OP does not want to store arbitrary real numbers. All the
rescaling factors he wants to store arise as ratios of ints. In that case,
storing the two ints does represent the ratio without loss of precision.

Best

Kai-Uwe Bux

Kai-Uwe Bux, May 18, 2008
5. ### SomebodyGuest

> So, what to do? Cast x to a double.
> Change the line in the program to:
> double z = static_cast<double>( x ) / y;
> and the output is
> 0.333333

I know that ... I was only including psuedo-code... but the point is:

double x = 100;
double cx = 300;
double ratio = x / cx; // = 0.33333

double newwidth = 300;
double newpos = ratio * newwidth; // result = 99, NOT 100 which is what it
should be.

My solution of storing the numerator and denomenator to get a real scaling
factor worked.

Somebody, May 18, 2008
6. ### SomebodyGuest

> That way, in my case off 1/3, I'll be able to fully recover the original
> value. Ie...:

>Not unless your doubles use a base 3, or a power of 3.

Huh? What does this have to do with 3's?

My point was, in the case of a 1/3 ratio (or any ratio with an infinite
repeating decimal), I'll never be able to recalculate the numerator exactly
given the denomenator and ratio.

But by storing the numerator and denomenator as ints instead of a ratio, I
would.

Somebody, May 18, 2008
7. ### SomebodyGuest

> Well, the OP does not want to store arbitrary real numbers. All the
> rescaling factors he wants to store arise as ratios of ints. In that case,
> storing the two ints does represent the ratio without loss of precision.
>
>
> Best
>
> Kai-Uwe Bux

Thanks Kai-Uwe. Seems like you are the only one who understood the question
.

Somebody, May 18, 2008
8. ### Paul BrettschneiderGuest

Somebody wrote:

>> So, what to do? Cast x to a double.
>> Change the line in the program to:
>> double z = static_cast<double>( x ) / y;
>> and the output is
>> 0.333333

>
> I know that ... I was only including psuedo-code... but the point is:
>
> double x = 100;
> double cx = 300;
> double ratio = x / cx; // = 0.33333
>
> double newwidth = 300;
> double newpos = ratio * newwidth; // result = 99, NOT 100 which is what it
> should be.

#include <iostream>

int main()
{
double x = 100;
double cx = 300;
double ratio = x / cx;

double newwidth = 300;
double newpos = ratio * newwidth;

std::cout << newpos << std::endl;
}

gives 100 for me. Of course the internal representation might correspond to
99.99999 or something like that but *definitely* not something closer to 99
than to 100.

Paul Brettschneider, May 18, 2008
9. ### James KanzeGuest

On 18 mai, 20:02, "Somebody" <> wrote:
> > So, what to do? Cast x to a double.
> > Change the line in the program to:
> > double z = static_cast<double>( x ) / y;
> > and the output is
> > 0.333333

> I know that ... I was only including psuedo-code... but the point is:

> double x = 100;
> double cx = 300;
> double ratio = x / cx; // = 0.33333

> double newwidth = 300;
> double newpos = ratio * newwidth; // result = 99, NOT 100 which is what it
> should be.

Are you kidding? The result won't be 100.0, but it will
be fairly close to 100. (In fact, it might actually end up as
100.0; it does on my machine, anyway. But of course, you can't
count on it; you can only count on it being fairly close.)

> My solution of storing the numerator and denomenator to get a
> real scaling factor worked.

It's guaranteed to be 100% accurate. And very slow, and liable
to overflow in integral arithmetic. Depending on the
application, it might be what's needed, or it might not be.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze, May 18, 2008
10. ### James KanzeGuest

On 18 mai, 20:05, "Somebody" <> wrote:
> > That way, in my case off 1/3, I'll be able to fully recover the original
> > value. Ie...:
> >Not unless your doubles use a base 3, or a power of 3.

> Huh? What does this have to do with 3's?

The fraction 1/3 will only be exactly representable in a double
if the base of the double is 3 or a multiple of 3.

> My point was, in the case of a 1/3 ratio (or any ratio with an
> infinite repeating decimal), I'll never be able to recalculate
> the numerator exactly given the denomenator and ratio.

> But by storing the numerator and denomenator as ints instead
> of a ratio, I would.

That's one solution. If the target value is an int, after
rescaling, it's probable that the double will store the ratio
with enough precision, provided that you round the results
correctly.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze, May 18, 2008
11. ### SomebodyGuest

>Are you kidding? The result won't be 100.0, but it will
>be fairly close to 100. (In fact, it might actually end up as
>100.0; it does on my machine, anyway. But of course, you can't
>count on it; you can only count on it being fairly close.)

Fairly close to 100 is not 100, now is it? . In fact, when I convert it to
an int, it would get truncated down to 99.

Imagine this scenario to explain why I needed it EXACT. You have an object
on the screen at x,y = 100,100. You do something on the screen that causes
the layout to be recalculated and suddenly the object moves to 99,99. Not
very good.

Somebody, May 18, 2008
12. ### SomebodyGuest

> gives 100 for me. Of course the internal representation might correspond
> to
> 99.99999 or something like that but *definitely* not something closer to
> 99
> than to 100.

Hmm... so it does for me too (in a test app). I was definitely seeing round
off errors in my layout when I was using doubles. Possible I might have had
that because of the way I did the casting throughout the algorithm. Oh well,
its working with the int pair solution. No point in going back to try to
figure it out.

Somebody, May 18, 2008
13. ### Thomas J. GritzanGuest

Somebody schrieb:
>> Are you kidding? The result won't be 100.0, but it will
>> be fairly close to 100. (In fact, it might actually end up as
>> 100.0; it does on my machine, anyway. But of course, you can't
>> count on it; you can only count on it being fairly close.)

>
> Fairly close to 100 is not 100, now is it? . In fact, when I convert it to
> an int, it would get truncated down to 99.
>
> Imagine this scenario to explain why I needed it EXACT. You have an object
> on the screen at x,y = 100,100. You do something on the screen that causes
> the layout to be recalculated and suddenly the object moves to 99,99. Not
> very good.

You could try rounding the double to nearest integer when converting to int:

int roundToNearest(double d)
{
return static_cast<int>(d + 0.5);
}

This will round values in the range [98.5, 99.5) to 99 and [99.5, 100.5)
to 100. Simple casting to int will round the value down.

--
Thomas

Thomas J. Gritzan, May 18, 2008
14. ### James KanzeGuest

On May 18, 9:58 pm, "Somebody" <> wrote:
> >Are you kidding? The result won't be 100.0, but it will
> >be fairly close to 100. (In fact, it might actually end up as
> >100.0; it does on my machine, anyway. But of course, you can't
> >count on it; you can only count on it being fairly close.)

> Fairly close to 100 is not 100, now is it? . In fact, when I
> convert it to an int, it would get truncated down to 99.

If you want it rounded to a certain precision, you round it to
that precision. If you round the value to an int, you'll get
100, and not 99.

> Imagine this scenario to explain why I needed it EXACT. You
> have an object on the screen at x,y = 100,100. You do
> something on the screen that causes the layout to be
> recalculated and suddenly the object moves to 99,99. Not very
> good.

So round correctly when you need to determine the pixel.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze, May 19, 2008
15. ### Frank BirbacherGuest

Hi!

Somebody schrieb:
> My point was, in the case of a 1/3 ratio (or any ratio with an infinite
> repeating decimal), I'll never be able to recalculate the numerator exactly
> given the denomenator and ratio.

Although your statement is logically correct the reverse it not:

Not every finite decimal (that is no repeating decimal) is exactly
representable as a float/double.

The point is: you must not forget that doubles are 2-based and not
10-based. That's why a number like 0.3 cannot be exactly stored in a
double, because it has an infinitly repeating binary representation. But
0.25 can (one fourth, or 0.01 in binary, or 1e-2 in binary).

You must learn that floating point calculations are not exact. You must
learn there is no operator == in floating point math. For your problem
either use proper rounding or fractional numbers (as you proposed).

Regards,
Frank

Frank Birbacher, May 20, 2008