Skip to content

Commit cb3243d

Browse files
committed
adding is_integer
1 parent bbdd72c commit cb3243d

File tree

2 files changed

+141
-399
lines changed

2 files changed

+141
-399
lines changed

quaddtype/numpy_quaddtype/src/scalar.c

Lines changed: 6 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -393,13 +393,17 @@ QuadPrecision_is_integer(QuadPrecisionObject *self, PyObject *Py_UNUSED(ignored)
393393
value = self->value.sleef_value;
394394
}
395395
else {
396+
// lets also tackle ld from sleef functions as well
396397
value = Sleef_cast_from_doubleq1((double)self->value.longdouble_value);
397398
}
398399

400+
if(Sleef_iunordq1(value, value)) {
401+
Py_RETURN_FALSE;
402+
}
403+
399404
// Check if value is finite (not inf or nan)
400-
// Using the same approach as quad_isfinite: abs(x) < inf
401405
Sleef_quad abs_value = Sleef_fabsq1(value);
402-
Sleef_quad pos_inf = Sleef_cast_from_doubleq1(INFINITY);
406+
Sleef_quad pos_inf = sleef_q(+0x1000000000000LL, 0x0000000000000000ULL, 16384);
403407
int32_t is_finite = Sleef_icmpltq1(abs_value, pos_inf);
404408

405409
if (!is_finite) {
@@ -421,179 +425,7 @@ QuadPrecision_is_integer(QuadPrecisionObject *self, PyObject *Py_UNUSED(ignored)
421425
static PyObject *
422426
QuadPrecision_as_integer_ratio(QuadPrecisionObject *self, PyObject *Py_UNUSED(ignored))
423427
{
424-
Sleef_quad value;
425-
426-
if (self->backend == BACKEND_SLEEF) {
427-
value = self->value.sleef_value;
428-
}
429-
else {
430-
value = Sleef_cast_from_doubleq1((double)self->value.longdouble_value);
431-
}
432-
433-
// Check for infinity using: abs(x) == inf
434-
Sleef_quad abs_value = Sleef_fabsq1(value);
435-
Sleef_quad pos_inf = Sleef_cast_from_doubleq1(INFINITY);
436-
int32_t is_inf = Sleef_icmpeqq1(abs_value, pos_inf);
437-
438-
if (is_inf) {
439-
PyErr_SetString(PyExc_OverflowError, "cannot convert Infinity to integer ratio");
440-
return NULL;
441-
}
442-
443-
// Check for NaN using: x != x (NaN property)
444-
int32_t is_nan = !Sleef_icmpeqq1(value, value);
445-
446-
if (is_nan) {
447-
PyErr_SetString(PyExc_ValueError, "cannot convert NaN to integer ratio");
448-
return NULL;
449-
}
450-
451-
// Handle zero
452-
Sleef_quad zero = Sleef_cast_from_int64q1(0);
453-
if (Sleef_icmpeqq1(value, zero)) {
454-
PyObject *numerator = PyLong_FromLong(0);
455-
PyObject *denominator = PyLong_FromLong(1);
456-
if (!numerator || !denominator) {
457-
Py_XDECREF(numerator);
458-
Py_XDECREF(denominator);
459-
return NULL;
460-
}
461-
PyObject *result = PyTuple_Pack(2, numerator, denominator);
462-
Py_DECREF(numerator);
463-
Py_DECREF(denominator);
464-
return result;
465-
}
466-
467-
// Remember the sign and work with absolute value
468-
int is_negative = Sleef_icmpltq1(value, zero);
469-
abs_value = Sleef_fabsq1(value);
470-
471-
// Extract mantissa and exponent using frexp
472-
// frexp returns value = mantissa * 2^exponent, where 0.5 <= |mantissa| < 1
473-
int exponent;
474-
Sleef_quad mantissa = Sleef_frexpq1(abs_value, &exponent);
475-
476-
// For quad precision, we have 113 bits of precision
477-
// Scale mantissa by 2^113 to get all significant bits as an integer
478-
const int QUAD_MANT_DIG = 113;
479-
480-
// We'll build the numerator by converting the mantissa to a hex string
481-
// and parsing it, which preserves all the precision
482-
char hex_buffer[64];
483-
Sleef_snprintf(hex_buffer, sizeof(hex_buffer), "%.28Qa", mantissa);
484-
485-
// Parse the hex representation to get exact mantissa bits
486-
// The format is like "0x1.fffffp+0" or similar
487-
// We need to extract the mantissa and exponent separately
488-
489-
// Instead of using hex parsing (which is complex), let's use a different approach:
490-
// Build the mantissa as an integer by extracting 64-bit chunks
491-
492-
// Multiply mantissa by 2^113 to shift all bits into the integer part
493-
Sleef_quad scaled = Sleef_ldexpq1(mantissa, QUAD_MANT_DIG);
494-
495-
// Now extract the integer value in two 64-bit chunks
496-
// First get the upper 64 bits
497-
Sleef_quad two_64 = Sleef_cast_from_doubleq1(18446744073709551616.0); // 2^64
498-
Sleef_quad upper_part = Sleef_floorq1(Sleef_divq1_u05(scaled, two_64));
499-
uint64_t upper_bits = Sleef_cast_to_uint64q1(upper_part);
500-
501-
// Get the lower 64 bits
502-
Sleef_quad lower_part_quad = Sleef_subq1_u05(scaled, Sleef_mulq1_u05(upper_part, two_64));
503-
uint64_t lower_bits = Sleef_cast_to_uint64q1(lower_part_quad);
504-
505-
// Build Python integer from the two 64-bit parts
506-
PyObject *upper_py = PyLong_FromUnsignedLongLong(upper_bits);
507-
if (!upper_py) {
508-
return NULL;
509-
}
510-
511-
PyObject *shift_64 = PyLong_FromLong(64);
512-
if (!shift_64) {
513-
Py_DECREF(upper_py);
514-
return NULL;
515-
}
516-
517-
PyObject *shifted_upper = PyNumber_Lshift(upper_py, shift_64);
518-
Py_DECREF(upper_py);
519-
Py_DECREF(shift_64);
520-
if (!shifted_upper) {
521-
return NULL;
522-
}
523-
524-
PyObject *lower_py = PyLong_FromUnsignedLongLong(lower_bits);
525-
if (!lower_py) {
526-
Py_DECREF(shifted_upper);
527-
return NULL;
528-
}
529-
530-
PyObject *numerator = PyNumber_Add(shifted_upper, lower_py);
531-
Py_DECREF(shifted_upper);
532-
Py_DECREF(lower_py);
533-
if (!numerator) {
534-
return NULL;
535-
}
536-
537-
// Calculate the final exponent
538-
// value = mantissa * 2^exponent = (numerator / 2^113) * 2^exponent
539-
// value = numerator * 2^(exponent - 113)
540-
int final_exponent = exponent - QUAD_MANT_DIG;
541-
542-
PyObject *denominator;
543-
if (final_exponent >= 0) {
544-
// Shift numerator left
545-
PyObject *shift = PyLong_FromLong(final_exponent);
546-
if (!shift) {
547-
Py_DECREF(numerator);
548-
return NULL;
549-
}
550-
PyObject *new_numerator = PyNumber_Lshift(numerator, shift);
551-
Py_DECREF(shift);
552-
Py_DECREF(numerator);
553-
if (!new_numerator) {
554-
return NULL;
555-
}
556-
numerator = new_numerator;
557-
denominator = PyLong_FromLong(1);
558-
}
559-
else {
560-
// Shift denominator left (denominator = 2^(-final_exponent))
561-
PyObject *shift = PyLong_FromLong(-final_exponent);
562-
if (!shift) {
563-
Py_DECREF(numerator);
564-
return NULL;
565-
}
566-
PyObject *one = PyLong_FromLong(1);
567-
if (!one) {
568-
Py_DECREF(shift);
569-
Py_DECREF(numerator);
570-
return NULL;
571-
}
572-
denominator = PyNumber_Lshift(one, shift);
573-
Py_DECREF(one);
574-
Py_DECREF(shift);
575-
if (!denominator) {
576-
Py_DECREF(numerator);
577-
return NULL;
578-
}
579-
}
580-
581-
// Apply sign
582-
if (is_negative) {
583-
PyObject *new_numerator = PyNumber_Negative(numerator);
584-
Py_DECREF(numerator);
585-
if (!new_numerator) {
586-
Py_DECREF(denominator);
587-
return NULL;
588-
}
589-
numerator = new_numerator;
590-
}
591428

592-
// Create and return the tuple
593-
PyObject *result = PyTuple_Pack(2, numerator, denominator);
594-
Py_DECREF(numerator);
595-
Py_DECREF(denominator);
596-
return result;
597429
}
598430

599431
static PyMethodDef QuadPrecision_methods[] = {

0 commit comments

Comments
 (0)