diff options
author | Tim Hentenaar <tim@hentenaar.com> | 2014-03-22 02:47:33 +0100 |
---|---|---|
committer | Tim Hentenaar <tim@hentenaar.com> | 2019-02-18 03:48:17 +0100 |
commit | c4f1bdb16b560d813e6ded83c2d7a4f4d280a90a (patch) | |
tree | 4c66bd8d991bb57ddc7c0ea94dc51248dcdc4efe /math.c | |
parent | be5114cebfdc29788cf038d349c0ed6cce4bb536 (diff) |
Add bitwise ops and base conversion (DEC/OCT/HEX) in TI mode
These operations implicitly truncate their parameters, and result to
integers:
* not
* and
* or
* xor
* shl
* shr
* mod
* trunc
Base 2 was left out of the base conversion code intentionally as it
would require making the UI at least one third wider.
Attempts to change base with negative values will simply display
"error." Note that with larger numbers, the result may be inaccurate
due to rounding.
I've also bound the Return key to the equal() action.
Signed-off-by: Tim Hentenaar <tim@hentenaar.com>
Diffstat (limited to 'math.c')
-rw-r--r-- | math.c | 185 |
1 files changed, 149 insertions, 36 deletions
@@ -43,7 +43,7 @@ jmp_buf env; * functions. Much of it is shared between the infix and rpn modes. */ -static int flagINV, flagPAREN, flagM, drgmode; /* display flags */ +static int flagINV, flagPAREN, flagM, drgmode, numbase; /* display flags */ static double drg2rad=M_PI/180.0; /* Conversion factors for trig funcs */ static double rad2drg=180.0/M_PI; @@ -94,17 +94,47 @@ strlcpy(char *dst, const char *src, size_t size) * is non-zero then an error has occurred. On some systems (e.g. Ultrix), * sscanf will call lower level routines that will set errno. */ - static void -parse_double (const char *src, const char *fmt, double *dp) +parse_double(double *dp) { + unsigned long n = 0; int olderrno = errno; - (void) sscanf (src, fmt, dp); + switch (numbase) { + case 8: + (void)sscanf(dispstr, "%lo", &n); + *dp = (double)n; + break; + case 16: + (void)sscanf(dispstr, "%lX", &n); + *dp = (double)n; + break; + default: + (void)sscanf(dispstr, "%lf", dp); + } + errno = olderrno; return; } +/** + * Format the given double according to the + * selected number base. + */ +static void +format_double(double n) +{ + switch (numbase) { + case 8: + snprintf(dispstr, sizeof(dispstr), "%lo", (long)n); + break; + case 16: + snprintf(dispstr, sizeof(dispstr), "%lX", (long)n); + break; + default: + snprintf(dispstr, sizeof(dispstr), "%.8g", n); + } +} /*********************************/ int pre_op(int keynum) @@ -181,12 +211,13 @@ void post_op(void) } #endif } + /*-------------------------------------------------------------------------*/ static void DrawDisplay(void) { - if (strlen(dispstr) > 12) { /* strip out some decimal digits */ - char *estr = strchr(dispstr,'e'); /* search for exponent part */ + if (strlen(dispstr) >= MAXDISP) { /* strip out some decimal digits */ + char *estr = index(dispstr,'e'); /* search for exponent part */ if (!estr) dispstr[12]='\0'; /* no exp, just trunc. */ else { char tmp[32]; @@ -204,6 +235,28 @@ DrawDisplay(void) setflag(XCalc_RADIAN, (drgmode==RAD)); setflag(XCalc_GRADAM, (drgmode==GRAD)); setflag(XCalc_PAREN, (flagPAREN)); + setflag(XCalc_HEX, (numbase==16)); + setflag(XCalc_DEC, (numbase==10)); + setflag(XCalc_OCT, (numbase==8)); +} + +/*-------------------------------------------------------------------------*/ +void +change_base(void) +{ + parse_double(&dnum); + + if (dnum >= 0) { + switch (numbase) { + case 8: numbase = 10; break; + case 10: numbase = 16; break; + case 16: numbase = 8; break; + } + + format_double(dnum); + } else strlcpy(dispstr, "error", sizeof(dispstr)); + + DrawDisplay(); } /*-------------------------------------------------------------------------*/ @@ -239,7 +292,7 @@ numeric(int keynum) case kRCL: PushNum(dnum); dnum = mem[cell]; - snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); + format_double(dnum); lift_enabled = 1; entered = 1; clrdisp++; @@ -268,7 +321,9 @@ numeric(int keynum) if ((int) strlen(dispstr) >= MAXDISP) return; + st[0] = '\0'; switch (keynum){ + case kZERO: st[0] = '0'; break; case kONE: st[0] = '1'; break; case kTWO: st[0] = '2'; break; case kTHREE: st[0] = '3'; break; @@ -276,12 +331,20 @@ numeric(int keynum) case kFIVE: st[0] = '5'; break; case kSIX: st[0] = '6'; break; case kSEVEN: st[0] = '7'; break; - case kEIGHT: st[0] = '8'; break; - case kNINE: st[0] = '9'; break; - case kZERO: st[0] = '0'; break; - } - st[1] = '\0'; - strcat(dispstr,st); + case kEIGHT: if (numbase > 8) st[0] = '8'; break; + case kNINE: if (numbase > 8) st[0] = '9'; break; + case kxA: if (numbase > 10) st[0] = 'A'; break; + case kxB: if (numbase > 10) st[0] = 'B'; break; + case kxC: if (numbase > 10) st[0] = 'C'; break; + case kxD: if (numbase > 10) st[0] = 'D'; break; + case kxE: if (numbase > 10) st[0] = 'E'; break; + case kxF: if (numbase > 10) st[0] = 'F'; break; + } + + if (st[0] == '\0') + return; + st[1] = '\0'; + strcat(dispstr,st); DrawDisplay(); if (clrdisp && keynum != kZERO) @@ -433,7 +496,7 @@ twoop(int keynum) } if (entered==1) - parse_double(dispstr,"%lf",&dnum); + parse_double(&dnum); clrdisp=CLR=1; entered=Dpoint=exponent=0; @@ -451,7 +514,7 @@ twoop(int keynum) /* now, if the current op (keynum) is of higher priority than the lastop, the current op and number are just pushed on top - Priorities: (Y^X) > *,/ > +,- */ + Priorities: (Y^X) > *,/ > +,- > >>,<< > & > ^ > ~ */ if (priority(keynum) > priority(lastop)) { PushNum(dnum); @@ -466,10 +529,17 @@ twoop(int keynum) case kMUL: acc *= dnum; break; case kDIV: acc /= dnum; break; case kPOW: acc = pow(acc,dnum); break; - } + case kMOD: acc = (long)acc % (long)dnum; break; + case kAND: acc = (long)acc & (long)dnum; break; + case kOR: acc = (long)acc | (long)dnum; break; + case kXOR: acc = (long)acc ^ (long)dnum; break; + case kSHL: acc = (long)acc << (long)dnum; break; + case kSHR: acc = (long)acc >> (long)dnum; break; + } + PushNum(acc); PushOp(keynum); - snprintf(dispstr, sizeof(dispstr), "%.8g", acc); + format_double(acc); DrawDisplay(); dnum=acc; } @@ -491,7 +561,7 @@ twof(int keynum) if (!entered) return; if (entered==1) - parse_double(dispstr, "%lf", &dnum); + parse_double(&dnum); acc = PopNum(); switch(keynum) { case kADD: acc += dnum; break; @@ -499,9 +569,16 @@ twof(int keynum) case kMUL: acc *= dnum; break; case kDIV: acc /= dnum; break; case kPOW: acc = pow(acc,dnum); break; - case kXXY: PushNum(dnum); + case kXXY: PushNum(dnum); break; + case kMOD: acc = (long)acc % (long)dnum; break; + case kAND: acc = (long)acc & (long)dnum; break; + case kOR: acc = (long)acc | (long)dnum; break; + case kXOR: acc = (long)acc ^ (long)dnum; break; + case kSHL: acc = (long)acc << (long)dnum; break; + case kSHR: acc = (long)acc >> (long)dnum; break; } - snprintf(dispstr, sizeof(dispstr), "%.8g", acc); + + format_double(acc); DrawDisplay(); clrdisp++; Dpoint = exponent = 0; @@ -521,7 +598,7 @@ entrf(void) Dpoint=exponent=0; if (entered==1) - parse_double(dispstr,"%lf",&dnum); + parse_double(&dnum); entered=2; memop = kENTR; PushNum(dnum); @@ -539,7 +616,7 @@ equf(void) Dpoint=exponent=0; if (entered==1) - parse_double(dispstr,"%lf",&dnum); + parse_double(&dnum); entered=2; PushNum(dnum); @@ -562,12 +639,24 @@ equf(void) case kLPAR: flagPAREN--; PushNum(acc); break; + case kMOD: acc = (long)acc % (long)dnum; + break; + case kAND: acc = (long)acc & (long)dnum; + break; + case kOR: acc = (long)acc | (long)dnum; + break; + case kXOR: acc = (long)acc ^ (long)dnum; + break; + case kSHL: acc = (long)acc << (long)dnum; + break; + case kSHR: acc = (long)acc >> (long)dnum; + break; } dnum=acc; PushNum(dnum); } - snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); + format_double(dnum); DrawDisplay(); } @@ -586,13 +675,13 @@ rollf(void) if (!entered) return; if (entered==1) - parse_double(dispstr, "%lf", &dnum); + parse_double(&dnum); entered = 2; lift_enabled = 1; RollNum(flagINV); flagINV=0; clrdisp++; - snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); + format_double(dnum); DrawDisplay(); } @@ -610,7 +699,7 @@ rparf(void) Dpoint=exponent=0; if (entered==1) - parse_double(dispstr,"%lf",&dnum); + parse_double(&dnum); entered=2; PushNum(dnum); @@ -629,6 +718,18 @@ rparf(void) break; case kPOW: acc = pow(acc,dnum); break; + case kMOD: acc = (long)acc % (long)dnum; + break; + case kAND: acc = (long)acc & (long)dnum; + break; + case kOR: acc = (long)acc | (long)dnum; + break; + case kXOR: acc = (long)acc ^ (long)dnum; + break; + case kSHL: acc = (long)acc << (long)dnum; + break; + case kSHR: acc = (long)acc >> (long)dnum; + break; } dnum=acc; PushNum(dnum); @@ -636,7 +737,7 @@ rparf(void) (void) PopNum(); flagPAREN--; entered=2; - snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); + format_double(dnum); DrawDisplay(); } @@ -645,7 +746,7 @@ drgf(void) { if (flagINV) { if (entered==1) - parse_double(dispstr,"%lf",&dnum); + parse_double(&dnum); switch (drgmode) { case DEG: dnum=dnum*M_PI/180.0; break; case RAD: dnum=dnum*200.0/M_PI; break; @@ -654,7 +755,7 @@ drgf(void) entered=2; clrdisp=1; flagINV=0; - snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); + format_double(dnum); } flagINV=0; @@ -685,7 +786,7 @@ memf(int keynum) { memop = keynum; if (entered==1) - parse_double(dispstr,"%lf",&dnum); + parse_double(&dnum); entered = 2; clrdisp++; lift_enabled = 0; @@ -698,7 +799,7 @@ oneop(int keynum) double dtmp; if (entered==1) - parse_double(dispstr,"%lf",&dnum); + parse_double(&dnum); entered = 2; switch (keynum) { /* do the actual math fn. */ @@ -741,6 +842,8 @@ oneop(int keynum) for (j=1,dnum=1.0; j<=i; j++) dnum*=(float) j; break; + case kNOT: dnum = ~(long)dnum; break; + case kTRUNC: dnum = trunc(dnum); break; } if (entered==3) { /* error */ @@ -753,7 +856,7 @@ oneop(int keynum) clrdisp=1; flagINV=0; lift_enabled = 1; - snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); + format_double(dnum); DrawDisplay(); } @@ -899,12 +1002,18 @@ priority(int op) /*******/ { switch (op) { - case kPOW: return(2); + case kPOW: return(6); case kMUL: - case kDIV: return(1); + case kDIV: + case kMOD: return(5); case kADD: - case kSUB: return(0); - } + case kSUB: return(4); + case kSHL: + case kSHR: return(3); + case kAND: return(2); + case kXOR: return(1); + case kOR: return(0); + } return 0; } @@ -915,12 +1024,16 @@ ResetCalc(void) /********/ { flagM=flagINV=flagPAREN=0; drgmode=DEG; + numbase=(!numbase ? 10 : numbase); setflag(XCalc_MEMORY, False); setflag(XCalc_INVERSE, False); setflag(XCalc_PAREN, False); setflag(XCalc_RADIAN, False); setflag(XCalc_GRADAM, False); setflag(XCalc_DEGREE, True); + setflag(XCalc_HEX, False); + setflag(XCalc_DEC, True); + setflag(XCalc_OCT, False); strlcpy(dispstr, "0", sizeof(dispstr)); draw(dispstr); ClearStacks(); |