diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2026-01-17 13:52:49 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2026-01-17 13:52:49 -0500 |
| commit | 819179c5838e9a2ebba69d5569f3c08d093194d2 (patch) | |
| tree | ece13dd89641b93175c1e74348f40592d523d830 | |
| parent | 3112916e708278e4066792832cf40936825e4da6 (diff) | |
Simplify equality checks for common cases.
| -rw-r--r-- | src/stdlib/reals.c | 35 | ||||
| -rw-r--r-- | src/stdlib/reals.h | 1 |
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); |
