Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/big_endian.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ permissions:

jobs:
big_endian_tests:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
continue-on-error: true
strategy:
fail-fast: false
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- uses: astral-sh/setup-uv@v7.1.4
with:
activate-environment: true
python-version: "3.11"
python-version: "3.12"

- name: install
working-directory: quaddtype
Expand Down
16 changes: 13 additions & 3 deletions quaddtype/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ if sleef_dep.found() and sleef_dep.type_name() != 'internal'
# SLEEF found system-wide - verify quad-precision support
cpp = meson.get_compiler('cpp')
sleefquad_lib = cpp.find_library('sleefquad', required: false)
tlfloat_lib = cpp.find_library('tlfloat', required: false)

if sleefquad_lib.found()
if sleefquad_lib.found() and tlfloat_lib.found()
sleefquad_test_code = '''
#include <sleefquad.h>

Expand All @@ -40,14 +41,17 @@ if sleef_dep.found() and sleef_dep.type_name() != 'internal'
# this should compile and link
quad_works = cpp.links(
sleefquad_test_code,
dependencies: [sleef_dep, sleefquad_lib],
dependencies: [sleef_dep, sleefquad_lib, tlfloat_lib],
name: 'SLEEF quad-precision support'
)

if quad_works
sleefquad_dep = declare_dependency(
dependencies: [sleef_dep, sleefquad_lib]
)
tlfloat_dep = declare_dependency(
dependencies: [tlfloat_lib]
)
use_system_sleef = true
else
fallback_reason = 'System-wide SLEEF installation found but a test for quad precision support failed.'
Expand All @@ -65,6 +69,7 @@ else
sleef_subproj = subproject('sleef')
sleef_dep = sleef_subproj.get_variable('sleef_dep')
sleefquad_dep = sleef_subproj.get_variable('sleefquad_dep')
tlfloat_dep = sleef_subproj.get_variable('tlfloat_dep')
warning(fallback_reason)
message('Proceeding with vendored SLEEF subproject instead')
endif
Expand All @@ -84,7 +89,7 @@ message('Using NumPy version: @0@'.format(numpy_version))
npymath_path = incdir_numpy / '..' / 'lib'
npymath_lib = c.find_library('npymath', dirs: npymath_path)

dependencies = [py_dep, qblas_dep, sleef_dep, sleefquad_dep, npymath_lib]
dependencies = [py_dep, qblas_dep, sleef_dep, sleefquad_dep, tlfloat_dep, npymath_lib]

# Add OpenMP dependency (optional, for threading)
openmp_dep = dependency('openmp', required: false, static: false)
Expand All @@ -99,6 +104,11 @@ if not is_windows
if cpp.has_argument('-fext-numeric-literals')
add_project_arguments('-fext-numeric-literals', language: 'cpp')
endif

# Suppress warnings from system headers (sleefquad.h has many unused inline functions)
if cpp.has_argument('-Wno-unused-function')
add_project_arguments('-Wno-unused-function', language: ['c', 'cpp'])
endif
endif

# Thread-local storage detection (borrowed from NumPy)
Expand Down
2 changes: 1 addition & 1 deletion quaddtype/numpy_quaddtype/_quaddtype_main.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class QuadPrecision(np.floating[_128Bit]):
@override
def __add__(self, other: _IntoQuad, /) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
@override
def __radd__(self, other: _IntoQuad, /) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
def __radd__(self, other: _IntoQuad, /) -> Self: ... # type: ignore[override, misc] # pyright: ignore[reportIncompatibleMethodOverride]
@override
def __sub__(self, other: _IntoQuad, /) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
@override
Expand Down
9 changes: 5 additions & 4 deletions quaddtype/numpy_quaddtype/src/dragon4.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ Modifications are specific to support the SLEEF_QUAD
#include "scalar.h"


// Undefine NPY_TLS if already defined (avoid redefinition warning)
#ifdef NPY_TLS
#undef NPY_TLS
#endif

#ifdef __cplusplus
#define NPY_TLS thread_local
#elif defined(HAVE_THREAD_LOCAL)
Expand Down Expand Up @@ -2005,8 +2010,6 @@ PyObject *
Dragon4_Positional(PyObject *obj, DigitMode digit_mode, CutoffMode cutoff_mode, int precision,
int min_digits, int sign, TrimMode trim, int pad_left, int pad_right)
{
npy_double v;

if (PyObject_TypeCheck(obj, &QuadPrecision_Type)) {
QuadPrecisionObject *quad_obj = (QuadPrecisionObject *)obj;
if (quad_obj->backend == BACKEND_SLEEF) {
Expand All @@ -2028,8 +2031,6 @@ PyObject *
Dragon4_Scientific(PyObject *obj, DigitMode digit_mode, int precision, int min_digits, int sign,
TrimMode trim, int pad_left, int exp_digits)
{
npy_double val;

if (PyObject_TypeCheck(obj, &QuadPrecision_Type)) {
QuadPrecisionObject *quad_obj = (QuadPrecisionObject *)obj;
if (quad_obj->backend == BACKEND_SLEEF) {
Expand Down
8 changes: 4 additions & 4 deletions quaddtype/numpy_quaddtype/src/dtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,11 @@ quadprec_scanfunc(FILE *fp, void *dptr, char *ignore, PyArray_Descr *descr_gener
}
buffer[i] = '\0';

/* Convert string to quad precision */
/* Convert string to quad precision (supports inf/nan) */
char *endptr;
quad_value val;
int err = cstring_to_quad(buffer, descr->backend, &val, &endptr, true);
if (err < 0) {
int err = NumPyOS_ascii_strtoq(buffer, descr->backend, &val, &endptr);
if (err < 0 || *endptr != '\0') {
return 0; /* Return 0 on parse error (no items read) */
}
if (descr->backend == BACKEND_SLEEF) {
Expand All @@ -376,7 +376,7 @@ quadprec_fromstr(char *s, void *dptr, char **endptr, PyArray_Descr *descr_generi
{
QuadPrecDTypeObject *descr = (QuadPrecDTypeObject *)descr_generic;
quad_value val;
int err = cstring_to_quad(s, descr->backend, &val, endptr, false);
int err = NumPyOS_ascii_strtoq(s, descr->backend, &val, endptr);
if (err < 0) {
return -1;
}
Expand Down
8 changes: 4 additions & 4 deletions quaddtype/numpy_quaddtype/src/ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ typedef Sleef_quad (*unary_op_quad_def)(const Sleef_quad *);
// Unary Quad operations with 2 outputs (for modf, frexp)
typedef void (*unary_op_2out_quad_def)(const Sleef_quad *, Sleef_quad *, Sleef_quad *);

static Sleef_quad
[[maybe_unused]] static Sleef_quad
quad_negative(const Sleef_quad *op)
{
return Sleef_negq1(*op);
}

static Sleef_quad
[[maybe_unused]] static Sleef_quad
quad_positive(const Sleef_quad *op)
{
return *op;
Expand Down Expand Up @@ -929,15 +929,15 @@ static inline Sleef_quad quad_set_words64(int64_t hx, uint64_t lx)
static inline Sleef_quad
quad_nextafter(const Sleef_quad *x, const Sleef_quad *y)
{
int64_t hx, hy, ix, iy;
int64_t hx, hy, ix;
uint64_t lx, ly;

quad_get_words64(&hx, &lx, *x);
quad_get_words64(&hy, &ly, *y);

// extracting absolute value
ix = hx & 0x7fffffffffffffffLL;
iy = hy & 0x7fffffffffffffffLL;
(void)ly; // unused but needed for quad_get_words64

// NaN if either is NaN
if (Sleef_iunordq1(*x, *y)) {
Expand Down
35 changes: 20 additions & 15 deletions quaddtype/numpy_quaddtype/src/scalar.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,21 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
else if (PyUnicode_Check(value)) {
const char *s = PyUnicode_AsUTF8(value);
char *endptr = NULL;
int err = cstring_to_quad(s, backend, &self->value, &endptr, true);
int err = NumPyOS_ascii_strtoq(s, backend, &self->value, &endptr);
if (err < 0) {
PyErr_SetString(PyExc_ValueError, "Unable to parse string to QuadPrecision");
Py_DECREF(self);
return NULL;
}
// Skip trailing whitespace (matches Python's float() behavior)
while (ascii_isspace(*endptr)) {
endptr++;
}
if (*endptr != '\0') {
PyErr_SetString(PyExc_ValueError, "Unable to parse string to QuadPrecision");
Py_DECREF(self);
return NULL;
}
}
else if (PyBytes_Check(value)) {
const char *s = PyBytes_AsString(value);
Expand All @@ -205,12 +214,21 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
return NULL;
}
char *endptr = NULL;
int err = cstring_to_quad(s, backend, &self->value, &endptr, true);
int err = NumPyOS_ascii_strtoq(s, backend, &self->value, &endptr);
if (err < 0) {
PyErr_SetString(PyExc_ValueError, "Unable to parse bytes to QuadPrecision");
Py_DECREF(self);
return NULL;
}
// Skip trailing whitespace (matches Python's float() behavior)
while (ascii_isspace(*endptr)) {
endptr++;
}
if (*endptr != '\0') {
PyErr_SetString(PyExc_ValueError, "Unable to parse bytes to QuadPrecision");
Py_DECREF(self);
return NULL;
}
}
else if (PyLong_Check(value)) {
return quad_from_py_int(value, backend, self);
Expand Down Expand Up @@ -320,19 +338,6 @@ QuadPrecision_str(QuadPrecisionObject *self)
return PyUnicode_FromString(buffer);
}

static PyObject *
QuadPrecision_repr(QuadPrecisionObject *self)
{
PyObject *str = QuadPrecision_str(self);
if (str == NULL) {
return NULL;
}
const char *backend_str = (self->backend == BACKEND_SLEEF) ? "sleef" : "longdouble";
PyObject *res = PyUnicode_FromFormat("QuadPrecision('%S', backend='%s')", str, backend_str);
Py_DECREF(str);
return res;
}

static PyObject *
QuadPrecision_repr_dragon4(QuadPrecisionObject *self)
{
Expand Down
54 changes: 0 additions & 54 deletions quaddtype/numpy_quaddtype/src/umath/umath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,60 +25,6 @@ extern "C" {
#include "comparison_ops.h"
#include "matmul.h"

// helper debugging function
static const char *
get_dtype_name(PyArray_DTypeMeta *dtype)
{
if (dtype == &QuadPrecDType) {
return "QuadPrecDType";
}
else if (dtype == &PyArray_BoolDType) {
return "BoolDType";
}
else if (dtype == &PyArray_ByteDType) {
return "ByteDType";
}
else if (dtype == &PyArray_UByteDType) {
return "UByteDType";
}
else if (dtype == &PyArray_ShortDType) {
return "ShortDType";
}
else if (dtype == &PyArray_UShortDType) {
return "UShortDType";
}
else if (dtype == &PyArray_IntDType) {
return "IntDType";
}
else if (dtype == &PyArray_UIntDType) {
return "UIntDType";
}
else if (dtype == &PyArray_LongDType) {
return "LongDType";
}
else if (dtype == &PyArray_ULongDType) {
return "ULongDType";
}
else if (dtype == &PyArray_LongLongDType) {
return "LongLongDType";
}
else if (dtype == &PyArray_ULongLongDType) {
return "ULongLongDType";
}
else if (dtype == &PyArray_FloatDType) {
return "FloatDType";
}
else if (dtype == &PyArray_DoubleDType) {
return "DoubleDType";
}
else if (dtype == &PyArray_LongDoubleDType) {
return "LongDoubleDType";
}
else {
return "UnknownDType";
}
}

int
init_quad_umath(void)
{
Expand Down
Loading