This is a discussion on sprintf() and negative zero within the mailing.openbsd.tech forums, part of the OpenBSD category; --> Hi, Myself and another developer are working to bring llvm to OpenBSD and have hit an interesting bug in ...
| |||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| Hi, Myself and another developer are working to bring llvm to OpenBSD and have hit an interesting bug in either sprintf() or llvm's regression tests. I have brought it to the attention of the llvm developers. Full thread here: http://lists.cs.uiuc.edu/pipermail/l...ly/015569.html And they are suggesting that our sprintf() is not in line with the C99 standard: http://lists.cs.uiuc.edu/pipermail/l...ly/015587.html Maybe, maybe not. I don't know. The regress test in question itself makes two "minus zero" numbers (in llvm bytecode) and assembles it, the disassembles it to see if the result is the same. Linux ofcourse works, but our sprintf() which is called in the dis-assembler strips the minus from minus zero. printf() does the same. The LLVM team are correct that 0 != -0 in floating point number representation. For example a double (on i386): 0x8000000000000000 vs 0x0000000000000000 Here is a simple test for repro: #include <stdio.h> int main(void) { double a = -0; printf("%x = %e\n",a, a); return 0; } puff% ./a.out 0 = 0.000000e+00 Thoughts appreciated. |
| |||
| On Tue, Jul 01, 2008 at 08:15:05PM +0100, Edd Barrett wrote: > Hi, > > Myself and another developer are working to bring llvm to OpenBSD and > have hit an interesting bug in either sprintf() or llvm's regression > tests. > > I have brought it to the attention of the llvm developers. Full thread > here: http://lists.cs.uiuc.edu/pipermail/l...ly/015569.html > > And they are suggesting that our sprintf() is not in line with the C99 > standard: > http://lists.cs.uiuc.edu/pipermail/l...ly/015587.html > > Maybe, maybe not. I don't know. > > The regress test in question itself makes two "minus zero" numbers (in > llvm bytecode) and assembles it, the disassembles it to see if the > result is the same. Linux ofcourse works, but our sprintf() which is > called in the dis-assembler strips the minus from minus zero. printf() > does the same. > > The LLVM team are correct that 0 != -0 in floating point number > representation. > > For example a double (on i386): > 0x8000000000000000 vs 0x0000000000000000 > > Here is a simple test for repro: > > #include <stdio.h> > > int > main(void) > { > double a = -0; > printf("%x = %e\n",a, a); > return 0; > } > > puff% ./a.out > 0 = 0.000000e+00 > > Thoughts appreciated. This test program is bogus. You cannnot pass a double to printf and print it as an int. Also, the converison on -0 will first be to integer 0 and then to double 0.0. That said, I actually don't know if printf should make a distinction between +0.0 and -0.0. -Otto |
| |||
| On 7/1/08, Edd Barrett <vext01@gmail.com> wrote: > And they are suggesting that our sprintf() is not in line with the C99 > standard: > http://lists.cs.uiuc.edu/pipermail/l...ly/015587.html for those following along at home, it's footnote 236 in the draft. |
| |||
| Otto Moerbeek wrote: > On Tue, Jul 01, 2008 at 08:15:05PM +0100, Edd Barrett wrote: >> Here is a simple test for repro: >> >> #include <stdio.h> >> >> int >> main(void) >> { >> double a = -0; >> printf("%x = %e\n",a, a); >> return 0; >> } >> >> puff% ./a.out >> 0 = 0.000000e+00 >> >> Thoughts appreciated. > > This test program is bogus. You cannnot pass a double to printf and > print it as an int. Also, the converison on -0 will first be to > integer 0 and then to double 0.0. Yup! I had a "doh!" moment whilst in the shower a few minutes ago. Try this: #include <stdio.h> int main(void) { double a; /* Raw */ printf("%f\n", 0x8000000000000000); /* Force Sign */ printf("%+f\n", 0x8000000000000000); /* Test on real -ve number */ a = -0.666; printf("%+f\n", a); return 0; } puff% ./a.out 0.000000 +0.000000 -0.666000 Also FWIW we md5'd the binary made from the assembler on linux and OpenBSD and they match. > > That said, I actually don't know if printf should make a distinction between > +0.0 and -0.0. *shrugs* |
| |||
| On Tue, Jul 01, 2008 at 09:34:11PM +0200, Otto Moerbeek wrote: > On Tue, Jul 01, 2008 at 08:15:05PM +0100, Edd Barrett wrote: > > > Hi, > > > > Myself and another developer are working to bring llvm to OpenBSD and > > have hit an interesting bug in either sprintf() or llvm's regression > > tests. > > > > I have brought it to the attention of the llvm developers. Full thread > > here: http://lists.cs.uiuc.edu/pipermail/l...ly/015569.html > > > > And they are suggesting that our sprintf() is not in line with the C99 > > standard: > > http://lists.cs.uiuc.edu/pipermail/l...ly/015587.html > > > > Maybe, maybe not. I don't know. > > > > The regress test in question itself makes two "minus zero" numbers (in > > llvm bytecode) and assembles it, the disassembles it to see if the > > result is the same. Linux ofcourse works, but our sprintf() which is > > called in the dis-assembler strips the minus from minus zero. printf() > > does the same. > > > > The LLVM team are correct that 0 != -0 in floating point number > > representation. > > > > For example a double (on i386): > > 0x8000000000000000 vs 0x0000000000000000 > > > > Here is a simple test for repro: > > > > #include <stdio.h> > > > > int > > main(void) > > { > > double a = -0; > > printf("%x = %e\n",a, a); > > return 0; > > } > > > > puff% ./a.out > > 0 = 0.000000e+00 > > > > Thoughts appreciated. > > This test program is bogus. You cannnot pass a double to printf and > print it as an int. Also, the converison on -0 will first be to > integer 0 and then to double 0.0. > > That said, I actually don't know if printf should make a distinction between > +0.0 and -0.0. > > -Otto Here's a better test program. Reading math(3) helps. Although +0.0 and -0.0 have a different bit representation, the values should compare equal. Indeed, C99 requires the -0.0 and +0.0 to be printed differently, but in my book it suggests footnote 234 only applies to the + format modifier. The program demonstrates that we print always +0.0. So that is a C99 bug. But we never promise we actually implement C99. See printf(3), STANDARDS section (I'm too lazy now to check what C89 says). [otto@pepper:45]$ cat y.c #include <math.h> #include <stdio.h> void pr(void *p) { int i; unsigned char *q = p; for (i = 0; i < 8; i++) printf("%02x ", q[i]); printf("\n"); } main() { double a = copysign(0.0, 0.0); double b = copysign(0.0, -1.0); pr(&a); pr(&b); printf("%+f %+f %d\n", a, b, a == b); return 0; } [otto@pepper:46]$ ./a.out 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 +0.000000 +0.000000 1 [otto@pepper:47]$ -Otto |
| |||
| On Tue, Jul 01, 2008 at 04:06:58PM -0400, Ted Unangst wrote: > On 7/1/08, Edd Barrett <vext01@gmail.com> wrote: > > And they are suggesting that our sprintf() is not in line with the C99 > > standard: > > http://lists.cs.uiuc.edu/pipermail/l...ly/015587.html > > for those following along at home, it's footnote 236 in the draft. but 234 in my copy, which includes the Corrigendum #1... -Otto |
| |||
| Otto Moerbeek wrote: > On Tue, Jul 01, 2008 at 04:06:58PM -0400, Ted Unangst wrote: > >> On 7/1/08, Edd Barrett <vext01@gmail.com> wrote: >>> And they are suggesting that our sprintf() is not in line with the C99 >>> standard: >>> http://lists.cs.uiuc.edu/pipermail/l...ly/015587.html >> for those following along at home, it's footnote 236 in the draft. > > but 234 in my copy, which includes the Corrigendum #1... > > -Otto Well it seems the llvm guys are willing to alter the test suite, but its up to you guys what you deem correct. Would it be useful to run a test on a handfull of different platforms to see what they do? Thanks |
| |||
| On Wed, Jul 02, 2008 at 01:59:58PM +0100, Edd Barrett wrote: > Otto Moerbeek wrote: >> On Tue, Jul 01, 2008 at 04:06:58PM -0400, Ted Unangst wrote: >> >>> On 7/1/08, Edd Barrett <vext01@gmail.com> wrote: >>>> And they are suggesting that our sprintf() is not in line with the C99 >>>> standard: >>>> http://lists.cs.uiuc.edu/pipermail/l...ly/015587.html >>> for those following along at home, it's footnote 236 in the draft. >> >> but 234 in my copy, which includes the Corrigendum #1... >> >> -Otto > > Well it seems the llvm guys are willing to alter the test suite, but its > up to you guys what you deem correct. > > Would it be useful to run a test on a handfull of different platforms to > see what they do? > > Thanks On the very short term I see no chanche of altering sprintf. But it would be useful indeed to check other platforms to see how the handle both %f and %+f. -Otto |
| |||
| On Thu, Jul 3, 2008 at 1:10 PM, viq <viq@viq.ath.cx> wrote: > On Thu, Jul 03, 2008 at 12:39:55PM +0200, Otto Moerbeek wrote: >> Everybody, please use this program, to get consistent results. >> >> #include <math.h> >> #include <stdio.h> >> >> void >> pr(void *p) >> { >> int i; >> unsigned char *q = p; >> >> for (i = 0; i < sizeof(double); i++) >> printf("%02x ", q[i]); >> printf("\n"); >> } >> >> main() >> { >> double a = copysign(0.0, 0.0); >> double b = copysign(0.0, -1.0); >> pr(&a); >> pr(&b); >> printf("%+f %+f %f %f %d\n", a, b, a, b, a == b); >> return 0; >> } Darwin nemo 8.11.1 Darwin Kernel Version 8.11.1: Wed Oct 10 18:23:28 PDT 2007; root:xnu-792.25.20~1/RELEASE_I386 i386 i386 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 +0.000000 -0.000000 0.000000 -0.000000 1 -- Bram Dumolin |
| ||||
| On Thu, Jul 3, 2008 at 8:39 PM, Otto Moerbeek <otto@drijf.net> wrote: > Everybody, please use this program, to get consistent results. adalg@melba:~ $uname -a HP-UX melba B.11.11 U 9000/800 3875018144 unlimited-user license adalg@melba:~ $gcc --version gcc (GCC) 3.4.3 Copyright (C) 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. adalg@melba:~ $gcc test-sprintf.c -lm /usr/ccs/bin/ld: (Warning) At least one PA 2.0 object file (/var/tmp//ccDJczyb.o) was detected. The linked output may not run on a PA 1.x system. adalg@melba:~ $./a.out 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 +0.000000 -0.000000 0.000000 -0.000000 1 and after making the function prototypes non-ansi, adalg@melba:~ $cc test-sprintf.c -lm /usr/ccs/bin/ld: (Warning) At least one PA 2.0 object file (test-sprintf.o) was detected. The linked output may not run on a PA 1.x system. adalg@melba:~ $./a.out 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 +0.000000 -0.000000 0.000000 -0.000000 1 |
| Thread Tools | |
| Display Modes | |
|
|