Skip to content

Commit 380fb83

Browse files
authored
Merge pull request #141 from SwayamInSync/main
[Fix] Same Subnormal value over all platform
2 parents 47c9409 + 1ced8a6 commit 380fb83

File tree

5 files changed

+95
-3
lines changed

5 files changed

+95
-3
lines changed

quaddtype/meson.build

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,44 @@ if openmp_dep.found()
3030
dependencies += openmp_dep
3131
endif
3232

33+
# Thread-local storage detection (borrowed from NumPy)
34+
optional_variable_attributes = [
35+
['thread_local', 'HAVE_THREAD_LOCAL'], # C23
36+
['_Thread_local', 'HAVE__THREAD_LOCAL'], # C11/C17
37+
['__thread', 'HAVE___THREAD'], # GCC/Clang
38+
['__declspec(thread)', 'HAVE___DECLSPEC_THREAD_'] # MSVC
39+
]
40+
41+
if not is_variable('cdata')
42+
cdata = configuration_data()
43+
endif
44+
45+
foreach optional_attr: optional_variable_attributes
46+
attr = optional_attr[0]
47+
code = '''
48+
#pragma GCC diagnostic error "-Wattributes"
49+
#pragma clang diagnostic error "-Wattributes"
50+
51+
int @0@ foo;
52+
53+
int main() {
54+
return 0;
55+
}
56+
'''.format(attr)
57+
58+
if c.compiles(code, name: optional_attr[0])
59+
cdata.set10(optional_attr[1], true)
60+
message('Thread-local storage support found: @0@'.format(attr))
61+
endif
62+
endforeach
63+
64+
configure_file(
65+
output: 'quaddtype_config.h',
66+
configuration: cdata
67+
)
68+
69+
build_includes = include_directories('.')
70+
3371
includes = include_directories(
3472
[
3573
incdir_numpy,
@@ -84,5 +122,5 @@ py.extension_module('_quaddtype_main',
84122
dependencies: dependencies,
85123
install: true,
86124
subdir: 'numpy_quaddtype',
87-
include_directories: includes
125+
include_directories: [includes, build_includes]
88126
)

quaddtype/numpy_quaddtype/src/dragon4.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ Modifications are specific to support the SLEEF_QUAD
1111
#include <sleef.h>
1212
#include <sleefquad.h>
1313

14+
#include "quaddtype_config.h"
15+
16+
1417
#define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API
1518
#define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API
1619
#define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION
@@ -22,6 +25,21 @@ Modifications are specific to support the SLEEF_QUAD
2225
#include "dtype.h"
2326
#include "scalar.h"
2427

28+
29+
#ifdef __cplusplus
30+
#define NPY_TLS thread_local
31+
#elif defined(HAVE_THREAD_LOCAL)
32+
#define NPY_TLS thread_local
33+
#elif defined(HAVE__THREAD_LOCAL)
34+
#define NPY_TLS _Thread_local
35+
#elif defined(HAVE___THREAD)
36+
#define NPY_TLS __thread
37+
#elif defined(HAVE___DECLSPEC_THREAD_)
38+
#define NPY_TLS __declspec(thread)
39+
#else
40+
#define NPY_TLS
41+
#endif
42+
2543
#if 0
2644
#define DEBUG_ASSERT(stmnt) assert(stmnt)
2745
#else

quaddtype/numpy_quaddtype/src/quaddtype_main.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,29 @@ py_is_longdouble_128(PyObject *self, PyObject *args)
3030
}
3131
}
3232

33+
#ifdef SLEEF_QUAD_C
34+
static const Sleef_quad SMALLEST_SUBNORMAL_VALUE = SLEEF_QUAD_DENORM_MIN;
35+
#else
36+
// Use the exact same struct layout as the original buggy code
37+
static const union {
38+
struct {
39+
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
40+
uint64_t h, l;
41+
#else
42+
uint64_t l, h;
43+
#endif
44+
} parts;
45+
Sleef_quad value;
46+
} smallest_subnormal_const = {.parts = {
47+
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
48+
.h = 0x0000000000000000ULL, .l = 0x0000000000000001ULL
49+
#else
50+
.l = 0x0000000000000001ULL, .h = 0x0000000000000000ULL
51+
#endif
52+
}};
53+
#define SMALLEST_SUBNORMAL_VALUE (smallest_subnormal_const.value)
54+
#endif
55+
3356
static PyObject *
3457
get_sleef_constant(PyObject *self, PyObject *args)
3558
{
@@ -71,7 +94,7 @@ get_sleef_constant(PyObject *self, PyObject *args)
7194
result->value.sleef_value = SLEEF_QUAD_MIN;
7295
}
7396
else if (strcmp(constant_name, "smallest_subnormal") == 0) {
74-
result->value.sleef_value = SLEEF_QUAD_DENORM_MIN;
97+
result->value.sleef_value = SMALLEST_SUBNORMAL_VALUE;
7598
}
7699
else if (strcmp(constant_name, "bits") == 0) {
77100
Py_DECREF(result);

quaddtype/numpy_quaddtype/src/scalar.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
#include "scalar_ops.h"
1616
#include "dragon4.h"
1717

18+
1819
QuadPrecisionObject *
1920
QuadPrecision_raw_new(QuadBackendType backend)
2021
{
21-
QuadPrecisionObject *new = PyObject_New(QuadPrecisionObject, &QuadPrecision_Type);
22+
QuadPrecisionObject *new;
23+
new = PyObject_New(QuadPrecisionObject, &QuadPrecision_Type);
24+
2225
if (!new)
2326
return NULL;
2427
new->backend = backend;

quaddtype/tests/test_quaddtype.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ def test_finfo_constant(name):
2424
assert isinstance(getattr(numpy_quaddtype, name), QuadPrecision)
2525

2626

27+
def test_smallest_subnormal_value():
28+
"""Test that smallest_subnormal has the correct value across all platforms."""
29+
smallest_sub = numpy_quaddtype.smallest_subnormal
30+
repr_str = repr(smallest_sub)
31+
32+
# The repr should show QuadPrecision('6.0e-4966', backend='sleef')
33+
assert "6.0e-4966" in repr_str, f"Expected '6.0e-4966' in repr, got {repr_str}"
34+
35+
assert smallest_sub > 0, "smallest_subnormal should be positive"
36+
2737
@pytest.mark.parametrize("name,value", [("bits", 128), ("precision", 33)])
2838
def test_finfo_int_constant(name, value):
2939
assert getattr(numpy_quaddtype, name) == value

0 commit comments

Comments
 (0)