Date: Mon, 16 Jan 2012 09:15:52 -0700 From: Ian Lepore <freebsd@damnhippie.dyndns.org> To: David Schultz <das@freebsd.org> Cc: freebsd-arm <freebsd-arm@freebsd.org> Subject: Re: fenv.h fixes for softfloat Message-ID: <1326730552.1669.29.camel@revolution.hippie.lan> In-Reply-To: <20120116022647.GA36657@zim.MIT.EDU> References: <20120111101833.GA88428@ci0.org> <1326291254.2419.55.camel@revolution.hippie.lan> <20120111175516.GA99475@zim.MIT.EDU> <1326509894.48691.100.camel@revolution.hippie.lan> <20120114081214.GA14925@zim.MIT.EDU> <1326563626.1678.34.camel@revolution.hippie.lan> <20120114182933.GA17739@zim.MIT.EDU> <1326568038.1678.43.camel@revolution.hippie.lan> <20120114211039.GA18310@zim.MIT.EDU> <1326591214.1678.85.camel@revolution.hippie.lan> <20120116022647.GA36657@zim.MIT.EDU>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 2012-01-15 at 21:26 -0500, David Schultz wrote: > On Sat, Jan 14, 2012, Ian Lepore wrote: > I believe 0x10 is FE_INEXACT on arm, not FE_INVALID. FE_INEXACT > is correct here, because w+TWO52[sx] is inexact. That still > doesn't explain the lrint() failures, but it makes them less > mysterious. For instance, the implementation of the cast from > double to int could raise a bogus inexact exception when the > number is an integer to begin with. In practice, I think the > emulated casts don't raise the proper exceptions even when they > should. It might depend on whether it's linking against libgcc's > __fixdfsi() or libc's. Doh! I could've sworn at one point I was seeing FE_INVALID set after the cast, but now the only thing I'm really sure of is that in jumping from one theory and way of testing it to another I seem to have thoroughly confused myself (and probably you too, sorry about that). So, on theory that there's probably nothing wrong with rint() but maybe something wrong with casting, I tried a test that does what the guts of llrint() does, but breaking the casting into a separate step and looking at the flags after each operation. I also tried casting to (long) versus (long long) and the results are different. Here's the broken down test code: fenv_t env; volatile long long llr; volatile double dr; volatile double _d = 1.0; feclearexcept(FE_ALL_EXCEPT); feholdexcept(&env); printf("except 1: %#x\n", fetestexcept(FE_ALL_EXCEPT)); dr = rint(_d); printf("except 2: %#x\n", fetestexcept(FE_ALL_EXCEPT)); if (fetestexcept(FE_INVALID)) feclearexcept(FE_INEXACT); printf("except 3: %#x\n", fetestexcept(FE_ALL_EXCEPT)); llr = (long)dr; printf("except 4: %#x\n", fetestexcept(FE_ALL_EXCEPT)); llr = (long long)dr; printf("except 5: %#x\n", fetestexcept(FE_ALL_EXCEPT)); feupdateenv(&env); printf("except 6: %#x _d=%f dr=%f llr=%lld\n", fetestexcept(FE_ALL_EXCEPT), _d, dr, llr); And here's the output from running it: except 1: 0 except 2: 0 except 3: 0 except 4: 0 except 5: 0x10 except 6: 0x10 _d=1.000000 dr=1.000000 llr=1 It's interesting that a cast to 32 bits is fine but a cast directly to 64 bits raises FE_INEXACT for the same value. I did spot-check a few values other than 1.0, and they behaved the same (IE, 1.0 is not special, it happens with anything.0), and of course with non-integer starting values FE_INEXACT is set coming out of rint() as you'd expect. BTW, I never reposted the results of running all the tests after fixing the long double printf glitch, but basically it looked like they were identical to the prior results except that the values were printedly correctly. That is, it appears that everything that was failing still failed, but I'm going to confirm that more rigorously soon (like making sure I don't have any forgotten hacks/tweaks in any lib or test code). -- Ian
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1326730552.1669.29.camel>