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.
- `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
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
1. The calculator does not properly check for underflow or overflow.
1. After division by 0, it's possible to negate `Error` to get an invalid number.
1. The calculator does not properly check for underflow or overflow sometimes.
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.
# Internals

View File

@ -25,7 +25,7 @@ static void pop(){
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){
StackPtr--;
}
@ -36,7 +36,7 @@ void clear_x(void){
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);
}

View File

@ -16,10 +16,10 @@ extern "C" {
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 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_y(void);

View File

@ -53,20 +53,20 @@ void copy_decn(dec80* dest, const dec80* src){
}
}
int16_t get_exponent(const dec80* x){
int16_t exponent = x->exponent;
if (exponent & 0x4000){ //negative
return exponent | 0x8000;
int8_t get_exponent(const dec80* x){
int8_t exponent = x->exponent;
if (exponent & 0x40){ //negative
return exponent | 0x80;
} 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){
exponent |= 0x8000;
exponent |= 0x80;
} else {
exponent &= 0x7fff;
exponent &= 0x7f;
}
acc->exponent = exponent;
@ -103,7 +103,7 @@ static void shift_left(dec80* x){
static void remove_leading_zeros(dec80* x){
uint8_t digit100;
uint8_t is_negative = (x->exponent < 0);
int16_t exponent = get_exponent(x);
int8_t exponent = get_exponent(x);
//find first non-zero 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);
}
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 {
SIGN_ZERO,
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 i;
if (x->exponent != DEC80_NAN_EXP){
if (x->exponent & 0x7f != DEC80_NAN_EXP){
return 0;
}
for (i = 0; i < DEC80_NUM_LSU; i++){
@ -366,13 +366,13 @@ void set_dec80_NaN(dec80* dest){
#endif
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;
}
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;
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
static __xdata dec80 a_tmp, b_tmp;
//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
//rescales acc up to exponent (increase exponent of acc, while shifting right)
//the actual value of acc->exponent remains unchanged
static void _incr_exp(dec80* acc, int16_t exponent){
int16_t curr_exp = get_exponent(acc);
static void _incr_exp(dec80* acc, int8_t exponent){
int8_t curr_exp = get_exponent(acc);
#ifdef DEBUG_ADD
uint8_t is_neg = (acc->exponent < 0);
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
if (carry > 0){
int16_t curr_exp = get_exponent(acc);
int8_t curr_exp = get_exponent(acc);
rel = (acc->exponent < 0); //is_neg?
#ifdef DEBUG_ADD
printf(" carry out: %d", carry);
@ -639,7 +639,7 @@ void mult_decn(dec80* acc, const dec80* x){
int8_t i, j;
uint8_t carry = 0;
uint8_t is_neg;
int16_t new_exponent;
int8_t new_exponent;
//initialize values
copy_decn(&tmp, x);
set_dec80_zero(&acc_tmp);
@ -647,7 +647,7 @@ void mult_decn(dec80* acc, const dec80* x){
remove_leading_zeros(acc);
remove_leading_zeros(&tmp);
//store new sign
if ((acc->exponent & 0x8000) ^ (tmp.exponent & 0x8000)){ //signs differ
if ((acc->exponent & 0x80) ^ (tmp.exponent & 0x80)){ //signs differ
is_neg = 1;
} else {
is_neg = 0;
@ -709,8 +709,13 @@ void mult_decn(dec80* acc, const dec80* x){
//add back carry to MSdigit in MSdigit100
acc_tmp.lsu[0] += carry*10;
}
//set new exponent
set_exponent(&acc_tmp, new_exponent, is_neg);
//set new exponent, checking for over/underflow
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_decn(acc, &acc_tmp);
//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 acc_copy; //holds copy of original acc
uint8_t i;
int16_t initial_exp;
int8_t initial_exp;
//check divide by zero
#ifdef EXTRA_CHECKS
if (decn_is_zero(x)){
@ -781,24 +786,28 @@ void div_decn(dec80* acc, const dec80* x){
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
int8_t decn_to_str(char* buf, const dec80* x){
#define INSERT_DOT() buf[i++]='.'
uint8_t i = 0;
uint8_t digit100;
int16_t exponent = 0;
int8_t exponent = 0;
uint8_t trailing_zeros = 0;
uint8_t use_sci = 0;
static __xdata dec80 tmp;
//handle corner case of NaN
if (decn_is_nan(x)){
buf[0] = 'E';
buf[1] = 'r';
buf[2] = 'r';
buf[3] = 'o';
buf[4] = 'r';
buf[5] = '\0';
set_str_error(buf);
#ifdef DEBUG
printf (" corner case NaN ");
#endif
@ -914,6 +923,10 @@ int8_t decn_to_str(char* buf, const dec80* x){
#endif
//print exponent
if (use_sci){
if (exponent > DEC80_MAX_EXP || exponent < DEC80_MIN_EXP){
set_str_error(buf);
return 0;
}
return exponent;
} else {
return 0;

View File

@ -16,15 +16,15 @@ extern "C" {
#define DEC80_NUM_LSU 9
//allow full range, but reserve -16384 for special numbers
#define DEC80_MIN_EXP (-16383)
#define DEC80_MAX_EXP 16383
#define DEC80_NAN_EXP (-16383 - 1)
//allow full range, but reserve -128 for special numbers
#define DEC80_MIN_EXP (-63)
#define DEC80_MAX_EXP 63
#define DEC80_NAN_EXP (-63 - 1) //-64
//decimal80 unpacked into 80 bits
// for computation
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)
//implicit decimal point between (lsu[0]/10) and (lsu[0]%10)
} dec80;
@ -36,13 +36,13 @@ static const dec80 DECN_1 = {
};
//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 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_NaN(dec80* dest);

View File

@ -80,7 +80,7 @@ int main(void){
printf(" : %s\n\n", Buf);
//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);
decn_to_str_complete(Buf, &acc);
printf(" acc: %s\n", Buf);
@ -89,8 +89,8 @@ int main(void){
div_decn(&acc, &b);
decn_to_str_complete(Buf, &acc);
printf("acc/b: %s\n", Buf);
printf(" : %s\n", "-2.09333333333333334E90");
build_dec80(&diff, "-2.09333333333333334", 90);
printf(" : %s\n", "-2.09333333333333334E62");
build_dec80(&diff, "-2.09333333333333334", 62);
negate_decn(&diff);
add_decn(&diff, &acc);
decn_to_str_complete(Buf, &diff);