X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f X-Recipient: djgpp-workers AT delorie DOT com X-Authenticated: #27081556 X-Provags-ID: V01U2FsdGVkX1/e+UlBzafe/Z2ARLACNnnyBrVQvNx66wRKJbjTlD dEiJz/pghvnvWn From: Juan Manuel Guerrero To: djgpp-workers AT delorie DOT com Subject: Re: atan2 bug Date: Tue, 15 Sep 2009 00:25:37 +0200 User-Agent: KMail/1.9.10 References: <200909142122 DOT 34236 DOT juan DOT guerrero AT gmx DOT de> <83y6ohxos6 DOT fsf AT gnu DOT org> In-Reply-To: <83y6ohxos6.fsf@gnu.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200909150025.37854.juan.guerrero@gmx.de> X-Y-GMX-Trusted: 0 X-FuHaFi: 0.42 Reply-To: djgpp-workers AT delorie DOT com Am Montag, 14. September 2009 schrieb Eli Zaretskii: [snip] > Do you have a test that actually trips it? If so, how about adding it > to tests/libc/ansi/math? > Below is a test progran that will trigger the bug. If y is positive finite and x is positive infinity then the result of atan2(y, x) must be +0.0 but atan2 returns errno=1 and NaN as result. The explanaition has already be given in the previuos post. If y is negative finite and x is negative infinite the result must be -PI, but again errno=1 and result set to NaN. Here is the original (offending) code snippet: aby: movl 8(%esp), %eax /* inf or NaN */ <== loads mantissa high part of double y. testl $0x000FFFFF, %eax jne badarg /* y = NaN */ movl 4(%esp), %eax <== loads mantissa low part of double y. testl %eax, %eax jnz badarg movl 16(%esp), %eax andl $0x7FF00000,%eax cmpl $0x7FF00000,%eax jne argok /* x is finite */ jmp badarg abx: movl 16(%esp), %eax /* inf or NaN */ <== loads mantissa high part of double x. testl $0x000FFFFF, %eax jnz badarg movl 4(%esp), %eax <== loads mantissa low part of double y instead of double x. testl %eax, %eax jnz badarg movl 8(%esp), %eax andl $0x7FF00000,%eax cmpl $0x7FF00000,%eax jne argok /* y is finite */ A quick inspection of the marked lines show that the test ist broken and will never work properly. Every time the 32 bits at 4(%esp) are different from zero the value of x will be interpreted as NaN and this is simply wrong. With this code there is no way to identify x as infinite because the low part of the x- mantissa is never evaluated. Regards, Juan M. Guerrero 2009-09-14 Juan Manuel Guerrero Diffs against djgpp CVS head of 2009-08-16. * src/libc/ansi/math/atan2.S: Check mantissa of y and not mantissa of x. diff -aprNU5 djgpp.orig/src/libc/ansi/math/atan2.S djgpp/src/libc/ansi/math/atan2.S --- djgpp.orig/src/libc/ansi/math/atan2.S 1999-08-04 19:58:20 +0000 +++ djgpp/src/libc/ansi/math/atan2.S 2009-09-15 00:16:18 +0000 @@ -45,12 +45,12 @@ aby: jmp badarg abx: movl 16(%esp), %eax /* inf or NaN */ testl $0x000FFFFF, %eax - jnz badarg - movl 4(%esp), %eax + jne badarg /* x = NaN */ + movl 12(%esp), %eax testl %eax, %eax jnz badarg movl 8(%esp), %eax andl $0x7FF00000,%eax diff -aprNU5 djgpp.orig/tests/libc/ansi/math/elefunt/atan2.c djgpp/tests/libc/ansi/math/elefunt/atan2.c --- djgpp.orig/tests/libc/ansi/math/elefunt/atan2.c 1970-01-01 00:00:00 +0000 +++ djgpp/tests/libc/ansi/math/elefunt/atan2.c 2009-09-15 00:12:56 +0000 @@ -0,0 +1,48 @@ +#include +#include +#include +#include + + +int main(void) +{ + _double_union_t x, y; + double result; + + y.d = M_PI; + x.dt.sign = 0; + x.dt.exponent = 0x07FF; + x.dt.mantissah = 0x000000000; + x.dt.mantissal = 0x000000000; /* +Infinity. */ + + /* + * Compute atan of the quotient of a positive finite number with pos. infinite. + * The result must be +0.0 + */ + errno = 0; + result = atan2(y.d, x.d); + if (errno) + printf("errno=%d\ny=%f x=%f: result=%f result must be +0.0\n", errno, y.d, x.d, result); + else if (result == +0.0) + printf("test passed.\n"); + else + printf("test failed.\n"); + + + /* + * Compute atan of the quotient of a negative finite number with pos. infinite. + * The result must be -0.0 + */ + errno = 0; + y.dt.sign = 1; + x.dt.sign = 1; + result = atan2(y.d, x.d); + if (errno) + printf("errno=%d\ny=%f x=%f: result=%f result must be -0.0\n", errno, y.d, x.d, result); + else if (result == -M_PI) + printf("test passed.\n"); + else + printf("test failed.\n"); + + return 0; +} diff -aprNU5 djgpp.orig/tests/libc/ansi/math/elefunt/makefile djgpp/tests/libc/ansi/math/elefunt/makefile --- djgpp.orig/tests/libc/ansi/math/elefunt/makefile 2003-04-20 14:10:34 +0000 +++ djgpp/tests/libc/ansi/math/elefunt/makefile 2009-09-15 00:16:18 +0000 @@ -98,11 +98,12 @@ TARGETS = \ tpower.$(LOG) \ tsin.$(LOG) \ tsinh.$(LOG) \ tsqrt.$(LOG) \ ttan.$(LOG) \ - ttanh.$(LOG) + ttanh.$(LOG) \ + atan2.$(LOG) # $(EXECUTABLES) = $(TARGETS:/s/.$(LOG)/$(EXE)) all :: $(TARGETS) @rem.com @@ -120,11 +121,11 @@ summary: egrep "^1|ESTIMATED LOSS" *$(LOG) clean: $(RM) *.o *.obj *.bak *.exe $(RM) talog tasin tatan texp tpower tsin tsinh - $(RM) tsqrt ttan ttanh tmacha + $(RM) tsqrt ttan ttanh tmacha atan2 realclean : clean # delete log files, too $(RM) *.djl *.bcl *.tcl ifdef BORLAND tmacha$(EXE): tmacha.$(OE) $(OBJS) @@ -180,10 +181,12 @@ tsqrt$(EXE): msqrt.$(OE) tsqrt.$(OE) $(O $(LD) $(LDFLAGS) $(OUT) $@ $^ $(LIBS) ttan$(EXE): mtan.$(OE) ttan.$(OE) $(OBJS) $(LD) $(LDFLAGS) $(OUT) $@ $^ $(LIBS) ttanh$(EXE): mtanh.$(OE) ttanh.$(OE) $(OBJS) $(LD) $(LDFLAGS) $(OUT) $@ $^ $(LIBS) +tatan2$(EXE): atan2.$(OE) + $(LD) $(LDFLAGS) $(OUT) $@ $^ $(LIBS) endif # dependencies found by gcc -MM *.c tpower.$(OE) : tpower.c elefunt.h @@ -195,10 +198,11 @@ tsinh.$(OE) : tsinh.c elefunt.h tsqrt.$(OE) : tsqrt.c elefunt.h ttan.$(OE) : ttan.c elefunt.h ttanh.$(OE) : ttanh.c elefunt.h tmacha.$(OE) : tmacha.c elefunt.h atan.$(OE) : atan.c +atan2.$(OE) : atan2.c exp.$(OE) : exp.c ipow.$(OE) : ipow.c elefunt.h ldexp.$(OE) : ldexp.c tsmach.$(OE) : tsmach.c elefunt.h malog.$(OE) : malog.c elefunt.h