mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
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:
39
LIBRARY
39
LIBRARY
@@ -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
87
qfunc.c
@@ -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;
|
||||||
|
}
|
||||||
|
1
qmath.h
1
qmath.h
@@ -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);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
70
qtrans.c
70
qtrans.c
@@ -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
17
zfunc.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
2
zmath.h
2
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 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);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user