change exponent from int16_t to int8_t to free up some space
This commit is contained in:
parent
836d4fc122
commit
fcf16153f6
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user