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.
This commit is contained in:
Landon Curt Noll
2023-08-27 23:50:44 -07:00
parent 4e5fcc8812
commit 4dbc4dfe9a
6 changed files with 131 additions and 89 deletions

39
LIBRARY
View File

@@ -393,12 +393,6 @@ ZVALUE yourself. Examples of such checks are:
zge32b(z) (number is >= 2^32) zge32b(z) (number is >= 2^32)
zge64b(z) (number is >= 2^64) 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 Typically the largest unsigned long is typedefed to FULL. The following
macros are useful in dealing with this data type: 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 the first one is smaller, 0 if they are the same, and 1 if the first one
is larger. 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 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 integral, fractional, real, or exponential formats. Examples of allocating
numbers are: numbers are:
NUMBER *q1, *q2, *q3; NUMBER *q1, *q2, *q3, *q4;
q1 = itoq(66L); q1 = itoq(66L);
q2 = iitoq(2L, 3L); q2 = iitoq(2L, 3L);
q3 = str2q("456.78"); q3 = str2q("456.78");
q4 = utoq((FULL) 1234567890L);
Also unlike ZVALUEs, NUMBERs are quickly copied. This is because they contain 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 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 onto a free list for quick reuse. The following is an example of allocating
NUMBERs, copying them, adding them, and finally deleting them again. NUMBERs, copying them, adding them, and finally deleting them again.
NUMBER *q1, *q2, *q3; NUMBER *q1, *q2, *q3, *q4;
q1 = itoq(111L); q1 = itoq(111L);
q2 = qlink(q1); q2 = qlink(q1);
q3 = qqadd(q1, q2); q3 = qqadd(q1, q2);
q4 = qnum(q2, q3);
qfree(q1); qfree(q1);
qfree(q2); qfree(q2);
qfree(q3); 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_); q1 = qlink(&_qonehalf_);
q2 = qlink(&_qone_); 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 USING COMPLEX NUMBERS
--------------------- ---------------------

87
qfunc.c
View File

@@ -1849,3 +1849,90 @@ qprimetest(NUMBER *q1, NUMBER *q2, NUMBER *q3)
} }
return zprimetest(q1->num, ztoi(q2->num), q3->num); 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;
}

View File

@@ -170,6 +170,7 @@ E_FUNC long qdigits(NUMBER *q, ZVALUE base);
E_FUNC void setepsilon(NUMBER *q); E_FUNC void setepsilon(NUMBER *q);
E_FUNC NUMBER *qbitvalue(long i); E_FUNC NUMBER *qbitvalue(long i);
E_FUNC NUMBER *qtenpow(long i); E_FUNC NUMBER *qtenpow(long i);
E_FUNC bool qispowerof2(NUMBER *q, NUMBER **qlog2);
/* /*

View File

@@ -1245,78 +1245,12 @@ qlog2(NUMBER *q, NUMBER *epsilon)
/* /*
* special case: q is integer power of 2 * 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(); ret = qalloc();
zcopy(zlog2, &ret->num); if (qispowerof2(q, &ret)) {
zfree(zlog2);
return ret; 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);
}
}
} }
qfree(ret);
/* /*
* compute ln(c) first * compute ln(c) first

17
zfunc.c
View File

@@ -2243,30 +2243,29 @@ zissquare(ZVALUE z)
* *
* given: * given:
* z value to check if it is a power of 2 * z value to check if it is a power of 2
* zlog2 >= 0 ==> *zlog2 power of 2 of z (return true) * log2 when z is an integer power of 2 (true return), *log2 is set to log base 2 of z
* < 0 z is not a power of 2 (return false) * when z is NOT an integer power of 2 (false return), *log2 is not touched
* *
* returns: * returns:
* true z is a power of 2 * true z is a power of 2
* false z is not a power of 2 * false z is not a power of 2
*/ */
bool 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 */ HALF tophalf; /* most significant HALF in z */
LEN len; /* length of z in HALFs */ LEN len; /* length of z in HALFs */
int i; int i;
/* firewall */ /* firewall */
if (zlog2 == NULL) { if (log2 == NULL) {
math_error("%s: zlog2 NULL", __func__); math_error("%s: log2 NULL", __func__);
not_reached(); not_reached();
} }
/* zero and negative values are never integer powers of 2 */ /* zero and negative values are never integer powers of 2 */
if (ziszero(z) || zisneg(z)) { if (ziszero(z) || zisneg(z)) {
*zlog2 = _neg_one_;
return false; return false;
} }
@@ -2283,7 +2282,6 @@ zispowerof2(ZVALUE z, ZVALUE *zlog2)
len = z.len; len = z.len;
for (i=0, ilogz=0; i < len-1; ++i, ilogz+=BASEB) { for (i=0, ilogz=0; i < len-1; ++i, ilogz+=BASEB) {
if (z.v[i] != 0) { if (z.v[i] != 0) {
*zlog2 = _neg_one_;
return false; return false;
} }
} }
@@ -2297,7 +2295,6 @@ zispowerof2(ZVALUE z, ZVALUE *zlog2)
*/ */
tophalf = z.v[len-1]; tophalf = z.v[len-1];
if ((tophalf == 0) || ((tophalf & (tophalf-1)) != 0)) { if ((tophalf == 0) || ((tophalf & (tophalf-1)) != 0)) {
*zlog2 = _neg_one_;
return false; return false;
} }
@@ -2311,6 +2308,6 @@ zispowerof2(ZVALUE z, ZVALUE *zlog2)
/* /*
* return power of 2 * return power of 2
*/ */
utoz(ilogz, zlog2); *log2 = ilogz;
return true; return true;
} }

View File

@@ -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 void zroot(ZVALUE z1, ZVALUE z2, ZVALUE *dest);
E_FUNC bool zissquare(ZVALUE z); E_FUNC bool zissquare(ZVALUE z);
E_FUNC void zhnrmod(ZVALUE v, ZVALUE h, ZVALUE zn, ZVALUE zr, ZVALUE *res); 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);
/* /*