'''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 typedef struct { // Input fix16_t a; // Correct output fix16_t sqrt; } 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))) out.write(' {0x%08x, 0x%08x}, // %d\n' % (to_ui32(a), to_ui32(sqrt), 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()