summaryrefslogtreecommitdiff
path: root/src/cairo-wideint.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-wideint.c')
-rw-r--r--src/cairo-wideint.c461
1 files changed, 46 insertions, 415 deletions
diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c
index 60946d90..9e4914e6 100644
--- a/src/cairo-wideint.c
+++ b/src/cairo-wideint.c
@@ -1,5 +1,5 @@
/*
- * $Id: cairo-wideint.c,v 1.5 2005-06-03 21:51:57 cworth Exp $
+ * $Id: cairo-wideint.c,v 1.6 2005-07-30 19:57:54 keithp Exp $
*
* Copyright © 2004 Keith Packard
*
@@ -36,22 +36,6 @@
#include "cairoint.h"
-#if !HAVE_UINT64_T || !HAVE_UINT128_T
-
-static const unsigned char top_bit[256] =
-{
- 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-};
-
-#endif
-
#if HAVE_UINT64_T
#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
@@ -157,7 +141,8 @@ _cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
cairo_int64_t
_cairo_int32x32_64_mul (int32_t a, int32_t b)
{
- s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t b));
+ cairo_int64_t s;
+ s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t) b);
if (a < 0)
s.hi -= b;
if (b < 0)
@@ -270,200 +255,38 @@ _cairo_uint64_negate (cairo_uint64_t a)
}
/*
- * The design of this algorithm comes from GCC,
- * but the actual implementation is new
+ * Simple bit-at-a-time divide.
*/
-
-static const int
-_cairo_leading_zeros32 (uint32_t i)
-{
- int top;
-
- if (i < 0x100)
- top = 0;
- else if (i < 0x10000)
- top = 8;
- else if (i < 0x1000000)
- top = 16;
- else
- top = 24;
- top = top + top_bit [i >> top];
- return 32 - top;
-}
-
-typedef struct _cairo_uquorem32_t {
- uint32_t quo;
- uint32_t rem;
-} cairo_uquorem32_t;
-
-/*
- * den >= num.hi
- */
-static const cairo_uquorem32_t
-_cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
-{
- cairo_uquorem32_t qr;
- uint32_t q0, q1, r0, r1;
- uint16_t d0, d1;
- uint32_t t;
-
- d0 = den & 0xffff;
- d1 = den >> 16;
-
- q1 = num.hi / d1;
- r1 = num.hi % d1;
-
- t = q1 * d0;
- r1 = (r1 << 16) | (num.lo >> 16);
- if (r1 < t)
- {
- q1--;
- r1 += den;
- if (r1 >= den && r1 < t)
- {
- q1--;
- r1 += den;
- }
- }
-
- r1 -= t;
-
- q0 = r1 / d1;
- r0 = r1 % d1;
- t = q0 * d0;
- r0 = (r0 << 16) | (num.lo & 0xffff);
- if (r0 < t)
- {
- q0--;
- r0 += den;
- if (r0 >= den && r0 < t)
- {
- q0--;
- r0 += den;
- }
- }
- r0 -= t;
- qr.quo = (q1 << 16) | q0;
- qr.rem = r0;
- return qr;
-}
-
cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
- cairo_uquorem32_t qr32;
cairo_uquorem64_t qr;
- int norm;
- uint32_t q1, q0, r1, r0;
-
- if (den.hi == 0)
+ cairo_uint64_t bit;
+ cairo_uint64_t quo;
+
+ bit = _cairo_uint32_to_uint64 (1);
+
+ /* normalize to make den >= num, but not overflow */
+ while (_cairo_uint64_lt (den, num) && (den.hi & 0x80000000) == 0)
{
- if (den.lo > num.hi)
- {
- /* 0q = nn / 0d */
-
- norm = _cairo_leading_zeros32 (den.lo);
- if (norm)
- {
- den.lo <<= norm;
- num = _cairo_uint64_lsl (num, norm);
- }
- q1 = 0;
- }
- else
- {
- /* qq = NN / 0d */
-
- if (den.lo == 0)
- den.lo = 1 / den.lo;
-
- norm = _cairo_leading_zeros32 (den.lo);
- if (norm)
- {
- cairo_uint64_t num1;
- den.lo <<= norm;
- num1 = _cairo_uint64_rsl (num, 32 - norm);
- qr32 = _cairo_uint64x32_normalized_divrem (num1, den.lo);
- q1 = qr32.quo;
- num.hi = qr32.rem;
- num.lo <<= norm;
- }
- else
- {
- num.hi -= den.lo;
- q1 = 1;
- }
- }
- qr32 = _cairo_uint64x32_normalized_divrem (num, den.lo);
- q0 = qr32.quo;
- r1 = 0;
- r0 = qr32.rem >> norm;
+ bit = _cairo_uint64_lsl (bit, 1);
+ den = _cairo_uint64_lsl (den, 1);
}
- else
+ quo = _cairo_uint32_to_uint64 (0);
+
+ /* generate quotient, one bit at a time */
+ while (bit.hi | bit.lo)
{
- if (den.hi > num.hi)
- {
- /* 00 = nn / DD */
- q0 = q1 = 0;
- r0 = num.lo;
- r1 = num.hi;
- }
- else
+ if (_cairo_uint64_le (den, num))
{
- /* 0q = NN / dd */
-
- norm = _cairo_leading_zeros32 (den.hi);
- if (norm == 0)
- {
- if (num.hi > den.hi || num.lo >= den.lo)
- {
- q0 = 1;
- num = _cairo_uint64_sub (num, den);
- }
- else
- {
- q0 = 0;
- }
-
- q1 = 0;
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- cairo_uint64_t num1;
- cairo_uint64_t part;
-
- num1 = _cairo_uint64_rsl (num, 32 - norm);
- den = _cairo_uint64_lsl (den, norm);
-
- qr32 = _cairo_uint64x32_normalized_divrem (num1, den.hi);
- part = _cairo_uint32x32_64_mul (qr32.quo, den.lo);
-
- q0 = qr32.quo;
-
- num.lo <<= norm;
- num.hi = qr32.rem;
-
- if (_cairo_uint64_gt (part, num))
- {
- q0--;
- part = _cairo_uint64_sub (part, den);
- }
-
- q1 = 0;
-
- num = _cairo_uint64_sub (num, part);
- num = _cairo_uint64_rsl (num, norm);
- r0 = num.lo;
- r1 = num.hi;
- }
+ num = _cairo_uint64_sub (num, den);
+ quo = _cairo_uint64_add (quo, bit);
}
+ bit = _cairo_uint64_rsl (bit, 1);
+ den = _cairo_uint64_rsl (den, 1);
}
- qr.quo.lo = q0;
- qr.quo.hi = q1;
- qr.rem.lo = r0;
- qr.rem.hi = r1;
+ qr.quo = quo;
+ qr.rem = num;
return qr;
}
@@ -754,234 +577,42 @@ _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
_cairo_uint64_eq (a.lo, b.lo));
}
-/*
- * The design of this algorithm comes from GCC,
- * but the actual implementation is new
- */
-
-/*
- * den >= num.hi
- */
-static cairo_uquorem64_t
-_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
-{
- cairo_uquorem64_t qr64;
- cairo_uquorem64_t qr;
- uint32_t q0, q1;
- cairo_uint64_t r0, r1;
- uint32_t d0, d1;
- cairo_uint64_t t;
-
- d0 = uint64_lo32 (den);
- d1 = uint64_hi32 (den);
-
- qr64 = _cairo_uint64_divrem (num.hi, _cairo_uint32_to_uint64 (d1));
- q1 = _cairo_uint64_to_uint32 (qr64.quo);
- r1 = qr64.rem;
-
- t = _cairo_uint32x32_64_mul (q1, d0);
-
- r1 = _cairo_uint64_add (_cairo_uint64_lsl (r1, 32),
- _cairo_uint64_rsl (num.lo, 32));
-
- if (_cairo_uint64_lt (r1, t))
- {
- q1--;
- r1 = _cairo_uint64_add (r1, den);
- if (_cairo_uint64_ge (r1, den) && _cairo_uint64_lt (r1, t))
- {
- q1--;
- r1 = _cairo_uint64_add (r1, den);
- }
- }
-
- r1 = _cairo_uint64_sub (r1, t);
-
- qr64 = _cairo_uint64_divrem (r1, _cairo_uint32_to_uint64 (d1));
-
- q0 = _cairo_uint64_to_uint32 (qr64.quo);
- r0 = qr64.rem;
-
- t = _cairo_uint32x32_64_mul (q0, d0);
-
- r0 = _cairo_uint64_add (_cairo_uint64_lsl (r0, 32),
- _cairo_uint32_to_uint64 (_cairo_uint64_to_uint32 (num.lo)));
- if (_cairo_uint64_lt (r0, t))
- {
- q0--;
- r0 = _cairo_uint64_add (r0, den);
- if (_cairo_uint64_ge (r0, den) && _cairo_uint64_lt (r0, t))
- {
- q0--;
- r0 = _cairo_uint64_add (r0, den);
- }
- }
-
- r0 = _cairo_uint64_sub (r0, t);
-
- qr.quo = _cairo_uint32s_to_uint64 (q1, q0);
- qr.rem = r0;
- return qr;
-}
-
#if HAVE_UINT64_T
-
-static int
-_cairo_leading_zeros64 (cairo_uint64_t q)
-{
- int top = 0;
-
- if (q >= (uint64_t) 0x10000 << 16)
- {
- top += 32;
- q >>= 32;
- }
- if (q >= (uint64_t) 0x10000)
- {
- top += 16;
- q >>= 16;
- }
- if (q >= (uint64_t) 0x100)
- {
- top += 8;
- q >>= 8;
- }
- top += top_bit [q];
- return 64 - top;
-}
-
+#define _cairo_msbset64(q) (q & ((uint64_t) 1 << 63))
#else
-
-static const int
-_cairo_leading_zeros64 (cairo_uint64_t d)
-{
- if (d.hi)
- return _cairo_leading_zeros32 (d.hi);
- else
- return 32 + _cairo_leading_zeros32 (d.lo);
-}
-
+#define _cairo_msbset64(q) (q.hi & ((uint32_t) 1 << 31))
#endif
cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
- cairo_uquorem64_t qr64;
cairo_uquorem128_t qr;
- int norm;
- cairo_uint64_t q1, q0, r1, r0;
-
- if (_cairo_uint64_eq (den.hi, _cairo_uint32_to_uint64 (0)))
+ cairo_uint128_t bit;
+ cairo_uint128_t quo;
+
+ bit = _cairo_uint32_to_uint128 (1);
+
+ /* normalize to make den >= num, but not overflow */
+ while (_cairo_uint128_lt (den, num) && !_cairo_msbset64(den.hi))
{
- if (_cairo_uint64_gt (den.lo, num.hi))
- {
- /* 0q = nn / 0d */
-
- norm = _cairo_leading_zeros64 (den.lo);
- if (norm)
- {
- den.lo = _cairo_uint64_lsl (den.lo, norm);
- num = _cairo_uint128_lsl (num, norm);
- }
- q1 = _cairo_uint32_to_uint64 (0);
- }
- else
- {
- /* qq = NN / 0d */
-
- if (_cairo_uint64_eq (den.lo, _cairo_uint32_to_uint64 (0)))
- den.lo = _cairo_uint64_divrem (_cairo_uint32_to_uint64 (1),
- den.lo).quo;
-
- norm = _cairo_leading_zeros64 (den.lo);
- if (norm)
- {
- cairo_uint128_t num1;
-
- den.lo = _cairo_uint64_lsl (den.lo, norm);
- num1 = _cairo_uint128_rsl (num, 64 - norm);
- qr64 = _cairo_uint128x64_normalized_divrem (num1, den.lo);
- q1 = qr64.quo;
- num.hi = qr64.rem;
- num.lo = _cairo_uint64_lsl (num.lo, norm);
- }
- else
- {
- num.hi = _cairo_uint64_sub (num.hi, den.lo);
- q1 = _cairo_uint32_to_uint64 (1);
- }
- }
- qr64 = _cairo_uint128x64_normalized_divrem (num, den.lo);
- q0 = qr64.quo;
- r1 = _cairo_uint32_to_uint64 (0);
- r0 = _cairo_uint64_rsl (qr64.rem, norm);
+ bit = _cairo_uint128_lsl (bit, 1);
+ den = _cairo_uint128_lsl (den, 1);
}
- else
+ quo = _cairo_uint32_to_uint128 (0);
+
+ /* generate quotient, one bit at a time */
+ while (_cairo_uint128_ne (bit, _cairo_uint32_to_uint128(0)))
{
- if (_cairo_uint64_gt (den.hi, num.hi))
- {
- /* 00 = nn / DD */
- q0 = q1 = _cairo_uint32_to_uint64 (0);
- r0 = num.lo;
- r1 = num.hi;
- }
- else
+ if (_cairo_uint128_le (den, num))
{
- /* 0q = NN / dd */
-
- norm = _cairo_leading_zeros64 (den.hi);
- if (norm == 0)
- {
- if (_cairo_uint64_gt (num.hi, den.hi) ||
- _cairo_uint64_ge (num.lo, den.lo))
- {
- q0 = _cairo_uint32_to_uint64 (1);
- num = _cairo_uint128_sub (num, den);
- }
- else
- {
- q0 = _cairo_uint32_to_uint64 (0);
- }
-
- q1 = _cairo_uint32_to_uint64 (0);
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- cairo_uint128_t num1;
- cairo_uint128_t part;
-
- num1 = _cairo_uint128_rsl (num, 64 - norm);
- den = _cairo_uint128_lsl (den, norm);
-
- qr64 = _cairo_uint128x64_normalized_divrem (num1, den.hi);
- part = _cairo_uint64x64_128_mul (qr64.quo, den.lo);
-
- q0 = qr64.quo;
-
- num.lo = _cairo_uint64_lsl (num.lo, norm);
- num.hi = qr64.rem;
-
- if (_cairo_uint128_gt (part, num))
- {
- q0 = _cairo_uint64_sub (q0, _cairo_uint32_to_uint64 (1));
- part = _cairo_uint128_sub (part, den);
- }
-
- q1 = _cairo_uint32_to_uint64 (0);
-
- num = _cairo_uint128_sub (num, part);
- num = _cairo_uint128_rsl (num, norm);
- r0 = num.lo;
- r1 = num.hi;
- }
+ num = _cairo_uint128_sub (num, den);
+ quo = _cairo_uint128_add (quo, bit);
}
+ bit = _cairo_uint128_rsl (bit, 1);
+ den = _cairo_uint128_rsl (den, 1);
}
- qr.quo.lo = q0;
- qr.quo.hi = q1;
- qr.rem.lo = r0;
- qr.rem.hi = r1;
+ qr.quo = quo;
+ qr.rem = num;
return qr;
}