A computer components & hardware forum. HardwareBanter

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

Go Back   Home » HardwareBanter forum » Processors » Intel
Site Map Home Register Authors List Search Today's Posts Mark Forums Read Web Partners

Floating point error (more info)



 
 
Thread Tools Display Modes
  #1  
Old July 16th 03, 03:33 AM
Dylan Nicholson
external usenet poster
 
Posts: n/a
Default Floating point error (more info)

I just posted regarding a possible floating point error (not sure
where), and have since discovered that:

float f = 5.15002;
double d = 5.15002;
if (float(d) f)
puts("huh 1?");
float f2 = float(d);
if (f2 f)
puts("huh 2?");


Causes 'huh 1' to be printed, but NOT 'huh 2'.

I can't tell if this is a compiler program (MSVC 6), an FPU problem or
what!

The assembly code is:

6: float f = 5.15002;
00401028 C7 45 FC F7 CC A4 40 mov dword ptr [ebp-4],40A4CCF7h
7: double d = 5.15002;
0040102F C7 45 F4 D2 FB C6 D7 mov dword ptr
[ebp-0Ch],0D7C6FBD2h
00401036 C7 45 F8 9E 99 14 40 mov dword ptr [ebp-8],4014999Eh
8: if (float(d) f)
0040103D DD 45 F4 fld qword ptr [ebp-0Ch]
00401040 D9 55 EC fst dword ptr [ebp-14h]
00401043 D8 5D FC fcomp dword ptr [ebp-4]
00401046 DF E0 fnstsw ax
00401048 F6 C4 01 test ah,1
0040104B 74 0D je main+4Ah (0040105a)
9: puts("huh 1?");
0040104D 68 24 60 42 00 push offset string "huh 1?"
(00426024)
00401052 E8 39 00 00 00 call puts (00401090)
00401057 83 C4 04 add esp,4
10: float f2 = float(d);
0040105A DD 45 F4 fld qword ptr [ebp-0Ch]
0040105D D9 5D F0 fstp dword ptr [ebp-10h]
11: if (f2 f)
00401060 D9 45 F0 fld dword ptr [ebp-10h]
00401063 D8 5D FC fcomp dword ptr [ebp-4]
00401066 DF E0 fnstsw ax
00401068 F6 C4 01 test ah,1
0040106B 74 0D je main+6Ah (0040107a)
12: puts("huh 2?");
0040106D 68 1C 60 42 00 push offset string "huh 2?"
(0042601c)
00401072 E8 19 00 00 00 call puts (00401090)
00401077 83 C4 04 add esp,4

  #2  
Old July 16th 03, 08:23 AM
Joel Kittinger
external usenet poster
 
Posts: n/a
Default

In general, floating point numbers cannot be represented precisely.

You can probably find various texts on this by searching the web for IEEE
Floating Pointing with your favorite search engine.
One such reference that may be helpful is:

http://msdn.microsoft.com/library/de...us/vccore/html
/_core_why_floating_point_numbers_may_lose_precisio n.asp

If you build your program for debug, step thru it, and look at the memory
contents
(the actual hex values, not the converted base 10 representation) being
compared this will probably be clearer.

- joel


"Dylan Nicholson" wrote in message
om...
I just posted regarding a possible floating point error (not sure
where), and have since discovered that:

float f = 5.15002;
double d = 5.15002;
if (float(d) f)
puts("huh 1?");
float f2 = float(d);
if (f2 f)
puts("huh 2?");


Causes 'huh 1' to be printed, but NOT 'huh 2'.

I can't tell if this is a compiler program (MSVC 6), an FPU problem or
what!

The assembly code is:

6: float f = 5.15002;
00401028 C7 45 FC F7 CC A4 40 mov dword ptr [ebp-4],40A4CCF7h
7: double d = 5.15002;
0040102F C7 45 F4 D2 FB C6 D7 mov dword ptr
[ebp-0Ch],0D7C6FBD2h
00401036 C7 45 F8 9E 99 14 40 mov dword ptr [ebp-8],4014999Eh
8: if (float(d) f)
0040103D DD 45 F4 fld qword ptr [ebp-0Ch]
00401040 D9 55 EC fst dword ptr [ebp-14h]
00401043 D8 5D FC fcomp dword ptr [ebp-4]
00401046 DF E0 fnstsw ax
00401048 F6 C4 01 test ah,1
0040104B 74 0D je main+4Ah (0040105a)
9: puts("huh 1?");
0040104D 68 24 60 42 00 push offset string "huh 1?"
(00426024)
00401052 E8 39 00 00 00 call puts (00401090)
00401057 83 C4 04 add esp,4
10: float f2 = float(d);
0040105A DD 45 F4 fld qword ptr [ebp-0Ch]
0040105D D9 5D F0 fstp dword ptr [ebp-10h]
11: if (f2 f)
00401060 D9 45 F0 fld dword ptr [ebp-10h]
00401063 D8 5D FC fcomp dword ptr [ebp-4]
00401066 DF E0 fnstsw ax
00401068 F6 C4 01 test ah,1
0040106B 74 0D je main+6Ah (0040107a)
12: puts("huh 2?");
0040106D 68 1C 60 42 00 push offset string "huh 2?"
(0042601c)
00401072 E8 19 00 00 00 call puts (00401090)
00401077 83 C4 04 add esp,4



  #3  
Old July 16th 03, 12:39 PM
Bruce Wheeler
external usenet poster
 
Posts: n/a
Default

On 15 Jul 2003 19:33:07 -0700, (Dylan Nicholson)
wrote:

I just posted regarding a possible floating point error (not sure
where), and have since discovered that:

float f = 5.15002;
double d = 5.15002;
if (float(d) f)
puts("huh 1?");
float f2 = float(d);
if (f2 f)
puts("huh 2?");


Causes 'huh 1' to be printed, but NOT 'huh 2'.


First, this appears to be c++, not c, although the concepts are
essentially the same in this case. VC6 supports C90, and not C99, so
there are several compiler errors in the above.

Second, set your compiler to conforming mode:
/Za Disable Language Extensions (check box selected) ANSI C
compatibility. Language constructs not compatible with ANSI C are
flagged as errors. Note that this also turns on the /Op (Improve Float
Consistency) flag, which is what is required here.

With /Za set, neither "huh 1" nor "huh 2" is output, and there are no
anomalies, and the behavior is conforming.

However, without /Za set, VC will default to a mode where floating-point
values remain in registers, and are not type-converted in all cases
dictated by the standard. I got both "huh 1" and "huh 2" output, which
is what I would expect, given VC's default behavior.

Relative to your first post,

float f = 5.15002;
double d = 5.15002;
if (d + FLT_EPSILON f)
puts("huh?");


it would appear that f is rounded up when converted from double to
float, more than FLT_EPSILON. Note that 5.15002 has type double.

Informally, what I see in the debugger is
5.1500201225281 = f (as double)
5.1500201192093 = d + FLT_EPSILON
5.1500200000000 = d
so the result we get is consistent with what we see here.

As another poster has suggested, you may want to look into the problems
associated with floating-point representations.

Regards,
Bruce Wheeler


  #4  
Old July 17th 03, 09:21 AM
Glen Herrmannsfeldt
external usenet poster
 
Posts: n/a
Default


"Dylan Nicholson" wrote in message
om...

(snip)

| float f = 5.15002;
| double d = 5.15002;
| if (float(d) f)
| puts("huh 1?");
| float f2 = float(d);
| if (f2 f)
| puts("huh 2?");
|
|
| Causes 'huh 1' to be printed, but NOT 'huh 2'.
|
| I can't tell if this is a compiler program (MSVC 6), an FPU problem or
| what!

snip
If you first cast the double to a float, both numbers are
truncated to 6 digits and compare equal.

Um, if you look at the code, that's exactly what I did, in both cases.
However only one of the comparisons behaves unexpectedly.
I can't see how the above can be anything other than a compiler error
or a FPU instruction set inconsistency (unfortunately I'm not at all
familiar with FPU instructions).


That is not how you cast in C. I don't know that a float() function exists,
though.

It should be if((float)df) or, to be sure about precedence
if(((float)d)f)

In any case, because of the way the internal registers in the floating point
processor it is common for values to be held with a higher precision than
specified. Good or bad, C allows this. Sometimes more precision is good,
sometimes bad.

-- glen
-- glen


  #5  
Old July 17th 03, 11:27 AM
Kevin Easton
external usenet poster
 
Posts: n/a
Default

In comp.lang.c Glen Herrmannsfeldt wrote:
[...]
It should be if((float)df) or, to be sure about precedence
if(((float)d)f)


There is a simple rule that applies here, which is worth memorising -
all unary operators (typecasts are unary operators) have higher
precedence than the binary operators.

- Kevin

  #6  
Old July 17th 03, 11:50 PM
Dylan Nicholson
external usenet poster
 
Posts: n/a
Default

(Bruce Wheeler) wrote in message ...
On 15 Jul 2003 19:33:07 -0700,
(Dylan Nicholson)
wrote:

I just posted regarding a possible floating point error (not sure
where), and have since discovered that:

float f = 5.15002;
double d = 5.15002;
if (float(d) f)
puts("huh 1?");
float f2 = float(d);
if (f2 f)
puts("huh 2?");


Causes 'huh 1' to be printed, but NOT 'huh 2'.


First, this appears to be c++, not c, although the concepts are
essentially the same in this case. VC6 supports C90, and not C99, so
there are several compiler errors in the above.


Ah yes, sorry...I meant to convert to C before posting it...
snip

However, without /Za set, VC will default to a mode where floating-point
values remain in registers, and are not type-converted in all cases
dictated by the standard. I got both "huh 1" and "huh 2" output, which
is what I would expect, given VC's default behavior.

So you can't get it to just output huh 1 but not huh 2? You may need
to do it in debug mode (in fact in release mode the floating
comparisons are optimized out, as they are fixed at compile time).
I still don't understand how it could matter which way the casting is
done (explictly inline, or implicity via storing to a float variable).
And I just don't know the x87 FPU instruction set well enough to
understand the difference in the compiled output.

Relative to your first post,

float f = 5.15002;
double d = 5.15002;
if (d + FLT_EPSILON f)
puts("huh?");


it would appear that f is rounded up when converted from double to
float, more than FLT_EPSILON. Note that 5.15002 has type double.

Informally, what I see in the debugger is
5.1500201225281 = f (as double)
5.1500201192093 = d + FLT_EPSILON
5.1500200000000 = d
so the result we get is consistent with what we see here.

Still, even in this example, it's because I'm using a mixture of
doubles and floats that the problem occurs.

As another poster has suggested, you may want to look into the problems
associated with floating-point representations.

Well yes I'm well aware of those problems, but I don't see how they're
relevant here. I know I was using FLT_EPSILON incorrectly, but
likewise I can't see how that should matter. In general if you assign
the *same* decimal value to two floats, they should never compare as
anything but equal, even if they aren't exactly the value I assigned
to them.

Dylan

  #7  
Old July 18th 03, 03:16 AM
Hank Oredson
external usenet poster
 
Posts: n/a
Default


"Dylan Nicholson" wrote in message
om...
(Bruce Wheeler) wrote in message

...
On 15 Jul 2003 19:33:07 -0700,
(Dylan Nicholson)
wrote:

I just posted regarding a possible floating point error (not sure
where), and have since discovered that:

float f = 5.15002;
double d = 5.15002;
if (float(d) f)
puts("huh 1?");
float f2 = float(d);
if (f2 f)
puts("huh 2?");


Causes 'huh 1' to be printed, but NOT 'huh 2'.


First, this appears to be c++, not c, although the concepts are
essentially the same in this case. VC6 supports C90, and not C99, so
there are several compiler errors in the above.


Ah yes, sorry...I meant to convert to C before posting it...
snip

However, without /Za set, VC will default to a mode where floating-point
values remain in registers, and are not type-converted in all cases
dictated by the standard. I got both "huh 1" and "huh 2" output, which
is what I would expect, given VC's default behavior.

So you can't get it to just output huh 1 but not huh 2? You may need
to do it in debug mode (in fact in release mode the floating
comparisons are optimized out, as they are fixed at compile time).
I still don't understand how it could matter which way the casting is
done (explictly inline, or implicity via storing to a float variable).
And I just don't know the x87 FPU instruction set well enough to
understand the difference in the compiled output.

Relative to your first post,

float f = 5.15002;
double d = 5.15002;
if (d + FLT_EPSILON f)
puts("huh?");


it would appear that f is rounded up when converted from double to
float, more than FLT_EPSILON. Note that 5.15002 has type double.

Informally, what I see in the debugger is
5.1500201225281 = f (as double)
5.1500201192093 = d + FLT_EPSILON
5.1500200000000 = d
so the result we get is consistent with what we see here.

Still, even in this example, it's because I'm using a mixture of
doubles and floats that the problem occurs.

As another poster has suggested, you may want to look into the problems
associated with floating-point representations.

Well yes I'm well aware of those problems, but I don't see how they're
relevant here. I know I was using FLT_EPSILON incorrectly, but
likewise I can't see how that should matter. In general if you assign
the *same* decimal value to two floats, they should never compare as
anything but equal, even if they aren't exactly the value I assigned
to them.



But you didn't have the "same" value, one was float, one was double.
The two approximations of 5.15002 are different. If you wanted them
to be the same, you might have said something like:

float f = (float)5.15002;
double d = (float)5.15002;

You chose instead to allow the compiler to decide what particular
approximation of 5.15002 was loaded into each variable.

In other languages you would have been more precise in your
description of the precision of each variable and each constant.

Just for grins, try it with a number that has an exact representation
in a float, and see what happens :-)

--

... Hank

Hank:
http://horedson.home.att.net
W0RLI: http://w0rli.home.att.net


 




Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Balance Point, AGP Overclocking David B. Overclocking 6 April 19th 05 01:42 PM
Passmark Performance Test, Division, Floating Point Division, 2DShapes @(none) General 0 August 19th 04 11:57 PM
my new mobo o/c's great rockerrock Overclocking AMD Processors 9 June 30th 04 08:17 PM
AMD64 vs. a floating point operation (FLOP) Only NoSpammers AMD x86-64 Processors 8 June 27th 04 03:55 PM
Upgrade Difficulties Ron B Gateway Computers 0 February 14th 04 03:26 AM


All times are GMT +1. The time now is 07:38 PM.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Copyright ©2004-2024 HardwareBanter.
The comments are property of their posters.