## X * 1/Y != X/Y

39 posts / 0 new
Author
Message

I have run into this issue:
float Y=123;
float X;
X * 1/Y != X/Y //They are not equal !!

The compiler can't handle 1/Y.

Another example, X + 1/Y is also wrong, where Y is a constant. I have to calculate 1/Y manually.

Y=123;
float X;
X + 1/Y != X + 0.00813008

Why is this?

HAve you tried putting parenthesis around things?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Try Googling C Operator Precedence, You'll find that it is doing what you are telling it to do. Take Johns suggestion and use parenthesis. I have in the past been yelled at for saying "Do not memorize operator precedence, use parenthesis instead" but you can see how such advice might have saved you some trouble.

Ah, what the hey, from Workshop 4:

Quote:

Precedence and Order of Evaluation
When a statement has a sequence of operators such as:

x = 50 + 10 / 2 â€“ 20 * 4;

The compiler follows an order of calculation based on operator precedence. But what the compiler does, may not be what you intended. Calculate the value of x. Did you get 40? If you performed the calculations sequentially beginning at the left you get:

x = 50 + 10 / 2 â€“ 20 * 4
x = 60 / 2 â€“ 20 * 4
x = 30 â€“ 20 * 4
x = 10 * 4
x = 40

So the answer is 40, right? Wrong, according to C it is â€“25. The compiler does the division and multiplication first, then the addition and subtraction:
x = 50 + 10 / 2 â€“ 20 * 4
x = 50 + 10 / 2 â€“ 80
x = 50 + 5 â€“ 80
x = 55 â€“ 80
x = -25

Some C gurus will memorize the precedence and associativity table and actually write statements like x = 50 + 10 / 2 â€“ 20 * 4. Such clever programmers are dangerous and should be avoided when possible. The Germans have a word for clever: kluge, and in programming â€˜klugeâ€™ is a well-deserved insult. Donâ€™t be clever be clear. Clever programming is difficult to read and understand. If the clever programmer gets run over by a truck (hopefully) his code will be inherited by some poor guy who will have to figure things out. DO NOT memorize the Table of Operator Precedence and Associativity in C (which I refuse even to show). DO use â€™(â€˜ and â€˜)â€™ to make your program clear!

Which is clearer:
x = 50 + 10 / 2 â€“ 20 * 4;
or:
x = 50 + (10 / 2) â€“ (20 * 4);

The second adds nothing for the compiler, but tells the reader what you intended. What if you really meant to have the operations performed in the order listed? Then you would write:
x = ((((50 + 10) / 2) â€“ 20) * 4);

Which would make x = 40. The parentheses can get mighty confusing, but not nearly as confusing as their absence.

Hmmm... where did I put those asbestos long-johns?

Smiley

And you have to be aware of the data types involved.
1 is not equal to 1.0 and 1/3 is not equal to
1.0/3.0.

Smiley,
I guess I'm not understanding how this is a precedence problem.

The precedence of C for math operators is the same as that for math equations. While I tend to often use parens for clarity I don't see anything wrong with not using them in mathematical expressions as the precedence for mathematical operators is taught in grade school math class and should be well understood by those programming.

* and / are higher than + and -
and when there are multiple of the same precedence they go left to right.

So the original questions were how come

When Y = 123

X * 1 / Y != X / Y

There is a * not a +, so these two should be equal. At least I would think so.
And they are equal for i386 GCC on my windows PC.
(Haven't tried this with avr-gcc yet)

and

X + 1/Y != X + 0.00813008

The second one I can understand as 1/123
is not 0.00813008
There are other digits to the right of the 8 that are not zero.

So maybe this is a simple case of hand miscalculating 1/123 ?

I'm off to try this on avr-gcc.

--- bill

As far as I remember 1/3 is evaluated as int/int
and the value of int/int is the integer pat of int/int.
So 1/3 is 0 and the 0 is an int. I think
it has to do with type promotion rules.

How large or small is X, actually?

Remember this is 32-bit floating-point numbers, with about
6...7 decimal digits of precision. So if your X is larger

Also, comparing floating-point numbers for (un)equality is
not useful most of the time, because there's always a good
chance they differ by a single bit in their mantissa (so they
compare unequal). The most notable exception from this rule
is to compare against an absolute zero (which has the bit
pattern 0x00000000).

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

Ok, so since I use floats & doubles so rarely. (I think on 3-4 projects in the past 25 years),
I guess I'm a bit rusty on my float vs double sizes and precision.

I have a test program compiled with GCC on on windows and avr-gcc.

With GCC on the PC, the first expression is equal but not the second as 1/123 has more significant digits.
(I used a value of 20 for X)

On avr-gcc both are equal.

I do have one question:

If I use percent f and try to printf a float, I get a prototype compiler error that percent f is for doubles.

In looking at the avr libc documentation format string of percent f on printf() is for doubles yet percent f on scanf() is for floats.

I can print doubles using percent f on avr-libc.
and if you change the floats to double then the behavior of avr-gcc is just like the PC version of gcc using floats.
1st expression is equal but second is not.

So how the heck do you print floats with avr-libc?
I thought f was floats and lf was for doubles.

I am using the floating point vprintf and the -lm math library.

--- bill

Testing for equality with floats is always prone to difficulties, precisely because they are an imperfect representation of real numbers. It is good practice to formulate your algorithms to use inequality comparisons of floating point types instead of equality comparisons.

bperrybap wrote:
So how the heck do you print floats with avr-libc?
avr-gcc uses the same representation for floats as for doubles (the C standard merely dictates that doubles must be at least as precise as floats, so this is a standards-compliant thing to do). Thus you can just:
```#include

float x;

printf("#f\n", (double)x); // % replaced with # for the usual reason
```

and it will work and compile without warning.

Christopher Hicks
==

Quote:

float Y=123;
float X;
X * 1/Y != X/Y //They are not equal !!

The compiler can't handle 1/Y.

Try it with Y=10 even - the fact is that binary fractions simply cannot hold some fractions accurately. Decimal fractions aren't exempt from this effect. In decimal fractions you simply cannot represent 1/3rd because the decimal fraction is 0.3333333... recurring.

In the same way 1/10 cannot be expressed accurately in binary.

Go to this page (for an example of one of many onlne IEEE754 converters):

http://www.h-schmidt.net/FloatAp...

and type "0.1" into the decimal representation box. Note the hex representation: 3DCCCCCD - if this were held in a wider representation the 'C's would go on recurring infinitely but in this case the last nybble is rounded up to 'D' and hence the number is actually just a shade over 0.1

This inaccuracy is just one of the many reasons to avoid floats in a microcontroller.

Cliff

http://en.wikipedia.org/wiki/Flo...

Last Edited: Tue. Oct 27, 2009 - 10:36 AM

One should never use == != on floats !!!
But ABS(x)<0.000001 or something like that.
When numberes can't be made exat in 2(power n)*x
there will be a rounding and it's pure luck if the
result is the same.
If you need speed you can just see if the exponent is small.

Jens

Pedantic perhaps, but the "#f" specifier requires a float argument, and "#lf" a double argument.

Both versions will work fine with most AVR compilers. But one day you will port the code to an ARM or use a compiler with real doubles.

David.

Quote:

Pedantic perhaps, but the "#f" specifier requires a float argument, and "#lf" a double argument.

This isn't what the AVR-LibC manual says:
Quote:
fF The double argument is rounded and converted to decimal notation in the format "[-]ddd.ddd", where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; if the precision is explicitly zero, no decimal-point character appears. If a decimal point appears, at least one digit appears before it.

See

http://www.nongnu.org/avr-libc/u...

sparrow2 has it right, see attached and http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

## Attachment(s): NeverUseEquals.c

I wrote:
It is good practice to formulate your algorithms to use inequality comparisons of floating point types instead of equality comparisons.

NeverUseEquals.c wrote:

```#include

main()
{
double x = 2;
while(x != 0)
{
printf("#lf\n", x); // percent bug on forum
x -= 0.2;
}
return 0;
}
```

```#include

main()
{
double x = 2;
while(x > 0)
{
printf("#lf\n", x); // percent bug on forum
x -= 0.2;
}
return 0;
}
```

and you get the behaviour that is (presumably) desired.

CH
==

sparrow2 wrote:
One should never use == != on floats !!!
But ABS(x)<0.000001 or something like that.

That wouldn't work either: the very point of using float is to be able to work with nubers far down or up the scale.

Maybe abs((x - y) / x) would be more appropriate, except the potential divide by zero.

Maybe we should appeal to the standard-makers and library-makers to include a close_enough() function into the standard float libraries... ;-)

JW

The desired behavior of the program is to demonstrate that == and != are EVIL when used in floating-point arithmetic :-)

Even "while(x > 0)" won't work reliably as X might end up ever so slightly larger than 0 causing the loop to run one too many times.

sprinkmeier wrote:
Even "while(x > 0)" won't work reliably as X might end up ever so slightly larger than 0 causing the loop to run one too many times.
Or it might not, but it's a fair point none the less.

CH
==

close_enough() function

You need to figure out if you're interested in the absolute error or the relative error, then you could do something like

```close_enough(double x, double y, double tolerance, int absolute)
{
if (absolute)
{
return (x - y) < tolerance;
}
if (x == y) return 1;
return fabs(x-y)/max(fabs(x)-fabs(y)) < tolerance;
}```

in my style, i prefer integer calculation than float, so i'd rather do this:

```X = X * 1000
X = X / Y
```

then put a dot (or comma) in between the first and the second digit. please, keep in mind if this is only useful if used to display the value in LCD or 7 segment or serial terminal. the value "1000" is chosen to suites your own precision need.
some compiler must use typecasting inside your formula so your calculation can be done properly.

```uint16_t X,Y;
uint32_t Z;
Z = X * Y;
```

X * Y will be done in 16 bit arithmetic and the result is stored in 16 bit wide to the Z, even though Z is declared as 32 bit.

```uint16_t X,Y;
uint32_t Z;
Z = (uint32_t) X * Y;
```

X is typecasted to 32 bit, so the X * Y calculation is done in 32 bit format and stored in Z as is.

KISS - Keep It Simple Stupid!

sprinkmeier wrote:
close_enough() function

```close_enough(double x, double y, double tolerance, int absolute)
{
if (absolute)
{
return (x - y) < tolerance;
}
if (x == y) return 1;
return fabs(x-y)/max(fabs(x)-fabs(y)) < tolerance;
}```

Humm. A library function is supposed to be error-free... You surely meant:

```close_enough(double x, double y, double tolerance, int absolute) {
if (absolute)
{
return fabs(x - y) < tolerance;
}
if max(fabs(x), fabs(y)) == 0 return 1;
return fabs(x-y)/max(fabs(x), fabs(y)) < tolerance;
}```

I am still not sure about the "== 0" in the above.

And, philosophically/etymologically, "close enough" perhaps grants usage of "<=" instead of "<"... ;-)

JW

> One should never use == != on floats !!!

Not entirely right, see my remark above. There are some exceptions to
this rule (so it rules out the "never"), most notably the exception to
possibly compare against a true 0, because that one is guaranteed to have
a distinct bit pattern. Note however, that a true 0 is only guaranteed to
be the result of initialization or assignment with 0.0; the result of a
computation could always be a very small number (including a denormal
one) that will not compare equal to 0.0. (The other exceptions are INF
and -INF which also have distinct and comparable bit patterns.)

The % f mismatch between scanf and printf is defined that way in the C
standard, sorry. Nothing we could change.

Actually, 32-bit floating-point "double"s are not fully compliant to the
C99 standard because they do not match the minimal presision requirements
of the final standard (they did match the requirements of earlier drafts,
that has been changed before the C99 release). They have been implemented
that way as a pragmatic compromise between the resource consumption on one
hand, and the ability to offer integrated floating-point support at all on
the other hand. We've been searching for a volunteer for years to add
(optional) 64-bit "double" support to AVR-GCC and avr-libc, but so far
nobody stepped up.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

dl8dtl wrote:
We've been searching for a volunteer for years to add
(optional) 64-bit "double" support to AVR-GCC and avr-libc, but so far
nobody stepped up.
[flame on] And, I hope, nobody ever will; see "float vs 8-bit microcontrollers". [flame off]

JW

split63 wrote:
I have run into this issue:
float Y=123;
float X;
X * 1/Y != X/Y //They are not equal !!
I'd like to see the code that demonstrates this.

Iluvatar is the better part of Valar.

split63 wrote:
I have run into this issue:
float Y=123;
float X;
X * 1/Y != X/Y //They are not equal !!

The compiler can't handle 1/Y.

Another example, X + 1/Y is also wrong, where Y is a constant. I have to calculate 1/Y manually.

Y=123;
float X;
X + 1/Y != X + 0.00813008

Why is this?

With apologies for jumping in late, I'd like to pompously suggest that these C expressions you're writing aren't intended to solve algebra problems; they're intended to evaluate arithmetic problems. If your test program is literally as you've shown it, then I'd point out that you've not initialized X to anything before expecting (X * 1/Y) to be meaningful. If X is an automatic variable in a subroutine, and its uninitialized, garbage value happens to be a "Not A Number", then you might be experiencing the intentional behavior of NANs : they don't even evaluate as being equal to themselves! And all operations on NANs produce NAN results...

If X is initialized validly, then (as others have said) your problem is that the equality operator is fussily demanding an exact match between two imprecise results arrived at through different operations. You need to be a little more easygoing when comparing floating-point numbers. One sleazy hack that's given me good service is to rely on the fact that the binary encodings for IEEE-format floating point numbers have the same less-than/greater-than relationship to each other that the numbers themselves do. Here's an "approximate equality" routine you could try:

```#define Epsilon 4
bool purtyClose(float thissen, float thattun)
{
uint32_t difference = Epsilon
+ (*((uint32_t *) &thissen))
- (*((uint32_t *) &thattun));

return (difference < (2 * Epsilon));
}```

wek wrote:

> [flame on] And, I hope, nobody ever will; see "float vs 8-bit microcontrollers". [flame off]

That's why I wrote "optional". There are people interested
in using it, and the plain fact they can only handle 8 bits at a time
does not mean they could not handle 64-bit data at all (uint64_t is
supported already). Also, it's a common misconception that floating-point
numbers were the root of all evil. They aren't, otherwise they wouldn't
be there in our computing world today. Scaled 64-bit integers don't
really produce smaller or faster code than 64-bit FP does.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

cmhicks wrote:

bperrybap wrote:
So how the heck do you print floats with avr-libc?
avr-gcc uses the same representation for floats as for doubles (the C standard merely dictates that doubles must be at least as precise as floats, so this is a standards-compliant thing to do). Thus you can just:
```#include

float x;

printf("#f\n", (double)x); // % replaced with # for the usual reason
```

and it will work and compile without warning.

Christopher Hicks
==

That is not printing a float it is printing a double.

I bet that isn't always portable.

While the avr-libc documentation is quite clear on this, I guess I've never seen or would have expected a printf() with a percent f format to require a double argument.

Also it seems odd that percent f on vfprintf() means double but on vfscanf() it means float.

Seems like a bug to me.

--- bill

Wow, tangent city.

Let me clarify my original post.

the 1/Y fails to render the right result, parenthesis or not. However, I left out that Y is a constant.
#define Y 300
float X;
X = 1/Y;

In the cases that I recall, "Y" is always a constant when I have run into this problem.

split63 wrote:
Wow, tangent city.

Let me clarify my original post.

the 1/Y fails to render the right result, parenthesis or not. However, I left out that Y is a constant.
#define Y 300
float X;
X = 1/Y;

In this case, X should be 0.0f .
Let's see the code that caused the problem.
I'm still dubious.
Quote:
In the cases that I recall, "Y" is always a constant when I have run into this problem.

Iluvatar is the better part of Valar.

> That is not printing a float it is printing a double.

> I bet that isn't always portable.

It is, at least within environments supporting the C standard.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

wek wrote:

Humm. A library function is supposed to be error-free... You surely meant:
...

I never suggested my hack was even close to a library function quality.

I think your version handles NaN's better. Not sure about +/-inf, +/- underflow and +/-0, see
http://en.wikipedia.org/wiki/Floating_point#Special_values

skeeve wrote:
I'd like to see the code that demonstrates this.

Closest I got is:

```#include
main()
{
float Y=123;
float X;

for (X = -10; X < 10; X += 0.1)
{
float A =  1/Y;
A *= X;
float B = X/Y;
float C = X * (1 / Y);
if (A == B) continue;
printf("#f, #f, #f, #f, #d, #d, #d\n", // percent-bug
X,
A, B, C,
A==B, A==C, B==C);
}
}
```

It seems "X * 1/Y " is optimised by the compiler(*) to "X / Y" (why do 2 floating point ops when you can do 1?) so A and C are always equal.
A and B are mathematically identical but sometimes not unequal in this program, which I believe demonstrates the problem.

(*) gcc 4.3.3-5ubuntu4 on Ubuntu 9.04, YMMV

bperrybap wrote:
That is not printing a float it is printing a double.
Well, OK, but it achieves the desired result (ie it produces an ASCII string which is a decimal approximation to the floating point parameter).
Quote:
I bet that isn't always portable.
I think it is, because I think a direct consequence of the way the standard requires floats and doubles to be constructed is that all floats are representable as doubles without loss of information.
Quote:
While the avr-libc documentation is quite clear on this, I guess I've never seen or would have expected a printf() with a percent f format to require a double argument.

Also it seems odd that percent f on vfprintf() means double but on vfscanf() it means float.

This is simply an oddity of the C standard. There are lots of slightly weird things in the standard, largely because C evolved over many years as a practical language, and was not designed from the ground up to be consistent, unambiguous and all those other things we would all like it to be!

Quote:
Seems like a bug to me.
I think it is (at most) an omission in the printf interface that there is no mechanism to print a float directly. This omission is largely inconsequential in the vast majority of cases. It is significant only in systems which (a) use different formats for float and double and (b) the overhead of converting a float to a double and passing a double parameter (compared to passing a float parameter) is significant, and (c) that work is significant compared with the work required to convert it to decimal ASCII.

CH
==
PS Sorry this has got rather off-topic.

> I think it is (at most) an omission in the printf interface
> that there is no mechanism to print a float directly. This
> omission is largely inconsequential in the vast majority of cases.

It is an artifact of the way argument passing works for variadic
functions: in this case, the usual promotion rules apply (both,
for integer and floating-point arguments), so the minimal sized
arguments that can be passed are "int" and "double", respectively.

In contrast, the scanf family gets a *pointer* to an object passed
down, so of course, it can be able to just store the right-sized
data into the address this pointer points to.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

sprinkmeier wrote:
skeeve wrote:
I'd like to see the code that demonstrates this.

Closest I got is:

```#include
main()
{
float Y=123;
float X;

for (X = -10; X < 10; X += 0.1)
{
float A =  1/Y;
A *= X;
float B = X/Y;
float C = X * (1 / Y);
if (A == B) continue;
printf("#f, #f, #f, #f, #d, #d, #d\n", // percent-bug
X,
A, B, C,
A==B, A==C, B==C);
}
}
```

It seems "X * 1/Y " is optimised by the compiler(*) to "X / Y" (why do 2 floating point ops when you can do 1?) so A and C are always equal.

On any system that can multiply by 1.0f correctly, X*1/Y==X/Y, if X/Y==X/Y.
The OP claimed otherwise with avr-gcc.
That was why I wanted to see code.
floats are not reals.
That X*(1/Y) != X/Y should not be a surprise.
How to deal with it is problem dependent.
There is not always a good answer.
Quote:
A and B are mathematically identical but sometimes not unequal in this program, which I believe demonstrates the problem.

(*) gcc 4.3.3-5ubuntu4 on Ubuntu 9.04, YMMV

Iluvatar is the better part of Valar.

to JÃ¶rg Wunsch

One should never use == != on floats !!!

Ok I change it wording to

One should never use == != on floats !!!
in a program that make any sence because one day it will catch up with you.
Because the sign magnitude structure you have two different 0.0 (the other is -0.0) and then there is the rounding problem up down or or near zero, that all are legal !!! and depending of the lib.

Jens

I actualy need a 24bit (16man 8 exp)float more, so the FP calculations can be speeded up (I need speed over precision). For a lot of things it would be better than 32int because of the bigger dynamic range and speed. We still have to remember that this is a 8 bit micro.

Jens

> One should never use == != on floats !!!
> in a program that make any sence because one day it will catch up with you.

No. It is completely portable and legal to do things like:

```double gamma;

void
getuserinput(void)
{
double x;
// ... do some user interaction

if (gamma == 0.0)
{
// user has not set this value before
x = getdouble();
if (validate_value_makes_sense(x))
gamma = x;
else
complain();
}
}
```

Obviously, that will only work if 0.0 is not a legal user input for
"gamma".

> you have two different 0.0 (the other is -0.0)

For IEEE 754 machines (which covers certainly everything we are using
these days), +0.0 and -0.0 always compare equal. This is *not* a
bitwise comparison.

I didn't mean to imply you should rely on values being zero that are
the result of a computation that could either be zero or just a very
small number. But it's safe to rely on any explicitly given 0.0 to
be compared for equality. This also includes comparing e.g. against
a function result where the function performs something like:

```double
doit(...)
{
// ...
if (certain_condition_matches)
return 0.0;

// compute something
return result;
}
```

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

Yes and in those cases I would use a int or boolean.