diff --git a/lib/msun/src/s_roundf.c b/lib/msun/src/s_roundf.c --- a/lib/msun/src/s_roundf.c +++ b/lib/msun/src/s_roundf.c @@ -32,22 +32,42 @@ float roundf(float x) { - float t; - uint32_t hx; + uint32_t hx, ix, sign; + int e; GET_FLOAT_WORD(hx, x); - if ((hx & 0x7fffffff) == 0x7f800000) - return (x + x); - - if (!(hx & 0x80000000)) { - t = floorf(x); - if (t - x <= -0.5F) - t += 1; - return (t); - } else { - t = floorf(-x); - if (t + x <= -0.5F) - t += 1; - return (-t); + sign = hx & 0x80000000; + ix = hx & 0x7fffffff; + + /* Inf/NaN or |x| >= 2^23 */ + if (ix >= 0x4b000000) + return (ix > 0x7f800000) ? (x + x) : x; + + e = (ix >> 23) - 127; + + /* |x| < 0.5: return ±0 */ + if (e < -1) { + SET_FLOAT_WORD(x, sign); + return x; + } + + /* |x| in [0.5, 1): return ±1 */ + if (e < 0) { + SET_FLOAT_WORD(x, sign | 0x3f800000); + return x; } + + /* 1 <= |x| < 2^23: truncate and add 0.5 based on fraction */ + uint32_t mask = 0x007fffff >> e; + + /* If no fractional bits, already integer */ + if ((ix & mask) == 0) + return x; + + /* Add 0.5 in the correct bit position */ + hx += 0x00400000 >> e; + hx &= ~mask; + + SET_FLOAT_WORD(x, hx); + return x; }