Welcome! Please see the About page for a little more info on how this works.

0 votes
in Java Interop by

Trying to convert from BigDecimal to long

(long 201608081812113241M) => 201608081812113248 ;; not really our number

let's just use BigDecimal.longValue()

(.longValue 201608081812113241M) => 201608081812113241 ;; ok, correct value

looking into clojure.lang.RT and suspecting incorrect conversion chain

(.longValue (.doubleValue 201608081812113241M)) => 201608081812113248 ;; yep, incorrect

Cause: long cast from BigDecimal will use Number.longValue(), which in this case produces an incorrect value even though the conversion is possible. The javadoc indicates that this call is equivalent to a double to long conversion and is potentially lossy in several ways.

Approach: add explicit case in long cast to handle BigDecimal and instead call longValueExact(). Patch adds additional cast tests for some BigInteger and BigDecimal values. The unchecked-long cast does not seem to be affected (returned the proper value with no changes).

Questions: while it may be confusing, the incorrect result may actually be the one that is consistent with Java. unchecked-long would give the expected result and may be the better choice for the example here. So it's possible that we should NOT apply this patch and instead do nothing. If we do move forward with the patch, we may want to also apply an equivalent change to call byteValueExact(), shortValueExact(), intValueExact(), and toBigIntegerExact() in the appropriate places as well.

Patch: clj-2001.patch

4 Answers

0 votes
by

Comment made by: alexmiller

Yeah, RT.longCast() doesn't seem to explicitly handle BigDecimal.

0 votes
by

Comment made by: gshayban

Patch seems like it may negatively affect inlining

0 votes
by

Comment made by: alexmiller

Indeed that's a possibility, although I think it's probably rare in this case.

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-2001 (reported by alex+import)
...