generate_testcases.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. '''This script precalculates the correct solutions for a set of test numbers,
  2. and writes them to testcases.c. This is aimed for running the tests on-target,
  3. therefore it doesn't test all the cases or use floating point math, but
  4. instead generates a ~10k binary.
  5. The tests are chosen randomly, so there is quite good chance to eventually
  6. catch most errors. Because the list is not regenerated automatically, the
  7. functioning of the benchmark application is still deterministic and easy
  8. to debug.
  9. '''
  10. import math
  11. import random
  12. import struct
  13. # Fix16 scaling factor
  14. scale = 65536.
  15. # Fix16 overflow indicator
  16. overflow = -2**31
  17. def f16_to_float(val):
  18. return val / scale
  19. def float_to_f16(val):
  20. val = int(round(val * scale))
  21. if val >= 2**31 or val < -2**31:
  22. val = overflow
  23. return val
  24. def to_ui32(val):
  25. return struct.unpack('I', struct.pack('i', val))[0]
  26. testcases = [
  27. # Small numbers
  28. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
  29. -1, -2, -3, -4, -5, -6, -7, -8, -9, -10,
  30. # Integer numbers
  31. 0x10000, -0x10000, 0x20000, -0x20000, 0x30000, -0x30000,
  32. 0x40000, -0x40000, 0x50000, -0x50000, 0x60000, -0x60000,
  33. # Fractions (1/2, 1/4, 1/8)
  34. 0x8000, -0x8000, 0x4000, -0x4000, 0x2000, -0x2000,
  35. # Problematic carry
  36. 0xFFFF, -0xFFFF, 0x1FFFF, -0x1FFFF, 0x3FFFF, -0x3FFFF,
  37. # Smallest and largest values
  38. 0x7FFFFFFF, -0x80000000
  39. ]
  40. for i in range(10):
  41. # Large random numbers
  42. testcases.append(random.randint(-0x80000000, 0x7FFFFFFF))
  43. # Small random numbers
  44. testcases.append(random.randint(-100000, 100000))
  45. # Tiny random numbers
  46. testcases.append(random.randint(-200, 200))
  47. out = open("testcases.c", "w")
  48. out.write('''
  49. /* Automatically generated testcases for fix16 operations
  50. * See generate_testcases.py for the generator.
  51. */
  52. #include <fix16.h>
  53. typedef struct {
  54. // Input
  55. fix16_t a;
  56. // Correct output
  57. fix16_t sqrt;
  58. fix16_t exp;
  59. } fix16_1op_testcase;
  60. typedef struct {
  61. // Inputs
  62. fix16_t a;
  63. fix16_t b;
  64. // Correct output
  65. fix16_t add;
  66. fix16_t sub;
  67. fix16_t mul;
  68. fix16_t div;
  69. } fix16_2op_testcase;
  70. #define TESTCASES1_COUNT (sizeof(testcases1)/sizeof(testcases1[0]))
  71. #define TESTCASES2_COUNT (sizeof(testcases2)/sizeof(testcases2[0]))
  72. ''')
  73. # Write testcases for 1-operand functions
  74. out.write('static const fix16_1op_testcase testcases1[] = {\n')
  75. for i in range(10):
  76. a = random.choice(testcases)
  77. if a >= 0:
  78. sqrt = float_to_f16(math.sqrt(f16_to_float(a)))
  79. else:
  80. sqrt = 0
  81. try:
  82. exp = float_to_f16(math.exp(f16_to_float(a)))
  83. except OverflowError:
  84. exp = 0x7FFFFFFF
  85. out.write(' {0x%08x, 0x%08x, 0x%08x}, // %d\n'
  86. % (to_ui32(a), to_ui32(sqrt), to_ui32(exp), i))
  87. out.write('};\n\n')
  88. # Write testcases for 2-operand functions
  89. out.write('static const fix16_2op_testcase testcases2[] = {\n')
  90. for i in range(50):
  91. a = random.choice(testcases)
  92. b = random.choice(testcases)
  93. add = float_to_f16(f16_to_float(a) + f16_to_float(b))
  94. sub = float_to_f16(f16_to_float(a) - f16_to_float(b))
  95. mul = float_to_f16(f16_to_float(a) * f16_to_float(b))
  96. if b != 0:
  97. div = float_to_f16(f16_to_float(a) / f16_to_float(b))
  98. else:
  99. div = 0
  100. out.write(' {0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x}, // %d\n'
  101. % (to_ui32(a), to_ui32(b), to_ui32(add), to_ui32(sub), to_ui32(mul), to_ui32(div), i))
  102. out.write('};\n\n')
  103. out.close()