Date: Fri, 2 Dec 2005 13:45:06 +0000 (UTC) From: Bruce Evans <bde@FreeBSD.org> To: src-committers@FreeBSD.org, cvs-src@FreeBSD.org, cvs-all@FreeBSD.org Subject: cvs commit: src/lib/msun/src s_round.c s_roundf.c s_roundl.c Message-ID: <200512021345.jB2Dj6D3057000@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
bde 2005-12-02 13:45:06 UTC FreeBSD src repository Modified files: lib/msun/src s_round.c s_roundf.c s_roundl.c Log: Fixed roundf(). The following cases never worked in FreeBSD: - in round-towards-minus-infinity mode, on all machines, roundf(x) never worked for 0 < |x| < 0.5 (2*0x3effffff cases in all, or almost half of float space). It was -0 for 0 < x < 0.5 and 0 for -0.5 < x < 0, but should be 0 and -0, respectively. This is because t = ceilf(|x|) = 1 for these args, and when we adjust t from 1 to 0 by subtracting 1, we get -0 in this rounding mode, but we want and expected to get 0. - in round-towards-minus-infinity, round towards zero and round-to-nearest modes, on machines that evaluate float expressions in float precision (most machines except i386's), roundf(x) never worked for |x| = <float value immediately below 0.5> (2 cases in all). It was +-1 but should have been +-0. This is because t = ceilf(|x|) = 1 for these args, and when we try to classify |x| by subtracting it from 1 we get an unexpected rounding error -- the result is 0.5 after rounding to float in all 3 rounding modes, so we we have forgotten the difference between |x| and 0.5 and end up returning the same value as for +-0.5. The fix is to use floorf() instead of ceilf() and to add 1 instead of -1 in the adjustment. With floorf() all the expressions used are always evaluated exactly so there are no rounding problems, and with adjustments of +1 we don't go near -0 when adjusting. Attempted to fix round() and roundl() by cloning the fix for roundf(). This has only been tested for round(), only on args representable as floats. Double expressions are evaluated in double precision even on i386's, so round(0.5-epsilon) was broken even on i386's. roundl() must be completely broken on i386's since long double precision is not really supported. There seem to be no other dependencies on the precision. Revision Changes Path 1.4 +6 -6 src/lib/msun/src/s_round.c 1.4 +6 -6 src/lib/msun/src/s_roundf.c 1.2 +6 -6 src/lib/msun/src/s_roundl.c
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200512021345.jB2Dj6D3057000>