Unix Technical Forum

sprintf() and negative zero

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 ...


Go Back   Unix Technical Forum > Unix Operating Systems > OpenBSD > mailing.openbsd.tech

FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 07-02-2008, 05:10 AM
Edd Barrett
 
Posts: n/a
Default sprintf() and negative zero

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.

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #2 (permalink)  
Old 07-02-2008, 05:10 AM
Otto Moerbeek
 
Posts: n/a
Default Re: sprintf() and negative zero

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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #3 (permalink)  
Old 07-02-2008, 05:10 AM
Ted Unangst
 
Posts: n/a
Default Re: sprintf() and negative zero

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.

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #4 (permalink)  
Old 07-02-2008, 05:10 AM
Edd Barrett
 
Posts: n/a
Default Re: sprintf() and negative zero

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*

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #5 (permalink)  
Old 07-02-2008, 05:10 AM
Otto Moerbeek
 
Posts: n/a
Default Re: sprintf() and negative zero

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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #6 (permalink)  
Old 07-02-2008, 05:10 AM
Otto Moerbeek
 
Posts: n/a
Default Re: sprintf() and negative zero

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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #7 (permalink)  
Old 07-02-2008, 03:06 PM
Edd Barrett
 
Posts: n/a
Default Re: sprintf() and negative zero

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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #8 (permalink)  
Old 07-02-2008, 03:06 PM
Otto Moerbeek
 
Posts: n/a
Default Re: sprintf() and negative zero

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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #9 (permalink)  
Old 07-04-2008, 06:48 AM
Bram Dumolin
 
Posts: n/a
Default Re: sprintf() and negative zero

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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #10 (permalink)  
Old 07-04-2008, 06:48 AM
Andrew Dalgleish
 
Posts: n/a
Default Re: sprintf() and negative zero

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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 11:36 PM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0
www.UnixAdminTalk.com