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>