📄 qmath.c
字号:
*/NUMBER *qnum(NUMBER *q){ register NUMBER *r; if (qisint(q)) return qlink(q); if (zisunit(q->num)) { r = (qisneg(q) ? &_qnegone_ : &_qone_); return qlink(r); } r = qalloc(); zcopy(q->num, &r->num); return r;}/* * Return just the denominator of a number. * q2 = qden(q1); */NUMBER *qden(NUMBER *q){ register NUMBER *r; if (qisint(q)) return qlink(&_qone_); r = qalloc(); zcopy(q->den, &r->num); return r;}/* * Return the fractional part of a number. * q2 = qfrac(q1); */NUMBER *qfrac(NUMBER *q){ register NUMBER *r; if (qisint(q)) return qlink(&_qzero_); if ((q->num.len < q->den.len) || ((q->num.len == q->den.len) && (q->num.v[q->num.len - 1] < q->den.v[q->num.len - 1]))) return qlink(q); r = qalloc(); zmod(q->num, q->den, &r->num, 2); zcopy(q->den, &r->den); return r;}/* * Return the integral part of a number. * q2 = qint(q1); */NUMBER *qint(NUMBER *q){ register NUMBER *r; if (qisint(q)) return qlink(q); if ((q->num.len < q->den.len) || ((q->num.len == q->den.len) && (q->num.v[q->num.len - 1] < q->den.v[q->num.len - 1]))) return qlink(&_qzero_); r = qalloc(); zquo(q->num, q->den, &r->num, 2); return r;}/* * Compute the square of a number. */NUMBER *qsquare(NUMBER *q){ ZVALUE num, zden; if (qiszero(q)) return qlink(&_qzero_); if (qisunit(q)) return qlink(&_qone_); num = q->num; zden = q->den; q = qalloc(); if (!zisunit(num)) zsquare(num, &q->num); if (!zisunit(zden)) zsquare(zden, &q->den); return q;}/* * Shift an integer by a given number of bits. This multiplies the number * by the appropriate power of two. Positive numbers shift left, negative * ones shift right. Low bits are truncated when shifting right. */NUMBER *qshift(NUMBER *q, long n){ register NUMBER *r; if (qisfrac(q)) { math_error("Shift of non-integer"); /*NOTREACHED*/ } if (qiszero(q) || (n == 0)) return qlink(q); if (n <= -(q->num.len * BASEB)) return qlink(&_qzero_); r = qalloc(); zshift(q->num, n, &r->num); return r;}/* * Scale a number by a power of two, as in: * ans = q * 2^n. * This is similar to shifting, except that fractions work. */NUMBER *qscale(NUMBER *q, long pow){ long numshift, denshift, tmp; NUMBER *r; if (qiszero(q) || (pow == 0)) return qlink(q); numshift = zisodd(q->num) ? 0 : zlowbit(q->num); denshift = zisodd(q->den) ? 0 : zlowbit(q->den); if (pow > 0) { tmp = pow; if (tmp > denshift) tmp = denshift; denshift = -tmp; numshift = (pow - tmp); } else { pow = -pow; tmp = pow; if (tmp > numshift) tmp = numshift; numshift = -tmp; denshift = (pow - tmp); } r = qalloc(); if (numshift) zshift(q->num, numshift, &r->num); else zcopy(q->num, &r->num); if (denshift) zshift(q->den, denshift, &r->den); else zcopy(q->den, &r->den); return r;}/* * Return the minimum of two numbers. */NUMBER *qmin(NUMBER *q1, NUMBER *q2){ if (q1 == q2) return qlink(q1); if (qrel(q1, q2) > 0) q1 = q2; return qlink(q1);}/* * Return the maximum of two numbers. */NUMBER *qmax(NUMBER *q1, NUMBER *q2){ if (q1 == q2) return qlink(q1); if (qrel(q1, q2) < 0) q1 = q2; return qlink(q1);}/* * Perform the bitwise OR of two integers. */NUMBER *qor(NUMBER *q1, NUMBER *q2){ register NUMBER *r; NUMBER *q1tmp, *q2tmp, *q; if (qisfrac(q1) || qisfrac(q2)) { math_error("Non-integers for bitwise or"); /*NOTREACHED*/ } if (qcmp(q1,q2) == 0 || qiszero(q2)) return qlink(q1); if (qiszero(q1)) return qlink(q2); if (qisneg(q1)) { q1tmp = qcomp(q1); if (qisneg(q2)) { q2tmp = qcomp(q2); q = qand(q1tmp,q2tmp); r = qcomp(q); qfree(q1tmp); qfree(q2tmp); qfree(q); return r; } q = qandnot(q1tmp, q2); qfree(q1tmp); r = qcomp(q); qfree(q); return r; } if (qisneg(q2)) { q2tmp = qcomp(q2); q = qandnot(q2tmp, q1); qfree(q2tmp); r = qcomp(q); qfree(q); return r; } r = qalloc(); zor(q1->num, q2->num, &r->num); return r;}/* * Perform the bitwise AND of two integers. */NUMBER *qand(NUMBER *q1, NUMBER *q2){ register NUMBER *r; NUMBER *q1tmp, *q2tmp, *q; ZVALUE res; if (qisfrac(q1) || qisfrac(q2)) { math_error("Non-integers for bitwise and"); /*NOTREACHED*/ } if (qcmp(q1, q2) == 0) return qlink(q1); if (qiszero(q1) || qiszero(q2)) return qlink(&_qzero_); if (qisneg(q1)) { q1tmp = qcomp(q1); if (qisneg(q2)) { q2tmp = qcomp(q2); q = qor(q1tmp, q2tmp); qfree(q1tmp); qfree(q2tmp); r = qcomp(q); qfree(q); return r; } r = qandnot(q2, q1tmp); qfree(q1tmp); return r; } if (qisneg(q2)) { q2tmp = qcomp(q2); r = qandnot(q1, q2tmp); qfree(q2tmp); return r; } zand(q1->num, q2->num, &res); if (ziszero(res)) { zfree(res); return qlink(&_qzero_); } r = qalloc(); r->num = res; return r;}/* * Perform the bitwise XOR of two integers. */NUMBER *qxor(NUMBER *q1, NUMBER *q2){ register NUMBER *r; NUMBER *q1tmp, *q2tmp, *q; ZVALUE res; if (qisfrac(q1) || qisfrac(q2)) { math_error("Non-integers for bitwise xor"); /*NOTREACHED*/ } if (qcmp(q1,q2) == 0) return qlink(&_qzero_); if (qiszero(q1)) return qlink(q2); if (qiszero(q2)) return qlink(q1); if (qisneg(q1)) { q1tmp = qcomp(q1); if (qisneg(q2)) { q2tmp = qcomp(q2); r = qxor(q1tmp, q2tmp); qfree(q1tmp); qfree(q2tmp); return r; } q = qxor(q1tmp, q2); qfree(q1tmp); r = qcomp(q); qfree(q); return r; } if (qisneg(q2)) { q2tmp = qcomp(q2); q = qxor(q1, q2tmp); qfree(q2tmp); r = qcomp(q); qfree(q); return r; } zxor(q1->num, q2->num, &res); if (ziszero(res)) { zfree(res); return qlink(&_qzero_); } r = qalloc(); r->num = res; return r;}/* * Perform the bitwise ANDNOT of two integers. */NUMBER *qandnot(NUMBER *q1, NUMBER *q2){ register NUMBER *r; NUMBER *q1tmp, *q2tmp, *q; if (qisfrac(q1) || qisfrac(q2)) { math_error("Non-integers for bitwise xor"); /*NOTREACHED*/ } if (qcmp(q1,q2) == 0 || qiszero(q1)) return qlink(&_qzero_); if (qiszero(q2)) return qlink(q1); if (qisneg(q1)) { q1tmp = qcomp(q1); if (qisneg(q2)) { q2tmp = qcomp(q2); r = qandnot(q2tmp, q1tmp); qfree(q1tmp); qfree(q2tmp); return r; } q = qor(q1tmp, q2); qfree(q1tmp); r = qcomp(q); qfree(q); return r; } if (qisneg(q2)) { q2tmp = qcomp(q2); r = qand(q1, q2tmp); qfree(q2tmp); return r; } r = qalloc(); zandnot(q1->num, q2->num, &r->num); return r;}/* * Return the bitwise "complement" of a number. This is - q -1 if q is an * integer, - q otherwise. */NUMBER *qcomp(NUMBER *q){ NUMBER *qtmp; NUMBER *res; if (qiszero(q)) return qlink(&_qnegone_); if (qisnegone(q)) return qlink(&_qzero_); qtmp = qneg(q); if (qisfrac(q)) return qtmp; res = qdec(qtmp); qfree(qtmp); return res;}/* * Return the number whose binary representation only has the specified * bit set (counting from zero). This thus produces a given power of two. */NUMBER *qbitvalue(long n){ register NUMBER *r; if (n == 0) return qlink(&_qone_); r = qalloc(); if (n > 0) zbitvalue(n, &r->num); else zbitvalue(-n, &r->den); return r;}/* * Return 10^n */NUMBER *qtenpow(long n){ register NUMBER *r; if (n == 0) return qlink(&_qone_); r = qalloc(); if (n > 0) ztenpow(n, &r->num); else ztenpow(-n, &r->den); return r;}/* * Return the precision of a number (usually for examining an epsilon value). * The precision of a number e less than 1 is the positive * integer p for which e = 2^-p * f, where 1 <= f < 2. * Numbers greater than or equal to one have a precision of zero. * For example, the precision of e is 6 if 1/64 <= e < 1/32. */longqprecision(NUMBER *q){ long r; if (qiszero(q) || qisneg(q)) { math_error("Non-positive number for precision"); /*NOTREACHED*/ } r = - qilog2(q); return (r < 0 ? 0 : r);}/* * Determine whether or not one number exactly divides another one. * Returns TRUE if the first number is an integer multiple of the second one. */BOOLqdivides(NUMBER *q1, NUMBER *q2){ if (qiszero(q1)) return TRUE; if (qisint(q1) && qisint(q2)) { if (qisunit(q2)) return TRUE; return zdivides(q1->num, q2->num); } return zdivides(q1->num, q2->num) && zdivides(q2->den, q1->den);}/* * Compare two numbers and return an integer indicating their relative size. * i = qrel(q1, q2); */FLAGqrel(NUMBER *q1, NUMBER *q2){ ZVALUE z1, z2; long wc1, wc2; int sign; int z1f = 0, z2f = 0; if (q1 == q2) return 0; sign = q2->num.sign - q1->num.sign; if (sign) return sign; if (qiszero(q2)) return !qiszero(q1); if (qiszero(q1)) return -1; /* * Make a quick comparison by calculating the number of words resulting as * if we multiplied through by the denominators, and then comparing the * word counts. */ sign = 1; if (qisneg(q1)) sign = -1; wc1 = q1->num.len + q2->den.len; wc2 = q2->num.len + q1->den.len; if (wc1 < wc2 - 1) return -sign; if (wc2 < wc1 - 1) return sign; /* * Quick check failed, must actually do the full comparison. */ if (zisunit(q2->den)) { z1 = q1->num; } else if (zisone(q1->num)) { z1 = q2->den; } else { z1f = 1; zmul(q1->num, q2->den, &z1); } if (zisunit(q1->den)) { z2 = q2->num; } else if (zisone(q2->num)) { z2 = q1->den; } else { z2f = 1; zmul(q2->num, q1->den, &z2); } sign = zrel(z1, z2); if (z1f) zfree(z1); if (z2f) zfree(z2); return sign;}/* * Compare two numbers to see if they are equal. * This differs from qrel in that the numbers are not ordered. * Returns TRUE if they differ. */BOOLqcmp(NUMBER *q1, NUMBER *q2){ if (q1 == q2) return FALSE; if ((q1->num.sign != q2->num.sign) || (q1->num.len != q2->num.len) || (q2->den.len != q2->den.len) || (*q1->num.v != *q2->num.v) || (*q1->den.v != *q2->den.v)) return TRUE; if (zcmp(q1->num, q2->num)) return TRUE; if (qisint(q1)) return FALSE; return zcmp(q1->den, q2->den);}/* * Compare a number against a normal small integer. * Returns 1, 0, or -1, according to whether the first number is greater, * equal, or less than the second number. * res = qreli(q, n); */FLAGqreli(NUMBER *q, long n){ ZVALUE z1, z2; FLAG res; if (qiszero(q)) return ((n > 0) ? -1 : (n < 0)); if (n == 0) return (q->num.sign ? -1 : 0); if (q->num.sign != (n < 0)) return ((n < 0) ? 1 : -1); itoz(n, &z1); if (qisfrac(q)) { zmul(q->den, z1, &z2); zfree(z1); z1 = z2; } res = zrel(q->num, z1); zfree(z1); return res;}/* * Compare a number against a small integer to see if they are equal. * Returns TRUE if they differ. */BOOLqcmpi(NUMBER *q, long n){ long len;#if LONG_BITS > BASEB FULL nf;#endif len = q->num.len; if (qisfrac(q) || (q->num.sign != (n < 0))) return TRUE; if (n < 0) n = -n; if (((HALF)(n)) != q->num.v[0]) return TRUE;#if LONG_BITS > BASEB nf = ((FULL) n) >> BASEB; return ((nf != 0 || len > 1) && (len != 2 || nf != q->num.v[1]));#else return (len > 1);#endif}/* * Number node allocation routines */#define NNALLOC 1000static NUMBER *freeNum = NULL;static NUMBER **firstNums = NULL;static long blockcount = 0;NUMBER *qalloc(void){ NUMBER *temp; NUMBER ** newfn; if (freeNum == NULL) { freeNum = (NUMBER *) malloc(sizeof (NUMBER) * NNALLOC); if (freeNum == NULL) { math_error("Not enough memory"); /*NOTREACHED*/ } freeNum[NNALLOC - 1].next = NULL; freeNum[NNALLOC - 1].links = 0; /* * We prevent the temp pointer from walking behind freeNum * by stopping one short of the end and running the loop one * more time. * * We would stop the loop with just temp >= freeNum, but * doing this helps make code checkers such as insure happy. */ for (temp = freeNum + NNALLOC - 2; temp > freeNum; --temp) { temp->next = temp + 1; temp->links = 0; } /* run the loop manually one last time */ temp->next = temp + 1; temp->links = 0; blockcount++; if (firstNums == NULL) { newfn = (NUMBER **) malloc(blockcount * sizeof(NUMBER *)); } else { newfn = (NUMBER **) realloc(firstNums, blockcount * sizeof(NUMBER *)); } if (newfn == NULL) { math_error("Cannot allocate new number block"); /*NOTREACHED*/ } firstNums = newfn; firstNums[blockcount - 1] = freeNum; } temp = freeNum; freeNum = temp->next; temp->links = 1; temp->num = _one_; temp->den = _one_; return temp;}voidqfreenum(NUMBER *q){ if (q == NULL) { math_error("Calling qfreenum with null argument!!!"); /*NOTREACHED*/ } if (q->links != 0) { math_error("Calling qfreenum with nozero links!!!"); /*NOTREACHED*/ } zfree(q->num); zfree(q->den); q->next = freeNum; freeNum = q;}voidshownumbers(void){ NUMBER *vp; long i, j, k; long count = 0; printf("Index Links Digits Value\n"); printf("----- ----- ------ -----\n"); for (i = 0, k = 0; i < INITCONSTCOUNT; i++) { count++; vp = initnumbs[i]; printf("%6ld %4ld ", k++, vp->links); fitprint(vp, 40); printf("\n"); } for (i = 0; i < blockcount; i++) { vp = firstNums[i]; for (j = 0; j < NNALLOC; j++, k++, vp++) { if (vp->links > 0) { count++; printf("%6ld %4ld ", k, vp->links); fitprint(vp, 40); printf("\n"); } } } printf("\nNumber: %ld\n", count);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -