Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 30 Mar 2010 09:05:25 -0600 (MDT)
From:      "M. Warner Losh" <imp@bsdimp.com>
To:        mav@FreeBSD.org
Cc:        freebsd-arm@FreeBSD.org
Subject:   Re: printf(long double)
Message-ID:  <20100330.090525.956847443318914833.imp@bsdimp.com>
In-Reply-To: <4BB1C5C9.8000402@FreeBSD.org>
References:  <4BB1C5C9.8000402@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
In message: <4BB1C5C9.8000402@FreeBSD.org>
            Alexander Motin <mav@FreeBSD.org> writes:
: Hi.
: 
: Playing with SheevaPlug (Marvell 88F6281 rev A0) with fresh 9-CURRENT
: I've found that many system statistics utilities are lying, showing
: number few times smaller then expected. After some investigation I've
: found that the problem possibly goes from different meaning of (long
: double) type for compiler and printf() code.

Yes.  That's possible.  Your code has some mis-match between printf
args, which most likely is causing problems.

: I've written small test to check it:
: #include <stdio.h>
: int
: main (void)
: {
:         printf("%d %d\n", sizeof(long double), sizeof(double));
:         printf("%Lf %f %Lf %f\n", (long double)14.5, (long double)14.5,
:                 (double)14.5, (double)14.5);
: }
: 
: On amd64 it prints:
: # ./a.out
: 
: But on arm:
: %./a.out
: 
: Can somebody comment this?

amd64: 16 8
arm  : 8 8

long double is only guaranteed to be as long as double, but may be
longer.  Even on i386 it is really only 80 bits, even though you'd
think it should be 128 bits.  On ARM we use soft floating point, so
long double is folded into double.  There may be away to have 128-bit
floating point support, but nobody has climbed that hill for ARM or
for MIPS.



amd64: 14.500000 14.500000 14.500000 14.500000
arm  : 6.500000 14.500000 6.500000 14.500000

First, your code gives warnings:

g.c:5: warning: format '%d' expects type 'int', but argument 2 has type 'long unsigned int'
g.c:5: warning: format '%d' expects type 'int', but argument 3 has type 'long unsigned int'
g.c:7: warning: format '%f' expects type 'double', but argument 3 has type 'long double'
g.c:7: warning: format '%Lf' expects type 'long double', but argument 4 has type 'double'

The first two are benign since the sizes are the same (long and int
are the same in both ABIs).

The second two show that two of the results should be wrong, depending
on the ABIs.  Looking at the generated code on amd64, it looks like 8
bytes are used for each element passed into.  But it also looks like
the floating point xmm registers are used, which is likely why it gets
things right.  I don't know enough about the amd64 ABI to know if this
is a correct analysis, but likely is something close, since otherwise
I'd have expected the results to be wrong.

ARM should have passed the same size element for both the double and
the long double, but didn't.  You should try fixing the printf and
running again.  I don't have the ARM ABI docs handy to look it up, but
I know that some args are passed on the stack, while others are passed
in registers.  This difference likely accounts for the numbers being
printed wrong.

On x86, we get:
12 8
14.500000 -9124881235244390437282343211400582649786457014497119861158385035798550334417354773011825622634742799557284619147188814621377409442750875996505322639444428376503989348720529900165748384493207552.000000 0.000000 14.500000

which doesn't look right to me.  Fixing the warnings we get:
12 8
14.500000 14.500000 14.500000 14.500000

Warner



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100330.090525.956847443318914833.imp>