Skip to content

Commit 73620ea

Browse files
committed
Fix overflows and edge cases
For example when difference between two longs is larger than a long it would overflow. Also when bit-difference was exactly Long/MIN_VALUE it would error when getting the absolute value. Use bignum to work around these. Also makes it compatible with older Clojure versions that didn't have `abs`.
1 parent 13285a6 commit 73620ea

File tree

3 files changed

+15
-4
lines changed

3 files changed

+15
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55
## Versions
66

77
## [Unreleased]
8+
- Fix bug that would return true for `(ish? 1.0 2.0)` in recent Java versions (found/tested in Java 17)
9+
- Fix some overflows and edge cases when comparing doubles that are not close
810

911
## [0.1.7] - 2025-02-09
1012
- Remove deprecated single-segment namespace

src/same/platform.cljc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,18 @@
7474
(Math/ulp (double f)))
7575
:cljs (ulp* f)))
7676

77+
(defn abs-val
78+
[v]
79+
(cond
80+
(= v Long/MIN_VALUE) (- (bigint v))
81+
(neg? v) (- v)
82+
:else v))
83+
7784
(defn bit-diff-double
7885
"Difference between two doubles in ULPs (i.e. number of representable numbers between them + 1)."
7986
[f1 f2]
80-
#?(:clj (abs (- (Double/doubleToLongBits f1)
81-
(Double/doubleToLongBits f2)))
87+
#?(:clj (abs-val (- (bigint (Double/doubleToLongBits f1))
88+
(bigint (Double/doubleToLongBits f2))))
8289
:cljs (let [buf (js/ArrayBuffer. 16)
8390
dv (js/DataView. buf)]
8491
(.setFloat64 dv 0 (double f1))
@@ -90,8 +97,8 @@
9097
(defn bit-diff-float
9198
"Difference between two floats in ULPs (i.e. number of representable numbers between them + 1)."
9299
[f1 f2]
93-
#?(:clj (abs ^long (- (Float/floatToIntBits f1)
94-
(Float/floatToIntBits f2)))
100+
#?(:clj (abs-val (- (Float/floatToIntBits f1)
101+
(Float/floatToIntBits f2)))
95102
:cljs (let [buf (js/ArrayBuffer. 8)
96103
dv (js/DataView. buf)]
97104
(.setFloat32 dv 0 (float f1))

test/same/platform_test.cljc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646

4747
(deftest bit-diff-double-test
4848
(is (zero? (p/bit-diff-double 1.0 1.0)))
49+
(is (= 0x8000000000000000N (p/bit-diff-double 1.0 -1.0)))
50+
(is (= 0x8000000000000000N (p/bit-diff-double -1.0 1.0)))
4951
(is (= 1 (p/bit-diff-double 1.0 1.0000000000000002)))
5052
(is (= 1 (p/bit-diff-double 1.0000000000000002 1.0)))
5153
(is (= 0x8000000000000 (p/bit-diff-double 1.0 1.5)))

0 commit comments

Comments
 (0)