nxu/test-fix16.py

160 lines
5.0 KiB
Python
Raw Normal View History

2022-11-06 21:49:02 -05:00
#!/usr/bin/python
2022-11-07 14:52:29 -05:00
from math import floor, log, sin, cos, tan, copysign
2022-11-06 21:49:02 -05:00
from os import environ
from random import randint
from subprocess import Popen, PIPE, run
2022-11-07 14:52:29 -05:00
def tosigned(x):
return x if x < 32768 else x - 65536
2022-11-06 21:49:02 -05:00
u8 = {'sz': 1 << 8, 'fmt': b'%02x'}
u16 = {'sz': 1 << 16, 'fmt': b'%04x'}
z16 = {'sz': 1 << 16, 'fmt': b'%04x'}
2022-11-07 14:52:29 -05:00
p16 = {'sz': 1 << 16, 'fmt': b'%04x'}
t16 = {'sz': 1 << 16, 'fmt': b'%04x'}
2022-11-06 21:49:02 -05:00
def eq(got, expected):
return got == expected
def booleq(got, expected):
return bool(got) == bool(expected)
2022-11-07 14:52:29 -05:00
def releq(got0, expected0):
got, expected = tosigned(got0), tosigned(expected0)
2022-11-06 21:49:02 -05:00
if (expected - 1) <= got and got <= (expected + 1):
return True
else:
error = abs(got - expected) / (abs(expected) + 0.001)
return error < 0.01
2022-11-07 14:52:29 -05:00
def abseq(got0, expected0):
got, expected = tosigned(got0), tosigned(expected0)
if (expected - 10) <= got and got <= (expected + 10):
return True
else:
return False
def taneq(got0, expected0):
got, expected = tosigned(got0), tosigned(expected0)
if (expected - 1) <= got and got <= (expected + 1):
return True
else:
error = abs(got - expected) / (abs(expected) + 0.001)
return error < 0.1
2022-11-06 21:49:02 -05:00
def testcase(p, sym, args, out, f, eq):
vals = []
for name, g in args:
val = randint(0, g['sz'] - 1)
2022-11-07 14:52:29 -05:00
while ((val == 0 and (g is z16 or g is p16)) or
(val >= 0x8000 and g is p16) or
(g is t16 and ((val >= 804) or ((val % 804) == 402)))):
2022-11-06 21:49:02 -05:00
val = randint(0, g['sz'] - 1)
vals.append((name, g, val))
p.stdin.write(sym)
for _, g, x in vals:
p.stdin.write(g['fmt'] % x)
p.stdin.write(b'\n')
p.stdin.flush()
got = int(p.stdout.readline().strip().decode('utf-8'), 16)
xs = [x for _, _, x in vals]
z = f(*xs)
expected = z
if eq(got, expected):
return None
else:
res = {'got': got, 'expected': expected}
for name, _, x in vals:
res[name] = x
return res
def test(p, trials, sym, args, out, f, eq=eq):
fails = 0
cases = []
for i in range(0, trials):
case1 = testcase(p, sym, args, out, f, eq)
if case1 is not None:
fails += 1
cases.append(case1)
name = sym.decode('utf-8')
if fails == 0:
print('%s passed %d trials' % (name, trials))
else:
print('%s failed %d/%d trials (%r)' % (name, fails, trials, cases))
def pipe():
return Popen(['uxncli', 'run.rom'], stdin=PIPE, stdout=PIPE)
def x16_add(x, y):
return (x + y) % 65536
def x16_sub(x, y):
return (x - y) % 65536
def x16_mul(x, y):
return ((x * y) // 256) % 65536
def x16_div(x, y):
return ((x * 256) // y) % 65536
def x16_quot(x, y):
return x16_div(x, y) & 0xff00
def x16_rem(x, y):
return x % y
def x16_is_whole(x):
return int((x & 0xff) == 0)
def x16_negate(x):
if x == 32768 or x == 0:
return x
else:
return 65536 - x
def x16_eq(x, y):
return x == y
def x16_ne(x, y):
return x != y
def x16_lt(x, y):
return int(tosigned(x) < tosigned(y))
def x16_gt(x, y):
return int(tosigned(x) > tosigned(y))
def x16_lteq(x, y):
return int(tosigned(x) <= tosigned(y))
def x16_gteq(x, y):
return int(tosigned(x) >= tosigned(y))
2022-11-07 14:52:29 -05:00
def x16_sin(x):
z = round(sin(x / 256) * 256)
return z if z >= 0 else 65536 + z
def x16_cos(x):
z = round(cos(x / 256) * 256)
return z if z >= 0 else 65536 + z
def x16_tan(x):
z0 = round(tan(x / 256) * 256)
z = min(max(z0, -0x7fff), 0x7fff)
return z if z >= 0 else 65536 + z
def x16_log(x):
z = round(log(x / 256) * 256)
return z if z >= 0 else 65536 + z
2022-11-06 21:49:02 -05:00
def main():
2022-11-07 14:52:29 -05:00
trials = 10000
2022-11-06 21:49:02 -05:00
run(['uxnasm', 'test-fix16.tal', 'run.rom'])
p = pipe()
test(p, trials, b'+', [('x', u16), ('y', u16)], u16, x16_add)
test(p, trials, b'-', [('x', u16), ('y', u16)], u16, x16_sub)
test(p, trials, b'*', [('x', u16), ('y', u16)], u16, x16_mul)
test(p, trials, b'/', [('x', u16), ('y', z16)], u16, x16_div, eq=releq)
test(p, trials, b'\\', [('x', u16), ('y', z16)], u16, x16_quot)
test(p, trials, b'%', [('x', u16), ('y', z16)], u16, x16_rem)
test(p, trials, b'w', [('x', u16)], u8, x16_is_whole, eq=booleq)
test(p, trials, b'N', [('x', u16)], u16, x16_negate)
test(p, trials, b'=', [('x', u16), ('y', u16)], u8, x16_eq)
test(p, trials, b'!', [('x', u16), ('y', u16)], u8, x16_ne)
test(p, trials, b'<', [('x', u16), ('y', u16)], u8, x16_lt)
test(p, trials, b'>', [('x', u16), ('y', u16)], u8, x16_gt)
test(p, trials, b'{', [('x', u16), ('y', u16)], u8, x16_lteq)
test(p, trials, b'}', [('x', u16), ('y', u16)], u8, x16_gteq)
2022-11-07 14:52:29 -05:00
test(p, trials, b's', [('x', p16)], u16, x16_sin, eq=abseq)
test(p, trials, b'c', [('x', p16)], u16, x16_cos, eq=abseq)
test(p, trials, b't', [('x', t16)], u16, x16_tan, eq=taneq)
test(p, trials, b'l', [('x', p16)], u16, x16_log, eq=releq)
2022-11-06 21:49:02 -05:00
p.stdin.write(b'\n\n')
p.stdin.flush()
p.stdin.close()
p.stdout.close()
p.kill()
if __name__ == "__main__":
main()