From e770bffe214016325c15e8148a283c7b5cdfd19b Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sat, 29 Jun 2019 22:33:04 -0700 Subject: [PATCH] add more tests --- src/ieee754/div_rem_sqrt_rsqrt/algorithm.py | 16 +- .../div_rem_sqrt_rsqrt/test_algorithm.py | 212 +++++++++++++++++- 2 files changed, 222 insertions(+), 6 deletions(-) diff --git a/src/ieee754/div_rem_sqrt_rsqrt/algorithm.py b/src/ieee754/div_rem_sqrt_rsqrt/algorithm.py index 74b7dec1..7ec21510 100644 --- a/src/ieee754/div_rem_sqrt_rsqrt/algorithm.py +++ b/src/ieee754/div_rem_sqrt_rsqrt/algorithm.py @@ -7,6 +7,7 @@ code for simulating/testing the various algorithms """ from nmigen.hdl.ast import Const +import math def div_rem(dividend, divisor, bit_width, signed): @@ -175,6 +176,9 @@ class Fixed: def __init__(self, value, fract_width, bit_width, signed): """ Create a new Fixed. + Note: ``value`` is not the same as ``bits``. To put a particular number + in ``bits``, use ``Fixed.from_bits``. + :param value: the value of the fixed-point number :param fract_width: the number of bits in the fractional portion :param bit_width: the total number of bits @@ -190,7 +194,7 @@ class Fixed: elif isinstance(value, int): bits = value << fract_width else: - bits = floor(value * 2 ** fract_width) + bits = math.floor(value * 2 ** fract_width) self.bits = Const.normalize(bits, (bit_width, signed)) self.fract_width = fract_width self.bit_width = bit_width @@ -198,7 +202,8 @@ class Fixed: def __repr__(self): """ Get representation.""" - return f"Fixed({self.bits}, {self.fract_width}, {self.bit_width})" + retval = f"Fixed.from_bits({self.bits}, {self.fract_width}, " + return retval + f"{self.bit_width}, {self.signed})" def __trunc__(self): """ Truncate to integer.""" @@ -387,9 +392,10 @@ class Fixed: # round up fract_width to nearest multiple of 4 fract_width = (self.fract_width + 3) & ~3 fract_part <<= (fract_width - self.fract_width) - fract_width_in_hex_digits = fract_width / 4 - retval += f"{int_part:x}." - retval += f"{fract_part:x}".zfill(fract_width_in_hex_digits) + fract_width_in_hex_digits = fract_width // 4 + retval += f"0x{int_part:x}." + if fract_width_in_hex_digits != 0: + retval += f"{fract_part:x}".zfill(fract_width_in_hex_digits) return retval diff --git a/src/ieee754/div_rem_sqrt_rsqrt/test_algorithm.py b/src/ieee754/div_rem_sqrt_rsqrt/test_algorithm.py index c81127c0..b1a944d9 100644 --- a/src/ieee754/div_rem_sqrt_rsqrt/test_algorithm.py +++ b/src/ieee754/div_rem_sqrt_rsqrt/test_algorithm.py @@ -5,6 +5,7 @@ from nmigen.hdl.ast import Const from .algorithm import (div_rem, UnsignedDivRem, DivRem, Fixed, fixed_sqrt, FixedSqrt, fixed_rsqrt, FixedRSqrt) import unittest +import math class TestDivRemFn(unittest.TestCase): @@ -348,4 +349,213 @@ class TestDivRem(unittest.TestCase): def test_radix_16(self): self.helper(4) -# FIXME: add tests for Fract, fract_sqrt, FractSqrt, fract_rsqrt, and FractRSqrt + +class TestFixed(unittest.TestCase): + def test_constructor(self): + value = Fixed(0, 0, 1, False) + self.assertEqual(value.bits, 0) + self.assertEqual(value.fract_width, 0) + self.assertEqual(value.bit_width, 1) + self.assertEqual(value.signed, False) + value = Fixed(1, 2, 3, True) + self.assertEqual(value.bits, -4) + self.assertEqual(value.fract_width, 2) + self.assertEqual(value.bit_width, 3) + self.assertEqual(value.signed, True) + value = Fixed(1, 2, 4, True) + self.assertEqual(value.bits, 4) + self.assertEqual(value.fract_width, 2) + self.assertEqual(value.bit_width, 4) + self.assertEqual(value.signed, True) + value = Fixed(1.25, 4, 8, True) + self.assertEqual(value.bits, 0x14) + self.assertEqual(value.fract_width, 4) + self.assertEqual(value.bit_width, 8) + self.assertEqual(value.signed, True) + value = Fixed(Fixed(2, 0, 12, False), 4, 8, True) + self.assertEqual(value.bits, 0x20) + self.assertEqual(value.fract_width, 4) + self.assertEqual(value.bit_width, 8) + self.assertEqual(value.signed, True) + value = Fixed(0x2FF / 2 ** 8, 8, 12, False) + self.assertEqual(value.bits, 0x2FF) + self.assertEqual(value.fract_width, 8) + self.assertEqual(value.bit_width, 12) + self.assertEqual(value.signed, False) + value = Fixed(value, 4, 8, True) + self.assertEqual(value.bits, 0x2F) + self.assertEqual(value.fract_width, 4) + self.assertEqual(value.bit_width, 8) + self.assertEqual(value.signed, True) + + def helper_test_from_bits(self, bit_width, fract_width): + signed = False + for bits in range(1 << bit_width): + with self.subTest(bit_width=bit_width, + fract_width=fract_width, + signed=signed, + bits=hex(bits)): + value = Fixed.from_bits(bits, fract_width, bit_width, signed) + self.assertEqual(value.bit_width, bit_width) + self.assertEqual(value.fract_width, fract_width) + self.assertEqual(value.signed, signed) + self.assertEqual(value.bits, bits) + signed = True + for bits in range(-1 << (bit_width - 1), 1 << (bit_width - 1)): + with self.subTest(bit_width=bit_width, + fract_width=fract_width, + signed=signed, + bits=hex(bits)): + value = Fixed.from_bits(bits, fract_width, bit_width, signed) + self.assertEqual(value.bit_width, bit_width) + self.assertEqual(value.fract_width, fract_width) + self.assertEqual(value.signed, signed) + self.assertEqual(value.bits, bits) + + def test_from_bits(self): + for bit_width in range(1, 5): + for fract_width in range(bit_width): + self.helper_test_from_bits(bit_width, fract_width) + + def test_repr(self): + self.assertEqual(repr(Fixed.from_bits(1, 2, 3, False)), + "Fixed.from_bits(1, 2, 3, False)") + self.assertEqual(repr(Fixed.from_bits(-4, 2, 3, True)), + "Fixed.from_bits(-4, 2, 3, True)") + self.assertEqual(repr(Fixed.from_bits(-4, 7, 10, True)), + "Fixed.from_bits(-4, 7, 10, True)") + + def test_trunc(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + with self.subTest(value=repr(value)): + self.assertEqual(math.trunc(value), math.trunc(i / 4)) + + def test_int(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + with self.subTest(value=repr(value)): + self.assertEqual(int(value), math.trunc(value)) + + def test_float(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + with self.subTest(value=repr(value)): + self.assertEqual(float(value), i / 4) + + def test_floor(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + with self.subTest(value=repr(value)): + self.assertEqual(math.floor(value), math.floor(i / 4)) + + def test_ceil(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + with self.subTest(value=repr(value)): + self.assertEqual(math.ceil(value), math.ceil(i / 4)) + + def test_neg(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + expected = -i / 4 if i != -8 else -2.0 # handle wrap-around + with self.subTest(value=repr(value)): + self.assertEqual(float(-value), expected) + + def test_pos(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + with self.subTest(value=repr(value)): + value = +value + self.assertEqual(value.bits, i) + + def test_abs(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + expected = abs(i) / 4 if i != -8 else -2.0 # handle wrap-around + with self.subTest(value=repr(value)): + self.assertEqual(float(abs(value)), expected) + + def test_not(self): + for i in range(-8, 8): + value = Fixed.from_bits(i, 2, 4, True) + with self.subTest(value=repr(value)): + self.assertEqual(float(~value), (~i) / 4) + + # TODO: add test for _binary_op + # TODO: add test for __add__ + # TODO: add test for __radd__ + # TODO: add test for __sub__ + # TODO: add test for __rsub__ + # TODO: add test for __and__ + # TODO: add test for __rand__ + # TODO: add test for __or__ + # TODO: add test for __ror__ + # TODO: add test for __xor__ + # TODO: add test for __rxor__ + # TODO: add test for __mul__ + # TODO: add test for _cmp_impl + # TODO: add test for cmp + # TODO: add test for __lt__ + # TODO: add test for __le__ + # TODO: add test for __eq__ + # TODO: add test for __ne__ + # TODO: add test for __gt__ + # TODO: add test for __ge__ + # TODO: add test for __bool__ + + def test_str(self): + self.assertEqual(str(Fixed.from_bits(0x1234, 0, 16, False)), + "fixed:0x1234.") + self.assertEqual(str(Fixed.from_bits(-0x1234, 0, 16, True)), + "fixed:-0x1234.") + self.assertEqual(str(Fixed.from_bits(0x12345, 3, 20, True)), + "fixed:0x2468.a") + self.assertEqual(str(Fixed(123.625, 3, 12, True)), + "fixed:0x7b.a") + + self.assertEqual(str(Fixed.from_bits(0x1, 0, 20, True)), + "fixed:0x1.") + self.assertEqual(str(Fixed.from_bits(0x2, 1, 20, True)), + "fixed:0x1.0") + self.assertEqual(str(Fixed.from_bits(0x4, 2, 20, True)), + "fixed:0x1.0") + self.assertEqual(str(Fixed.from_bits(0x9, 3, 20, True)), + "fixed:0x1.2") + self.assertEqual(str(Fixed.from_bits(0x12, 4, 20, True)), + "fixed:0x1.2") + self.assertEqual(str(Fixed.from_bits(0x24, 5, 20, True)), + "fixed:0x1.20") + self.assertEqual(str(Fixed.from_bits(0x48, 6, 20, True)), + "fixed:0x1.20") + self.assertEqual(str(Fixed.from_bits(0x91, 7, 20, True)), + "fixed:0x1.22") + self.assertEqual(str(Fixed.from_bits(0x123, 8, 20, True)), + "fixed:0x1.23") + self.assertEqual(str(Fixed.from_bits(0x246, 9, 20, True)), + "fixed:0x1.230") + self.assertEqual(str(Fixed.from_bits(0x48d, 10, 20, True)), + "fixed:0x1.234") + self.assertEqual(str(Fixed.from_bits(0x91a, 11, 20, True)), + "fixed:0x1.234") + self.assertEqual(str(Fixed.from_bits(0x1234, 12, 20, True)), + "fixed:0x1.234") + self.assertEqual(str(Fixed.from_bits(0x2468, 13, 20, True)), + "fixed:0x1.2340") + self.assertEqual(str(Fixed.from_bits(0x48d1, 14, 20, True)), + "fixed:0x1.2344") + self.assertEqual(str(Fixed.from_bits(0x91a2, 15, 20, True)), + "fixed:0x1.2344") + self.assertEqual(str(Fixed.from_bits(0x12345, 16, 20, True)), + "fixed:0x1.2345") + self.assertEqual(str(Fixed.from_bits(0x2468a, 17, 20, True)), + "fixed:0x1.23450") + self.assertEqual(str(Fixed.from_bits(0x48d14, 18, 20, True)), + "fixed:0x1.23450") + self.assertEqual(str(Fixed.from_bits(0x91a28, 19, 20, True)), + "fixed:-0x0.dcbb0") + self.assertEqual(str(Fixed.from_bits(0x91a28, 19, 20, False)), + "fixed:0x1.23450") + + +# FIXME: add tests for fract_sqrt, FractSqrt, fract_rsqrt, and FractRSqrt -- 2.30.2