int main(int argc, char** argv) { printf("libfixmath test tool\n"); hiclock_init(); uintptr_t args = (1 << 8); uintptr_t iter = (1 << 8); uintptr_t pass = (1 << 8); uintptr_t i; srand(time(NULL)); hiclock_t fix_duration = 0; hiclock_t flt_duration = 0; fix16_t fix_error = 0; uintptr_t k; for(k = 0; k < pass; k++) { fix16_t fix_args[args]; for(i = 0; i < args; i++) fix_args[i] = (rand() ^ (rand() << 16)); fix16_t fix_result[args]; hiclock_t fix_start = hiclock(); for(i = 0; i < iter; i++) { uintptr_t j; for(j = 0; j < args; j++) fix_result[j] = fix_func(fix_args[j]); } hiclock_t fix_end = hiclock(); float flt_args[args]; for(i = 0; i < args; i++) flt_args[i] = fix16_to_float(fix_args[i]); float flt_result[args]; hiclock_t flt_start = hiclock(); for(i = 0; i < iter; i++) { uintptr_t j; for(j = 0; j < args; j++) flt_result[j] = flt_func(flt_args[j]); } hiclock_t flt_end = hiclock(); for(i = 0; i < args; i++) fix_error += abs(fix16_from_float(flt_result[i]) - fix_result[i]); flt_duration += (flt_end - flt_start); fix_duration += (fix_end - fix_start); } printf("%16s: %08"PRIuHICLOCK" @ %"PRIu32"Hz\n", flt_func_str, flt_duration, HICLOCKS_PER_SEC); printf("%16s: %08"PRIuHICLOCK" @ %"PRIu32"Hz\n", fix_func_str, fix_duration, HICLOCKS_PER_SEC); printf(" Difference: %08"PRIiHICLOCK" (% 3.2f%%)\n", (flt_duration - fix_duration), ((fix_duration * 100.0) / flt_duration)); printf(" Error: %f%%\n", ((fix16_to_dbl(fix_error) * 100.0) / (args * pass))); return EXIT_SUCCESS; }
// Receive real number from serial link. The real number should be in Q16.16 // representation. This is so that the device under test doesn't have to // do the conversion to floating-point. static double receiveDouble(void) { uint8_t buffer[4]; int j; for (j = 0; j < 4; j++) { buffer[j] = receiveByte(); } // The cast from uint32_t to fix16_t isn't platform-independent, because // the C99 specification doesn't make any guarantees about conversions // to signed integer types (...if the destination type cannot store the // source value, which will be the case if the fix16_t is negative). // But it should work on nearly every contemporary platform. return fix16_to_dbl((fix16_t)readU32LittleEndian(buffer)); }
operator double() const { return fix16_to_dbl(value); }
int main() { int status = 0; { COMMENT("Testing fix16_exp() corner cases"); TEST(fix16_exp(0) == fix16_one); TEST(fix16_exp(fix16_minimum) == 0); TEST(fix16_exp(fix16_maximum) == fix16_maximum); } { COMMENT("Testing fix16_exp() accuracy over -11..4"); fix16_t max_delta = -1; fix16_t worst = 0; fix16_t sum = 0; int count = 0; fix16_t a; for (a = fix16_from_dbl(-11.0); a < fix16_from_dbl(4.0); a += 31) { fix16_t result = fix16_exp(a); fix16_t resultf = fix16_from_dbl(exp(fix16_to_dbl(a))); fix16_t d = delta(result, resultf); if (d > max_delta) { max_delta = d; worst = a; } sum += d; count++; } printf("Worst delta %d with input %d\n", max_delta, worst); printf("Average delta %0.2f\n", (float)sum / count); TEST(max_delta < 200); } { COMMENT("Testing fix16_exp() accuracy over full range"); float max_delta = -1; fix16_t worst = 0; float sum = 0; int count = 0; fix16_t a; // Test the whole range of results 0..32768 with a bit less samples for (a = -772243; a < 681391; a += 113) { fix16_t result = fix16_exp(a); fix16_t resultf = fix16_from_dbl(exp(fix16_to_dbl(a))); fix16_t d1 = delta(result, resultf); if (d1 > 0) d1--; // Forgive +-1 for the fix16_t inaccuracy float d = (float)d1 / resultf * 100; if (resultf < 1000) continue; // Percentages can explode when result is almost 0. if (d > max_delta) { max_delta = d; worst = a; } sum += d; count++; } printf("Worst delta %0.4f%% with input %d\n", max_delta, worst); printf("Average delta %0.4f%%\n", sum / count); TEST(max_delta < 1); } { COMMENT("Testing fix16_log() accuracy over full range"); fix16_t max_delta = -1; fix16_t worst = 0; fix16_t sum = 0; int count = 0; fix16_t a; for (a = 100; a > 0 && a < fix16_maximum - 7561; a += 7561) { fix16_t result = fix16_log(a); fix16_t resultf = fix16_from_dbl(log(fix16_to_dbl(a))); fix16_t d = delta(result, resultf); if (d > max_delta) { max_delta = d; worst = a; } sum += d; count++; } printf("Worst delta %d with input %d\n", max_delta, worst); printf("Average delta %0.2f\n", (float)sum / count); TEST(max_delta < 20); } if (status != 0) fprintf(stdout, "\n\nSome tests FAILED!\n"); return status; }