aboutsummaryrefslogtreecommitdiff
path: root/src/stdlib
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2026-01-11 19:44:04 -0500
committerBruce Hill <bruce@bruce-hill.com>2026-01-11 19:44:04 -0500
commit5d5c7b572f39b72e41ddaab3c69413af6e0e4846 (patch)
treed5955d3efd3607b8a434133083bf53df998a1ff5 /src/stdlib
parent6068a746896407b5ef33bca72a8be6fced14439b (diff)
Fix some volatility issues
Diffstat (limited to 'src/stdlib')
-rw-r--r--src/stdlib/datatypes.h4
-rw-r--r--src/stdlib/reals.c50
2 files changed, 41 insertions, 13 deletions
diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h
index 085a507c..8e2b8da5 100644
--- a/src/stdlib/datatypes.h
+++ b/src/stdlib/datatypes.h
@@ -36,8 +36,8 @@ typedef union {
#define OptionalInt_t Int_t
typedef union {
- double d;
- uint64_t u64;
+ volatile double d;
+ volatile uint64_t u64;
} Real_t;
#define OptionalReal_t Real_t
diff --git a/src/stdlib/reals.c b/src/stdlib/reals.c
index e9a6b2ef..2ee6da40 100644
--- a/src/stdlib/reals.c
+++ b/src/stdlib/reals.c
@@ -25,6 +25,7 @@ typedef struct {
} constructive_t;
typedef enum {
+ SYM_INVALID,
SYM_ADD,
SYM_SUB,
SYM_MUL,
@@ -70,7 +71,8 @@ static inline void *get_ptr(Real_t n) {
return (void *)(uintptr_t)(n.u64 & PTR_MASK);
}
-static inline Real_t box_ptr(void *ptr, uint64_t tag) {
+static inline PUREFUNC Real_t box_ptr(void *ptr, uint64_t tag) {
+ assert(((uint64_t)(uintptr_t)ptr & (~PTR_MASK)) == 0);
Real_t n;
n.u64 = QNAN_MASK | tag | ((uint64_t)(uintptr_t)ptr & PTR_MASK);
return n;
@@ -173,6 +175,7 @@ double Real$as_float64(Real_t n, bool truncate) {
double left = Real$as_float64(s->left, truncate);
double right = Real$as_float64(s->right, truncate);
switch (s->op) {
+ case SYM_INVALID: fail("Invalid!");
case SYM_ADD: return left + right;
case SYM_SUB: return left - right;
case SYM_MUL: return left * right;
@@ -206,7 +209,7 @@ public
Real_t Real$plus(Real_t a, Real_t b) {
if (!Real$is_boxed(a) && !Real$is_boxed(b)) {
feclearexcept(FE_INEXACT);
- double result = a.d + b.d;
+ volatile double result = a.d + b.d;
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
@@ -214,6 +217,18 @@ Real_t Real$plus(Real_t a, Real_t b) {
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);
+ }
+ }
+
// Handle exact rational arithmetic
if (Real$tag(a) == REAL_TAG_RATIONAL && Real$tag(b) == REAL_TAG_RATIONAL) {
rational_t *ra = get_ptr(a);
@@ -236,7 +251,7 @@ public
Real_t Real$minus(Real_t a, Real_t b) {
if (!Real$is_boxed(a) && !Real$is_boxed(b)) {
feclearexcept(FE_INEXACT);
- double result = a.d - b.d;
+ volatile double result = a.d - b.d;
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
@@ -264,7 +279,7 @@ public
Real_t Real$times(Real_t a, Real_t b) {
if (!Real$is_boxed(a) && !Real$is_boxed(b)) {
feclearexcept(FE_INEXACT);
- double result = a.d * b.d;
+ volatile double result = a.d * b.d;
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
@@ -272,6 +287,18 @@ Real_t Real$times(Real_t a, Real_t b) {
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$tag(a) == REAL_TAG_RATIONAL && Real$tag(b) == REAL_TAG_RATIONAL) {
rational_t *ra = get_ptr(a);
rational_t *rb = get_ptr(b);
@@ -308,7 +335,7 @@ public
Real_t Real$divided_by(Real_t a, Real_t b) {
if (!Real$is_boxed(a) && !Real$is_boxed(b)) {
feclearexcept(FE_INEXACT);
- double result = a.d / b.d;
+ volatile double result = a.d / b.d;
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
@@ -427,9 +454,9 @@ Real_t Real$clamped(Real_t x, Real_t low, Real_t high) {
public
Real_t Real$sqrt(Real_t a) {
if (!Real$is_boxed(a)) {
- double d = sqrt(a.d);
feclearexcept(FE_INEXACT);
- double check = d * d;
+ volatile double d = sqrt(a.d);
+ volatile double check = d * d;
if (!fetestexcept(FE_INEXACT) && check == a.d) {
return make_double(d);
}
@@ -471,7 +498,7 @@ public
Real_t Real$power(Real_t base, Real_t exp) {
if (!Real$is_boxed(base) && !Real$is_boxed(exp)) {
feclearexcept(FE_INEXACT);
- double result = pow(base.d, exp.d);
+ volatile double result = pow(base.d, exp.d);
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
@@ -643,6 +670,7 @@ Text_t Real$as_text(const void *n, bool colorize, const TypeInfo_t *type) {
Text_t right = Real$as_text(&s->right, colorize, type);
switch (s->op) {
+ case SYM_INVALID: return Text("INVALID REAL NUMBER");
case SYM_ADD: return format_binary_op(left, right, " + ", colorize);
case SYM_SUB: return format_binary_op(left, right, " - ", colorize);
case SYM_MUL: return format_binary_op(left, right, " * ", colorize);
@@ -1058,7 +1086,7 @@ public
Real_t Real$exp(Real_t x) {
if (!Real$is_boxed(x)) {
feclearexcept(FE_INEXACT);
- double result = exp(x.d);
+ volatile double result = exp(x.d);
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
@@ -1075,7 +1103,7 @@ public
Real_t Real$log(Real_t x) {
if (!Real$is_boxed(x)) {
feclearexcept(FE_INEXACT);
- double result = log(x.d);
+ volatile double result = log(x.d);
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}
@@ -1092,7 +1120,7 @@ public
Real_t Real$log10(Real_t x) {
if (!Real$is_boxed(x)) {
feclearexcept(FE_INEXACT);
- double result = log10(x.d);
+ volatile double result = log10(x.d);
if (!fetestexcept(FE_INEXACT) && isfinite(result)) {
return make_double(result);
}