Node:Emulator accuracy,
Next:Emulation in Windows,
Previous:Emulation,
Up:Floating point
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
double
s. 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.