Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/test_old_cpu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ jobs:

- name: Install Intel SDE
run: |
curl -o /tmp/sde.tar.xz https://downloadmirror.intel.com/859732/sde-external-9.58.0-2025-06-16-lin.tar.xz
SDE_URL="https://github.com/SwayamInSync/numpy-quaddtype/releases/download/sde-toolchain/sde-external-10.8.0-2026-03-15-lin.tar.xz"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL isn't working for curl(same in NumPy repo), although interactively works.
Self-hosting from my fork, till some other solution comes in

SDE_SHA256="50b320cd226acef7a491f5b321fc1be3c3c7984f9e27a456e64894b5b0979dd3"
curl -fSL -o /tmp/sde.tar.xz "$SDE_URL"
echo "$SDE_SHA256 /tmp/sde.tar.xz" | sha256sum -c -
mkdir /tmp/sde && tar -xvf /tmp/sde.tar.xz -C /tmp/sde/
sudo mv /tmp/sde/* /opt/sde && sudo ln -s /opt/sde/sde64 /usr/bin/sde

Expand Down
54 changes: 43 additions & 11 deletions src/csrc/scalar.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <sleef.h>
#include <sleefquad.h>
#include <stdlib.h>
#include <math.h>

#define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API
#define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION
Expand All @@ -21,6 +22,11 @@
#include "pythoncapi_compat.h"


// forward declaration
static Sleef_quad
longdouble_to_quad(long double value);


QuadPrecisionObject *
QuadPrecision_raw_new(QuadBackendType backend)
{
Expand Down Expand Up @@ -443,8 +449,7 @@ QuadPrecision_is_integer(QuadPrecisionObject *self, PyObject *Py_UNUSED(ignored)
value = self->value.sleef_value;
}
else {
// lets also tackle ld from sleef functions as well
value = Sleef_cast_from_doubleq1((double)self->value.longdouble_value);
value = longdouble_to_quad(self->value.longdouble_value);
}

if(Sleef_iunordq1(value, value)) {
Expand All @@ -462,9 +467,7 @@ QuadPrecision_is_integer(QuadPrecisionObject *self, PyObject *Py_UNUSED(ignored)

// Check if value equals its truncated version
Sleef_quad truncated = Sleef_truncq1(value);
int32_t is_equal = Sleef_icmpeqq1(value, truncated);

if (is_equal) {
if (Sleef_icmpeqq1(value, truncated)) {
Py_RETURN_TRUE;
}
else {
Expand All @@ -474,7 +477,7 @@ QuadPrecision_is_integer(QuadPrecisionObject *self, PyObject *Py_UNUSED(ignored)

PyObject* quad_to_pylong(Sleef_quad value)
{
char buffer[128];
char buffer[4936]; // 4933 + sign + null terminator, enough for 128-bit integer in decimal

// Sleef_snprintf call is thread-unsafe
LOCK_SLEEF;
Expand All @@ -492,6 +495,37 @@ PyObject* quad_to_pylong(Sleef_quad value)
return result;
}

PyObject* longdouble_to_pylong(long double value)
{
char buffer[4936]; // 4933 + sign + null terminator, enough for 128-bit integer in decimal

// POSIX guarantees thread-safety of snprintf
int written = snprintf(buffer, sizeof(buffer), "%.0Lf", value);
if (written < 0 || written >= sizeof(buffer)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to convert long double to string");
return NULL;
}

// Already raises ValueError and returns NULL on failure
return PyLong_FromString(buffer, NULL, 10);
}

static Sleef_quad
longdouble_to_quad(long double value)
{
if (isnan(value) || isinf(value) || value == 0.0L)
return Sleef_cast_from_doubleq1((double)value);

int exp;
long double mantissa = frexpl(value, &exp);
long double scaled = ldexpl(mantissa, 64);
exp -= 64;
Sleef_quad q = (scaled < 0)
? Sleef_negq1(Sleef_cast_from_uint64q1((uint64_t)(-scaled)))
: Sleef_cast_from_uint64q1((uint64_t)scaled);
return Sleef_ldexpq1(q, exp);
}

// inspired by the CPython implementation
// https://github.com/python/cpython/blob/ac1ffd77858b62d169a08040c08aa5de26e145ac/Objects/floatobject.c#L1503C1-L1572C2
static PyObject *
Expand All @@ -504,10 +538,8 @@ QuadPrecision_as_integer_ratio(QuadPrecisionObject *self, PyObject *Py_UNUSED(ig

if (self->backend == BACKEND_SLEEF) {
value = self->value.sleef_value;
}
else {
// lets also tackle ld from sleef functions as well
value = Sleef_cast_from_doubleq1((double)self->value.longdouble_value);
} else {
value = longdouble_to_quad(self->value.longdouble_value);
}

if(Sleef_iunordq1(value, value)) {
Expand Down Expand Up @@ -653,7 +685,7 @@ QuadPrecision_hash(QuadPrecisionObject *self)
value = self->value.sleef_value;
}
else {
value = Sleef_cast_from_doubleq1((double)self->value.longdouble_value);
value = longdouble_to_quad(self->value.longdouble_value);
}

// Check for NaN - use pointer hash (each NaN instance gets unique hash)
Expand Down
33 changes: 29 additions & 4 deletions src/csrc/scalar_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#define NPY_TARGET_VERSION NPY_2_4_API_VERSION
#define NO_IMPORT_ARRAY

#include <cmath>

extern "C" {
#include <Python.h>

Expand Down Expand Up @@ -224,12 +226,35 @@ QuadPrecision_float(QuadPrecisionObject *self)
static PyObject *
QuadPrecision_int(QuadPrecisionObject *self)
{
if (self->backend == BACKEND_SLEEF) {
return PyLong_FromLongLong(Sleef_cast_to_int64q1(self->value.sleef_value));
if (self->backend == BACKEND_SLEEF)
{
Sleef_quad value = self->value.sleef_value;
if (quad_isnan(&value)) {
PyErr_SetString(PyExc_ValueError, "cannot convert float NaN to integer");
return NULL;
}
else {
return PyLong_FromLongLong((long long)self->value.longdouble_value);
if (quad_isinf(&value))
{
PyErr_SetString(PyExc_OverflowError,
"cannot convert float infinity to integer");
return NULL;
}
return quad_to_pylong(Sleef_truncq1(value));

}

long double value = self->value.longdouble_value;
if(std::isnan(value))
{
PyErr_SetString(PyExc_ValueError, "cannot convert float NaN to integer");
return NULL;
}
if(std::isinf(value))
{
PyErr_SetString(PyExc_OverflowError, "cannot convert float infinity to integer");
return NULL;
}
return longdouble_to_pylong(truncl(value));
}

template <binary_op_quad_def sleef_op, binary_op_longdouble_def longdouble_op>
Expand Down
6 changes: 6 additions & 0 deletions src/include/scalar.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern "C" {

#include <Python.h>
#include <sleef.h>
#include <sleefquad.h>
#include "quad_common.h"

typedef struct {
Expand All @@ -26,6 +27,11 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend);
int
init_quadprecision_scalar(void);

PyObject *
quad_to_pylong(Sleef_quad value);
PyObject *
longdouble_to_pylong(long double value);

#ifdef __cplusplus
}
#endif
Expand Down
Loading
Loading