diff --git a/quaddtype/numpy_quaddtype/src/scalar.c b/quaddtype/numpy_quaddtype/src/scalar.c index 2be5078..b8e6e64 100644 --- a/quaddtype/numpy_quaddtype/src/scalar.c +++ b/quaddtype/numpy_quaddtype/src/scalar.c @@ -76,14 +76,39 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend) Py_DECREF(self); return NULL; } - long long lval = PyLong_AsLongLong(py_int); - Py_DECREF(py_int); - if (backend == BACKEND_SLEEF) { - self->value.sleef_value = Sleef_cast_from_int64q1(lval); + int overflow = 0; + long long lval = PyLong_AsLongLongAndOverflow(py_int, &overflow); + + if (overflow != 0) + { + // Integer is too large, convert to string and recursively call this function + PyObject *str_obj = PyObject_Str(py_int); + Py_DECREF(py_int); + if (str_obj == NULL) { + Py_DECREF(self); + return NULL; + } + + // Recursively convert from string + QuadPrecisionObject *result = QuadPrecision_from_object(str_obj, backend); + Py_DECREF(str_obj); + Py_DECREF(self); // discard the default one + return result; + } + else if (lval == -1 && PyErr_Occurred()) { + Py_DECREF(py_int); + Py_DECREF(self); + return NULL; } else { - self->value.longdouble_value = (long double)lval; + Py_DECREF(py_int); + if (backend == BACKEND_SLEEF) { + self->value.sleef_value = Sleef_cast_from_int64q1(lval); + } + else { + self->value.longdouble_value = (long double)lval; + } } return self; } @@ -94,9 +119,16 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend) Py_DECREF(self); return NULL; } + + // Booleans are always 0 or 1, so no overflow check needed long long lval = PyLong_AsLongLong(py_int); Py_DECREF(py_int); + if (lval == -1 && PyErr_Occurred()) { + Py_DECREF(self); + return NULL; + } + if (backend == BACKEND_SLEEF) { self->value.sleef_value = Sleef_cast_from_int64q1(lval); } @@ -145,7 +177,7 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend) self->value.longdouble_value = (long double)dval; } } - else if (PyUnicode_CheckExact(value)) { + else if (PyUnicode_Check(value)) { const char *s = PyUnicode_AsUTF8(value); char *endptr = NULL; if (backend == BACKEND_SLEEF) { @@ -161,17 +193,35 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend) } } else if (PyLong_Check(value)) { - long long val = PyLong_AsLongLong(value); - if (val == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_OverflowError, "Overflow Error, value out of range"); + int overflow = 0; + long long val = PyLong_AsLongLongAndOverflow(value, &overflow); + + if (overflow != 0) { + // Integer is too large, convert to string and recursively call this function + PyObject *str_obj = PyObject_Str(value); + if (str_obj == NULL) { + Py_DECREF(self); + return NULL; + } + + // Recursively convert from string + QuadPrecisionObject *result = QuadPrecision_from_object(str_obj, backend); + Py_DECREF(str_obj); + Py_DECREF(self); // discard the default one + return result; + } + else if (val == -1 && PyErr_Occurred()) { Py_DECREF(self); return NULL; } - if (backend == BACKEND_SLEEF) { - self->value.sleef_value = Sleef_cast_from_int64q1(val); - } else { - self->value.longdouble_value = (long double)val; + // No overflow, use the integer value directly + if (backend == BACKEND_SLEEF) { + self->value.sleef_value = Sleef_cast_from_int64q1(val); + } + else { + self->value.longdouble_value = (long double)val; + } } } else if (Py_TYPE(value) == &QuadPrecision_Type) { diff --git a/quaddtype/tests/test_quaddtype.py b/quaddtype/tests/test_quaddtype.py index 7d396e9..e2d7b27 100644 --- a/quaddtype/tests/test_quaddtype.py +++ b/quaddtype/tests/test_quaddtype.py @@ -16,6 +16,45 @@ def test_create_scalar_simple(): assert isinstance(QuadPrecision(1), QuadPrecision) +@pytest.mark.parametrize("int_val", [ + # Very large integers that exceed long double range + 2 ** 1024, + 2 ** 2048, + 10 ** 308, + 10 ** 4000, + # Edge cases + 0, + 1, + -1, + # Negative large integers + -(2 ** 1024), +]) +def test_create_scalar_from_large_int(int_val): + """Test that QuadPrecision can handle very large integers beyond long double range. + + This test ensures that integers like 2**1024, which overflow standard long double, + are properly converted via string representation to QuadPrecision without raising + overflow errors. The conversion should match the string-based conversion. + """ + # Convert large int to QuadPrecision + result = QuadPrecision(int_val) + assert isinstance(result, QuadPrecision) + + # String conversion should give the same result + str_val = str(int_val) + result_from_str = QuadPrecision(str_val) + + # Both conversions should produce the same value + # (can be inf==inf on some platforms for very large values) + assert result == result_from_str + + # For zero and small values, verify exact conversion + if int_val == 0: + assert float(result) == 0.0 + elif abs(int_val) == 1: + assert float(result) == float(int_val) + + class TestQuadPrecisionArrayCreation: """Test suite for QuadPrecision array creation from sequences and arrays."""