8

我正在尝试在 Clojure 中使用 BigDecimals 来建模(如有必要)任意精度数。当我尝试从未缩放的值和比例因子实例化 BigDecimal 时,我遇到了一个奇怪的错误:

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

这里的问题是 clojure 大整数不是 java.math.BigInteger 对象。即使 (bigint x) 也不起作用:

user=> (doc bigint)
-------------------------
clojure.core/bigint
([x])
  Coerce to BigInt
nil

顺便说一句,BigInteger 构造函数不直接接受数值。我知道我也可以做类似的事情:

user=> (BigDecimal. (BigInteger. (.toByteArray (.unscaledValue 1.31M))) (.scale 1.31M))
1.31M

我的问题是:有没有更惯用的方式从 Clojure 直接管理 BigInteger 对象?还是我坚持将所有内容包装在自定义库中,例如:

user=> (defn my-bigint [x] (BigInteger. (.toString x)))
#'user/my-bigint
user=> (my-bigint 131)
131
user=> (BigDecimal. (my-bigint 131) 2)
1.31M

在此先感谢您的帮助!

更新:我需要一个 BigInteger 用于序列化目的:我的想法是将 BigDecimal 存储为字节数组和整数。我的问题是,在 Clojure 中,如果我愿意,我不能来回传递 .unscaledValue 的结果,因为 Clojure 不处理从 Integers 创建的 BigInteger(Java 也不处理,这很重要):

user=> (BigInteger. 3)
IllegalArgumentException No matching ctor found for class java.math.BigInteger  clojure.lang.Reflector.invokeConstructor (Reflector.java:183)

对数字调用 .toString 对序列化的语义没有用(而且更容易出错)。我想知道在 Clojure 中是否有一种惯用的方式来编写类似的内容:

user=> (bigdec 131N 2)

没有 .movePointLeft (创建两个不同的对象没有好处),没有 .toString (我有一个数字,我将它字符串化,然后从它创建一个 BigInteger,另一个数字?),没有缓慢和间接的方法:只是简单的 BigInteger 和缩放价值。

文兹

4

3 回答 3

9
=> (type (.unscaledValue 1.31M))
java.math.BigInteger

=> (type (biginteger 131))
java.math.BigInteger

=> (BigDecimal. (biginteger 131) 2)
1.31M
于 2012-06-11T15:25:05.483 回答
4
user=> (.movePointLeft (bigdec 131) 2)
1.31M
user=> (.movePointLeft (bigdec 131N) 2)
1.31M

user=> (source bigdec)
(defn bigdec
  "Coerce to BigDecimal"
  {:tag BigDecimal
   :added "1.0"
   :static true}
  [x] (cond
       (decimal? x) x
       (float? x) (. BigDecimal valueOf (double x))
       (ratio? x) (/ (BigDecimal. (.numerator x)) (.denominator x))
       (instance? BigInteger x) (BigDecimal. ^BigInteger x)
       (number? x) (BigDecimal/valueOf (long x))
       :else (BigDecimal. x)))
于 2012-06-11T13:53:43.873 回答
0

我更喜欢这个:

(-> 131M (.movePointLeft 2))
于 2012-06-11T13:56:20.813 回答