www.digitalmars.com         C & C++   DMDScript  

c++ - cos bug

reply "Steve Hall" <sthall lorrexinc.com> writes:
The following code return wrong result:

#include <math.h>
#include <stdio.h>

int main()
{
float vf = 7.7915e19;
double vd = 7.7915e19;
long double vl = 7.7915e19;

printf("cosf(%lg) = %lg\n", vf, cosf(vf));
printf("cos(%lg) = %lg\n", vd, cos(vd));
printf("cosl(%Lg) = %Lg", vl, cosl(vl));

return 0;
}

The output is:
cosf(7.7915e+19) = 7.7915e+19
cos(7.7915e+19) = 7.7915e+19
cosl(7.7915e+19) = 7.7915e+19

The used compiler is Digital Mars Compiler v8.34.

Regards,
Steve
Jun 04 2003
parent reply Heinz Saathoff <hsaat bre.ipnet.de> writes:
Steve Hall schrieb...
 include <math.h>
 #include <stdio.h>
 
 int main()
 {
 float vf = 7.7915e19;
 double vd = 7.7915e19;
 long double vl = 7.7915e19;
 
 printf("cosf(%lg) = %lg\n", vf, cosf(vf));
 printf("cos(%lg) = %lg\n", vd, cos(vd));
 printf("cosl(%Lg) = %Lg", vl, cosl(vl));
 
 return 0;
 }
 
 The output is:
 cosf(7.7915e+19) = 7.7915e+19
 cos(7.7915e+19) = 7.7915e+19
 cosl(7.7915e+19) = 7.7915e+19
 
 The used compiler is Digital Mars Compiler v8.34.

1. Why use such a huge number as argument to cos? 2. My old 486 Processor handbook tells me that the argument range is abs(arg) < 2^63 2^63 = 9.2233e+18 I would assume this is also valid for the pentiom family? So your argument is already out of range for the numeric coprozessor. When the coprocessor exception is ignored (as is with DM) then the argument on FPU stack isn't changed and you get back the argument unmodified. - Heinz
Jun 05 2003
parent reply "Steve Hall" <sthall lorrexinc.com> writes:
Heinz, thank you  for your reply.

dmc v3.34 is a C99 conformed compiler with IEC 60559 support according to
macros __STDC_VERSION__(199901) and __STDC_IEC_559__. Types float and double
are respectively single and double precision types from IEC 60559(Binary
floating-point arithmetic for microprocessor systems, second edition). The
floating-point standard is independent of the hardware.
According to C99 the maximum representable number for type float is FLT_MAX
= 3.40282347E+38, for type double is DBL_MAX = 1.7976931348623157E+308. Type
double is subset of type long double, which is compiler dependent(for dmc
v3.34 long double contain 80 bits).

The same code compiled with gcc v3.2.3 (mingw special 20030504-1) return
reasonable results for functions cos and cosf(the recent version of MinGW
gcc doesn't support properly displaying of long double type thru printf
function).

The software that I develop depend on precision C99 floating-point
arithmetic.

Regards,
Steve

"Heinz Saathoff" <hsaat bre.ipnet.de> wrote in message
news:MPG.194952a884bb81f79896bc news.digitalmars.com...
 Steve Hall schrieb...
 include <math.h>
 #include <stdio.h>

 int main()
 {
 float vf = 7.7915e19;
 double vd = 7.7915e19;
 long double vl = 7.7915e19;

 printf("cosf(%lg) = %lg\n", vf, cosf(vf));
 printf("cos(%lg) = %lg\n", vd, cos(vd));
 printf("cosl(%Lg) = %Lg", vl, cosl(vl));

 return 0;
 }

 The output is:
 cosf(7.7915e+19) = 7.7915e+19
 cos(7.7915e+19) = 7.7915e+19
 cosl(7.7915e+19) = 7.7915e+19

 The used compiler is Digital Mars Compiler v8.34.

1. Why use such a huge number as argument to cos? 2. My old 486 Processor handbook tells me that the argument range is abs(arg) < 2^63 2^63 = 9.2233e+18 I would assume this is also valid for the pentiom family? So your argument is already out of range for the numeric coprozessor. When the coprocessor exception is ignored (as is with DM) then the argument on FPU stack isn't changed and you get back the argument unmodified. - Heinz

Jun 05 2003
next sibling parent reply Keith Fuller <Keith_member pathlink.com> writes:
In article <bbnl8t$2g9$1 digitaldaemon.com>, Steve Hall says...

The same code compiled with gcc v3.2.3 (mingw special 20030504-1) return
reasonable results for functions cos and cosf(the recent version of MinGW
gcc doesn't support properly displaying of long double type thru printf
function).

gcc may return a "reasonable"-looking result for cos and cosf, but that result is totally meaningless. The FPU is rejecting your calculation for good reason. If you start with, float vf = 7.7915e19; and subtract a multiple of 2*pi (=m) such that 0 <= vf - (m*2*pi) < 2*pi, all you are really left with is just random rounding error garbage. If you try to calculate (vf) - (vf - 1); do you really get 1? Maybe with 80 bits of precision; otherwise I don't think so.
The software that I develop depend on precision C99 floating-point
arithmetic.

If you really need to know the cosine of such a large number, I would suggest you use an arbitrary precision math package. Or else consider writing your own cos function that just returns zero if the argument is too large. But I don't know if it is good to slow down everyone else just for people with weird requirements performing meaningless cosine calculations.
Regards,
Steve

Keith Fuller keithfx h.tmail.com
Jun 05 2003
parent reply "Steve Hall" <sthall lorrexinc.com> writes:
But I don't know if it is good to slow down everyone else just for people

Thanks for your answer. You are right that cos of big values return "just random rounding error garbage". Any value between [-1; 1] is acceptable for cos function with such argument. But value outside of this region is mathematicaly unacceptable.
If you really need to know the cosine of such a large number, I would

writing your own cos function that just returns zero if the argument is too large. In fact the compiler is mathematical based language translator. It must mathematical accurately to translate every piece of the code in precise machine readable form. If it fail, the compiled code will produce "just random rounding error garbage". What you think Walter about this (thanks for the correction of powl bug)? Do you accept to close your eyes in front of outstanding mathematical inaccuracy of your compiler? Do you accept to sell mathematical inaccurate compiler and prefer everyone of your clients to know that you haven't interest to correct such a poblems? Can I develop mathematical/logicaly stable software if the used compiler contain mathematical bugs? From your point of view all you need to do is just to ignore this post, because I'm the only one who want mathematical stable compiler. Thank you for your patience Walter, Steve Hall
Jun 05 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Steve Hall" <sthall lorrexinc.com> wrote in message
news:bboebu$ptk$1 digitaldaemon.com...
 What you think Walter about this (thanks for the correction of powl bug)?
 Do you accept to close your eyes in front of outstanding mathematical
 inaccuracy of your compiler? Do you accept to sell mathematical inaccurate
 compiler and prefer everyone of your clients to know that you haven't
 interest to correct such a poblems?
 Can I develop mathematical/logicaly stable software if the used compiler
 contain mathematical bugs?
 From your point of view all you need to do is just to ignore this post,
 because I'm the only one who want mathematical stable compiler.
 Thank you for your patience Walter,
 Steve Hall

The fundamental problem is DMC++ gets killed in benchmark comparisons unless cos() is recognized by the compiler and replaced with the single FCOS instruction. So, it is depending on the FPU to get it right. The FPU sets C2 if it is out of range, which you can test with the JP instruction. Alternatively, you can: #include <math.h> #undef cos which will disable the insertion of the fcos instruction, and will instead call the library cos() function. The library routine will test C2 and attempt argument reduction. It'll be significantly slower, though. To sum up, accurate and fast floating point are often at odds with each other.
Jun 05 2003
parent reply "Steve Hall" <sthall lorrexinc.com> writes:
Thank you Walter.

Would you tell me how I can use cosl and sinl library functions?

Do you intend to implement tgmath.h or do you have plans to finish C99
support for the math functions?

Steve

"Walter" <walter digitalmars.com> wrote in message
news:bbohg1$sh1$1 digitaldaemon.com...
 "Steve Hall" <sthall lorrexinc.com> wrote in message
 news:bboebu$ptk$1 digitaldaemon.com...
 What you think Walter about this (thanks for the correction of powl


 Do you accept to close your eyes in front of outstanding mathematical
 inaccuracy of your compiler? Do you accept to sell mathematical


 compiler and prefer everyone of your clients to know that you haven't
 interest to correct such a poblems?
 Can I develop mathematical/logicaly stable software if the used compiler
 contain mathematical bugs?
 From your point of view all you need to do is just to ignore this post,
 because I'm the only one who want mathematical stable compiler.
 Thank you for your patience Walter,
 Steve Hall

The fundamental problem is DMC++ gets killed in benchmark comparisons

 cos() is recognized by the compiler and replaced with the single FCOS
 instruction. So, it is depending on the FPU to get it right. The FPU sets

 if it is out of range, which you can test with the JP instruction.

 Alternatively, you can:

     #include <math.h>
     #undef cos

 which will disable the insertion of the fcos instruction, and will instead
 call the library cos() function. The library routine will test C2 and
 attempt argument reduction. It'll be significantly slower, though.

 To sum up, accurate and fast floating point are often at odds with each
 other.

Jun 06 2003
parent "Walter" <walter digitalmars.com> writes:
"Steve Hall" <sthall lorrexinc.com> wrote in message
news:bbpms5$1uae$1 digitaldaemon.com...
 Would you tell me how I can use cosl and sinl library functions?

At the moment, you can just use the inline FCOS and FSIN versions.
 Do you intend to implement tgmath.h

That turns out to be a **** to implement.
 or do you have plans to finish C99
 support for the math functions?

Yes.
Jun 06 2003
prev sibling parent Keith Fuller <Keith_member pathlink.com> writes:
Can I develop mathematical/logicaly stable software if the used compiler
contain mathematical bugs?

If this were a meaningful calculation, I would agree with you. If this were another programming language, I would probably agree with you. But this is C. There is no lower-level language available. People using C would rather have the maximum performance and smallest code instead of catering to goofy calculations.
Thank you for your patience Walter,
Steve Hall

Keith Fuller keithfx.h tmail.com
Jun 05 2003
prev sibling parent reply Heinz Saathoff <hsaat bre.ipnet.de> writes:
Steve Hall schrieb...
 dmc v3.34 is a C99 conformed compiler with IEC 60559 support according to
 macros __STDC_VERSION__(199901) and __STDC_IEC_559__. Types float and double
 are respectively single and double precision types from IEC 60559(Binary
 floating-point arithmetic for microprocessor systems, second edition). The
 floating-point standard is independent of the hardware.

I don't have the C99 Standard here but would assume that the floating point specs rely on the IEEE spec, and that is the basic for FPU implementations.
 According to C99 the maximum representable number for type float is FLT_MAX
 = 3.40282347E+38, for type double is DBL_MAX = 1.7976931348623157E+308. Type
 double is subset of type long double, which is compiler dependent(for dmc
 v3.34 long double contain 80 bits).

So far DMC doesn't have a problem. It would be interesting to see what the C99 standard tells about argument ranges. Is it required for sin/cos to provide a reasonable (not correct, only range [-1,1]) result for all float/double arguments? What about tan, when the huge argument reduces to PI/2?
 The same code compiled with gcc v3.2.3 (mingw special 20030504-1) return
 reasonable results for functions cos and cosf(the recent version of MinGW
 gcc doesn't support properly displaying of long double type thru printf
 function).

I don't have access to mingw. Maybe the compiler evaluates the FPU flags to detect the fault and corrects ist? To Walter: is this where the difference between -f and -ff is? As I understand the -ff (fast floating point) option doesn't check for special cases (nan, overflows). - Heinz
Jun 06 2003
parent "Walter" <walter digitalmars.com> writes:
"Heinz Saathoff" <hsaat bre.ipnet.de> wrote in message
news:MPG.194a68fa681300f79896be news.digitalmars.com...
 To Walter:
 is this where the difference between -f and -ff is? As I understand the
 -ff (fast floating point) option doesn't check for special cases (nan,
 overflows).

Right. It was put in there for benchmarking floating point against compilers which do not handle nans.
Jun 06 2003