Node:Emulator accuracy, Next:, Previous:Emulation, Up:Floating point

11.2 Floating point inaccuracies when using emulator

Q: I am experiencing inaccurate results in some floating point calculations, sometimes in the 2nd or 3rd significant digit (like getting 118.401 instead of 120.0). This is really unacceptable! (And no, I'm not using a buggy Pentium CPU.)

Q: I get some very inaccurate results when my program runs on a machine lacking an FPU....

A: Are you using the emu387.dxe emulator? If so, it might be that the emulator isn't as accurate as you expect. Versions of the emulator distributed with DJGPP 2.02 and earlier had a bug that affected addition, subtraction, and comparison of floating-point numbers with some specific bit patterns. This bug could produce inaccuracies in math functions such as sqrt, sin and tan for some specific argument values, and even cause a program to be trapped in an infinite loop. The emulation of the FPATAN instruction and functions based on it, like atan, asin and acos, also suffered loss of accuracy for some specific arguments. DJGPP v2.03 solves these problems, so upgrade and see if your problems go away.

However, even the emulator supplied with v2.03 and later suffers some accuracy degradation when computing trigonometric functions for arguments that are integral multiples of Pi/2 or Pi/4 (depending on the particular function you call), and when computing inverse trigonometric functions which should yield results that are such multiples. So, for example, if you use 4*atan(1.) to get the value of Pi, that might be your problem.

The reason for this accuracy degradation is that emu387.dxe does not store the value of Pi, with extra precision, like the real FPU does, and trig functions in libc.a rely on such extra accuracy to deliver accurate results.

For computing the value of Pi, the solution is simple: make it a constant, as God intended. The header file <math.h> includes the constant M_PI which you can use; or get the value of Pi from the net.

In many cases that involve trigonometric functions and yield inaccurate results, linking your program with the -lm switch might help. This switch causes the linker to use an alternative math library, libm.a, which doesn't rely on x87 instructions, and thus is more accurate when the emulator deviates from the actual x87.

The alternate emulator WMEMU is known to be accurate to 7 significant digits for float variables, and 15 digits for doubles. It also much more faithfully emulates the behavior of the x87 processor when abnormal arguments (Inf, NaN, etc.) are involved. So if emu387.dxe which comes with DJGPP v2.03 doesn't solve your problems, you might try using WMEMU as a solution.