diff options
Diffstat (limited to 'libtwin/twin_fixed.c')
-rw-r--r-- | libtwin/twin_fixed.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/libtwin/twin_fixed.c b/libtwin/twin_fixed.c new file mode 100644 index 0000000..060fb08 --- /dev/null +++ b/libtwin/twin_fixed.c @@ -0,0 +1,142 @@ +/* + * Twin - A Tiny Window System + * Copyright © 2004 Keith Packard <keithp@keithp.com> + * All rights reserved. + * + * This Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Twin Library; see the file COPYING. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "twinint.h" + +#if 0 +#include <stdio.h> +#define F(f) twin_fixed_to_double(f) +#define DBGMSG(x) printf x +#else +#define DBGMSG(x) +#endif + +#define uint32_lo(i) ((i) & 0xffff) +#define uint32_hi(i) ((i) >> 16) +#define uint32_carry16 ((1) << 16) + +#if 0 +twin_fixed_t +twin_fixed_mul (twin_fixed_t af, twin_fixed_t bf) +{ + uint32_t a; + uint32_t b; + uint16_t ah, al, bh, bl; + uint32_t r0, r1, r2, r3; + uint32_t hi, lo; + twin_fixed_t r; + twin_bool_t negative = TWIN_FALSE; + + a = (uint32_t) af; + b = (uint32_t) bf; + if (af < 0) + { + negative = !negative; + a = -a; + } + if (bf < 0) + { + negative = !negative; + b = -b; + } + + al = uint32_lo (a); + ah = uint32_hi (a); + bl = uint32_lo (b); + bh = uint32_hi (b); + + r0 = (uint32_t) al * bl; + r1 = (uint32_t) al * bh; + r2 = (uint32_t) ah * bl; + r3 = (uint32_t) ah * bh; + + r1 += uint32_hi(r0); /* no carry possible */ + r1 += r2; /* but this can carry */ + if (r1 < r2) /* check */ + r3 += uint32_carry16; + + hi = r3 + uint32_hi(r1); + lo = (uint32_lo (r1) << 16) + uint32_lo (r0); + + DBGMSG (("0x%x * 0x%x = 0x%x%08x\n", a, b, hi, lo)); + + r = (twin_fixed_t) ((hi << 16) | (lo >> 16)); + if (negative) + r = -r; + DBGMSG (("%9.4f * %9.4f = %9.4f\n", + twin_fixed_to_double(af), twin_fixed_to_double(bf), + twin_fixed_to_double (r))); + return r; +} +#endif + +#if 0 +twin_fixed_t +twin_fixed_div (twin_fixed_t a, twin_fixed_t b) +{ + twin_fixed_t q; + q = (twin_fixed_t) ((((int64_t) a) << 16) / b); + return q; +} +#endif + +twin_fixed_t +twin_fixed_sqrt (twin_fixed_t a) +{ + twin_fixed_t max, min, mid; + twin_fixed_t sqr; + + max = a; + min = 0; + while (max > min) + { + mid = (max + min) >> 1; + sqr = twin_fixed_mul (mid, mid); + if (sqr == a) + return mid; + if (sqr < a) + min = mid + 1; + else + max = mid - 1; + } + return (max + min) >> 1; +} + +twin_sfixed_t +_twin_sfixed_sqrt (twin_sfixed_t as) +{ + twin_dfixed_t max = as, min = 0, mid; + twin_dfixed_t a = twin_sfixed_to_dfixed (as); + twin_dfixed_t sqr; + + while (max > min) + { + mid = (max + min) >> 1; + sqr = mid * mid; + if (sqr == a) + return (twin_sfixed_t) mid; + if (sqr < a) + min = mid + 1; + else + max = mid - 1; + } + return (twin_sfixed_t) ((max + min) >> 1); +} |