forked from tinygrad/tinygrad
75 lines
3.8 KiB
Python
75 lines
3.8 KiB
Python
import unittest, math
|
|
import numpy as np
|
|
from tinygrad import dtypes
|
|
from tinygrad.uop.ops import UOp
|
|
from tinygrad.codegen.decomp.transcendental import payne_hanek_reduction, cody_waite_reduction, frexp, rintk, pow2if
|
|
from test.helpers import eval_uop
|
|
|
|
class TestTranscendentalFunctions(unittest.TestCase):
|
|
def test_payne_hanek_reduction(self):
|
|
# TODO: Test constant input when constant folding is fixed (or maybe test both variants)
|
|
# Load input value from a buffer to prevent constant folding
|
|
input_buf = UOp.param(1, dtypes.double, (1,))
|
|
loaded_value = input_buf.index(UOp.const(0)).load()
|
|
def eval_payne_hanek_reduction(v:float) -> tuple[float, int]:
|
|
return tuple(eval_uop(u, [(dtypes.float64, [v])]) for u in payne_hanek_reduction(loaded_value))
|
|
|
|
r, q = eval_payne_hanek_reduction(12 * math.pi + 0.1)
|
|
np.testing.assert_allclose(r, 0.1 - math.pi / 2)
|
|
np.testing.assert_equal(q, 1)
|
|
|
|
r, q = eval_payne_hanek_reduction(12 * math.pi)
|
|
np.testing.assert_allclose(r, 0.0, atol=1e-8)
|
|
np.testing.assert_equal(q, 4)
|
|
|
|
r, q = eval_payne_hanek_reduction(12 * math.pi - 0.1)
|
|
np.testing.assert_allclose(r, -0.1)
|
|
np.testing.assert_equal(q, 4)
|
|
|
|
def test_cody_waite_reduction(self):
|
|
r, q = (eval_uop(u) for u in cody_waite_reduction(UOp.const(12 * math.pi + 0.1).cast(dtypes.float64)))
|
|
np.testing.assert_allclose(r, 0.1)
|
|
np.testing.assert_equal(q, 12)
|
|
|
|
def test_frexp(self):
|
|
for x in (1, -1):
|
|
mantissa, exponent = (eval_uop(u) for u in frexp(UOp.const(float(x)).cast(dtypes.float64)))
|
|
np.testing.assert_equal(mantissa, 0.5)
|
|
np.testing.assert_equal(exponent, 1)
|
|
|
|
for x in (2, -2):
|
|
mantissa, exponent = (eval_uop(u) for u in frexp(UOp.const(2.0).cast(dtypes.float64)))
|
|
np.testing.assert_equal(mantissa, 0.5)
|
|
np.testing.assert_equal(exponent, 2)
|
|
|
|
mantissa, exponent = (eval_uop(u) for u in frexp(UOp.const(5.0).cast(dtypes.float64)))
|
|
np.testing.assert_equal(mantissa, 0.625)
|
|
np.testing.assert_equal(exponent, 3)
|
|
|
|
mantissa, exponent = (eval_uop(u) for u in frexp(UOp.const(1000.0).cast(dtypes.float64)))
|
|
np.testing.assert_allclose(mantissa, 0.9765625)
|
|
np.testing.assert_equal(exponent, 10)
|
|
|
|
def test_rintk(self):
|
|
np.testing.assert_allclose(eval_uop(rintk(UOp.const(0.0).cast(dtypes.float))), 0)
|
|
np.testing.assert_allclose(eval_uop(rintk(UOp.const(5.0).cast(dtypes.float))), 5)
|
|
np.testing.assert_allclose(eval_uop(rintk(UOp.const(5.5).cast(dtypes.float))), 6)
|
|
np.testing.assert_allclose(eval_uop(rintk(UOp.const(5.999).cast(dtypes.float))), 6)
|
|
np.testing.assert_allclose(eval_uop(rintk(UOp.const(-5.0).cast(dtypes.float))), -5)
|
|
np.testing.assert_allclose(eval_uop(rintk(UOp.const(-5.5).cast(dtypes.float))), -6)
|
|
np.testing.assert_allclose(eval_uop(rintk(UOp.const(-5.999).cast(dtypes.float))), -6)
|
|
|
|
def test_pow2if(self):
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(0).cast(dtypes.int), dtypes.float)), 1.0)
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(1).cast(dtypes.int), dtypes.float)), 2.0)
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(2).cast(dtypes.int), dtypes.float)), 4.0)
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(10).cast(dtypes.int), dtypes.float)), 1024.0)
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(63).cast(dtypes.int), dtypes.float)), 2**63)
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(-1).cast(dtypes.int), dtypes.float)), 0.5)
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(-2).cast(dtypes.int), dtypes.float)), 0.25)
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(-10).cast(dtypes.int), dtypes.float)), 2**-10)
|
|
np.testing.assert_allclose(eval_uop(pow2if(UOp.const(-63).cast(dtypes.int), dtypes.float)), 2**-63)
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|