Velocity Reviews > C++ > Help w/ Floats needed!

# Help w/ Floats needed!

Somebody
Guest
Posts: n/a

 05-18-2008
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!

Jim Langston
Guest
Posts: n/a

 05-18-2008
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
http://www.velocityreviews.com/forums/(E-Mail Removed)

James Kanze
Guest
Posts: n/a

 05-18-2008
On 18 mai, 06:43, "Somebody" <(E-Mail Removed)> 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:(E-Mail Removed)
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

Kai-Uwe Bux
Guest
Posts: n/a

 05-18-2008
James Kanze wrote:

> On 18 mai, 06:43, "Somebody" <(E-Mail Removed)> 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

Somebody
Guest
Posts: n/a

 05-18-2008
> 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
Guest
Posts: n/a

 05-18-2008
> 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
Guest
Posts: n/a

 05-18-2008

> 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
.

Paul Brettschneider
Guest
Posts: n/a

 05-18-2008
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.

James Kanze
Guest
Posts: n/a

 05-18-2008
On 18 mai, 20:02, "Somebody" <(E-Mail Removed)> 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:(E-Mail Removed)
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
Guest
Posts: n/a

 05-18-2008
On 18 mai, 20:05, "Somebody" <(E-Mail Removed)> 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:(E-Mail Removed)
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