mirror of
https://github.com/ish-app/ish.git
synced 2026-01-18 13:57:29 +00:00
209 lines
5.0 KiB
C
209 lines
5.0 KiB
C
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <math.h>
|
|
#include "float80.h"
|
|
|
|
//#define DENORMAL 1e-310
|
|
#define DENORMAL 1.11253692925360069155e-308
|
|
|
|
union f80 {
|
|
float80 f;
|
|
long double ld;
|
|
};
|
|
|
|
union f80 gf;
|
|
|
|
static bool bitwise_eq(long double a, long double b) {
|
|
union f80 ua = (union f80) a;
|
|
union f80 ub = (union f80) b;
|
|
return ua.f.signif == ub.f.signif && ua.f.signExp == ub.f.signExp;
|
|
}
|
|
|
|
static int tests_passed = 0;
|
|
static int tests_total = 0;
|
|
static int suite_passed = 0;
|
|
static int suite_total = 0;
|
|
|
|
#define suite_start() _suite_start(__FUNCTION__)
|
|
#define suite_end() _suite_end(__FUNCTION__)
|
|
void _suite_start(const char *suite) {
|
|
printf("==== %s ====\n", suite);
|
|
suite_passed = 0;
|
|
suite_total = 0;
|
|
}
|
|
void _suite_end(const char *suite) {
|
|
printf("%s: %d/%d passed (%.0f%%)\n", suite, suite_passed, suite_total, (double) suite_passed / suite_total * 100);
|
|
}
|
|
|
|
void assertf(int cond, const char *msg, ...) {
|
|
tests_total++;
|
|
suite_total++;
|
|
if (cond) {
|
|
tests_passed++;
|
|
suite_passed++;
|
|
}
|
|
|
|
printf(cond ? "PASS ": "FAIL ");
|
|
//if (!cond) asm("int3");
|
|
char buf[1024];
|
|
va_list args;
|
|
va_start(args, msg);
|
|
vsprintf(buf, msg, args);
|
|
va_end(args);
|
|
puts(buf);
|
|
}
|
|
|
|
void test_int_convert() {
|
|
suite_start();
|
|
union f80 u;
|
|
int64_t i;
|
|
#define test(x) \
|
|
u.f = f80_from_int(x); \
|
|
assertf((int64_t) u.ld == x, "f80_from_int(%ld) = %Le", (int64_t) x, u.ld); \
|
|
i = f80_to_int(u.f); \
|
|
assertf(i == x, "f80_to_int(%Le) = %ld", u.ld, i)
|
|
|
|
test(0);
|
|
test(123); test(-123);
|
|
test(9489919999192); test(-9489919999192);
|
|
test(INT64_MIN); test(INT64_MAX);
|
|
#undef test
|
|
suite_end();
|
|
}
|
|
|
|
void test_double_convert() {
|
|
suite_start();
|
|
union f80 u;
|
|
double d;
|
|
#define test(x) \
|
|
u.f = f80_from_double(x); \
|
|
assertf(bitwise_eq(u.ld, x), "f80_from_double(%e) = %Le", (double) x, u.ld); \
|
|
d = f80_to_double(u.f); \
|
|
assertf(bitwise_eq(d, x), "f80_to_double(%Le) = %e", u.ld, d)
|
|
|
|
test(0); test(-0);
|
|
test(123); test(-123);
|
|
test(3991994929919994995881.0);
|
|
test(DENORMAL);
|
|
test(1e-310);
|
|
test(INFINITY); test(-INFINITY);
|
|
test(NAN);
|
|
#undef test
|
|
suite_end();
|
|
}
|
|
|
|
void test_math() {
|
|
suite_start();
|
|
union f80 ua, ub, u;
|
|
long double expected;
|
|
#define cop_add +
|
|
#define cop_sub -
|
|
#define cop_mul *
|
|
#define cop_div /
|
|
#define _test(op, a, b) \
|
|
ua.ld = a; ub.ld = b; \
|
|
u.f = f80_##op(ua.f, ub.f); \
|
|
expected = (long double) a cop_##op (long double) b; \
|
|
assertf(bitwise_eq(u.ld, expected), "f80_"#op"(%Le, %Le) = %Le", ua.ld, ub.ld, u.ld)
|
|
#define test(op, a, b) \
|
|
_test(op, a, b); \
|
|
_test(op, -a, b); \
|
|
_test(op, a, -b); \
|
|
_test(op, -a, -b)
|
|
|
|
test(add, 1, 1);
|
|
test(add, 123, 123);
|
|
test(add, 9942, 13459);
|
|
test(add, 222, 0.);
|
|
test(add, 0., 0.);
|
|
test(add, 12.0499, 91999);
|
|
test(add, 1e100, 100);
|
|
test(add, 1e-4949l, 1);
|
|
test(add, 1e-4949l, 1e-4949l);
|
|
test(add, INFINITY, 123);
|
|
test(add, INFINITY, INFINITY);
|
|
test(add, NAN, 123);
|
|
test(add, NAN, NAN);
|
|
|
|
test(mul, 0, 1);
|
|
test(mul, 1, 1);
|
|
test(mul, 123, 123);
|
|
test(mul, 1e100, 100);
|
|
test(mul, 12.3993l, 91934);
|
|
test(mul, 1e-4949l, 1);
|
|
test(mul, 1e-4949l, 1e-4949l);
|
|
test(mul, INFINITY, 11);
|
|
test(mul, INFINITY, INFINITY);
|
|
test(mul, INFINITY, 0);
|
|
test(mul, NAN, 123);
|
|
test(mul, NAN, NAN);
|
|
|
|
test(div, 1, 1);
|
|
test(div, 3, 2);
|
|
test(div, 0, 1);
|
|
test(div, 0, 0);
|
|
test(div, 1, 1e1000l);
|
|
test(div, 1, 1e-1000l);
|
|
test(div, 12.4123331, 934.11223e200);
|
|
test(div, 1e-4949l, 10);
|
|
test(div, 10, 1e-4949l);
|
|
test(div, 1e-4949l, 1e-4949l);
|
|
test(div, INFINITY, 100);
|
|
test(div, 100, INFINITY);
|
|
test(div, INFINITY, INFINITY);
|
|
test(div, INFINITY, 0);
|
|
test(div, NAN, 123);
|
|
test(div, NAN, NAN);
|
|
#undef test
|
|
#undef _test
|
|
suite_end();
|
|
}
|
|
|
|
void test_compare() {
|
|
suite_start();
|
|
union f80 ua, ub;
|
|
bool expected, actual;
|
|
#define cop_eq ==
|
|
#define cop_lt <
|
|
#define _test(op, a, b) \
|
|
ua.ld = a; ub.ld = b; \
|
|
actual = f80_##op(ua.f, ub.f); \
|
|
expected = (long double) a cop_##op (long double) b; \
|
|
assertf(actual == expected, "f80_"#op"(%Le, %Le) = %s", ua.ld, ub.ld, actual ? "true" : "false")
|
|
#define test(op, a, b) \
|
|
_test(op, a, b); \
|
|
_test(op, -a, b); \
|
|
_test(op, a, -b); \
|
|
_test(op, -a, -b)
|
|
|
|
test(eq, 0, 0);
|
|
test(eq, 1, 1);
|
|
test(eq, 0, 1);
|
|
test(eq, INFINITY, INFINITY);
|
|
test(eq, 1, INFINITY);
|
|
test(eq, NAN, 123);
|
|
test(eq, NAN, NAN);
|
|
test(lt, 0, 0);
|
|
test(lt, 1, 1);
|
|
test(lt, 0, 1);
|
|
test(lt, INFINITY, INFINITY);
|
|
test(lt, 1, INFINITY);
|
|
test(lt, NAN, 123);
|
|
test(lt, NAN, NAN);
|
|
#undef test
|
|
suite_end();
|
|
}
|
|
|
|
uint64_t fnmulh(uint64_t a, uint64_t b) {
|
|
return ((unsigned __int128) a * b) >> 64;
|
|
}
|
|
|
|
int main() {
|
|
test_int_convert();
|
|
test_double_convert();
|
|
test_math();
|
|
test_compare();
|
|
printf("%d/%d passed (%.0f%%)", tests_passed, tests_total, (double) tests_passed / tests_total * 100);
|
|
return tests_passed == tests_total ? 0 : 1;
|
|
}
|