various bugfixes for decn arithmetic

This commit is contained in:
Jeff Wang 2019-03-31 19:31:22 -04:00
parent 43edb291cf
commit 4ed3d1654e
2 changed files with 120 additions and 13 deletions

View File

@ -191,6 +191,11 @@ void build_dec80(dec80* dest, const char* signif_str, int16_t exponent){
}
}
nibble_i++;
//track number of digits R of decimal point
//must do this before changing is_zero
if (curr_sign == SIGN_ZERO_SEEN_POINT || curr_sign == SIGN_NEG_ZERO_SEEN_POINT){
num_lr_points = -1;
}
//track sign
if (curr_sign == SIGN_ZERO){
curr_sign = SIGN_POS;
@ -201,7 +206,7 @@ void build_dec80(dec80* dest, const char* signif_str, int16_t exponent){
} else if (curr_sign == SIGN_NEG_ZERO_SEEN_POINT){
curr_sign = SIGN_NEG_SEEN_POINT;
}
//track number digits L/R of decimal point
//track number digits L of decimal point
if (!SEEN_POINT(curr_sign)){ //haven't seen decimal point yet
num_lr_points++; //increase left count
}
@ -220,7 +225,9 @@ void build_dec80(dec80* dest, const char* signif_str, int16_t exponent){
//track number digits L/R of decimal point
if (SEEN_POINT(curr_sign)){
if (IS_ZERO(curr_sign)){ //tracking 0s to right of point
if (num_lr_points <= 0){ //no left count exists
if (num_lr_points == 0){ //no left count exists
num_lr_points = -2;
} else if (num_lr_points < 0){ //continue tracking count
num_lr_points--; //increase right count
}
}
@ -262,10 +269,9 @@ void build_dec80(dec80* dest, const char* signif_str, int16_t exponent){
}
#endif
} else if (num_lr_points < 0) { //right count exists
// (-num_past_point represents #0s right of decimal)
// (num_lr_points represents exponent shift)
// (this ends up being a subtraction)
new_exponent = exponent + num_lr_points;
new_exponent -= 1; //decimal point after 1st non-zero number
//check for underflow
#ifdef EXTRA_CHECKS
if (new_exponent > exponent || exponent < DEC80_MIN_EXP){
@ -284,6 +290,8 @@ void build_dec80(dec80* dest, const char* signif_str, int16_t exponent){
exponent = new_exponent;
//set negative bit
set_exponent(dest, exponent, IS_NEG(curr_sign));
//normalize
remove_leading_zeros(dest);
#ifdef DEBUG
printf(" num_lr_points (%d), new_exp (%d), sign (%d), exp (%d)\n",
num_lr_points, new_exponent, curr_sign, exponent);
@ -673,7 +681,7 @@ void mult_decn(dec80* acc, const dec80* x){
}
}
//handle last carry
if (carry > 10){
if (carry >= 10){
//shift
shift_right(&acc_tmp);
shift_right(&acc_tmp);
@ -698,6 +706,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;
//check divide by zero
#ifdef EXTRA_CHECKS
if (decn_is_zero(x)){
@ -708,14 +717,27 @@ void div_decn(dec80* acc, const dec80* x){
//store copy of acc for final multiply by 1/x
copy_decn(&acc_copy, acc);
//get initial estimate for 1/x, by negating exponent, and setting signif. to 1
set_exponent(&tmp, -get_exponent(x), (x->exponent < 0));
initial_exp = get_exponent(x);
#ifdef DEBUG_DIV
printf("exponent %d", initial_exp);
#endif
if (initial_exp >= 0){
//necessary to subtract 1 for convergence
initial_exp = -initial_exp - 1;
} else {
initial_exp = -initial_exp;
}
#ifdef DEBUG_DIV
printf(" -> %d\n", initial_exp);
#endif
set_exponent(&tmp, initial_exp, (x->exponent < 0)); //set exponent, copy sign
tmp.lsu[0] = 10; //1 with implicit point
for (i = 1; i < DEC80_NUM_LSU; i++){
tmp.lsu[i] = 0;
}
copy_decn(acc, &tmp);
//do newton raphson iterations
for (i = 0; i < 20; i++){ //just fix number of iterations for now
for (i = 0; i < DEC80_NUM_LSU + 4; i++){ //just fix number of iterations for now
#ifdef DEBUG_DIV
extern char Buf[80];
dec80_to_str(Buf, &tmp);
@ -806,7 +828,8 @@ void dec80_to_str(char* buf, const dec80* x){
}
//print 2nd digit
buf[i] = (tmp.lsu[0] % 10) + '0';
if (tmp.lsu[0] % 10 == 0){
if (tmp.lsu[0] % 10 == 0 && (use_sci || exponent < 0)){
trailing_zeros = 1;
}
i++;
@ -843,9 +866,11 @@ void dec80_to_str(char* buf, const dec80* x){
}
}
//track trailing 0s
if (tmp.lsu[digit100] == 0){
if (tmp.lsu[digit100] == 0 && (use_sci || exponent < -1)){
trailing_zeros += 2;
} else if (tmp.lsu[digit100] == 10){
} else if (tmp.lsu[digit100] == 0 && (use_sci || exponent < 0)){
trailing_zeros += 1;
} else if (tmp.lsu[digit100] == 10 && (use_sci || exponent < 0)){
trailing_zeros = 1;
} else {
trailing_zeros = 0;

View File

@ -34,14 +34,14 @@ int main(void){
//compare result of b - acc
add_decn(&acc, &b);
dec80_to_str(Buf, &acc);
printf("\nb - a: %s", Buf);
printf("\n : %s", "-10158.0246791358016");
printf("b - a: %s\n", Buf);
printf(" : %s\n", "-10158.0246791358016");
dec80 diff;
build_dec80(&diff, "-1.01580246791358016", 4);
negate_decn(&diff);
add_decn(&diff, &acc);
dec80_to_str(Buf, &diff);
printf("\n : %s\n\n", Buf);
printf(" : %s\n\n", Buf);
//new acc for acc - b test
dec80_to_str(Buf, &acc);
@ -96,6 +96,88 @@ int main(void){
dec80_to_str(Buf, &diff);
printf(" : %s\n\n", Buf);
//new acc and b for divide test
build_dec80(&acc, "4", 0);
build_dec80(&b, "4", 0);
dec80_to_str(Buf, &acc);
printf(" acc: %s\n", Buf);
dec80_to_str(Buf, &b);
printf(" b: %s\n", Buf);
div_decn(&acc, &b);
dec80_to_str(Buf, &acc);
printf("acc/b: %s\n", Buf);
printf(" : %s\n", "1.00000000");
build_dec80(&diff, "1", 0);
negate_decn(&diff);
add_decn(&diff, &acc);
dec80_to_str(Buf, &diff);
printf(" : %s\n\n", Buf);
//new acc and b for divide test
build_dec80(&acc, "1", 0);
build_dec80(&b, "3", 0);
dec80_to_str(Buf, &acc);
printf(" acc: %s\n", Buf);
dec80_to_str(Buf, &b);
printf(" b: %s\n", Buf);
div_decn(&acc, &b);
dec80_to_str(Buf, &acc);
printf("acc/b: %s\n", Buf);
printf(" : %s\n", "0.333333333333333336");
build_dec80(&diff, "3.33333333333333336", -1);
dec80_to_str(Buf, &diff);
printf(" : %s\n", Buf);
negate_decn(&diff);
add_decn(&diff, &acc);
dec80_to_str(Buf, &diff);
printf(" : %s\n\n", Buf);
//small fractions >= 1/10
build_dec80(&acc, "0.333", 0);
build_dec80(&b, "3.33", -1);
dec80_to_str(Buf, &acc);
printf(" a : %s\n", Buf);
dec80_to_str(Buf, &b);
printf(" b : %s\n", Buf);
negate_decn(&b);
add_decn(&acc, &b);
dec80_to_str(Buf, &acc);
printf("a - b: %s\n", Buf);
//new acc and b for divide test
build_dec80(&acc, "500", 0);
build_dec80(&b, "99", 0);
dec80_to_str(Buf, &acc);
printf(" acc: %s\n", Buf);
dec80_to_str(Buf, &b);
printf(" b: %s\n", Buf);
div_decn(&acc, &b);
dec80_to_str(Buf, &acc);
printf("acc/b: %s\n", Buf);
printf(" : %s\n", "5.05050505050505055");
build_dec80(&diff, "5.05050505050505055", 0);
negate_decn(&diff);
add_decn(&diff, &acc);
dec80_to_str(Buf, &diff);
printf(" : %s\n\n", Buf);
//new acc and b for divide test
build_dec80(&acc, "500", 0);
build_dec80(&b, "2", 0);
dec80_to_str(Buf, &acc);
printf(" acc: %s\n", Buf);
dec80_to_str(Buf, &b);
printf(" b: %s\n", Buf);
div_decn(&acc, &b);
dec80_to_str(Buf, &acc);
printf("acc/b: %s\n", Buf);
printf(" : %s\n", "250.0");
build_dec80(&diff, "250", 0);
negate_decn(&diff);
add_decn(&diff, &acc);
dec80_to_str(Buf, &diff);
printf(" : %s\n\n", Buf);
return 0;
}