add random logarithm tests, extra tests near log(1.0)

This commit is contained in:
Jeff Wang 2020-10-12 16:14:12 -04:00
parent 89f442cae8
commit 08f1d199c1
3 changed files with 136 additions and 33 deletions

View File

@ -196,7 +196,7 @@ static void shift_left(dec80* x){
}
}
static void remove_leading_zeros(dec80* x){
void remove_leading_zeros(dec80* x){
uint8_t digit100;
uint8_t is_negative = (x->exponent < 0);
exp_t exponent = get_exponent(x);

View File

@ -62,6 +62,8 @@ exp_t get_exponent(const dec80* const x);
void set_exponent(dec80* acc, exp_t exponent, uint8_t num_is_neg);
void remove_leading_zeros(dec80* x);
void copy_decn(dec80* const dest, const dec80* const src);

View File

@ -31,6 +31,8 @@
namespace bmp = boost::multiprecision;
using Catch::Matchers::Equals;
static const int NUM_RAND_TESTS = 1234567;
TEST_CASE("build decn"){
build_dec80("0.0009234567890123456", 7);
@ -345,7 +347,7 @@ TEST_CASE("division random"){
std::default_random_engine gen;
std::uniform_int_distribution<int> distrib(0, 99);
std::uniform_int_distribution<int> sign_distrib(0,1);
for (int j = 0; j < 12345; j++){
for (int j = 0; j < NUM_RAND_TESTS; j++){
AccDecn.lsu[0] = distrib(gen);
BDecn.lsu[0] = distrib(gen);
for (int i = 1; i < DEC80_NUM_LSU; i++){
@ -412,7 +414,7 @@ TEST_CASE("sqrt random"){
std::uniform_int_distribution<int> distribution(0,99);
std::uniform_int_distribution<int> exp_distrib(-99,99);
std::uniform_int_distribution<int> sign_distrib(0,1);
for (int j = 0; j < 12345; j++){
for (int j = 0; j < NUM_RAND_TESTS; j++){
for (int i = 0; i < DEC80_NUM_LSU; i++){
AccDecn.lsu[i] = distribution(generator);
}
@ -422,6 +424,94 @@ TEST_CASE("sqrt random"){
}
}
static void log_test_(bool base10, double epsilon){
bmp::mpfr_float::default_precision(50);
CAPTURE(base10);
decn_to_str_complete(&AccDecn);
CAPTURE(Buf);
//build mpfr float
bmp::mpfr_float x_actual(Buf);
//calculate result
if (base10){
log10_decn();
} else {
ln_decn();
}
decn_to_str_complete(&AccDecn);
CAPTURE(Buf); // log(x)
//calculate actual result
CAPTURE(x_actual);
if (decn_is_nan(&AccDecn)){
//check that NaN is from result of log(-)
CHECK(x_actual <= 0);
} else {
if (base10){
x_actual = log10(x_actual);
} else {
x_actual = log(x_actual);
}
bmp::mpfr_float calculated(Buf);
CAPTURE(calculated);
bmp::mpfr_float rel_diff = abs((x_actual - calculated) / x_actual);
CHECK(rel_diff < epsilon);
}
}
static void log_test(bool base10=false){
//check if near 1.0
remove_leading_zeros(&AccDecn);
double lsu0 = AccDecn.lsu[0];
int exp = get_exponent(&AccDecn);
if (exp == -1){
lsu0 /= (double) 10;
lsu0 += (double) AccDecn.lsu[1] / (10*100);
lsu0 += (double) AccDecn.lsu[2] / (10*100*100);
lsu0 += (double) AccDecn.lsu[3] / (10*100*100*100);
} else if (exp == 0){
lsu0 += (double) AccDecn.lsu[1] / 100;
lsu0 += (double) AccDecn.lsu[2] / (100*100);
lsu0 += (double) AccDecn.lsu[3] / (100*100*100);
}
CAPTURE((int) AccDecn.lsu[0]); CAPTURE((int) AccDecn.lsu[1]);
CAPTURE(exp);
CAPTURE(lsu0);
if (exp == 0 || exp == -1){
//check if near 1.0
if (lsu0 >= 7 && lsu0 < 8){
log_test_(base10, 7.5e-16);
} else if (lsu0 >= 8 && lsu0 < 9){
log_test_(base10, 1.5e-15);
} else if (lsu0 >= 9 && lsu0 < 9.6){
log_test_(base10, 1.0e-14);
} else if (lsu0 >= 9.6 && lsu0 < 9.9){
log_test_(base10, 4.1e-13);
} else if (lsu0 >= 9.9 && lsu0 < 9.999){
log_test_(base10, 1.5e-11);
} else if (lsu0 >= 9.999 && lsu0 < 9.99999){
log_test_(base10, 6.0e-10);
} else if (lsu0 >= 9.99999 && lsu0 < 9.9999999){
log_test_(base10, 3.0e-9);
} else if (lsu0 >= 9.9999999 && lsu0 < 10.0){
log_test_(base10, 1.3e-7);
} else if (lsu0 >= 10.0 && lsu0 < 10.00001){
log_test_(base10, 6.0e-10);
} else if (lsu0 >= 10.00001 && lsu0 < 10.001){
log_test_(base10, 6.0e-11);
} else if (lsu0 >= 10.001 && lsu0 < 10.1){
log_test_(base10, 1.5e-12);
} else if (lsu0 >= 10.1 && lsu0 < 11){
log_test_(base10, 1.6e-14);
} else if (lsu0 >= 11 && lsu0 < 13){
log_test_(base10, 2.0e-15);
} else {
log_test_(base10, 6.5e-16);
}
} else {
log_test_(base10, 2e-16);
}
}
static void log_test(
//input
const char* x_str, int x_exp,
@ -431,36 +521,7 @@ static void log_test(
CAPTURE(x_str); CAPTURE(x_exp);
CAPTURE(base10);
build_dec80(x_str, x_exp);
// decn_to_str_complete(&AccDecn);
// printf(" acc: %s\n", Buf);
if (base10){
log10_decn();
} else {
ln_decn();
}
decn_to_str_complete(&AccDecn);
CAPTURE(Buf); // log(x)
//calculate actual result
bmp::mpfr_float::default_precision(50);
std::string x_full_str(x_str);
x_full_str += "e" + std::to_string(x_exp);
CAPTURE(x_full_str);
bmp::mpfr_float x_actual(x_full_str);
CAPTURE(x_actual);
if (decn_is_nan(&AccDecn)){
//check that NaN is from result of log(-)
CHECK(x_actual <= 0);
} else {
if (base10){
x_actual = log10(x_actual);
} else {
x_actual = log(x_actual);
}
bmp::mpfr_float calculated(Buf);
bmp::mpfr_float rel_diff = abs((x_actual - calculated) / x_actual);
CHECK(rel_diff < 3e-16); //TODO
}
log_test(base10);
}
TEST_CASE("log"){
@ -476,6 +537,46 @@ TEST_CASE("log"){
log_test("123", 12345);
}
TEST_CASE("log random"){
std::default_random_engine gen;
std::uniform_int_distribution<int> distrib(0,99);
std::uniform_int_distribution<int> exp_distrib(-99,99);
std::uniform_int_distribution<int> sign_distrib(0,1);
for (int j = 0; j < NUM_RAND_TESTS; j++){
for (int i = 0; i < DEC80_NUM_LSU; i++){
AccDecn.lsu[i] = distrib(gen);
}
int exp = exp_distrib(gen);
set_exponent(&AccDecn, exp, 0);
int base10 = sign_distrib(gen);
log_test(base10);
}
}
static void log_test_near1(int lsu0_low, int lsu0_high, int exp){
std::default_random_engine gen;
std::uniform_int_distribution<int> lsu0_distrib(lsu0_low, lsu0_high);
std::uniform_int_distribution<int> distrib(0,99);
std::uniform_int_distribution<int> exp_distrib(-99,99);
std::uniform_int_distribution<int> sign_distrib(0,1);
for (int j = 0; j < NUM_RAND_TESTS; j++){
AccDecn.lsu[0] = lsu0_distrib(gen);
for (int i = 1; i < DEC80_NUM_LSU; i++){
AccDecn.lsu[i] = distrib(gen);
}
set_exponent(&AccDecn, exp, 0);
int base10 = sign_distrib(gen);
log_test(base10);
}
}
TEST_CASE("log random near 1"){
log_test_near1(0, 99, -1);
log_test_near1(80, 99, -1);
log_test_near1(10, 99, 0);
log_test_near1(10, 20, 0);
}
static void exp_test(
//input
const char* x_str, int x_exp,