141 lines
3.4 KiB
Python
141 lines
3.4 KiB
Python
'''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()
|
|
|