#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;
+int inbase = 10, outbase, divmode, sep, heads, fail, prompt;
enum { MAXARGS = 16 };
typedef struct Num Num;
}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)
return *p;
}
+static void
+printhead(int n, int s, int sp, char *t)
+{
+ char *q;
+ int i, j, k;
+
+ for(i = 1; i < n; i *= 10)
+ ;
+ while(i /= 10, i != 0){
+ q = t;
+ *--q = 0;
+ for(j = 0, k = 0; j < n; j += s, k++){
+ if(k == sep && sep != 0){
+ *--q = ' ';
+ k = 0;
+ }
+ if(j >= i || j == 0 && i == 1)
+ *--q = '0' + j / i % 10;
+ else
+ *--q = ' ';
+ }
+ for(j = 0; j < sp; j++)
+ *--q = ' ';
+ print("%s\n", q);
+ }
+}
+
void
numprint(Num *n)
{
int b;
- int l, i;
+ int l, i, st, sp;
char *s, *t, *p, *q;
if(n == nil) return;
l = strlen(s);
t = emalloc(l * 2 + 4);
q = t + l * 2 + 4;
+ if(heads){
+ switch(b){
+ case 16: st = 4; sp = 2; break;
+ case 8: st = 3; sp = 1; break;
+ case 2: st = 1; sp = 2; break;
+ default: st = 0; sp = 0;
+ }
+ if(n->sign < 0)
+ sp++;
+ if(st != 0)
+ printhead(mpsignif(n), st, sp, q);
+ }
*--q = 0;
for(p = s + l - 1, i = 0; p >= s && *p != '-'; p--, i++){
if(sep != 0 && i == sep){
if(mpcmp(n, mpzero) != 0)
switch(b){
case 16: *--q = 'x'; *--q = '0'; break;
- case 10: if(outbase != 0 && outbase != 10) {*--q = 'd'; *--q = '0';} break;
+ case 10: if(outbase != 0 && outbase != 10 || inbase != 10) {*--q = 'd'; *--q = '0';} break;
case 8: *--q = '0'; break;
case 2: *--q = 'b'; *--q = '0'; break;
}
save = outbase;
if(!fail)
outbase = mptoi($3);
- if(outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
+ if(outbase != 0 && outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
error("no.");
outbase = save;
}
numdecref(last);
last = nil;
}
+ | '\'' { save = inbase; inbase = 10; } expr {
+ inbase = save;
+ save = heads;
+ if(!fail)
+ heads = mptoi($3);
+ if(heads != 0 && heads != 1){
+ error("no.");
+ heads = save;
+ }
+ numdecref($3);
+ numdecref(last);
+ last = nil;
+ }
| error
expr: LNUM
| '+' 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;
if(c == '\n') prompted = 0;
if(isdigit(c)){
for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
- if(p < buf + sizeof(buf) - 1)
+ if(p < buf + sizeof(buf) - 1 && c != '_')
*p++ = c;
*p = 0;
Bungetc(in);
return r;
}
+Num *
+fnpb(int, Num **a)
+{
+ Num *r;
+ int b;
+
+ if(toint(a[1], &b, 1)){
+ out:
+ numdecref(a[0]);
+ numdecref(a[1]);
+ return nil;
+ }
+ if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
+ error("unsupported base");
+ goto out;
+ }
+ r = nummod(a[0]);
+ if(b == 0)
+ r->b = 0;
+ else
+ r->b = STRONG | b;
+ return r;
+}
+
Num *
fnabs(int, Num **a)
{
}
a[0] = nummod(a[0]);
itomp(mpsignif(a[0]), a[0]);
- a[0]->b = 10;
+ a[0]->b = 0;
return a[0];
}
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 *
+fnnsa(int, Num **a)
+{
+ int n, i;
+ mpdigit d;
+ a[0] = nummod(a[0]);
+ if(a[0]->sign < 0){
+ numdecref(a[0]);
+ return error("invalid argument");
+ }
+ n = 0;
+ for(i = 0; i < a[0]->top; i++){
+ d = a[0]->p[i];
+ for(; d != 0; d &= d-1)
+ n++;
+ }
+ itomp(n, a[0]);
+ 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];
+}
+
+Num *
+fnrev(int, Num **a)
+{
+ mpdigit v, m;
+ int i, j, n;
+
+ if(toint(a[1], &n, 1)){
+ numdecref(a[0]);
+ numdecref(a[1]);
+ return nil;
+ }
+ a[0] = nummod(a[0]);
+ mptrunc(a[0], n, a[0]);
+ for(i = 0; i < a[0]->top; i++){
+ v = a[0]->p[i];
+ m = -1;
+ for(j = sizeof(mpdigit) * 8; j >>= 1; ){
+ m ^= m << j;
+ v = v >> j & m | v << j & ~m;
+ }
+ a[0]->p[i] = v;
+ }
+ for(i = 0; i < a[0]->top / 2; i++){
+ v = a[0]->p[i];
+ a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
+ a[0]->p[a[0]->top - 1 - i] = v;
+ }
+ mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
+ numdecref(a[1]);
+ return a[0];
+}
+
+Num *
+fncat(int n, Num **a)
+{
+ int i, w;
+ Num *r;
+
+ if(n % 2 != 0){
+ error("cat: odd number of arguments");
+ i = 0;
+ fail:
+ for(; i < n; i++)
+ numdecref(a[i]);
+ return nil;
+ }
+ r = numalloc();
+ for(i = 0; i < n; i += 2){
+ if(toint(a[i+1], &w, 1)) goto fail;
+ mpleft(r, w, r);
+ if(a[i]->sign < 0 || mpsignif(a[i]) > w){
+ a[i] = nummod(a[i]);
+ mptrunc(a[i], w, a[i]);
+ }
+ r->b = basemax(r->b, a[i]->b);
+ mpor(r, a[i], r);
+ numdecref(a[i]);
+ numdecref(a[i+1]);
+ }
+ return r;
+}
void
main(int argc, char **argv)
regfunc("dec", fndec, 1);
regfunc("oct", fnoct, 1);
regfunc("bin", fnbin, 1);
+ regfunc("pb", fnpb, 2);
regfunc("abs", fnabs, 1);
regfunc("round", fnround, 2);
regfunc("floor", fnfloor, 2);
regfunc("xtend", fnxtend, 2);
regfunc("ubits", fnubits, 1);
regfunc("sbits", fnsbits, 1);
+ regfunc("nsa", fnnsa, 1);
+ regfunc("gcd", fngcd, 2);
+ regfunc("minv", fnminv, 2);
+ regfunc("rand", fnrand, 1);
+ regfunc("rev", fnrev, 2);
+ regfunc("cat", fncat, -1);
prompt = 1;
ARGBEGIN{