C sucks at math? (help)

J

Jordi

I have made a little C program that generates the following output:
227.000000 / 5 = 45.400002

Here's the code:
int main (int argc, char* argv[]) {
float var = 227;
printf("%f / 5 = %f\n", var, var / 5);
return 0;
}

Obviously, the output should be 45.4 (or 45.400000), but for some
mysterious reason C decided to add 0.000002* to the result. The error
might seem minor and this program is obviously trivial, but I need to
do similar calculations in a much bigger project and the problem I'm
encountering is caused by exactly this error.

* It seems that it is not .000002 is added, but rather
..0000015258789076710855... (which I found out after subtracting 45.4
from the result and then multiplying it with 10,000,000,000,000,000)

Why does C do this and what can I do about it?

Any help or tips are greatly appreciated!
 
I

Ian Collins

Jordi said:
I have made a little C program that generates the following output:
227.000000 / 5 = 45.400002

Here's the code:
int main (int argc, char* argv[]) {
float var = 227;
printf("%f / 5 = %f\n", var, var / 5);
return 0;
}

Obviously, the output should be 45.4 (or 45.400000), but for some
mysterious reason C decided to add 0.000002* to the result. The error
might seem minor and this program is obviously trivial, but I need to
do similar calculations in a much bigger project and the problem I'm
encountering is caused by exactly this error.

* It seems that it is not .000002 is added, but rather
..0000015258789076710855... (which I found out after subtracting 45.4
from the result and then multiplying it with 10,000,000,000,000,000)

Why does C do this and what can I do about it?
It doesn't, the floating point hardware or emulation does.

Floating point isn't precise. Avoid floats and use doubles, even then,
you have to understand the limitations of floating point math.

You must have a dodgy FPU, the result is 45.400000 on my system :)
 
W

Walter Roberson

I have made a little C program that generates the following output:
227.000000 / 5 = 45.400002
Here's the code:
int main (int argc, char* argv[]) {
float var = 227;
printf("%f / 5 = %f\n", var, var / 5);
return 0;
}

Your program uses undefined behaviour: you do not have a prototype
for printf() in scope.

[Admittedly, fixing that probably won't solve your difficulty ;-) ]
 
J

Jordi

Thanks for your reply!

I had just figured out that the emulation/casting was where it went
wrong and I was about to post it. I would probably not have thought of
using doubles anytime soon though (I thought they didn't exist in C and
that they were introduced with C++, which I normally use, or something,
thank God I'm wrong :p).
It seems that doubles work for the toy-program, so they probably will
for the entire project, but it's kind of big so I won't be altering it
right now (it's 2:36 am here).

By the way, I'm using an SSH program to log in on some old Macintosh
computer where the software is running, so that could probably be
considered 'dodgy'. :)

Anyway, thanks!


Ian said:
Jordi said:
I have made a little C program that generates the following output:
227.000000 / 5 = 45.400002

Here's the code:
int main (int argc, char* argv[]) {
float var = 227;
printf("%f / 5 = %f\n", var, var / 5);
return 0;
}

Obviously, the output should be 45.4 (or 45.400000), but for some
mysterious reason C decided to add 0.000002* to the result. The error
might seem minor and this program is obviously trivial, but I need to
do similar calculations in a much bigger project and the problem I'm
encountering is caused by exactly this error.

* It seems that it is not .000002 is added, but rather
..0000015258789076710855... (which I found out after subtracting 45.4
from the result and then multiplying it with 10,000,000,000,000,000)

Why does C do this and what can I do about it?
It doesn't, the floating point hardware or emulation does.

Floating point isn't precise. Avoid floats and use doubles, even then,
you have to understand the limitations of floating point math.

You must have a dodgy FPU, the result is 45.400000 on my system :)
 
N

Newsreader

see the attached link for an explanation on floating point numbers and why
they can be inaccurate. Simple answer is, blame your machine not the
compiler (because it usually the underlying machine code doing the floating
point work and making the "mistake")...

http://www.answers.com/topic/floating-point

go to the section titled "Problems with floating-point" for a detailed
reason...
 
G

Gordon Burditt

I have made a little C program that generates the following output:
227.000000 / 5 = 45.400002

There is no exact representation of most decimal numbers in binary
floating point. Float only claims to have 6 digits, and your output
is off by 2 counts in the 8th digit. You have little cause to complain
that you didn't get the accuracy advertised.

45.4 as float:
Before: 45.399997711181640625000000000000000000000000000000000000000000
Value: 45.400001525878906250000000000000000000000000000000000000000000
After: 45.400005340576171875000000000000000000000000000000000000000000

The three choices are shown above. The value you got was the closest
possible representation of the mathematically correct answer in an
IEEE 32-bit floating point number.
Obviously, the output should be 45.4 (or 45.400000), but for some

There is no such number exactly representable in binary floating point.
mysterious reason C decided to add 0.000002* to the result. The error
might seem minor and this program is obviously trivial, but I need to
do similar calculations in a much bigger project and the problem I'm
encountering is caused by exactly this error.

Then use a more precise floating-point value, like double or long double.
(That's just putting off the problem, though).
* It seems that it is not .000002 is added, but rather
.0000015258789076710855... (which I found out after subtracting 45.4
from the result and then multiplying it with 10,000,000,000,000,000)

Why does C do this and what can I do about it?

Use floating-point hardware with an infinite number of bits. Or,
if that's too expensive, just use MORE bits.

Gordon L. Burditt
 
J

Jordi

I said I wouldn't try doubles in the real project, but it didn't prove
that difficult and I couldn't let it rest. Anyway, it didn't work as
well as I hoped. This is some of the output I got:
x = 64.200000 / (107.000000 / 5) = 64.200000 / 21.400000 = 3.000000 = 2

Notice the 3.000000 = 2? That's what's screwing my program over.

Anyway, as I understand from you guys, I need infinite bits to get 100%
accuracy. That's probably not going to happen anytime soon, so I need
another solution. Is there a way to make the program use the calculated
3.000000 instead of the 2.9999999999999999999999999 it actually
calculated? Is there some way to specify how accurate I need things?

Thanks for any help!



Ian said:
Jordi said:
I have made a little C program that generates the following output:
227.000000 / 5 = 45.400002

Here's the code:
int main (int argc, char* argv[]) {
float var = 227;
printf("%f / 5 = %f\n", var, var / 5);
return 0;
}

Obviously, the output should be 45.4 (or 45.400000), but for some
mysterious reason C decided to add 0.000002* to the result. The error
might seem minor and this program is obviously trivial, but I need to
do similar calculations in a much bigger project and the problem I'm
encountering is caused by exactly this error.

* It seems that it is not .000002 is added, but rather
..0000015258789076710855... (which I found out after subtracting 45.4
from the result and then multiplying it with 10,000,000,000,000,000)

Why does C do this and what can I do about it?
It doesn't, the floating point hardware or emulation does.

Floating point isn't precise. Avoid floats and use doubles, even then,
you have to understand the limitations of floating point math.

You must have a dodgy FPU, the result is 45.400000 on my system :)
 
K

Keith Thompson

Jordi said:
I have made a little C program that generates the following output:
227.000000 / 5 = 45.400002

Here's the code:
int main (int argc, char* argv[]) {
float var = 227;
printf("%f / 5 = %f\n", var, var / 5);
return 0;
}

Obviously, the output should be 45.4 (or 45.400000), but for some
mysterious reason C decided to add 0.000002* to the result. The error
might seem minor and this program is obviously trivial, but I need to
do similar calculations in a much bigger project and the problem I'm
encountering is caused by exactly this error.

* It seems that it is not .000002 is added, but rather
.0000015258789076710855... (which I found out after subtracting 45.4
from the result and then multiplying it with 10,000,000,000,000,000)

Why does C do this and what can I do about it?

The comp.lang.c FAQ is at <http://www.c-faq.com/>. You've asked
question 14.1.
 
G

Gordon Burditt

I said I wouldn't try doubles in the real project, but it didn't prove
that difficult and I couldn't let it rest. Anyway, it didn't work as
well as I hoped. This is some of the output I got:
x = 64.200000 / (107.000000 / 5) = 64.200000 / 21.400000 = 3.000000 = 2

Notice the 3.000000 = 2? That's what's screwing my program over.

Anyway, as I understand from you guys, I need infinite bits to get 100%
accuracy. That's probably not going to happen anytime soon, so I need
another solution. Is there a way to make the program use the calculated
3.000000 instead of the 2.9999999999999999999999999 it actually
calculated? Is there some way to specify how accurate I need things?

Round it instead of truncating?

This is commonly done with
floor(x + 0.5)

You might also find it appropriate to use a small fudge factor (e.g. 0.01)
rather than doing normal rounding.

Gordon L. Burditt
 
P

pete

Jordi said:
I said I wouldn't try doubles in the real project,

doubles are for ordinary floating point calculations.
The type of (0.0), is double.
The %f format specifier for printf, is for type double.
The default argument promotions,
promote float types to type double.

Use float when you want the smallest float type.
(0.0f) is of type float.

Use long double when you want
the float type with the greatest range in C89.
 
W

Walter Roberson

I said I wouldn't try doubles in the real project, but it didn't prove
that difficult and I couldn't let it rest. Anyway, it didn't work as
well as I hoped. This is some of the output I got:
x = 64.200000 / (107.000000 / 5) = 64.200000 / 21.400000 = 3.000000 = 2
Notice the 3.000000 = 2? That's what's screwing my program over.

It looks to me as if you are doing an integer truncation of the value
that is approximately 3. If so, then you should consider rounding
the value instead.
Anyway, as I understand from you guys, I need infinite bits to get 100%
accuracy.

Yes, pretty much so.
That's probably not going to happen anytime soon, so I need
another solution. Is there a way to make the program use the calculated
3.000000 instead of the 2.9999999999999999999999999 it actually
calculated? Is there some way to specify how accurate I need things?

No, you cannot specify the accuracy.

Usually for problems such as this, you should do a numeric analysis
of the algorithm to figure out how to maximize the precision.

For any algorithm, there will be a maximum precision you could possibly
obtain by using double and carefully re-arranging the calculations.
If that precision is not enough, then you could consider using one
of the indefinite precision calculation libraries that are available
from various sources. Those libraries are not good substitutes for
realizing that, for example, 64.2 is not exactly representable in
standard binary floating point numbers, but sometimes the calculations
can be rejigged with rational numbers -- for example,
instead of 64.2, perhaps you could use 642/10 and a
rational- calculation package and only convert to floating point in the
final step.
 
I

inmatarian

Jordi said:
I said I wouldn't try doubles in the real project, but it didn't prove
that difficult and I couldn't let it rest. Anyway, it didn't work as
well as I hoped. This is some of the output I got:
x = 64.200000 / (107.000000 / 5) = 64.200000 / 21.400000 = 3.000000 = 2

Notice the 3.000000 = 2? That's what's screwing my program over.

Anyway, as I understand from you guys, I need infinite bits to get 100%
accuracy. That's probably not going to happen anytime soon, so I need
another solution. Is there a way to make the program use the calculated
3.000000 instead of the 2.9999999999999999999999999 it actually
calculated? Is there some way to specify how accurate I need things?

Thanks for any help!



Ian said:
Jordi said:
I have made a little C program that generates the following output:
227.000000 / 5 = 45.400002

Here's the code:
int main (int argc, char* argv[]) {
float var = 227;
printf("%f / 5 = %f\n", var, var / 5);
return 0;
}

Obviously, the output should be 45.4 (or 45.400000), but for some
mysterious reason C decided to add 0.000002* to the result. The error
might seem minor and this program is obviously trivial, but I need to
do similar calculations in a much bigger project and the problem I'm
encountering is caused by exactly this error.

* It seems that it is not .000002 is added, but rather
..0000015258789076710855... (which I found out after subtracting 45.4
from the result and then multiplying it with 10,000,000,000,000,000)

Why does C do this and what can I do about it?
It doesn't, the floating point hardware or emulation does.

Floating point isn't precise. Avoid floats and use doubles, even then,
you have to understand the limitations of floating point math.

You must have a dodgy FPU, the result is 45.400000 on my system :)

Eww, top posting.

What you need to do is figure out what degree of precision you need, and
after all of the calculations, perform your fix. See, your remark on 3.0
being equal to 2 makes me think you used a floor function in there
somewheres. Instead, use floor(x+0.5) to round to the nearest. Same if
use used and (int) cast. At any rate, this isn't C's fault, it's the
fault of IEEE's float specification, that says that you only need 32
bits of precision, instead of infinity.

Inmatarian.
 
B

Bill Pursell

Jordi said:
Anyway, as I understand from you guys, I need infinite bits to get 100%
accuracy.

Infinitely many bits doesn't give you "100% accuracy". You will
only be able to represent the algebraic numbers. If you
select a Real number at random, it will be transcendental
with probability 1, so you will be unable to represent nearly all
of them. (My Real Analysis is rusty, but I'm pretty sure
the algebraic numbers have measure 0, and less certain
that they are all representable with infinitely long binary
strings.)

In short, it's not C, nor the computer that is causing problems
here. It's the nature of mathematics. :)
 
K

Keith Thompson

Bill Pursell said:
Infinitely many bits doesn't give you "100% accuracy". You will
only be able to represent the algebraic numbers.
[...]

Sure, if you use one of those old-fashioned implementations that only
has aleph-null-bit floating-point. Any decent modern implementation
should provide at least aleph-one bits.

We should be getting the first computational results any eon now.
 
D

Dik T. Winter

>

>
> Infinitely many bits doesn't give you "100% accuracy". You will
> only be able to represent the algebraic numbers. If you
> select a Real number at random, it will be transcendental
> with probability 1, so you will be unable to represent nearly all
> of them. (My Real Analysis is rusty, but I'm pretty sure
> the algebraic numbers have measure 0, and less certain
> that they are all representable with infinitely long binary
> strings.)

Yup, definitely rusty. All real numbers are representable in infinitely
many bits.
 
D

Dik T. Winter

> "Bill Pursell said:
> >
> > Infinitely many bits doesn't give you "100% accuracy". You will
> > only be able to represent the algebraic numbers.
> [...]
>
> Sure, if you use one of those old-fashioned implementations that only
> has aleph-null-bit floating-point.

But than you can also represent all transcendental numbers.
 
R

Richard Tobin

No, that would be true for finite but arbitrarily long bit strings.
If you can have infinitely long strings, you can represent all the
reals. You may need a better editor to type in the initialiser
though.
Any decent modern implementation
should provide at least aleph-one bits.

Doesn't that have bit-order problems?

-- Richard
 
P

Peter Boettcher

Jordi said:
I said I wouldn't try doubles in the real project, but it didn't prove
that difficult and I couldn't let it rest. Anyway, it didn't work as
well as I hoped. This is some of the output I got:
x = 64.200000 / (107.000000 / 5) = 64.200000 / 21.400000 = 3.000000 = 2

Notice the 3.000000 = 2? That's what's screwing my program over.

Anyway, as I understand from you guys, I need infinite bits to get 100%
accuracy. That's probably not going to happen anytime soon, so I need
another solution. Is there a way to make the program use the calculated
3.000000 instead of the 2.9999999999999999999999999 it actually
calculated? Is there some way to specify how accurate I need things?

See "What Every Computer Scientist Should Know About Floating-Point
Arithmetic" by David Goldberg:

http://www.weblearn.hs-bremen.de/risse/RST/docs/goldberg.pdf


For comparing floating point values, I recommend

fabs(a-b) < tolerance

where you get to pick 'tolerance' based on your problem. fabs() is
for double, fabsf() for float.



-Peter
 
D

Dik T. Winter

> In article <[email protected]>,

>
> No, that would be true for finite but arbitrarily long bit strings.

And that is also false. Finite but arbitrarily long bit strings give
you only a subset of the rational numbers.

Rational numbers have either a finite representation or a representation
that will ultimately repeat (if the denominator is not a power of 2).
From the representation you can not distinguish irrational algebraic
numbers and transcendental numbers. But I think that most readers in
this newsgroup do not know what algebraic numbers are.
 

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,888
Messages
2,569,964
Members
46,294
Latest member
HollieYork

Latest Threads

Top