diff --git a/quaddtype/numpy_quaddtype/__init__.py b/quaddtype/numpy_quaddtype/__init__.py index 8da0a76..e4068ff 100644 --- a/quaddtype/numpy_quaddtype/__init__.py +++ b/quaddtype/numpy_quaddtype/__init__.py @@ -12,7 +12,8 @@ 'QuadPrecision', 'QuadPrecDType', 'SleefQuadPrecision', 'LongDoubleQuadPrecision', 'SleefQuadPrecDType', 'LongDoubleQuadPrecDType', 'is_longdouble_128', # Constants - 'pi', 'e', 'log2e', 'log10e', 'ln2', 'ln10', 'max_value', 'min_value', 'epsilon', + 'pi', 'e', 'log2e', 'log10e', 'ln2', 'ln10', 'max_value', 'epsilon', + 'smallest_normal', 'smallest_subnormal', # QuadBLAS related functions 'set_num_threads', 'get_num_threads', 'get_quadblas_version' ] @@ -35,6 +36,7 @@ def LongDoubleQuadPrecDType(): log10e = get_sleef_constant("log10e") ln2 = get_sleef_constant("ln2") ln10 = get_sleef_constant("ln10") -max_value = get_sleef_constant("quad_max") -min_value = get_sleef_constant("quad_min") -epsilon = get_sleef_constant("epsilon") \ No newline at end of file +max_value = get_sleef_constant("max_value") +epsilon = get_sleef_constant("epsilon") +smallest_normal = get_sleef_constant("smallest_normal") +smallest_subnormal = get_sleef_constant("smallest_subnormal") diff --git a/quaddtype/numpy_quaddtype/src/quaddtype_main.c b/quaddtype/numpy_quaddtype/src/quaddtype_main.c index 1e8fd53..3825dfc 100644 --- a/quaddtype/numpy_quaddtype/src/quaddtype_main.c +++ b/quaddtype/numpy_quaddtype/src/quaddtype_main.c @@ -61,15 +61,18 @@ get_sleef_constant(PyObject *self, PyObject *args) else if (strcmp(constant_name, "ln10") == 0) { result->value.sleef_value = SLEEF_M_LN10q; } - else if (strcmp(constant_name, "quad_max") == 0) { + else if (strcmp(constant_name, "max_value") == 0) { result->value.sleef_value = SLEEF_QUAD_MAX; } - else if (strcmp(constant_name, "quad_min") == 0) { - result->value.sleef_value = SLEEF_QUAD_MIN; - } else if (strcmp(constant_name, "epsilon") == 0) { result->value.sleef_value = SLEEF_QUAD_EPSILON; } + else if (strcmp(constant_name, "smallest_normal") == 0) { + result->value.sleef_value = SLEEF_QUAD_MIN; + } + else if (strcmp(constant_name, "smallest_subnormal") == 0) { + result->value.sleef_value = SLEEF_QUAD_DENORM_MIN; + } else { PyErr_SetString(PyExc_ValueError, "Unknown constant name"); Py_DECREF(result); diff --git a/quaddtype/tests/test_dot.py b/quaddtype/tests/test_dot.py index b1c16c6..d5845d5 100644 --- a/quaddtype/tests/test_dot.py +++ b/quaddtype/tests/test_dot.py @@ -268,7 +268,7 @@ def test_matrix_matrix_with_special_values(self, special_val): def test_all_nan_matrix(self): """Test matrices filled with NaN""" - A = create_quad_array([float('nan')] * 4, shape=(2, 2)) + A = create_quad_array([float("nan")] * 4, shape=(2, 2)) B = create_quad_array([1, 2, 3, 4], shape=(2, 2)) result = np.matmul(A, B) @@ -281,7 +281,7 @@ def test_all_nan_matrix(self): def test_inf_times_zero_produces_nan(self): """Test that Inf * 0 correctly produces NaN per IEEE 754""" # Create a scenario where Inf * 0 occurs in matrix multiplication - A = create_quad_array([float('inf'), 1.0], shape=(1, 2)) + A = create_quad_array([float("inf"), 1.0], shape=(1, 2)) B = create_quad_array([0.0, 1.0], shape=(2, 1)) result = np.matmul(A, B) @@ -291,7 +291,7 @@ def test_inf_times_zero_produces_nan(self): def test_nan_propagation(self): """Test that NaN properly propagates through matrix operations""" - A = create_quad_array([1.0, float('nan'), 3.0, 4.0], shape=(2, 2)) + A = create_quad_array([1.0, float("nan"), 3.0, 4.0], shape=(2, 2)) B = create_quad_array([1.0, 0.0, 0.0, 1.0], shape=(2, 2)) # Identity result = np.matmul(A, B) @@ -310,7 +310,7 @@ def test_zero_division_and_indeterminate_forms(self): # Test various indeterminate forms that should produce NaN # Case: Inf - Inf form - A = create_quad_array([float('inf'), float('inf')], shape=(1, 2)) + A = create_quad_array([float("inf"), float("inf")], shape=(1, 2)) B = create_quad_array([1.0, -1.0], shape=(2, 1)) result = np.matmul(A, B) @@ -321,7 +321,7 @@ def test_zero_division_and_indeterminate_forms(self): def test_mixed_inf_values(self): """Test matrices with mixed infinite values""" # Use all-ones matrix to avoid Inf * 0 = NaN issues - A = create_quad_array([float('inf'), 2, float('-inf'), 3], shape=(2, 2)) + A = create_quad_array([float("inf"), 2, float("-inf"), 3], shape=(2, 2)) B = create_quad_array([1, 1, 1, 1], shape=(2, 2)) # All ones to avoid Inf*0 result = np.matmul(A, B) diff --git a/quaddtype/tests/test_quaddtype.py b/quaddtype/tests/test_quaddtype.py index 6bf4af5..a8e271f 100644 --- a/quaddtype/tests/test_quaddtype.py +++ b/quaddtype/tests/test_quaddtype.py @@ -3,6 +3,7 @@ import numpy as np import operator +import numpy_quaddtype from numpy_quaddtype import QuadPrecDType, QuadPrecision @@ -11,6 +12,17 @@ def test_create_scalar_simple(): assert isinstance(QuadPrecision(1.63), QuadPrecision) assert isinstance(QuadPrecision(1), QuadPrecision) +@pytest.mark.parametrize("name,expected", [("pi", np.pi), ("e", np.e), ("log2e", np.log2(np.e)), ("log10e", np.log10(np.e)), ("ln2", np.log(2.0)), ("ln10", np.log(10.0))]) +def test_math_constant(name, expected): + assert isinstance(getattr(numpy_quaddtype, name), QuadPrecision) + + assert np.float64(getattr(numpy_quaddtype, name)) == expected + + +@pytest.mark.parametrize("name", ["max_value", "epsilon", "smallest_normal", "smallest_subnormal"]) +def test_finfo_constant(name): + assert isinstance(getattr(numpy_quaddtype, name), QuadPrecision) + def test_basic_equality(): assert QuadPrecision("12") == QuadPrecision( @@ -140,12 +152,12 @@ def test_inf(): def test_dtype_creation(): dtype = QuadPrecDType() assert isinstance(dtype, np.dtype) - assert dtype.name == 'QuadPrecDType128' + assert dtype.name == "QuadPrecDType128" def test_array_creation(): arr = np.array([1, 2, 3], dtype=QuadPrecDType()) - assert arr.dtype.name == 'QuadPrecDType128' + assert arr.dtype.name == "QuadPrecDType128" assert all(isinstance(x, QuadPrecision) for x in arr)