ref: e95082f66c099184afd273d7fc0a30fd2c5e0ba8
parent: a08bf6831f5122fc9bfc6dccf77096f6ac2e4d03
author: aiju <devnull@localhost>
date: Mon Aug 29 05:57:15 EDT 2016
pc: add gcd, rand and minv; set base of logical operation results to 0
--- a/sys/man/1/pc
+++ b/sys/man/1/pc
@@ -89,6 +89,15 @@
.TP
.I sbits(n)
The minimum number of bits required to represent \fIn\fR as an signed number.
+.TP
+.I gcd(n,m)
+The greatest common divisor of \fIn\fR and \fIm\fR.
+.TP
+.I minv(n,m)
+The inverse of \fIn\fR mod \fIm\fR.
+.TP
+.I rand(n)
+A random number satisfying 0 ≤ \fIrand(n)\fR < \fIn\fR.
.SS Control statements
.PP
Control statements are always evaluated with default input base 10.
--- a/sys/src/cmd/pc.y
+++ b/sys/src/cmd/pc.y
@@ -4,8 +4,8 @@
#include <bio.h>
#include <ctype.h>
#include <mp.h>
-#include <pool.h>
#include <thread.h>
+#include <libsec.h>
int inbase = 10, outbase, divmode, sep, fail, prompt;
enum { MAXARGS = 16 };
@@ -175,12 +175,12 @@
}else
mpasr(a, mptoi(b), a);
break;
- case '<': itomp(mpcmp(a, b) < 0, a); break;
- case '>': itomp(mpcmp(a, b) > 0, a); break;
- case LOLE: itomp(mpcmp(a, b) <= 0, a); break;
- case LOGE: itomp(mpcmp(a, b) >= 0, a); break;
- case LOEQ: itomp(mpcmp(a, b) == 0, a); break;
- case LONE: itomp(mpcmp(a, b) != 0, a); break;
+ case '<': itomp(mpcmp(a, b) < 0, a); a->b = 0; break;
+ case '>': itomp(mpcmp(a, b) > 0, a); a->b = 0; break;
+ case LOLE: itomp(mpcmp(a, b) <= 0, a); a->b = 0; break;
+ case LOGE: itomp(mpcmp(a, b) >= 0, a); a->b = 0; break;
+ case LOEQ: itomp(mpcmp(a, b) == 0, a); a->b = 0; break;
+ case LONE: itomp(mpcmp(a, b) != 0, a); a->b = 0; break;
case LOLAND:
a->b = b->b;
if(mpcmp(a, mpzero) == 0)
@@ -435,7 +435,7 @@
| '+' expr %prec unary { $$ = $2; }
| '-' expr %prec unary { $$ = nummod($2); if($$ != nil) mpsub(mpzero, $$, $$); }
| '~' expr %prec unary { $$ = nummod($2); if($$ != nil) mpnot($$, $$); }
- | '!' expr %prec unary { $$ = nummod($2); if($$ != nil) itomp(mpcmp($$, mpzero) == 0, $$); }
+ | '!' expr %prec unary { $$ = nummod($2); if($$ != nil) {itomp(mpcmp($$, mpzero) == 0, $$); $$->b = 0; } }
| expr '?' expr ':' expr %prec '?' {
if($1 == nil || mpcmp($1, mpzero) != 0){
$$ = $3;
@@ -752,7 +752,7 @@
}
a[0] = nummod(a[0]);
itomp(mpsignif(a[0]), a[0]);
- a[0]->b = 10;
+ a[0]->b = 0;
return a[0];
}
@@ -762,12 +762,48 @@
a[0] = nummod(a[0]);
if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
itomp(mpsignif(a[0]) + 1, a[0]);
- a[0]->b = 10;
+ a[0]->b = 0;
return a[0];
}
+Num *
+fngcd(int, Num **a)
+{
+ a[0] = nummod(a[0]);
+ a[0]->b = basemax(a[0]->b, a[1]->b);
+ mpextendedgcd(a[0], a[1], a[0], nil, nil);
+ return a[0];
+}
+Num *
+fnrand(int, Num **a)
+{
+ Num *n;
+ n = numalloc();
+ n->b = a[0]->b;
+ mpnrand(a[0], genrandom, n);
+ numdecref(a[0]);
+ return n;
+}
+
+Num *
+fnminv(int, Num **a)
+{
+ mpint *x;
+
+ a[0] = nummod(a[0]);
+ x = mpnew(0);
+ mpextendedgcd(a[0], a[1], x, a[0], nil);
+ if(mpcmp(x, mpone) != 0)
+ error("no modular inverse");
+ else
+ mpmod(a[0], a[1], a[0]);
+ mpfree(x);
+ numdecref(a[1]);
+ return a[0];
+}
+
void
main(int argc, char **argv)
{
@@ -791,6 +827,9 @@
regfunc("xtend", fnxtend, 2);
regfunc("ubits", fnubits, 1);
regfunc("sbits", fnsbits, 1);
+ regfunc("gcd", fngcd, 2);
+ regfunc("minv", fnminv, 2);
+ regfunc("rand", fnrand, 1);
prompt = 1;
ARGBEGIN{