aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2026-01-17 13:52:49 -0500
committerBruce Hill <bruce@bruce-hill.com>2026-01-17 13:52:49 -0500
commit819179c5838e9a2ebba69d5569f3c08d093194d2 (patch)
treeece13dd89641b93175c1e74348f40592d523d830
parent3112916e708278e4066792832cf40936825e4da6 (diff)
Simplify equality checks for common cases.
-rw-r--r--src/stdlib/reals.c35
-rw-r--r--src/stdlib/reals.h1
2 files changed, 35 insertions, 1 deletions
diff --git a/src/stdlib/reals.c b/src/stdlib/reals.c
index bbe19d0d..c7b101b6 100644
--- a/src/stdlib/reals.c
+++ b/src/stdlib/reals.c
@@ -211,6 +211,7 @@ public
Real_t Real$minus(Real_t a, Real_t b) {
if (Real$is_zero(b)) return a;
else if (Real$is_zero(a)) return Real$negative(b);
+ else if (Real$obviously_equal(a, b)) return R(0);
if (!Real$is_boxed(a) && !Real$is_boxed(b)) {
feclearexcept(FE_INEXACT);
@@ -270,6 +271,10 @@ Real_t Real$times(Real_t a, Real_t b) {
}
}
+ // Prefer putting symbolic in RHS to make simplifying easier
+ if (Real$tag(a) == REAL_TAG_SYMBOLIC && Real$tag(b) != REAL_TAG_SYMBOLIC)
+ return sym_to_real(.op = SYM_MUL, .left = b, .right = a);
+
return sym_to_real(.op = SYM_MUL, .left = a, .right = b);
}
@@ -738,9 +743,35 @@ PUREFUNC bool Real$is_none(const void *vn, const TypeInfo_t *type) {
// Equality check (may be undecidable for some symbolics)
public
-bool Real$equal_values(Real_t a, Real_t b) {
+PUREFUNC bool Real$obviously_equal(Real_t a, Real_t b) {
if (a.bits == b.bits) return true;
if (!Real$is_boxed(a) && !Real$is_boxed(b)) return REAL_DOUBLE(a) == REAL_DOUBLE(b);
+ if (Real$tag(a) != Real$tag(b)) return false;
+
+ switch (Real$tag(a)) {
+ case REAL_TAG_BIGINT: {
+ return Int$equal_value(*REAL_BIGINT(a), *REAL_BIGINT(b));
+ }
+ case REAL_TAG_RATIONAL: {
+ rational_t *ra = REAL_RATIONAL(a);
+ rational_t *rb = REAL_RATIONAL(b);
+ return mpq_equal(&ra->value, &rb->value);
+ }
+ case REAL_TAG_SYMBOLIC: {
+ symbolic_t *sa = REAL_SYMBOLIC(a);
+ symbolic_t *sb = REAL_SYMBOLIC(b);
+ if (sa->op != sb->op) return false;
+ return Real$obviously_equal(sa->left, sb->left) && Real$obviously_equal(sa->right, sb->right);
+ }
+ default: return false;
+ }
+}
+
+// Equality check (may be undecidable for some symbolics)
+public
+bool Real$equal_values(Real_t a, Real_t b) {
+ if (Real$obviously_equal(a, b)) return true;
+ if (!Real$is_boxed(a) && !Real$is_boxed(b)) return REAL_DOUBLE(a) == REAL_DOUBLE(b);
if (!Real$is_boxed(a)) a = Real$as_rational(REAL_DOUBLE(a));
if (!Real$is_boxed(b)) b = Real$as_rational(REAL_DOUBLE(b));
@@ -779,6 +810,8 @@ int32_t Real$compare_values(Real_t a, Real_t b) {
return (REAL_DOUBLE(a) > REAL_DOUBLE(b)) - (REAL_DOUBLE(a) < REAL_DOUBLE(b));
}
+ if (Real$obviously_equal(a, b)) return 0;
+
if (Real$tag(a) == REAL_TAG_RATIONAL && Real$tag(b) == REAL_TAG_RATIONAL) {
rational_t *ra = REAL_RATIONAL(a);
rational_t *rb = REAL_RATIONAL(b);
diff --git a/src/stdlib/reals.h b/src/stdlib/reals.h
index 13f9cea3..ae1ba968 100644
--- a/src/stdlib/reals.h
+++ b/src/stdlib/reals.h
@@ -48,6 +48,7 @@ Text_t Real$as_text(const void *n, bool colorize, const TypeInfo_t *type);
Text_t Real$value_as_text(Real_t x);
bool Real$equal(const void *va, const void *vb, const TypeInfo_t *t);
bool Real$equal_values(Real_t a, Real_t b);
+PUREFUNC bool Real$obviously_equal(Real_t a, Real_t b);
bool Real$get_rational(Real_t x, int64_t *num, int64_t *den);
bool Real$is_between(Real_t x, Real_t low, Real_t high);
double Real$as_float64(Real_t n, bool truncate);