change exponent from int16_t to int8_t to free up some space

This commit is contained in:
Jeff Wang 2019-04-05 02:17:10 -04:00
parent 836d4fc122
commit fcf16153f6
6 changed files with 61 additions and 44 deletions

View File

@ -138,12 +138,16 @@ The keys on the original calculator map as follows:
- The 3rd and subsequent presses negates the current exponent being entered. - The 3rd and subsequent presses negates the current exponent being entered.
- `mode`: reserved for a future shift key - `mode`: reserved for a future shift key
## Floating Point
The allowable range of exponents is +/-63. Trying to enter a number with a larger exponent will result in an error.
## Turning off ## Turning off
Hold `Shift` (the `mode` key on the physical calculator) and `0` at the same time to turn off. NOTE: There is no auto power off. Hold `Shift` (the `mode` key on the physical calculator) and `0` at the same time to turn off. NOTE: There is no auto power off.
# Bugs # Bugs
1. The calculator does not properly check for underflow or overflow. 1. The calculator does not properly check for underflow or overflow sometimes.
1. After division by 0, it's possible to negate `Error` to get an invalid number. 1. Calculations with numbers with exponents near the max/min of +/-63 may give improper results, especially for division where intermediate results may go out of range, even if the result is in range.
1. After division by 0 or over/underflow, it's possible to negate `Error` to get an invalid number. It's also possible to subtract `Error`.
1. There are probably more bugs waiting to be discovered. 1. There are probably more bugs waiting to be discovered.
# Internals # Internals

View File

@ -25,7 +25,7 @@ static void pop(){
StackPtr++; //adjust pointer StackPtr++; //adjust pointer
} }
void push_decn(const char* signif_str, int16_t exponent, uint8_t no_lift){ void push_decn(const char* signif_str, int8_t exponent, uint8_t no_lift){
if (!no_lift){ if (!no_lift){
StackPtr--; StackPtr--;
} }
@ -36,7 +36,7 @@ void clear_x(void){
set_dec80_zero(&stack(STACK_X)); set_dec80_zero(&stack(STACK_X));
} }
void set_x(const char* signif_str, int16_t exponent){ void set_x(const char* signif_str, int8_t exponent){
build_dec80(&stack(STACK_X), signif_str, exponent); build_dec80(&stack(STACK_X), signif_str, exponent);
} }

View File

@ -16,10 +16,10 @@ extern "C" {
void process_cmd(char cmd); void process_cmd(char cmd);
void push_decn(const char* signif_str, int16_t exponent, uint8_t no_lift); void push_decn(const char* signif_str, int8_t exponent, uint8_t no_lift);
void clear_x(void); void clear_x(void);
void set_x(const char* signif_str, int16_t exponent); void set_x(const char* signif_str, int8_t exponent);
__xdata dec80* get_x(void); __xdata dec80* get_x(void);
__xdata dec80* get_y(void); __xdata dec80* get_y(void);

View File

@ -53,20 +53,20 @@ void copy_decn(dec80* dest, const dec80* src){
} }
} }
int16_t get_exponent(const dec80* x){ int8_t get_exponent(const dec80* x){
int16_t exponent = x->exponent; int8_t exponent = x->exponent;
if (exponent & 0x4000){ //negative if (exponent & 0x40){ //negative
return exponent | 0x8000; return exponent | 0x80;
} else { //positive } else { //positive
return exponent & 0x7fff; return exponent & 0x7f;
} }
} }
void set_exponent(dec80* acc, int16_t exponent, uint8_t num_is_neg){ void set_exponent(dec80* acc, int8_t exponent, uint8_t num_is_neg){
if (num_is_neg){ if (num_is_neg){
exponent |= 0x8000; exponent |= 0x80;
} else { } else {
exponent &= 0x7fff; exponent &= 0x7f;
} }
acc->exponent = exponent; acc->exponent = exponent;
@ -103,7 +103,7 @@ static void shift_left(dec80* x){
static void remove_leading_zeros(dec80* x){ static void remove_leading_zeros(dec80* x){
uint8_t digit100; uint8_t digit100;
uint8_t is_negative = (x->exponent < 0); uint8_t is_negative = (x->exponent < 0);
int16_t exponent = get_exponent(x); int8_t exponent = get_exponent(x);
//find first non-zero digit100 //find first non-zero digit100
for (digit100 = 0; digit100 < DEC80_NUM_LSU; digit100++){ for (digit100 = 0; digit100 < DEC80_NUM_LSU; digit100++){
@ -133,7 +133,7 @@ static void remove_leading_zeros(dec80* x){
set_exponent(x, exponent, is_negative); set_exponent(x, exponent, is_negative);
} }
void build_dec80(dec80* dest, const char* signif_str, int16_t exponent){ void build_dec80(dec80* dest, const char* signif_str, int8_t exponent){
enum { enum {
SIGN_ZERO, SIGN_ZERO,
SIGN_ZERO_SEEN_POINT, SIGN_ZERO_SEEN_POINT,
@ -341,7 +341,7 @@ static uint8_t decn_is_zero(const dec80* x){
uint8_t decn_is_nan(const dec80* x){ uint8_t decn_is_nan(const dec80* x){
uint8_t i; uint8_t i;
if (x->exponent != DEC80_NAN_EXP){ if (x->exponent & 0x7f != DEC80_NAN_EXP){
return 0; return 0;
} }
for (i = 0; i < DEC80_NUM_LSU; i++){ for (i = 0; i < DEC80_NUM_LSU; i++){
@ -366,13 +366,13 @@ void set_dec80_NaN(dec80* dest){
#endif #endif
void negate_decn(dec80* x){ void negate_decn(dec80* x){
static const int16_t xor_val = -(0x7fff) - 1; static const int8_t xor_val = -(0x7f) - 1;
(x->exponent) ^= xor_val; (x->exponent) ^= xor_val;
} }
int8_t compare_magn(const dec80* a, const dec80* b){ //a<b: -1, a==b: 0, a>b: 1 int8_t compare_magn(const dec80* a, const dec80* b){ //a<b: -1, a==b: 0, a>b: 1
uint8_t a_i, b_i; uint8_t a_i, b_i;
int16_t a_exp=0, b_exp=0; int8_t a_exp=0, b_exp=0;
int8_t a_signif_b = 0; //a<b: -1, a==b: 0, a>b: 1 int8_t a_signif_b = 0; //a<b: -1, a==b: 0, a>b: 1
static __xdata dec80 a_tmp, b_tmp; static __xdata dec80 a_tmp, b_tmp;
//copy //copy
@ -460,8 +460,8 @@ int8_t compare_decn(const dec80* a, const dec80* b){ //a<b: -1, a==b: 0, a>b: 1
//acc and the number from which exponent was taken MUST be stripped of leading 0s first //acc and the number from which exponent was taken MUST be stripped of leading 0s first
//rescales acc up to exponent (increase exponent of acc, while shifting right) //rescales acc up to exponent (increase exponent of acc, while shifting right)
//the actual value of acc->exponent remains unchanged //the actual value of acc->exponent remains unchanged
static void _incr_exp(dec80* acc, int16_t exponent){ static void _incr_exp(dec80* acc, int8_t exponent){
int16_t curr_exp = get_exponent(acc); int8_t curr_exp = get_exponent(acc);
#ifdef DEBUG_ADD #ifdef DEBUG_ADD
uint8_t is_neg = (acc->exponent < 0); uint8_t is_neg = (acc->exponent < 0);
printf(" (is_neg,curr_exp,exponent)=(%d,%d,%d)\n", printf(" (is_neg,curr_exp,exponent)=(%d,%d,%d)\n",
@ -612,7 +612,7 @@ void add_decn(dec80* acc, const dec80* x){
} }
//may need to rescale number //may need to rescale number
if (carry > 0){ if (carry > 0){
int16_t curr_exp = get_exponent(acc); int8_t curr_exp = get_exponent(acc);
rel = (acc->exponent < 0); //is_neg? rel = (acc->exponent < 0); //is_neg?
#ifdef DEBUG_ADD #ifdef DEBUG_ADD
printf(" carry out: %d", carry); printf(" carry out: %d", carry);
@ -639,7 +639,7 @@ void mult_decn(dec80* acc, const dec80* x){
int8_t i, j; int8_t i, j;
uint8_t carry = 0; uint8_t carry = 0;
uint8_t is_neg; uint8_t is_neg;
int16_t new_exponent; int8_t new_exponent;
//initialize values //initialize values
copy_decn(&tmp, x); copy_decn(&tmp, x);
set_dec80_zero(&acc_tmp); set_dec80_zero(&acc_tmp);
@ -647,7 +647,7 @@ void mult_decn(dec80* acc, const dec80* x){
remove_leading_zeros(acc); remove_leading_zeros(acc);
remove_leading_zeros(&tmp); remove_leading_zeros(&tmp);
//store new sign //store new sign
if ((acc->exponent & 0x8000) ^ (tmp.exponent & 0x8000)){ //signs differ if ((acc->exponent & 0x80) ^ (tmp.exponent & 0x80)){ //signs differ
is_neg = 1; is_neg = 1;
} else { } else {
is_neg = 0; is_neg = 0;
@ -709,8 +709,13 @@ void mult_decn(dec80* acc, const dec80* x){
//add back carry to MSdigit in MSdigit100 //add back carry to MSdigit in MSdigit100
acc_tmp.lsu[0] += carry*10; acc_tmp.lsu[0] += carry*10;
} }
//set new exponent //set new exponent, checking for over/underflow
set_exponent(&acc_tmp, new_exponent, is_neg); if (new_exponent < DEC80_MAX_EXP && new_exponent > DEC80_MIN_EXP){
set_exponent(&acc_tmp, new_exponent, is_neg);
} else {
set_dec80_NaN(acc);
return;
}
//copy back to acc //copy back to acc
copy_decn(acc, &acc_tmp); copy_decn(acc, &acc_tmp);
//normalize //normalize
@ -721,7 +726,7 @@ void div_decn(dec80* acc, const dec80* x){
static __xdata dec80 tmp; //copy of x, holds current 1/x estimate static __xdata dec80 tmp; //copy of x, holds current 1/x estimate
static __xdata dec80 acc_copy; //holds copy of original acc static __xdata dec80 acc_copy; //holds copy of original acc
uint8_t i; uint8_t i;
int16_t initial_exp; int8_t initial_exp;
//check divide by zero //check divide by zero
#ifdef EXTRA_CHECKS #ifdef EXTRA_CHECKS
if (decn_is_zero(x)){ if (decn_is_zero(x)){
@ -781,24 +786,28 @@ void div_decn(dec80* acc, const dec80* x){
mult_decn(acc, &acc_copy); mult_decn(acc, &acc_copy);
} }
static void set_str_error(char* buf){
buf[0] = 'E';
buf[1] = 'r';
buf[2] = 'r';
buf[3] = 'o';
buf[4] = 'r';
buf[5] = '\0';
}
//buf should hold at least 18 + 4 + 5 + 1 = 28 //buf should hold at least 18 + 4 + 5 + 1 = 28
int8_t decn_to_str(char* buf, const dec80* x){ int8_t decn_to_str(char* buf, const dec80* x){
#define INSERT_DOT() buf[i++]='.' #define INSERT_DOT() buf[i++]='.'
uint8_t i = 0; uint8_t i = 0;
uint8_t digit100; uint8_t digit100;
int16_t exponent = 0; int8_t exponent = 0;
uint8_t trailing_zeros = 0; uint8_t trailing_zeros = 0;
uint8_t use_sci = 0; uint8_t use_sci = 0;
static __xdata dec80 tmp; static __xdata dec80 tmp;
//handle corner case of NaN //handle corner case of NaN
if (decn_is_nan(x)){ if (decn_is_nan(x)){
buf[0] = 'E'; set_str_error(buf);
buf[1] = 'r';
buf[2] = 'r';
buf[3] = 'o';
buf[4] = 'r';
buf[5] = '\0';
#ifdef DEBUG #ifdef DEBUG
printf (" corner case NaN "); printf (" corner case NaN ");
#endif #endif
@ -914,6 +923,10 @@ int8_t decn_to_str(char* buf, const dec80* x){
#endif #endif
//print exponent //print exponent
if (use_sci){ if (use_sci){
if (exponent > DEC80_MAX_EXP || exponent < DEC80_MIN_EXP){
set_str_error(buf);
return 0;
}
return exponent; return exponent;
} else { } else {
return 0; return 0;

View File

@ -16,15 +16,15 @@ extern "C" {
#define DEC80_NUM_LSU 9 #define DEC80_NUM_LSU 9
//allow full range, but reserve -16384 for special numbers //allow full range, but reserve -128 for special numbers
#define DEC80_MIN_EXP (-16383) #define DEC80_MIN_EXP (-63)
#define DEC80_MAX_EXP 16383 #define DEC80_MAX_EXP 63
#define DEC80_NAN_EXP (-16383 - 1) #define DEC80_NAN_EXP (-63 - 1) //-64
//decimal80 unpacked into 80 bits //decimal80 unpacked into 80 bits
// for computation // for computation
typedef struct { typedef struct {
int16_t exponent; //MSBit is sign of dec80 number, bottom 15 bits are 2's Compl exponent int8_t exponent; //MSBit is sign of dec80 number, bottom 15 bits are 2's Compl exponent
uint8_t lsu[DEC80_NUM_LSU]; //lsu[0] holds most-significant 2 digits (base 100) uint8_t lsu[DEC80_NUM_LSU]; //lsu[0] holds most-significant 2 digits (base 100)
//implicit decimal point between (lsu[0]/10) and (lsu[0]%10) //implicit decimal point between (lsu[0]/10) and (lsu[0]%10)
} dec80; } dec80;
@ -36,13 +36,13 @@ static const dec80 DECN_1 = {
}; };
//remove sign bit, and return 15 bit exponent sign-extended to 16 bits //remove sign bit, and return 15 bit exponent sign-extended to 16 bits
int16_t get_exponent(const dec80* x); int8_t get_exponent(const dec80* x);
//void dec64to80(dec80* dest, const dec64* src); //void dec64to80(dec80* dest, const dec64* src);
void copy_decn(dec80* dest, const dec80* src); void copy_decn(dec80* dest, const dec80* src);
void build_dec80(dec80* dest, const char* signif_str, int16_t exponent); void build_dec80(dec80* dest, const char* signif_str, int8_t exponent);
void set_dec80_zero(dec80* dest); void set_dec80_zero(dec80* dest);
void set_dec80_NaN(dec80* dest); void set_dec80_NaN(dec80* dest);

View File

@ -80,7 +80,7 @@ int main(void){
printf(" : %s\n\n", Buf); printf(" : %s\n\n", Buf);
//new acc and b for divide test //new acc and b for divide test
build_dec80(&acc, "3.14", 88); build_dec80(&acc, "3.14", 60);
build_dec80(&b, "-1.5", -2); build_dec80(&b, "-1.5", -2);
decn_to_str_complete(Buf, &acc); decn_to_str_complete(Buf, &acc);
printf(" acc: %s\n", Buf); printf(" acc: %s\n", Buf);
@ -89,8 +89,8 @@ int main(void){
div_decn(&acc, &b); div_decn(&acc, &b);
decn_to_str_complete(Buf, &acc); decn_to_str_complete(Buf, &acc);
printf("acc/b: %s\n", Buf); printf("acc/b: %s\n", Buf);
printf(" : %s\n", "-2.09333333333333334E90"); printf(" : %s\n", "-2.09333333333333334E62");
build_dec80(&diff, "-2.09333333333333334", 90); build_dec80(&diff, "-2.09333333333333334", 62);
negate_decn(&diff); negate_decn(&diff);
add_decn(&diff, &acc); add_decn(&diff, &acc);
decn_to_str_complete(Buf, &diff); decn_to_str_complete(Buf, &diff);