/* $NetBSD: dmisc.c,v 1.2.4.1.4.1 2008/04/08 21:10:55 jdc Exp $ */ | |
/**************************************************************** | |
The author of this software is David M. Gay. | |
Copyright (C) 1998 by Lucent Technologies | |
All Rights Reserved | |
Permission to use, copy, modify, and distribute this software and | |
its documentation for any purpose and without fee is hereby | |
granted, provided that the above copyright notice appear in all | |
copies and that both that the copyright notice and this | |
permission notice and warranty disclaimer appear in supporting | |
documentation, and that the name of Lucent or any of its entities | |
not be used in advertising or publicity pertaining to | |
distribution of the software without specific, written prior | |
permission. | |
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. | |
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY | |
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
THIS SOFTWARE. | |
****************************************************************/ | |
/* Please send bug reports to David M. Gay (dmg at acm dot org, | |
* with " at " changed at "@" and " dot " changed to "."). */ | |
#include <LibConfig.h> | |
#include "gdtoaimp.h" | |
#ifndef MULTIPLE_THREADS | |
char *dtoa_result; | |
#endif | |
char * | |
#ifdef KR_headers | |
rv_alloc(i) size_t i; | |
#else | |
rv_alloc(size_t i) | |
#endif | |
{ | |
size_t j; | |
int k, *r; | |
j = sizeof(ULong); | |
for(k = 0; | |
sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; | |
j <<= 1) | |
k++; | |
r = (int*)(void*)Balloc(k); | |
if (r == NULL) | |
return NULL; | |
*r = k; | |
return | |
#ifndef MULTIPLE_THREADS | |
dtoa_result = | |
#endif | |
(char *)(void *)(r+1); | |
} | |
char * | |
#ifdef KR_headers | |
nrv_alloc(s, rve, n) CONST char *s; char **rve; size_t n; | |
#else | |
nrv_alloc(CONST char *s, char **rve, size_t n) | |
#endif | |
{ | |
char *rv, *t; | |
t = rv = rv_alloc(n); | |
if (t == NULL) | |
return NULL; | |
while((*t = *s++) !=0) | |
t++; | |
if (rve) | |
*rve = t; | |
return rv; | |
} | |
/* freedtoa(s) must be used to free values s returned by dtoa | |
* when MULTIPLE_THREADS is #defined. It should be used in all cases, | |
* but for consistency with earlier versions of dtoa, it is optional | |
* when MULTIPLE_THREADS is not defined. | |
*/ | |
void | |
#ifdef KR_headers | |
freedtoa(s) char *s; | |
#else | |
freedtoa(char *s) | |
#endif | |
{ | |
Bigint *b = (Bigint *)(void *)((int *)(void *)s - 1); | |
b->maxwds = 1 << (b->k = *(int*)(void*)b); | |
Bfree(b); | |
#ifndef MULTIPLE_THREADS | |
if (s == dtoa_result) | |
dtoa_result = 0; | |
#endif | |
} | |
int | |
quorem | |
#ifdef KR_headers | |
(b, S) Bigint *b, *S; | |
#else | |
(Bigint *b, Bigint *S) | |
#endif | |
{ | |
int n; | |
ULong *bx, *bxe, q, *sx, *sxe; | |
#ifdef ULLong | |
ULLong borrow, carry, y, ys; | |
#else | |
ULong borrow, carry, y, ys; | |
#ifdef Pack_32 | |
ULong si, z, zs; | |
#endif | |
#endif | |
n = S->wds; | |
#ifdef DEBUG | |
/*debug*/ if (b->wds > n) | |
/*debug*/ Bug("oversize b in quorem"); | |
#endif | |
if (b->wds < n) | |
return 0; | |
sx = S->x; | |
sxe = sx + --n; | |
bx = b->x; | |
bxe = bx + n; | |
q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ | |
#ifdef DEBUG | |
/*debug*/ if (q > 9) | |
/*debug*/ Bug("oversized quotient in quorem"); | |
#endif | |
if (q) { | |
borrow = 0; | |
carry = 0; | |
do { | |
#ifdef ULLong | |
ys = *sx++ * (ULLong)q + carry; | |
carry = ys >> 32; | |
/* LINTED conversion */ | |
y = *bx - (ys & 0xffffffffUL) - borrow; | |
borrow = y >> 32 & 1UL; | |
/* LINTED conversion */ | |
*bx++ = (UINT32)(y & 0xffffffffUL); | |
#else | |
#ifdef Pack_32 | |
si = *sx++; | |
ys = (si & 0xffff) * q + carry; | |
zs = (si >> 16) * q + (ys >> 16); | |
carry = zs >> 16; | |
y = (*bx & 0xffff) - (ys & 0xffff) - borrow; | |
borrow = (y & 0x10000) >> 16; | |
z = (*bx >> 16) - (zs & 0xffff) - borrow; | |
borrow = (z & 0x10000) >> 16; | |
Storeinc(bx, z, y); | |
#else | |
ys = *sx++ * q + carry; | |
carry = ys >> 16; | |
y = *bx - (ys & 0xffff) - borrow; | |
borrow = (y & 0x10000) >> 16; | |
*bx++ = y & 0xffff; | |
#endif | |
#endif | |
} | |
while(sx <= sxe); | |
if (!*bxe) { | |
bx = b->x; | |
while(--bxe > bx && !*bxe) | |
--n; | |
b->wds = n; | |
} | |
} | |
if (cmp(b, S) >= 0) { | |
q++; | |
borrow = 0; | |
carry = 0; | |
bx = b->x; | |
sx = S->x; | |
do { | |
#ifdef ULLong | |
ys = *sx++ + carry; | |
carry = ys >> 32; | |
/* LINTED conversion */ | |
y = *bx - (ys & 0xffffffffUL) - borrow; | |
borrow = y >> 32 & 1UL; | |
/* LINTED conversion */ | |
*bx++ = (UINT32)(y & 0xffffffffUL); | |
#else | |
#ifdef Pack_32 | |
si = *sx++; | |
ys = (si & 0xffff) + carry; | |
zs = (si >> 16) + (ys >> 16); | |
carry = zs >> 16; | |
y = (*bx & 0xffff) - (ys & 0xffff) - borrow; | |
borrow = (y & 0x10000) >> 16; | |
z = (*bx >> 16) - (zs & 0xffff) - borrow; | |
borrow = (z & 0x10000) >> 16; | |
Storeinc(bx, z, y); | |
#else | |
ys = *sx++ + carry; | |
carry = ys >> 16; | |
y = *bx - (ys & 0xffff) - borrow; | |
borrow = (y & 0x10000) >> 16; | |
*bx++ = y & 0xffff; | |
#endif | |
#endif | |
} | |
while(sx <= sxe); | |
bx = b->x; | |
bxe = bx + n; | |
if (!*bxe) { | |
while(--bxe > bx && !*bxe) | |
--n; | |
b->wds = n; | |
} | |
} | |
return (int)q; | |
} |