Skip to content

Commit 1eb5202

Browse files
committed
PyLong_AsLongLongAndOverflow
1 parent 7cff6f3 commit 1eb5202

File tree

2 files changed

+124
-18
lines changed

2 files changed

+124
-18
lines changed

quaddtype/numpy_quaddtype/src/scalar.c

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,39 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
7676
Py_DECREF(self);
7777
return NULL;
7878
}
79-
long long lval = PyLong_AsLongLong(py_int);
80-
Py_DECREF(py_int);
8179

82-
if (backend == BACKEND_SLEEF) {
83-
self->value.sleef_value = Sleef_cast_from_int64q1(lval);
80+
int overflow = 0;
81+
long long lval = PyLong_AsLongLongAndOverflow(py_int, &overflow);
82+
83+
if (overflow != 0)
84+
{
85+
// Integer is too large, convert to string and recursively call this function
86+
PyObject *str_obj = PyObject_Str(py_int);
87+
Py_DECREF(py_int);
88+
if (str_obj == NULL) {
89+
Py_DECREF(self);
90+
return NULL;
91+
}
92+
93+
// Recursively convert from string
94+
QuadPrecisionObject *result = QuadPrecision_from_object(str_obj, backend);
95+
Py_DECREF(str_obj);
96+
Py_DECREF(self); // discard the default one
97+
return result;
98+
}
99+
else if (lval == -1 && PyErr_Occurred()) {
100+
Py_DECREF(py_int);
101+
Py_DECREF(self);
102+
return NULL;
84103
}
85104
else {
86-
self->value.longdouble_value = (long double)lval;
105+
Py_DECREF(py_int);
106+
if (backend == BACKEND_SLEEF) {
107+
self->value.sleef_value = Sleef_cast_from_int64q1(lval);
108+
}
109+
else {
110+
self->value.longdouble_value = (long double)lval;
111+
}
87112
}
88113
return self;
89114
}
@@ -94,14 +119,38 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
94119
Py_DECREF(self);
95120
return NULL;
96121
}
97-
long long lval = PyLong_AsLongLong(py_int);
98-
Py_DECREF(py_int);
99122

100-
if (backend == BACKEND_SLEEF) {
101-
self->value.sleef_value = Sleef_cast_from_int64q1(lval);
123+
int overflow = 0;
124+
long long lval = PyLong_AsLongLongAndOverflow(py_int, &overflow);
125+
126+
if (overflow != 0) {
127+
// Integer is too large, convert to string and recursively call this function
128+
PyObject *str_obj = PyObject_Str(py_int);
129+
Py_DECREF(py_int);
130+
if (str_obj == NULL) {
131+
Py_DECREF(self);
132+
return NULL;
133+
}
134+
135+
// Recursively convert from string
136+
QuadPrecisionObject *result = QuadPrecision_from_object(str_obj, backend);
137+
Py_DECREF(str_obj);
138+
Py_DECREF(self); // discard the default one
139+
return result;
140+
}
141+
else if (lval == -1 && PyErr_Occurred()) {
142+
Py_DECREF(py_int);
143+
Py_DECREF(self);
144+
return NULL;
102145
}
103146
else {
104-
self->value.longdouble_value = (long double)lval;
147+
Py_DECREF(py_int);
148+
if (backend == BACKEND_SLEEF) {
149+
self->value.sleef_value = Sleef_cast_from_int64q1(lval);
150+
}
151+
else {
152+
self->value.longdouble_value = (long double)lval;
153+
}
105154
}
106155
return self;
107156
}
@@ -145,7 +194,7 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
145194
self->value.longdouble_value = (long double)dval;
146195
}
147196
}
148-
else if (PyUnicode_CheckExact(value)) {
197+
else if (PyUnicode_Check(value)) {
149198
const char *s = PyUnicode_AsUTF8(value);
150199
char *endptr = NULL;
151200
if (backend == BACKEND_SLEEF) {
@@ -161,17 +210,35 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
161210
}
162211
}
163212
else if (PyLong_Check(value)) {
164-
long long val = PyLong_AsLongLong(value);
165-
if (val == -1 && PyErr_Occurred()) {
166-
PyErr_SetString(PyExc_OverflowError, "Overflow Error, value out of range");
213+
int overflow = 0;
214+
long long val = PyLong_AsLongLongAndOverflow(value, &overflow);
215+
216+
if (overflow != 0) {
217+
// Integer is too large, convert to string and recursively call this function
218+
PyObject *str_obj = PyObject_Str(value);
219+
if (str_obj == NULL) {
220+
Py_DECREF(self);
221+
return NULL;
222+
}
223+
224+
// Recursively convert from string
225+
QuadPrecisionObject *result = QuadPrecision_from_object(str_obj, backend);
226+
Py_DECREF(str_obj);
227+
Py_DECREF(self); // discard the default one
228+
return result;
229+
}
230+
else if (val == -1 && PyErr_Occurred()) {
167231
Py_DECREF(self);
168232
return NULL;
169233
}
170-
if (backend == BACKEND_SLEEF) {
171-
self->value.sleef_value = Sleef_cast_from_int64q1(val);
172-
}
173234
else {
174-
self->value.longdouble_value = (long double)val;
235+
// No overflow, use the integer value directly
236+
if (backend == BACKEND_SLEEF) {
237+
self->value.sleef_value = Sleef_cast_from_int64q1(val);
238+
}
239+
else {
240+
self->value.longdouble_value = (long double)val;
241+
}
175242
}
176243
}
177244
else if (Py_TYPE(value) == &QuadPrecision_Type) {

quaddtype/tests/test_quaddtype.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,45 @@ def test_create_scalar_simple():
1616
assert isinstance(QuadPrecision(1), QuadPrecision)
1717

1818

19+
@pytest.mark.parametrize("int_val", [
20+
# Very large integers that exceed long double range
21+
2 ** 1024,
22+
2 ** 2048,
23+
10 ** 308,
24+
10 ** 4000,
25+
# Edge cases
26+
0,
27+
1,
28+
-1,
29+
# Negative large integers
30+
-(2 ** 1024),
31+
])
32+
def test_create_scalar_from_large_int(int_val):
33+
"""Test that QuadPrecision can handle very large integers beyond long double range.
34+
35+
This test ensures that integers like 2**1024, which overflow standard long double,
36+
are properly converted via string representation to QuadPrecision without raising
37+
overflow errors. The conversion should match the string-based conversion.
38+
"""
39+
# Convert large int to QuadPrecision
40+
result = QuadPrecision(int_val)
41+
assert isinstance(result, QuadPrecision)
42+
43+
# String conversion should give the same result
44+
str_val = str(int_val)
45+
result_from_str = QuadPrecision(str_val)
46+
47+
# Both conversions should produce the same value
48+
# (can be inf==inf on some platforms for very large values)
49+
assert result == result_from_str
50+
51+
# For zero and small values, verify exact conversion
52+
if int_val == 0:
53+
assert float(result) == 0.0
54+
elif abs(int_val) == 1:
55+
assert float(result) == float(int_val)
56+
57+
1958
class TestQuadPrecisionArrayCreation:
2059
"""Test suite for QuadPrecision array creation from sequences and arrays."""
2160

0 commit comments

Comments
 (0)