diff options
Diffstat (limited to 'lib/libc/quad/fixunsdfdi.c')
-rw-r--r-- | lib/libc/quad/fixunsdfdi.c | 38 |
1 files changed, 11 insertions, 27 deletions
diff --git a/lib/libc/quad/fixunsdfdi.c b/lib/libc/quad/fixunsdfdi.c index 9eb5e8f2e66..7f1e093f9c8 100644 --- a/lib/libc/quad/fixunsdfdi.c +++ b/lib/libc/quad/fixunsdfdi.c @@ -32,12 +32,12 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$OpenBSD: fixunsdfdi.c,v 1.4 2004/04/25 21:05:01 dhartmei Exp $"; +static char rcsid[] = "$OpenBSD: fixunsdfdi.c,v 1.5 2004/04/27 17:46:46 otto Exp $"; #endif /* LIBC_SCCS and not lint */ #include "quad.h" -#define ONE_FOURTH ((long)1 << (LONG_BITS - 2)) +#define ONE_FOURTH ((int)1 << (INT_BITS - 2)) #define ONE_HALF (ONE_FOURTH * 2.0) #define ONE (ONE_FOURTH * 4.0) @@ -50,8 +50,8 @@ u_quad_t __fixunsdfdi(x) double x; { - double toppart; union uu t; + unsigned int tmp; if (x < 0) return (UQUAD_MAX); /* ??? should be 0? ERANGE??? */ @@ -63,30 +63,14 @@ __fixunsdfdi(x) return (UQUAD_MAX); #endif /* - * Get the upper part of the result. Note that the divide - * may round up; we want to avoid this if possible, so we - * subtract `1/2' first. + * Now we know that 0 <= x <= 18446744073709549568. The upper + * limit is one ulp less than 18446744073709551615 tested for above. + * Dividing this by 2^32 will *not* round irrespective of any + * rounding modes (except if the result is an IEEE denorm). + * Furthermore, the quotient will fit into a 32-bit integer. */ - toppart = (x - ONE_HALF) / ONE; - /* - * Now build a u_quad_t out of the top part. The difference - * between x and this is the bottom part (this may introduce - * a few fuzzy bits, but what the heck). With any luck this - * difference will be nonnegative: x should wind up in the - * range [0..ULONG_MAX]. For paranoia, we assume [LONG_MIN.. - * 2*ULONG_MAX] instead. - */ - t.ul[H] = (unsigned long)toppart; - t.ul[L] = 0; - x -= (double)t.uq; - if (x < 0) { - t.ul[H]--; - x += ULONG_MAX + 1; - } - if (x > ULONG_MAX) { - t.ul[H]++; - x -= ULONG_MAX + 1; - } - t.ul[L] = (u_long)x; + tmp = x / ONE; + t.ul[L] = (unsigned int) (x - tmp * ONE); + t.ul[H] = tmp; return (t.uq); } |