initial natural log implementation

This commit is contained in:
Jeff Wang 2019-10-02 22:43:23 -04:00
parent acc9c4821f
commit ac1aaac096
3 changed files with 223 additions and 5 deletions

View File

@ -17,6 +17,7 @@
// #define DEBUG_MULT
// #define DEBUG_MULT_ALL //even more verbose
// #define DEBUG_DIV
#define DEBUG_LOG
#ifndef DESKTOP
//#undef EXTRA_CHECKS
@ -25,6 +26,7 @@
#undef DEBUG_ADD
#undef DEBUG_MULT
#undef DEBUG_DIV
#undef DEBUG_LOG
#endif
#ifdef DESKTOP
@ -834,14 +836,184 @@ void div_decn(void){
//Accum now holds 1/x, multiply by original acc to complete division
copy_decn(&BDecn, &ACC_COPY);
mult_decn();
//try not to pollute namespace
//try not to pollute namespace
#undef CURR_RECIP
#undef X_COPY
#undef ACC_COPY
}
static void set_str_error(){
void ln_decn(void){
#define NUM_A_ARR 9
static const dec80 LN_A_ARR[NUM_A_ARR] = {
{0, {69, 31, 47, 18, 5, 59, 94, 53, 9}},
{0, {95, 31, 1, 79, 80, 43, 24, 86, 0}},
{0, {99, 50, 33, 8, 53, 16, 80, 82, 84}},
{0, {99, 95, 0, 33, 30, 83, 53, 31, 67}},
{0, {99, 99, 50, 0, 33, 33, 8, 33, 33}},
{0, {99, 99, 95, 0, 0, 33, 33, 29, 95}},
{0, {99, 99, 99, 50, 0, 0, 33, 5, 35}},
{0, {99, 99, 99, 95, 0, 0, 2, 76, 40}},
{0, {99, 99, 99, 99, 50, 0, 15, 98, 65}},
// {0, {99, 99, 99, 99, 95, 2, 19, 27, 11}},
};
uint8_t j, k;
#define B_j Tmp2Decn
#define NUM_TIMES Tmp3Decn
#define A_ARR_j Tmp4Decn
//normalize
exp_t initial_exp;
remove_leading_zeros(&AccDecn);
//TODO: error for negative numbers
//scale to between 1 and 10
initial_exp = get_exponent(&AccDecn) + 1;
AccDecn.exponent = 0;
#ifdef DEBUG_LOG
decn_to_str_complete(&AccDecn);
printf("ln() accum scaled between 1,10: %s\n", Buf);
#endif
//get initial a_arr[0] = 2
set_dec80_zero(&A_ARR_j);
A_ARR_j.lsu[0] = 20;
//get initial estimate (accum = 10 - A)
copy_decn(&BDecn, &DECN_1);
BDecn.exponent = 1; //BDecn = 10
negate_decn(&AccDecn);
add_decn();
copy_decn(&B_j, &AccDecn); //b_j = accum = 10 - A
#ifdef DEBUG_LOG
decn_to_str_complete(&AccDecn);
printf("ln() initial accum: %s (%d)\n", Buf, initial_exp);
#endif
//track number of times multiplied by a_arr[j]
for (j = 0; j < NUM_A_ARR; j++){
uint8_t k_j;
if (j != 0){
//b_j *= 10.0 //TODO: necessary?
shift_left(&B_j);
}
copy_decn(&AccDecn, &B_j); //accum = b_j
k_j = 0;
while (!(AccDecn.exponent < 0)){ //while >= 0 (!negative) TODO: should just be >
copy_decn(&B_j, &AccDecn); //b_j = accum
//accum *= a_arr[i]
copy_decn(&BDecn, &A_ARR_j);
mult_decn();
//accum -= 10
copy_decn(&BDecn, &DECN_1);
BDecn.exponent = 1; //BDecn = 10
negate_decn(&BDecn);
add_decn();
#ifdef DEBUG_LOG
// decn_to_str_complete(&B_j);
// printf(" %u: %s\n", k_j, Buf);
#endif
k_j++;
}
//track num times
NUM_TIMES.lsu[j] = k_j - 1;
#ifdef DEBUG_LOG
decn_to_str_complete(&B_j);
printf(" %u: num_times: %u, %s\n", j, NUM_TIMES.lsu[j], Buf);
#endif
//find next a_j (1 + 10^-j)
if (j == 0) {
//build value 1.1
set_dec80_zero(&A_ARR_j);
A_ARR_j.lsu[0] = 11;
} else {
//get next 1.000...1 value
A_ARR_j.lsu[0] &= 1;
shift_right(&A_ARR_j);
A_ARR_j.lsu[0] = 10;
}
#ifdef DEBUG_LOG
decn_to_str_complete(&A_ARR_j);
printf(" new a_j val: %s\n", Buf);
#endif
}
//build final value
copy_decn(&AccDecn, &B_j); //remainder
#ifdef DEBUG_LOG
decn_to_str_complete(&AccDecn);
printf("ln() remainder: %s\n", Buf);
#endif
//TODO: scale remainder?
for (j = NUM_A_ARR - 1; j < NUM_A_ARR; j--){ //sum in reverse order, note: (j < NUM_A_ARR) == signed(j >= 0)
for (k = 0; k < NUM_TIMES.lsu[j]; k++){
//accum += ln_a_arr[j];
copy_decn(&BDecn, &LN_A_ARR[j]);
add_decn();
}
shift_right(&AccDecn);
#ifdef DEBUG_LOG
decn_to_str_complete(&AccDecn);
printf("%u: ln() remainder: %s\n", j, Buf);
#endif
}
#ifdef DEBUG_LOG
decn_to_str_complete(&AccDecn);
printf("ln() accum after summing: %s\n", Buf);
#endif
//accum = -accum;
negate_decn(&AccDecn);
//add back in initial exponent
copy_decn(&B_j, &AccDecn); //temporarily store accum in B_j
set_dec80_zero(&AccDecn);
//check if negative
if (initial_exp < 0){
j = 1; //track is_neg
initial_exp = -initial_exp;
} else {
j = 0;
}
//check if too big for single lsu
#ifdef EXP16
if (initial_exp >= 10000){
AccDecn.lsu[0] = initial_exp / 10000;
initial_exp = initial_exp % 10000;
AccDecn.lsu[1] = initial_exp / 100;
AccDecn.lsu[2] = initial_exp % 100;
AccDecn.exponent = 4;
} else
#endif
if (initial_exp >= 100){
AccDecn.lsu[0] = initial_exp / 100;
AccDecn.lsu[1] = initial_exp % 100;
AccDecn.exponent = 2;
} else {
AccDecn.lsu[0] = initial_exp;
AccDecn.exponent = 1;
}
//check if need to negate
if (j) { //was negative
negate_decn(&AccDecn);
}
#ifdef DEBUG_LOG
decn_to_str_complete(&AccDecn);
printf("ln() exponent from initial: %s\n", Buf);
#endif
//initial exp * ln(10)
copy_decn(&BDecn, &DECN_LN_10);
mult_decn();
//add back stored accum
copy_decn(&BDecn, &B_j);
add_decn();
//TODO: AccDecn.exponent += ;
//try not to pollute namespace
#undef B_j
#undef NUM_TIMES
#undef A_ARR_j
#undef NUM_A_ARR
}
static void set_str_error(void){
Buf[0] = 'E';
Buf[1] = 'r';
Buf[2] = 'r';

View File

@ -43,8 +43,12 @@ typedef struct {
//1 constant
static const dec80 DECN_1 = {
0,
{10, 0}
0, {10, 0}
};
//ln(10) constant
static const dec80 DECN_LN_10 = {
0, {23, 2, 58, 50, 92, 99, 40, 45, 68}
};
//remove sign bit, and return 15 bit exponent sign-extended to 16 bits
@ -64,6 +68,8 @@ void add_decn(void);
void mult_decn(void);
void div_decn(void);
void ln_decn(void);
//Buf should hold at least 18 + 4 + 5 + 1 = 28
#define DECN_BUF_SIZE 28
extern __xdata char Buf[DECN_BUF_SIZE];

View File

@ -46,6 +46,22 @@ static void div_test(
printf(" : %s\n\n", Buf);
}
static void log_test(
const char* x_str, int x_exp,
const char* res_str, int res_exp)
{
build_dec80(x_str, x_exp);
decn_to_str_complete(&AccDecn);
printf(" a : %s\n", Buf);
ln_decn();
decn_to_str_complete(&AccDecn);
printf("ln(a): %s\n", Buf);
build_decn_at(&diff, res_str, res_exp);
take_diff();
decn_to_str_complete(&diff);
printf(" : %s\n\n", Buf);
}
int main(void){
// dec80 acc, b;
@ -186,5 +202,29 @@ int main(void){
"0.666666666666666672", 0
);
//new acc for log test
log_test(
"0.155", 0,
"-1.86433016206289043", 0
);
//new acc for log test
log_test(
"10", 0,
"2.30258509299404568", 0
);
//new acc for log test
log_test(
"1.1", 10,
"23.1211611097447817", 0
);
//new acc for log test
log_test(
"2.02", -10,
"-22.3227534185273434", 0
);
return 0;
}