aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2026-01-11 19:57:48 -0500
committerBruce Hill <bruce@bruce-hill.com>2026-01-11 19:57:48 -0500
commit4d47947b1564656fda307b01d6bcc145678c3a31 (patch)
tree47484beaaf5f325bd32311d2cdb87c6e2514e922
parent5d5c7b572f39b72e41ddaab3c69413af6e0e4846 (diff)
Bugfixes for promoting doubles to rational
-rw-r--r--src/stdlib/reals.c46
-rw-r--r--test/reals.tm2
2 files changed, 15 insertions, 33 deletions
diff --git a/src/stdlib/reals.c b/src/stdlib/reals.c
index 2ee6da40..6a6d7dc7 100644
--- a/src/stdlib/reals.c
+++ b/src/stdlib/reals.c
@@ -129,7 +129,7 @@ bool Real$get_rational(Real_t x, int64_t *num, int64_t *den) {
// Promote double to exact type if needed
static Real_t promote_double(double d) {
- if (isfinite(d) && d == floor(d) && fabs(d) < (1LL << 53)) {
+ if (!isfinite(d)) {
return make_double(d);
}
rational_t *r = GC_MALLOC(sizeof(rational_t));
@@ -213,21 +213,10 @@ Real_t Real$plus(Real_t a, Real_t b) {
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
- a = promote_double(a.d);
- b = promote_double(b.d);
}
- // Handle mixed rational/double cases by promoting double to rational
- if (Real$is_boxed(a) && Real$tag(a) == REAL_TAG_RATIONAL && !Real$is_boxed(b)) {
- if (isfinite(b.d)) {
- b = promote_double(b.d);
- }
- }
- if (!Real$is_boxed(a) && Real$is_boxed(b) && Real$tag(b) == REAL_TAG_RATIONAL) {
- if (isfinite(a.d)) {
- a = promote_double(a.d);
- }
- }
+ if (!Real$is_boxed(a)) a = promote_double(a.d);
+ if (!Real$is_boxed(b)) b = promote_double(b.d);
// Handle exact rational arithmetic
if (Real$tag(a) == REAL_TAG_RATIONAL && Real$tag(b) == REAL_TAG_RATIONAL) {
@@ -255,10 +244,11 @@ Real_t Real$minus(Real_t a, Real_t b) {
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
- a = promote_double(a.d);
- b = promote_double(b.d);
}
+ if (!Real$is_boxed(a)) a = promote_double(a.d);
+ if (!Real$is_boxed(b)) b = promote_double(b.d);
+
if (Real$tag(a) == REAL_TAG_RATIONAL && Real$tag(b) == REAL_TAG_RATIONAL) {
rational_t *ra = get_ptr(a);
rational_t *rb = get_ptr(b);
@@ -283,21 +273,10 @@ Real_t Real$times(Real_t a, Real_t b) {
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
- a = promote_double(a.d);
- b = promote_double(b.d);
}
- // Handle mixed rational/double cases by promoting double to rational
- if (Real$is_boxed(a) && Real$tag(a) == REAL_TAG_RATIONAL && !Real$is_boxed(b)) {
- if (isfinite(b.d)) {
- b = promote_double(b.d);
- }
- }
- if (!Real$is_boxed(a) && Real$is_boxed(b) && Real$tag(b) == REAL_TAG_RATIONAL) {
- if (isfinite(a.d)) {
- a = promote_double(a.d);
- }
- }
+ if (!Real$is_boxed(a)) a = promote_double(a.d);
+ if (!Real$is_boxed(b)) b = promote_double(b.d);
if (Real$tag(a) == REAL_TAG_RATIONAL && Real$tag(b) == REAL_TAG_RATIONAL) {
rational_t *ra = get_ptr(a);
@@ -339,10 +318,11 @@ Real_t Real$divided_by(Real_t a, Real_t b) {
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
- a = promote_double(a.d);
- b = promote_double(b.d);
}
+ if (!Real$is_boxed(a)) a = promote_double(a.d);
+ if (!Real$is_boxed(b)) b = promote_double(b.d);
+
if (Real$tag(a) == REAL_TAG_RATIONAL && Real$tag(b) == REAL_TAG_RATIONAL) {
rational_t *ra = get_ptr(a);
rational_t *rb = get_ptr(b);
@@ -844,7 +824,9 @@ PUREFUNC bool Real$is_none(const void *vn, const TypeInfo_t *type) {
public
bool Real$equal_values(Real_t a, Real_t b) {
if (!Real$is_boxed(a) && !Real$is_boxed(b)) return a.d == b.d;
- if (Real$is_boxed(a) != Real$is_boxed(b)) return 0;
+
+ if (!Real$is_boxed(a)) a = promote_double(a.d);
+ if (!Real$is_boxed(b)) b = promote_double(b.d);
if (Real$tag(a) == REAL_TAG_RATIONAL && Real$tag(b) == REAL_TAG_RATIONAL) {
rational_t *ra = get_ptr(a);
diff --git a/test/reals.tm b/test/reals.tm
index afb2f5f0..46ff6867 100644
--- a/test/reals.tm
+++ b/test/reals.tm
@@ -69,7 +69,7 @@ func main()
# Modulo
assert 7. mod 3. == 1.
assert -7. mod 3. == 2. # Euclidean division
- assert 7. mod -3. == -2.
+ assert 7. mod -3. == 1.
assert 2.5 mod 1.0 == 0.5
# Mod1