ref: e09adf59442cd36888eaea1d76e66ff3259d16b8
parent: e0087b2a78d7229d8d2b148b8def688be6639797
author: aiju <devnull@localhost>
date: Sun Apr 2 10:47:23 EDT 2017
pc(1): fix memory leak and add clog() function
--- a/sys/man/1/pc
+++ b/sys/man/1/pc
@@ -105,6 +105,9 @@
.I gcd(n,m)
The greatest common divisor of \fIn\fR and \fIm\fR.
.TP
+.I clog(a,b)
+The ceiling of the logarithm of \fIa\fR with respect to base \fIb\fR. \fIb\fR can be omitted, in which case it defaults to 2.
+.TP
.I minv(n,m)
The inverse of \fIn\fR mod \fIm\fR.
.TP
--- a/sys/src/cmd/pc.y
+++ b/sys/src/cmd/pc.y
@@ -310,15 +310,28 @@
free(t);
}
+void
+numdecrefs(int n, Num **x)
+{
+ int i;
+
+ for(i = 0; i < n; i++)
+ numdecref(x[i]);
+}
+
Num *
fncall(Symbol *s, int n, Num **x)
{
int i;
- if(s->t != SYMFUNC)
+ if(s->t != SYMFUNC){
+ numdecrefs(n, x);
return error("%s: not a function", s->name);
- else if(s->nargs >= 0 && s->nargs != n)
+ }
+ else if(s->nargs >= 0 && s->nargs != n){
+ numdecrefs(n, x);
return error("%s: wrong number of arguments", s->name);
+ }
for(i = 0; i < n; i++)
if(x[i] == nil)
return nil;
@@ -820,6 +833,39 @@
}
Num *
+fnclog(int n, Num **a)
+{
+ int r;
+
+ if(n != 1 && n != 2){
+ numdecrefs(n, a);
+ return error("clog: wrong number of arguments");
+ }
+ if(mpcmp(a[0], mpzero) <= 0 || n == 2 && mpcmp(a[1], mpone) <= 0){
+ numdecref(a[0]);
+ return error("invalid argument");
+ }
+ if(n == 1 || mpcmp(a[1], mptwo) == 0){
+ a[0] = nummod(a[0]);
+ mpsub(a[0], mpone, a[0]);
+ itomp(mpsignif(a[0]), a[0]);
+ a[0]->b = 0;
+ if(n == 2) numdecref(a[1]);
+ return a[0];
+ }
+ a[0] = nummod(a[0]);
+ for(r = 0; mpcmp(a[0], mpone) > 0; r++){
+ mpadd(a[0], a[1], a[0]);
+ mpsub(a[0], mpone, a[0]);
+ mpdiv(a[0], a[1], a[0], nil);
+ }
+ itomp(r, a[0]);
+ a[0]->b = 0;
+ numdecref(a[1]);
+ return a[0];
+}
+
+Num *
fnubits(int, Num **a)
{
if(a[0]->sign < 0){
@@ -986,6 +1032,7 @@
regfunc("ceil", fnceil, 2);
regfunc("trunc", fntrunc, 2);
regfunc("xtend", fnxtend, 2);
+ regfunc("clog", fnclog, -1);
regfunc("ubits", fnubits, 1);
regfunc("sbits", fnsbits, 1);
regfunc("nsa", fnnsa, 1);