aboutsummaryrefslogtreecommitdiff
path: root/Client/ThirdParty/libfixmath/benchmarks/generate_testcases.py
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-11-30 22:25:37 +0800
committerchai <chaifix@163.com>2021-11-30 22:25:37 +0800
commit9e0e01b7f4375063f06e494113187d48614628e0 (patch)
tree21a4901612ad92c121f4c887a33b1bbbe87c6b00 /Client/ThirdParty/libfixmath/benchmarks/generate_testcases.py
+init
Diffstat (limited to 'Client/ThirdParty/libfixmath/benchmarks/generate_testcases.py')
-rw-r--r--Client/ThirdParty/libfixmath/benchmarks/generate_testcases.py140
1 files changed, 140 insertions, 0 deletions
diff --git a/Client/ThirdParty/libfixmath/benchmarks/generate_testcases.py b/Client/ThirdParty/libfixmath/benchmarks/generate_testcases.py
new file mode 100644
index 0000000..560ba4d
--- /dev/null
+++ b/Client/ThirdParty/libfixmath/benchmarks/generate_testcases.py
@@ -0,0 +1,140 @@
+'''This script precalculates the correct solutions for a set of test numbers,
+and writes them to testcases.c. This is aimed for running the tests on-target,
+therefore it doesn't test all the cases or use floating point math, but
+instead generates a ~10k binary.
+
+The tests are chosen randomly, so there is quite good chance to eventually
+catch most errors. Because the list is not regenerated automatically, the
+functioning of the benchmark application is still deterministic and easy
+to debug.
+'''
+
+import math
+import random
+import struct
+
+# Fix16 scaling factor
+scale = 65536.
+
+# Fix16 overflow indicator
+overflow = -2**31
+
+def f16_to_float(val):
+ return val / scale
+
+def float_to_f16(val):
+ val = int(round(val * scale))
+ if val >= 2**31 or val < -2**31:
+ val = overflow
+ return val
+
+def to_ui32(val):
+ return struct.unpack('I', struct.pack('i', val))[0]
+
+testcases = [
+ # Small numbers
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ -1, -2, -3, -4, -5, -6, -7, -8, -9, -10,
+
+ # Integer numbers
+ 0x10000, -0x10000, 0x20000, -0x20000, 0x30000, -0x30000,
+ 0x40000, -0x40000, 0x50000, -0x50000, 0x60000, -0x60000,
+
+ # Fractions (1/2, 1/4, 1/8)
+ 0x8000, -0x8000, 0x4000, -0x4000, 0x2000, -0x2000,
+
+ # Problematic carry
+ 0xFFFF, -0xFFFF, 0x1FFFF, -0x1FFFF, 0x3FFFF, -0x3FFFF,
+
+ # Smallest and largest values
+ 0x7FFFFFFF, -0x80000000
+]
+
+for i in range(10):
+ # Large random numbers
+ testcases.append(random.randint(-0x80000000, 0x7FFFFFFF))
+
+ # Small random numbers
+ testcases.append(random.randint(-100000, 100000))
+
+ # Tiny random numbers
+ testcases.append(random.randint(-200, 200))
+
+out = open("testcases.c", "w")
+
+out.write('''
+/* Automatically generated testcases for fix16 operations
+ * See generate_testcases.py for the generator.
+ */
+
+#include <fix16.h>
+
+typedef struct {
+ // Input
+ fix16_t a;
+
+ // Correct output
+ fix16_t sqrt;
+ fix16_t exp;
+} fix16_1op_testcase;
+
+typedef struct {
+ // Inputs
+ fix16_t a;
+ fix16_t b;
+
+ // Correct output
+ fix16_t add;
+ fix16_t sub;
+ fix16_t mul;
+ fix16_t div;
+} fix16_2op_testcase;
+
+#define TESTCASES1_COUNT (sizeof(testcases1)/sizeof(testcases1[0]))
+#define TESTCASES2_COUNT (sizeof(testcases2)/sizeof(testcases2[0]))
+
+''')
+
+# Write testcases for 1-operand functions
+
+out.write('static const fix16_1op_testcase testcases1[] = {\n')
+
+for i in range(10):
+ a = random.choice(testcases)
+ if a >= 0:
+ sqrt = float_to_f16(math.sqrt(f16_to_float(a)))
+ else:
+ sqrt = 0
+
+ try:
+ exp = float_to_f16(math.exp(f16_to_float(a)))
+ except OverflowError:
+ exp = 0x7FFFFFFF
+
+ out.write(' {0x%08x, 0x%08x, 0x%08x}, // %d\n'
+ % (to_ui32(a), to_ui32(sqrt), to_ui32(exp), i))
+
+out.write('};\n\n')
+
+# Write testcases for 2-operand functions
+
+out.write('static const fix16_2op_testcase testcases2[] = {\n')
+
+for i in range(50):
+ a = random.choice(testcases)
+ b = random.choice(testcases)
+
+ add = float_to_f16(f16_to_float(a) + f16_to_float(b))
+ sub = float_to_f16(f16_to_float(a) - f16_to_float(b))
+ mul = float_to_f16(f16_to_float(a) * f16_to_float(b))
+ if b != 0:
+ div = float_to_f16(f16_to_float(a) / f16_to_float(b))
+ else:
+ div = 0
+ out.write(' {0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x}, // %d\n'
+ % (to_ui32(a), to_ui32(b), to_ui32(add), to_ui32(sub), to_ui32(mul), to_ui32(div), i))
+
+out.write('};\n\n')
+
+out.close()
+