public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: Rounding errors using doubles?
@ 1999-03-18 17:43 Ross Smith
       [not found] ` < 002d01be71aa$30d420e0$a8a11dcb@animal.ihug.co.nz >
  1999-03-31 23:46 ` Ross Smith
  0 siblings, 2 replies; 26+ messages in thread
From: Ross Smith @ 1999-03-18 17:43 UTC (permalink / raw)
  To: egcs

From: Sam Lantinga <slouken@devolution.com>
>
>I have to thank everyone here on this list for your responsiveness.
>The problem was caused by unexpected values in code using doubles
>that was ported from Windows.  Apparently, by default, Windows uses 
>53 bits of precision for it's double operations.  Linux uses 64 bits.
>
>Since the code relies on the exact behavior of doubles quite extensively,
>we are setting the precision of the FPU to 53 bits using the fldcw
>instruction. :)
>
>BTW, does anyone know what precision is used on the PPC and Alpha
>architectures?

It's not really a difference between operating systems or (to a first
approximation) CPUs.

There's a standard called IEC 559 (formerly IEEE 754), which specifies
three standard floating-point arithmetic formats. Two of them are
32-bit and 64-bit formats (with 24-bit and 53-bit precision,
respectively); modern C/C++ compilers almost universally equate these
to float and double. The third is an 80-bit (64-bit precision) format
used for intermediate results in multi-step calculations.

The Intel X86 processors have can perform arithmetic in all three
modes, although it always works internally in 80-bit mode and
inserts automatic conversions for the other two. I don't know
anything about PPCs or Alphas, but the IEC standard is pretty much
universal now, and I'd be mildly amazed if either of them differed
in any important ways.

Exactly how floating-point arithmetic is done is a function of the
compiler, not the operating system. You didn't say which compiler you
were using on Windows, but Microsoft Visual C++ is the most likely.
Both MSVC and EGCS perform intermediate calculations in 80-bit internal
registers wherever possible, but allow values to spill into 64-bit
memory when the compiler can't manage to fit the entire calculation
into registers (a common problem on the register-poor X86
architecture). (The details of exactly how EGCS should handle this
were the subject of heated debate on this list not so long ago.)

It looks like what happened was that, at some critical point in your
program, MSVC allowed a value to spill to 64 bits (thus truncating it
to 53-bit precision) while EGCS was able to keep it in an 80-bit
register (retaining 64-bit precision). (Incidentally, because people
tend to attach far too much importance to this sort of observation, I
hasten to add that this implies nothing about the relative performance
of the two compilers in general; perhaps they were using different
optimisation settings, or perhaps they simple made different decisions
about which intermediate results should be kept in registers and which
sacrificed.)

Both compilers have options to force pure 64-bit arithmetic (53-bit
precision) throughout (at some cost in speed): -ffloat-store on EGCS,
/Op on MSVC.

--
Ross Smith ................................... mailto:ross.s@ihug.co.nz
.............. The Internet Group, Auckland, New Zealand ..............
         "The award for the Most Effective Promotion of Linux
         goes to Microsoft."             -- Nicholas Petreley


^ permalink raw reply	[flat|nested] 26+ messages in thread
* Re: Rounding errors using doubles?
@ 1999-03-19  9:08 Sam Lantinga
       [not found] ` < E10O2lP-0006t2-00@roboto.devolution.com >
  1999-03-31 23:46 ` Sam Lantinga
  0 siblings, 2 replies; 26+ messages in thread
From: Sam Lantinga @ 1999-03-19  9:08 UTC (permalink / raw)
  To: craig; +Cc: slouken, egcs

> >Both compilers have options to force pure 64-bit arithmetic (53-bit
> >precision) throughout (at some cost in speed): -ffloat-store on EGCS,
> >/Op on MSVC.

> Take -ffloat-store off that list: it doesn't do the above.  It affects
> only explicit *stores* to *variables*, not intermediate coputations.  egcs
> provides no way to force 64-bit FP arithmetic.  In fact, I'd be surprised
> if -ffloat-store "improved" the behavior of the (buggy) program originally
> submitted in this thread.

Interestingly enough, the original project file (MS VC++ 5.0) did have the
/Op option, and -ffloat-store didn't force 64-bit FP arithmetic.  The
following code does force 64-bit arithmetic on Pentium style CPUs:

// Initialize the FPU at 53-bit precision to mimic Windows /Op behavior
// This code doesn't parse with the G++ parser because of the "::", but
// it works fine as a C file.
void Setup_FPU(void)
{
#ifdef i386
    unsigned short flags;

    asm volatile ("fnstcw %0":"=m" (flags));
    flags &= ~0x0300;       /* Clear precision flags */
    flags |=  0x0200;       /* Set 53-bit precision */
    asm volatile ("fldcw %0"::"m" (flags));
#endif
}

If this doesn't work on other x86 CPUs, I'd like to know.
Linux saves and restores the FPU flags on context switch, so this is
safe to call in an individual program.

BTW, I am on the list. :)

	-Sam Lantinga				(slouken@devolution.com)

Lead Programmer, Loki Entertainment Software
--
Author of Simple DirectMedia Layer -
	http://www.devolution.com/~slouken/SDL/
--

^ permalink raw reply	[flat|nested] 26+ messages in thread
* Re: Rounding errors using doubles?
@ 1999-03-18 16:45 Sam Lantinga
  1999-03-18 16:54 ` Dima Volodin
                   ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: Sam Lantinga @ 1999-03-18 16:45 UTC (permalink / raw)
  To: egcs; +Cc: highlander, slouken, dvenckus

> On Thu, Mar 18, 1999 at 03:41:32PM -0800, Sam Lantinga wrote:
> > On a Pentium II, the following code gives an incorrect result when using
> > doubles, but a correct result when using floats:

> I think this is normal.  You should probably learn why at
> http://www.linuxsupportline.com/~billm/ .

I have to thank everyone here on this list for your responsiveness.
The problem was caused by unexpected values in code using doubles
that was ported from Windows.  Apparently, by default, Windows uses 
53 bits of precision for it's double operations.  Linux uses 64 bits.

Since the code relies on the exact behavior of doubles quite extensively,
we are setting the precision of the FPU to 53 bits using the fldcw
instruction. :)

BTW, does anyone know what precision is used on the PPC and Alpha
architectures?

Thanks for your help!

	-Sam Lantinga				(slouken@devolution.com)

Lead Programmer, Loki Entertainment Software
--
Author of Simple DirectMedia Layer -
	http://www.devolution.com/~slouken/SDL/
--

^ permalink raw reply	[flat|nested] 26+ messages in thread
* Rounding errors using doubles?
@ 1999-03-18 15:41 Sam Lantinga
  1999-03-18 15:54 ` Dima Volodin
                   ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: Sam Lantinga @ 1999-03-18 15:41 UTC (permalink / raw)
  To: egcs

On a Pentium II, the following code gives an incorrect result when using
doubles, but a correct result when using floats:

#include <stdio.h>

#ifdef USE_FLOAT
/* This works */
typedef float percentage_type;
#else
/* This doesn't */
typedef double percentage_type;
#endif

main()
{
        int value = 86;
        percentage_type percentage;

        printf("Starting Percentage is: %d\n", value);
        percentage = ((percentage_type)value)/100.0;
        printf("Ending Percentage is: %d\n", (int)(percentage * 100.0));
}

Incorrect output:
Starting Percentage is: 86
Ending Percentage is: 85

This is VERY bad for our software.  An analysis of the offending assembly
output shows only one difference between the broken and the working versions:

--- t-bad.s     Thu Mar 18 13:32:32 1999
+++ t.s Thu Mar 18 13:33:40 1999
@@ -28,8 +28,8 @@
        fstp %st(0)
        fldl .LC1
        fdivrp %st,%st(1)
-       fstpl -12(%ebp)
-       fldl -12(%ebp)
+       fstps -8(%ebp)
+       flds -8(%ebp)
        fldl .LC1
        fstp %st(0)
        fldl .LC1

This is using egcs 1.1.1.  Any ideas?

Thanks,
	-Sam Lantinga				(slouken@devolution.com)

Lead Programmer, Loki Entertainment Software
--
Author of Simple DirectMedia Layer -
	http://www.devolution.com/~slouken/SDL/
--

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~1999-03-31 23:46 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-03-18 17:43 Rounding errors using doubles? Ross Smith
     [not found] ` < 002d01be71aa$30d420e0$a8a11dcb@animal.ihug.co.nz >
1999-03-19  6:36   ` craig
     [not found]     ` < 19990319142042.16973.qmail@deer >
1999-03-19  6:36       ` craig
1999-03-31 23:46         ` craig
1999-03-31 23:46     ` craig
1999-03-31 23:46 ` Ross Smith
  -- strict thread matches above, loose matches on Subject: below --
1999-03-19  9:08 Sam Lantinga
     [not found] ` < E10O2lP-0006t2-00@roboto.devolution.com >
1999-03-19  9:43   ` craig
1999-03-31 23:46     ` craig
1999-03-31 23:46 ` Sam Lantinga
1999-03-18 16:45 Sam Lantinga
1999-03-18 16:54 ` Dima Volodin
1999-03-31 23:46   ` Dima Volodin
     [not found] ` < E10NnPU-0006Cc-00@roboto.devolution.com >
1999-03-18 16:57   ` David Edelsohn
1999-03-31 23:46     ` David Edelsohn
1999-03-31 23:46 ` Sam Lantinga
1999-03-18 15:41 Sam Lantinga
1999-03-18 15:54 ` Dima Volodin
1999-03-31 23:46   ` Dima Volodin
     [not found] ` < E10NmPs-0005mx-00@roboto.devolution.com >
1999-03-18 15:51   ` Sylvain Pion
1999-03-31 23:46     ` Sylvain Pion
1999-03-18 16:12   ` Joe Buck
     [not found]     ` < 199903190011.QAA11085@atrus.synopsys.com >
1999-03-18 16:25       ` Joe Buck
1999-03-31 23:46         ` Joe Buck
1999-03-31 23:46     ` Joe Buck
1999-03-31 23:46 ` Sam Lantinga

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).