beginners 2025-11-09

Maybe I'm misunderstanding but I was expecting automatic promotion to BigDecimal when I added Double/MAX_VALUE twice. What am I getting wrong?

user=> (* 2 Double/MAX_VALUE)
##Inf
user=> (*' 2 Double/MAX_VALUE)
##Inf                                         ;; I was expecting automatic promotion, so 3.5953862697246314E+308M.
user=> (+' Double/MAX_VALUE Double/MAX_VALUE)
##Inf                                         ;; Automatic promotion here as well.
user=> (* 2 (bigdec Double/MAX_VALUE))
3.5953862697246314E+308M

Waited for the Conj to be over. @alexmiller Can you confirm if this is indeed a bug? I'm currently working on https://github.com/jank-lang/jank/pull/588 in jank and would love to contribute to Clojure as well if this is indeed a bug πŸ™‚.

Alex Miller (Clojure team) 2025-11-19T17:15:46.774379Z

I answered in Ask Clojure, this is not a bug and is by design

πŸ‘ 1

Yup, saw it. Although I was curious as to why promotion for floating point numbers was decided to be skipped.

Alex Miller (Clojure team) 2025-11-19T17:19:14.543199Z

Double vs bigdecimal is not about scale (double is huge) but about precision. Vs long to biginteger which is about scale

Alex Miller (Clojure team) 2025-11-19T17:20:36.365529Z

Feels like the same case, but is not

πŸ‘ 2

Is this why? "does not auto-promote longs"

user=> (clojure.repl/source *)
                             
(defn *
  "Returns the product of nums. (*) returns 1. Does not auto-promote
  longs, will throw on overflow. See also: *'"

;; ... snip ... 
)

Source for *' does not say it, but, looking at the shape of the code, I think this will also not auto-promote.

Maybe I'm looking in the wrong place 🀷.

In the addP of LongOps I see the logic for promotion.

πŸ€·β€β™‚οΈ I don't know enough about how Java maths works...

user=> (* 2 Double/MAX_VALUE)
##Inf
user=> (*' 2 Double/MAX_VALUE)
##Inf
But, overflows with Longs...
user=> (* 2 Long/MAX_VALUE)
Execution error (ArithmeticException) at java.lang.Math/multiplyExact (Math.java:1032).
long overflow
user=> (*' 2 Long/MAX_VALUE)
18446744073709551614N

Yeah, so the https://github.com/clojure/clojure/blob/6a4ba6aedc8575768b2fff6d9c9c7e6503a0a93a/src/jvm/clojure/lang/Numbers.java#L494 for Long to BigInt is visible in the Clojure compiler code but I don't see anything similar for promotion from Decimal to BigDecimal.

That must be it...

Alex Miller (Clojure team) 2025-11-09T14:23:33.112659Z

I would expect *’ to auto-promote, that is its purpose. My guess is that it’s the category crossing with long and decimal and the order these args come in. If you swap the args does it work?

Am I looking at the correct code segments of the Clojure compiler above? Since in there I don't see the logic for promotion in the DoubleOps as can be seen in the LongOps.

This also didn't work:

user=> (*' 2.0 Double/MAX_VALUE)
##Inf
user=> (*' Double/MAX_VALUE 2.0)
##Inf
user=> (*' Double/MAX_VALUE 2.0M)
##Inf
user=> (*' 2.0M Double/MAX_VALUE)
##Inf

I think this is a bug because the expected result would be that *' and +' autopromote.

I asked the question https://ask.clojure.org/index.php/14752/support-for-automatic-promotion-to-bigdecimal-in-etc with a few more details and sneakily have asked if I can work on the fix for the Clojure side as well 😜. Hopefully I used the correct tags, etc. 🀞.

πŸ‘ 1