From 4dbc4dfe9a7f078ac00814487d6d1113117ed0e9 Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Sun, 27 Aug 2023 23:50:44 -0700 Subject: [PATCH] add qispowerof2() to qfunc.c, improve log2() code Change zispowerof2() interaface to take a FULL ptr as the 2nd arg: zispowerof2(ZVALUE z, FULL *log2). Added qispowerof2(NUMBER *q, NUMBER **qlog2) to qfunc.c. Change log2() builtin to use the new qispowerof2() internal interface. Update LIBRARY to reflect the new zispowerof2() internal interface and the new qispowerof2() internal interface. --- LIBRARY | 39 +++++++++++++++++++------ qfunc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qmath.h | 1 + qtrans.c | 74 +++-------------------------------------------- zfunc.c | 17 +++++------ zmath.h | 2 +- 6 files changed, 131 insertions(+), 89 deletions(-) diff --git a/LIBRARY b/LIBRARY index 6599f60..438199c 100644 --- a/LIBRARY +++ b/LIBRARY @@ -393,12 +393,6 @@ ZVALUE yourself. Examples of such checks are: zge32b(z) (number is >= 2^32) zge64b(z) (number is >= 2^64) -Return true if z an integer power of 2: set zlog2 to log base 2 of z. -Return false if a is NOT integer power of 2: set zlog2 to 0. -The zlog2 arg must be a non-NULL pointer to a ZVALUE. - - zispowerof2(z, &zlog2) - Typically the largest unsigned long is typedefed to FULL. The following macros are useful in dealing with this data type: @@ -426,6 +420,18 @@ The zrel function tests the relative sizes of two ZVALUEs, returning -1 if the first one is smaller, 0 if they are the same, and 1 if the first one is larger. +To determine if z is an integer power of 2, use zispowerof2: + + ZVALUE z; /* value to check if it is a power of */ + FULL log2; /* set to log base 2 of z when is_power_of_2 is true */ + bool is_power_of_2; + + is_power_of_2 = zispowerof2(z, &log2) + +Returns true if z an integer power of 2: set log2 to log base 2 of z. +Returns false if z is NOT integer power of 2 and leave log2 untouched. +The log2 arg must be a non-NULL pointer to a ZVALUE. + --------------- USING FRACTIONS --------------- @@ -459,11 +465,12 @@ a number into the corresponding NUMBER. The str2q function accepts input in integral, fractional, real, or exponential formats. Examples of allocating numbers are: - NUMBER *q1, *q2, *q3; + NUMBER *q1, *q2, *q3, *q4; q1 = itoq(66L); q2 = iitoq(2L, 3L); q3 = str2q("456.78"); + q4 = utoq((FULL) 1234567890L); Also unlike ZVALUEs, NUMBERs are quickly copied. This is because they contain a link count, which is the number of pointers there are to the NUMBER. The @@ -479,11 +486,13 @@ the ZVALUEs contained within the NUMBER, and then puts the NUMBER structure onto a free list for quick reuse. The following is an example of allocating NUMBERs, copying them, adding them, and finally deleting them again. - NUMBER *q1, *q2, *q3; + NUMBER *q1, *q2, *q3, *q4; q1 = itoq(111L); q2 = qlink(q1); q3 = qqadd(q1, q2); + q4 = qnum(q2, q3); + qfree(q1); qfree(q2); qfree(q3); @@ -544,6 +553,20 @@ These have the values 0, 1, -1, and 1/2. An example of using them is: q1 = qlink(&_qonehalf_); q2 = qlink(&_qone_); +To determine if q is an integer power of 2, use qispowerof2: + + NUMBER *q; /* value to check if it is a power of */ + NUMBER *qlog2; /* set to log base 2 of q when is_power_of_2 is true */ + bool is_power_of_2; + + q = utoq((FULL) 1234567890L); + qlog2 = qalloc(); + is_power_of_2 = qispowerof2(q, &qlog2); + +Returns true if q an integer power of 2: set *qlog2 to log base 2 of q. +Returns false if q is NOT integer power of 2 and leave *qlog2 untouched. +Use qalloc() to setup the qlog2 arg before calling. + --------------------- USING COMPLEX NUMBERS --------------------- diff --git a/qfunc.c b/qfunc.c index 70324ed..38fc89a 100644 --- a/qfunc.c +++ b/qfunc.c @@ -1849,3 +1849,90 @@ qprimetest(NUMBER *q1, NUMBER *q2, NUMBER *q3) } return zprimetest(q1->num, ztoi(q2->num), q3->num); } + + +/* + * test if a number is an integer power of 2 + * + * given: + * q value to check if it is a power of 2 + * qlog2 when q is an integer power of 2 (return true), set to log base 2 of q + * when q is NOT an integer power of 2 (return false), *qlog2 is not set + * + * returns: + * true q is a power of 2 + * false q is not a power of 2 + */ +bool +qispowerof2(NUMBER *q, NUMBER **qlog2) +{ + FULL log2; /* base 2 logarithm as a ZVALUE */ + + /* firewall */ + if (q == NULL) { + math_error("%s: q NULL", __func__); + not_reached(); + } + if (qlog2 == NULL) { + math_error("%s: qlog2 NULL", __func__); + not_reached(); + } + if (*qlog2 == NULL) { + math_error("%s: *qlog2 NULL", __func__); + not_reached(); + } + + /* zero and negative values are never integer powers of 2 */ + if (qiszero(q) || qisneg(q)) { + /* leave *qlog2 untouched and return false */ + return false; + } + + /* + * case: q>0 is an integer + */ + if (qisint(q)) { + + /* + * check if q is an integer power of 2 + */ + if (zispowerof2(q->num, &log2)) { + + /* + * case: q is an integer power of 2 + * + * Set *qlog2 to base 2 logarithm of q and return true. + */ + *qlog2 = utoq(log2); + return true; + } + + /* + * case: q>0 is 1 over an integer + */ + } else if (qisreciprocal(q)) { + + /* + * check if q is 1 over an integer power of 2 + */ + if (zispowerof2(q->den, &log2)) { + + /* + * case: q>0 is an integer power of 2 + * + * Set *qlog2 to base 2 logarithm of q, which will be a negative value, + * and return true. + */ + *qlog2 = utoq(log2); + (*qlog2)->num.sign = !(*qlog2)->num.sign; /* set *qlog2 to -log2 */ + return true; + } + } + + /* + * q is not an integer power of 2 + * + * Leave *qlog2 untouched and return false. + */ + return false; +} diff --git a/qmath.h b/qmath.h index 90bbf93..eb32f3b 100644 --- a/qmath.h +++ b/qmath.h @@ -170,6 +170,7 @@ E_FUNC long qdigits(NUMBER *q, ZVALUE base); E_FUNC void setepsilon(NUMBER *q); E_FUNC NUMBER *qbitvalue(long i); E_FUNC NUMBER *qtenpow(long i); +E_FUNC bool qispowerof2(NUMBER *q, NUMBER **qlog2); /* diff --git a/qtrans.c b/qtrans.c index 7f6b00b..dcef696 100644 --- a/qtrans.c +++ b/qtrans.c @@ -1245,78 +1245,12 @@ qlog2(NUMBER *q, NUMBER *epsilon) /* * special case: q is integer power of 2 - * - * When q is integer power of 2, the base 2 logarithm is an integer. - * We return a base 2 logarithm that is in integer in this case. - * - * From above we know that q != 0, so we need to check that q>0. - * - * We have two cases for a power of two: a positive power of 2, and a - * negative power of 2 (i.e., 1 over a power of 2). */ - if (qispos(q)) { - ZVALUE zlog2; /* base 2 logarithm when q is power of 2 */ - - /* - * case: q>0 is an integer - */ - if (qisint(q)) { - - /* - * check if q is an integer power of 2 - */ - if (zispowerof2(q->num, &zlog2)) { - - /* - * case: q>0 is an integer power of 2 - * - * Return zlog2, which is an integer power of 2 as a NUMBER. - */ - ret = qalloc(); - zcopy(zlog2, &ret->num); - zfree(zlog2); - return ret; - - /* - * case: integer q is not an integer power of 2 - */ - } else { - - /* free the zispowerof2() 2nd arg and proceed to calculate ln(q)/ln(2) */ - zfree(zlog2); - } - - /* - * case: q>0 is 1 over an integer - */ - } else if (qisreciprocal(q)) { - - /* - * check if q is 1 over an integer power of 2 - */ - if (zispowerof2(q->den, &zlog2)) { - - /* - * case: q>0 is an integer power of 2 - * - * Return zlog2, which is an negative integer power of 2 as a NUMBER. - */ - ret = qalloc(); - zlog2.sign = !zlog2.sign; /* zlog2 = -zlog2 */ - zcopy(zlog2, &ret->num); - zfree(zlog2); - return ret; - - /* - * case: reciprocal q is not an integer power of 2 - */ - } else { - - /* free the zispowerof2() 2nd arg and proceed to calculate ln(q)/ln(2) */ - zfree(zlog2); - } - } + ret = qalloc(); + if (qispowerof2(q, &ret)) { + return ret; } + qfree(ret); /* * compute ln(c) first diff --git a/zfunc.c b/zfunc.c index 9f2fa75..3f717e9 100644 --- a/zfunc.c +++ b/zfunc.c @@ -2243,30 +2243,29 @@ zissquare(ZVALUE z) * * given: * z value to check if it is a power of 2 - * zlog2 >= 0 ==> *zlog2 power of 2 of z (return true) - * < 0 z is not a power of 2 (return false) + * log2 when z is an integer power of 2 (true return), *log2 is set to log base 2 of z + * when z is NOT an integer power of 2 (false return), *log2 is not touched * * returns: * true z is a power of 2 * false z is not a power of 2 */ bool -zispowerof2(ZVALUE z, ZVALUE *zlog2) +zispowerof2(ZVALUE z, FULL *log2) { - FULL ilogz=0; /* potential log base 2 return value or -1 */ + FULL ilogz; /* potential log base 2 return value or -1 */ HALF tophalf; /* most significant HALF in z */ LEN len; /* length of z in HALFs */ int i; /* firewall */ - if (zlog2 == NULL) { - math_error("%s: zlog2 NULL", __func__); + if (log2 == NULL) { + math_error("%s: log2 NULL", __func__); not_reached(); } /* zero and negative values are never integer powers of 2 */ if (ziszero(z) || zisneg(z)) { - *zlog2 = _neg_one_; return false; } @@ -2283,7 +2282,6 @@ zispowerof2(ZVALUE z, ZVALUE *zlog2) len = z.len; for (i=0, ilogz=0; i < len-1; ++i, ilogz+=BASEB) { if (z.v[i] != 0) { - *zlog2 = _neg_one_; return false; } } @@ -2297,7 +2295,6 @@ zispowerof2(ZVALUE z, ZVALUE *zlog2) */ tophalf = z.v[len-1]; if ((tophalf == 0) || ((tophalf & (tophalf-1)) != 0)) { - *zlog2 = _neg_one_; return false; } @@ -2311,6 +2308,6 @@ zispowerof2(ZVALUE z, ZVALUE *zlog2) /* * return power of 2 */ - utoz(ilogz, zlog2); + *log2 = ilogz; return true; } diff --git a/zmath.h b/zmath.h index 55b7e0d..f6ab11c 100644 --- a/zmath.h +++ b/zmath.h @@ -415,7 +415,7 @@ E_FUNC FLAG zsqrt(ZVALUE z1, ZVALUE *dest, long R); E_FUNC void zroot(ZVALUE z1, ZVALUE z2, ZVALUE *dest); E_FUNC bool zissquare(ZVALUE z); E_FUNC void zhnrmod(ZVALUE v, ZVALUE h, ZVALUE zn, ZVALUE zr, ZVALUE *res); -E_FUNC bool zispowerof2(ZVALUE z, ZVALUE *zlog2); +E_FUNC bool zispowerof2(ZVALUE z, FULL *log2); /*