summaryrefslogtreecommitdiffstats
path: root/lib/libc/quad/fixunsdfdi.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/quad/fixunsdfdi.c')
-rw-r--r--lib/libc/quad/fixunsdfdi.c38
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);
}