1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009 |
- #include "stdafx.h"
- #include "defs.h"
- #define MP_MIN_SIZE 2
- #define MP_MAX_FREE 500
- double convert_rational_to_double(U *);
- double convert_bignum_to_double(unsigned int *);
- int ge(unsigned int *, unsigned int *, int);
- int mtotal, mfreecount;
- unsigned int **free_stack;
- unsigned int *
- mnew(int n)
- {
- unsigned int *p;
- if (n < MP_MIN_SIZE)
- n = MP_MIN_SIZE;
- if (n == MP_MIN_SIZE && mfreecount)
- p = free_stack[--mfreecount];
- else {
- p = (unsigned int *) malloc((n + 3) * sizeof (int));
- if (p == 0)
- stop("malloc failure");
- }
- p[0] = n;
- mtotal += n;
- return p + 3;
- }
- void
- mfree(unsigned int *p)
- {
- p -= 3;
- mtotal -= p[0];
- if (p[0] == MP_MIN_SIZE && mfreecount < MP_MAX_FREE)
- free_stack[mfreecount++] = p;
- else
- free(p);
- }
- // convert int to bignum
- unsigned int *
- mint(int n)
- {
- unsigned int *p = mnew(1);
- if (n < 0)
- MSIGN(p) = -1;
- else
- MSIGN(p) = 1;
- MLENGTH(p) = 1;
- p[0] = abs(n);
- return p;
- }
- // copy bignum
- unsigned int *
- mcopy(unsigned int *a)
- {
- int i;
- unsigned int *b;
- b = mnew(MLENGTH(a));
- MSIGN(b) = MSIGN(a);
- MLENGTH(b) = MLENGTH(a);
- for (i = 0; i < MLENGTH(a); i++)
- b[i] = a[i];
- return b;
- }
- // a >= b ?
- int
- ge(unsigned int *a, unsigned int *b, int len)
- {
- int i;
- for (i = len - 1; i > 0; i--)
- if (a[i] == b[i])
- continue;
- else
- break;
- if (a[i] >= b[i])
- return 1;
- else
- return 0;
- }
- void
- add_numbers(void)
- {
- double a, b;
- if (isrational(stack[tos - 1]) && isrational(stack[tos - 2])) {
- qadd();
- return;
- }
- save();
- p2 = pop();
- p1 = pop();
- if (isdouble(p1))
- a = p1->u.d;
- else
- a = convert_rational_to_double(p1);
- if (isdouble(p2))
- b = p2->u.d;
- else
- b = convert_rational_to_double(p2);
- push_double(a + b);
- restore();
- }
- void
- subtract_numbers(void)
- {
- double a, b;
- if (isrational(stack[tos - 1]) && isrational(stack[tos - 2])) {
- qsub();
- return;
- }
- save();
- p2 = pop();
- p1 = pop();
- if (isdouble(p1))
- a = p1->u.d;
- else
- a = convert_rational_to_double(p1);
- if (isdouble(p2))
- b = p2->u.d;
- else
- b = convert_rational_to_double(p2);
- push_double(a - b);
- restore();
- }
- void
- multiply_numbers(void)
- {
- double a, b;
- if (isrational(stack[tos - 1]) && isrational(stack[tos - 2])) {
- qmul();
- return;
- }
- save();
- p2 = pop();
- p1 = pop();
- if (isdouble(p1))
- a = p1->u.d;
- else
- a = convert_rational_to_double(p1);
- if (isdouble(p2))
- b = p2->u.d;
- else
- b = convert_rational_to_double(p2);
- push_double(a * b);
- restore();
- }
- void
- divide_numbers(void)
- {
- double a, b;
- if (isrational(stack[tos - 1]) && isrational(stack[tos - 2])) {
- qdiv();
- return;
- }
- save();
- p2 = pop();
- p1 = pop();
- if (iszero(p2))
- stop("divide by zero");
- if (isdouble(p1))
- a = p1->u.d;
- else
- a = convert_rational_to_double(p1);
- if (isdouble(p2))
- b = p2->u.d;
- else
- b = convert_rational_to_double(p2);
- push_double(a / b);
- restore();
- }
- void
- invert_number(void)
- {
- unsigned int *a, *b;
- save();
- p1 = pop();
- if (iszero(p1))
- stop("divide by zero");
- if (isdouble(p1)) {
- push_double(1 / p1->u.d);
- restore();
- return;
- }
- a = mcopy(p1->u.q.a);
- b = mcopy(p1->u.q.b);
- MSIGN(b) = MSIGN(a);
- MSIGN(a) = 1;
- p1 = alloc();
- p1->k = NUM;
- p1->u.q.a = b;
- p1->u.q.b = a;
- push(p1);
- restore();
- }
- int
- compare_rationals(U *a, U *b)
- {
- int t;
- unsigned int *ab, *ba;
- ab = mmul(a->u.q.a, b->u.q.b);
- ba = mmul(a->u.q.b, b->u.q.a);
- t = mcmp(ab, ba);
- mfree(ab);
- mfree(ba);
- return t;
- }
- int
- compare_numbers(U *a, U *b)
- {
- double x, y;
- if (isrational(a) && isrational(b))
- return compare_rationals(a, b);
- if (isdouble(a))
- x = a->u.d;
- else
- x = convert_rational_to_double(a);
- if (isdouble(b))
- y = b->u.d;
- else
- y = convert_rational_to_double(b);
- if (x < y)
- return -1;
- if (x > y)
- return 1;
- return 0;
- }
- void
- negate_number(void)
- {
- save();
- p1 = pop();
- if (iszero(p1)) {
- push(p1);
- restore();
- return;
- }
- switch (p1->k) {
- case NUM:
- p2 = alloc();
- p2->k = NUM;
- p2->u.q.a = mcopy(p1->u.q.a);
- p2->u.q.b = mcopy(p1->u.q.b);
- MSIGN(p2->u.q.a) *= -1;
- push(p2);
- break;
- case DOUBLE:
- push_double(-p1->u.d);
- break;
- default:
- stop("bug caught in mp_negate_number");
- break;
- }
- restore();
- }
- void
- bignum_truncate(void)
- {
- unsigned int *a;
- save();
- p1 = pop();
- a = mdiv(p1->u.q.a, p1->u.q.b);
- p1 = alloc();
- p1->k = NUM;
- p1->u.q.a = a;
- p1->u.q.b = mint(1);
- push(p1);
- restore();
- }
- void
- mp_numerator(void)
- {
- save();
- p1 = pop();
- if (p1->k != NUM) {
- push(one);
- restore();
- return;
- }
- p2 = alloc();
- p2->k = NUM;
- p2->u.q.a = mcopy(p1->u.q.a);
- p2->u.q.b = mint(1);
- push(p2);
- restore();
- }
- void
- mp_denominator(void)
- {
- save();
- p1 = pop();
- if (p1->k != NUM) {
- push(one);
- restore();
- return;
- }
- p2 = alloc();
- p2->k = NUM;
- p2->u.q.a = mcopy(p1->u.q.b);
- p2->u.q.b = mint(1);
- push(p2);
- restore();
- }
- void
- bignum_power_number(int expo)
- {
- unsigned int *a, *b, *t;
- save();
- p1 = pop();
- a = mpow(p1->u.q.a, abs(expo));
- b = mpow(p1->u.q.b, abs(expo));
- if (expo < 0) {
- t = a;
- a = b;
- b = t;
- MSIGN(a) = MSIGN(b);
- MSIGN(b) = 1;
- }
- p1 = alloc();
- p1->k = NUM;
- p1->u.q.a = a;
- p1->u.q.b = b;
- push(p1);
- restore();
- }
- double
- convert_bignum_to_double(unsigned int *p)
- {
- int i;
- double d = 0.0;
- for (i = MLENGTH(p) - 1; i >= 0; i--)
- d = 4294967296.0 * d + p[i];
- if (MSIGN(p) == -1)
- d = -d;
- return d;
- }
- double
- convert_rational_to_double(U *p)
- {
- int i, n, na, nb;
- double a = 0.0, b = 0.0;
- na = MLENGTH(p->u.q.a);
- nb = MLENGTH(p->u.q.b);
- if (na < nb)
- n = na;
- else
- n = nb;
- for (i = 0; i < n; i++) {
- a = a / 4294967296.0 + p->u.q.a[i];
- b = b / 4294967296.0 + p->u.q.b[i];
- }
- if (na > nb)
- for (i = nb; i < na; i++) {
- a = a / 4294967296.0 + p->u.q.a[i];
- b = b / 4294967296.0;
- }
- if (na < nb)
- for (i = na; i < nb; i++) {
- a = a / 4294967296.0;
- b = b / 4294967296.0 + p->u.q.b[i];
- }
- if (MSIGN(p->u.q.a) == -1)
- a = -a;
- return a / b;
- }
- void
- push_integer(int n)
- {
- save();
- p1 = alloc();
- p1->k = NUM;
- p1->u.q.a = mint(n);
- p1->u.q.b = mint(1);
- push(p1);
- restore();
- }
- void
- push_double(double d)
- {
- save();
- p1 = alloc();
- p1->k = DOUBLE;
- p1->u.d = d;
- push(p1);
- restore();
- }
- void
- push_rational(int a, int b)
- {
- save();
- p1 = alloc();
- p1->k = NUM;
- p1->u.q.a = mint(a);
- p1->u.q.b = mint(b);
- /* FIXME -- normalize */
- push(p1);
- restore();
- }
- int
- pop_integer(void)
- {
- int n;
- save();
- p1 = pop();
- switch (p1->k) {
- case NUM:
- if (isinteger(p1) && MLENGTH(p1->u.q.a) == 1) {
- n = p1->u.q.a[0];
- if (n & 0x80000000)
- n = 0x80000000;
- else
- n *= MSIGN(p1->u.q.a);
- } else
- n = 0x80000000;
- break;
- case DOUBLE:
- n = (int) p1->u.d;
- if ((double) n != p1->u.d)
- n = 0x80000000;
- break;
- default:
- n = 0x80000000;
- break;
- }
- restore();
- return n;
- }
- void
- print_double(U *p, int flag)
- {
- static char buf[80];
- sprintf(buf, "%g", p->u.d);
- if (flag == 1 && *buf == '-')
- print_str(buf + 1);
- else
- print_str(buf);
- }
- void
- bignum_scan_integer(char *s)
- {
- unsigned int *a;
- char sign;
- save();
- sign = *s;
- if (sign == '+' || sign == '-')
- s++;
- a = mscan(s);
- p1 = alloc();
- p1->k = NUM;
- p1->u.q.a = a;
- p1->u.q.b = mint(1);
- push(p1);
- if (sign == '-')
- negate();
- restore();
- }
- #define FLT_MIN (1e-999)
- #define FLT_MAX (9.999999999999999e999)
- // the following strtod isn't used. but if I remove it, GCC's linker starts giving errors somewhere inside libm
- // *magic* DO NOT TOUCH *magic*
- // this strtod was deprecated because it didn't have enough precision
- double amystrtod(char *s, char **str_end) {
- // TODO handle exponential format, hex format, inf, nan
- double r = 0.0;
- int negative = 0;
- union { double rr; unsigned long long dd; } raw;
-
- while (isspace(*s)) s++; //skip leading whitespace
- if ((s[0] == 'i' || s[0] == 'I') && (s[1] == 'n' || s[1] == 'N') && (s[2] == 'f' || s[2] == 'F')) {
- if (str_end != NULL)
- *str_end = s+3;
- raw.dd = 0x7FF0000000000000; //positive infinity
- return raw.rr;
- }
- if ((s[0] == 'n' || s[0] == 'N') && (s[1] == 'a' || s[1] == 'A') && (s[2] == 'n' || s[2] == 'N')) {
- if (str_end != NULL)
- *str_end = s+3;
- raw.dd = 0x7FFFFFFFFFFFFFFF; //QNaN
- return raw.rr;
- }
- if (!isdigit(*s) && *s != '-' && *s != '+' && *s != '.') {
- if (str_end != NULL)
- *str_end = (char *)s;
- return 0;
- }
-
- switch (*s)
- {
- case '-':
- negative = 1;
- // Deliberate fallthrough
- case '+':
- s++;
- break;
- }
-
- while (isdigit(*s))
- {
- r *= 10.0;
- r += *s++ - '0';
- }
- if (*s == '.')
- {
- float f = 10.0f;
- s++;
- while (isdigit(*s))
- {
- r += (*s - '0')/f;
- f *= 10.0f;
- s++;
- }
- }
-
- if (*s == 'e' || *s == 'E') {
- int exponent = 0;
- bool sign = false;
- if (*(s+1) == '-' || *(s+1) == '+') {
- if (*(s+1) == '-') sign = true;
- if (isdigit(*(s+2))) {
- s+=2;
- while(isdigit(*s)) {
- exponent = (exponent*10) + (*s - '0');
- s++;
- }
- r = pow(r,((sign)?-exponent:exponent));
- }
- } else if (isdigit(*(s+1))) {
- s++;
- while(isdigit(*s)) {
- exponent = (exponent*10) + (*s - '0');
- s++;
- }
- r = pow(r,exponent);
- }
- }
-
- if (str_end != NULL)
- *str_end = (char *)s;
-
- // Portable? Nope. Fast? Yup.
- raw.rr = r;
- raw.dd |= (unsigned long long)negative << 63;
-
- if(raw.rr >= FLT_MIN || raw.rr <= -FLT_MIN)
- return raw.rr;
- else return 0;
- }
- #define DBL_MAX_EXP 999
- #define DBL_MIN_EXP (-999)
- //
- // strtod.c
- //
- // Convert string to double
- //
- // Copyright (C) 2002 Michael Ringgaard. All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions
- // are met:
- //
- // 1. Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // 2. Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the distribution.
- // 3. Neither the name of the project nor the names of its contributors
- // may be used to endorse or promote products derived from this software
- // without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- // SUCH DAMAGE.
- //
- double mystrtod(const char *str, char **endptr) {
- double number;
- int exponent;
- int negative;
- char *p = (char *) str;
- double p10;
- int n;
- int num_digits;
- int num_decimals;
- // Skip leading whitespace
- while (isspace(*p)) p++;
- // Handle optional sign
- negative = 0;
- switch (*p) {
- case '-': negative = 1; // Fall through to increment position
- case '+': p++;
- }
- number = 0.;
- exponent = 0;
- num_digits = 0;
- num_decimals = 0;
- // Process string of digits
- while (isdigit(*p)) {
- number = number * 10. + (*p - '0');
- p++;
- num_digits++;
- }
- // Process decimal part
- if (*p == '.') {
- p++;
- while (isdigit(*p)) {
- number = number * 10. + (*p - '0');
- p++;
- num_digits++;
- num_decimals++;
- }
- exponent -= num_decimals;
- }
- if (num_digits == 0) {
- errno = ERANGE;
- return 0.0;
- }
- // Correct for sign
- if (negative) number = -number;
- // Process an exponent string
- if (*p == 'e' || *p == 'E') {
- // Handle optional sign
- negative = 0;
- switch (*++p) {
- case '-': negative = 1; // Fall through to increment pos
- case '+': p++;
- }
- // Process string of digits
- n = 0;
- while (isdigit(*p)) {
- n = n * 10 + (*p - '0');
- p++;
- }
- if (negative) {
- exponent -= n;
- } else {
- exponent += n;
- }
- }
- if (exponent < DBL_MIN_EXP || exponent > DBL_MAX_EXP) {
- errno = ERANGE;
- return HUGE_VAL;
- }
- // Scale the result
- p10 = 10.;
- n = exponent;
- if (n < 0) n = -n;
- while (n) {
- if (n & 1) {
- if (exponent < 0) {
- number /= p10;
- } else {
- number *= p10;
- }
- }
- n >>= 1;
- p10 *= p10;
- }
- if (number == HUGE_VAL) errno = ERANGE;
- if (endptr) *endptr = p;
- return number;
- }
- void
- bignum_scan_float(char *s)
- {
- //push_double(atof(s));
- push_double(mystrtod((char*)s, NULL));
- }
- // print as unsigned
- void
- print_number(U *p)
- {
- char *s;
- static char buf[100];
- switch (p->k) {
- case NUM:
- s = mstr(p->u.q.a);
- if (*s == '+' || *s == '-')
- s++;
- print_str(s);
- if (isfraction(p)) {
- print_str("/");
- s = mstr(p->u.q.b);
- print_str(s);
- }
- break;
- case DOUBLE:
- sprintf(buf, "%.10g", p->u.d);
- if (*buf == '+' || *buf == '-')
- print_str(buf + 1);
- else
- print_str(buf);
- break;
- default:
- break;
- }
- }
- void
- gcd_numbers(void)
- {
- save();
- p2 = pop();
- p1 = pop();
- // if (!isinteger(p1) || !isinteger(p2))
- // stop("integer args expected for gcd");
- p3 = alloc();
- p3->k = NUM;
- p3->u.q.a = mgcd(p1->u.q.a, p2->u.q.a);
- p3->u.q.b = mgcd(p1->u.q.b, p2->u.q.b);
- MSIGN(p3->u.q.a) = 1;
- push(p3);
- restore();
- }
- double
- pop_double(void)
- {
- double d;
- save();
- p1 = pop();
- switch (p1->k) {
- case NUM:
- d = convert_rational_to_double(p1);
- break;
- case DOUBLE:
- d = p1->u.d;
- break;
- default:
- d = 0.0;
- break;
- }
- restore();
- return d;
- }
- void
- bignum_float(void)
- {
- double d;
- d = convert_rational_to_double(pop());
- push_double(d);
- }
- static unsigned int *__factorial(int);
- void
- bignum_factorial(int n)
- {
- save();
- p1 = alloc();
- p1->k = NUM;
- p1->u.q.a = __factorial(n);
- p1->u.q.b = mint(1);
- push(p1);
- restore();
- }
- static unsigned int *
- __factorial(int n)
- {
- int i;
- unsigned int *a, *b, *t;
- if (n == 0 || n == 1) {
- a = mint(1);
- return a;
- }
- a = mint(2);
- b = mint(0);
- for (i = 3; i <= n; i++) {
- b[0] = (unsigned int) i;
- t = mmul(a, b);
- mfree(a);
- a = t;
- }
- mfree(b);
- return a;
- }
- static unsigned int mask[32] = {
- 0x00000001,
- 0x00000002,
- 0x00000004,
- 0x00000008,
- 0x00000010,
- 0x00000020,
- 0x00000040,
- 0x00000080,
- 0x00000100,
- 0x00000200,
- 0x00000400,
- 0x00000800,
- 0x00001000,
- 0x00002000,
- 0x00004000,
- 0x00008000,
- 0x00010000,
- 0x00020000,
- 0x00040000,
- 0x00080000,
- 0x00100000,
- 0x00200000,
- 0x00400000,
- 0x00800000,
- 0x01000000,
- 0x02000000,
- 0x04000000,
- 0x08000000,
- 0x10000000,
- 0x20000000,
- 0x40000000,
- 0x80000000,
- };
- void
- mp_set_bit(unsigned int *x, unsigned int k)
- {
- x[k / 32] |= mask[k % 32];
- }
- void
- mp_clr_bit(unsigned int *x, unsigned int k)
- {
- x[k / 32] &= ~mask[k % 32];
- }
- void
- mshiftright(unsigned int *a)
- {
- int c, i, n;
- n = MLENGTH(a);
- c = 0;
- for (i = n - 1; i >= 0; i--)
- if (a[i] & 1) {
- a[i] = (a[i] >> 1) | c;
- c = 0x80000000;
- } else {
- a[i] = (a[i] >> 1) | c;
- c = 0;
- }
- if (n > 1 && a[n - 1] == 0)
- MLENGTH(a) = n - 1;
- }
|