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 とスケールのみ価値。
ヴィンツ