From 819179c5838e9a2ebba69d5569f3c08d093194d2 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sat, 17 Jan 2026 13:52:49 -0500 Subject: Simplify equality checks for common cases. --- src/stdlib/reals.c | 35 ++++++++++++++++++++++++++++++++++- src/stdlib/reals.h | 1 + 2 files changed, 35 insertions(+), 1 deletion(-) 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); -- cgit v1.2.3