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 の big integer が 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 なし (メリットのない 2 つの異なるオブジェクトの作成)、.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 に答える