# commit da13146da10360436941e843834c90a9aef5fd7a # Author: Alan Modra # Date: Sat Aug 17 18:30:23 2013 +0930 # # PowerPC floating point little-endian [10 of 15] # http://sourceware.org/ml/libc-alpha/2013-07/msg00201.html # # These two functions oddly test x+1>0 when a double x is >= 0.0, and # similarly when x is negative. I don't see the point of that since the # test should always be true. I also don't see any need to convert x+1 # to integer rather than simply using xr+1. Note that the standard # allows these functions to return any value when the input is outside # the range of long long, but it's not too hard to prevent xr+1 # overflowing so that's what I've done. # # (With rounding mode FE_UPWARD, x+1 can be a lot more than what you # might naively expect, but perhaps that situation was covered by the # x - xrf < 1.0 test.) # # * sysdeps/powerpc/fpu/s_llround.c (__llround): Rewrite. # * sysdeps/powerpc/fpu/s_llroundf.c (__llroundf): Rewrite. # diff -urN glibc-2.17-c758a686.orig/sysdeps/powerpc/fpu/s_llround.c glibc-2.17-c758a686.diff/sysdeps/powerpc/fpu/s_llround.c --- glibc-2.17-c758a686.orig/sysdeps/powerpc/fpu/s_llround.c 2014-05-27 22:38:55.000000000 -0500 +++ glibc-2.17-c758a686.diff/sysdeps/powerpc/fpu/s_llround.c 2014-05-27 22:38:58.000000000 -0500 @@ -19,29 +19,28 @@ #include #include -/* I think that what this routine is supposed to do is round a value - to the nearest integer, with values exactly on the boundary rounded - away from zero. */ -/* This routine relies on (long long)x, when x is out of range of a long long, - clipping to MAX_LLONG or MIN_LLONG. */ +/* Round to the nearest integer, with values exactly on a 0.5 boundary + rounded away from zero, regardless of the current rounding mode. + If (long long)x, when x is out of range of a long long, clips at + LLONG_MAX or LLONG_MIN, then this implementation also clips. */ long long int __llround (double x) { - double xrf; - long long int xr; - xr = (long long int) x; - xrf = (double) xr; + long long xr = (long long) x; + double xrf = (double) xr; + if (x >= 0.0) - if (x - xrf >= 0.5 && x - xrf < 1.0 && x+1 > 0) - return x+1; - else - return x; + { + if (x - xrf >= 0.5) + xr += (long long) ((unsigned long long) xr + 1) > 0; + } else - if (xrf - x >= 0.5 && xrf - x < 1.0 && x-1 < 0) - return x-1; - else - return x; + { + if (xrf - x >= 0.5) + xr -= (long long) ((unsigned long long) xr - 1) < 0; + } + return xr; } weak_alias (__llround, llround) #ifdef NO_LONG_DOUBLE diff -urN glibc-2.17-c758a686.orig/sysdeps/powerpc/fpu/s_llroundf.c glibc-2.17-c758a686.diff/sysdeps/powerpc/fpu/s_llroundf.c --- glibc-2.17-c758a686.orig/sysdeps/powerpc/fpu/s_llroundf.c 2014-05-27 22:38:55.000000000 -0500 +++ glibc-2.17-c758a686.diff/sysdeps/powerpc/fpu/s_llroundf.c 2014-05-27 22:38:58.000000000 -0500 @@ -18,28 +18,27 @@ #include -/* I think that what this routine is supposed to do is round a value - to the nearest integer, with values exactly on the boundary rounded - away from zero. */ -/* This routine relies on (long long)x, when x is out of range of a long long, - clipping to MAX_LLONG or MIN_LLONG. */ +/* Round to the nearest integer, with values exactly on a 0.5 boundary + rounded away from zero, regardless of the current rounding mode. + If (long long)x, when x is out of range of a long long, clips at + LLONG_MAX or LLONG_MIN, then this implementation also clips. */ long long int __llroundf (float x) { - float xrf; - long long int xr; - xr = (long long int) x; - xrf = (float) xr; + long long xr = (long long) x; + float xrf = (float) xr; + if (x >= 0.0) - if (x - xrf >= 0.5 && x - xrf < 1.0 && x+1 > 0) - return x+1; - else - return x; + { + if (x - xrf >= 0.5) + xr += (long long) ((unsigned long long) xr + 1) > 0; + } else - if (xrf - x >= 0.5 && xrf - x < 1.0 && x-1 < 0) - return x-1; - else - return x; + { + if (xrf - x >= 0.5) + xr -= (long long) ((unsigned long long) xr - 1) < 0; + } + return xr; } weak_alias (__llroundf, llroundf)