I'm trying to use BigDecimals in Clojure to model (if necessary) arbitrary precision numbers. I have a strange error when I try to instantiate a BigDecimal from an unscaled value and scale factor:
user=> 1.31M
1.31M (OK)
user=> (class 1.31M)
java.math.BigDecimal (OK)
user=> (.unscaledValue 1.31M)
131 (OK)
user=> (.scale 1.31M)
2 (OK)
user=> (.movePointLeft (BigDecimal. 131) 2)
1.31M (OK)
user=> (BigDecimal. (BigInteger. "131") 2)
1.31M
user=> (BigDecimal. 131N 2) (WRONG!!!)
IllegalArgumentException No matching ctor found for class java.math.BigDecimal clojure.lang.Reflector.invokeConstructor (Reflector.java:183)
user=> (BigDecimal. (BigInteger. "131") 2)
1.31M
The problem here is that the clojure big integer IS NOT a java.math.BigInteger object. Even (bigint x) doesn't work:
user=> (doc bigint)
-------------------------
clojure.core/bigint
([x])
Coerce to BigInt
nil
And by the way BigInteger constructor doesn't directly accept numeric values. I know I could also do something like:
user=> (BigDecimal. (BigInteger. (.toByteArray (.unscaledValue 1.31M))) (.scale 1.31M))
1.31M
My question is: is there a more idiomatic way of directly manage BigInteger objects from Clojure? Or am I stuck to wrap everything in a custom library, like:
user=> (defn my-bigint [x] (BigInteger. (.toString x)))
#'user/my-bigint
user=> (my-bigint 131)
131
user=> (BigDecimal. (my-bigint 131) 2)
1.31M
Thanks in advance for the help!
UPDATE: I NEED a BigInteger for serialization purposes: my idea is to store a BigDecimal as a byte array and an integer. My problem is that in Clojure, if I want, I cannot pass the result of .unscaledValue back and forth 'cause Clojure doesn't handle BigInteger created from Integers (neither do Java, for what it matters):
user=> (BigInteger. 3)
IllegalArgumentException No matching ctor found for class java.math.BigInteger clojure.lang.Reflector.invokeConstructor (Reflector.java:183)
A call to .toString on the number is unuseful for the semantics of serialization (and more error prone). I would like to know if in Clojure there is an idiomatic way to write something like:
user=> (bigdec 131N 2)
No .movePointLeft (creation of two different objects without benefits), no .toString (I have a number, I stringify it and then create a BigInteger, another number, from it?), no slow and indirect method: just plain BigInteger and scale value.
Vinz
=> (type (.unscaledValue 1.31M))
java.math.BigInteger
=> (type (biginteger 131))
java.math.BigInteger
=> (BigDecimal. (biginteger 131) 2)
1.31M
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With