23

10進値を表す文字列があります。例: "0.010"、 "0.0100000" "00.01000"

それらを指定された形式に丸めたい、例:#。##

Javaには次のものがあります。

public BigDecimal setScale(int newScale, RoundingMode roundingMode) {
    return setScale(newScale, roundingMode.oldMode);
}

相互運用を使用するのではなく、Clojureでこれを達成するための最良のアプローチは何ですか?

4

5 に答える 5

39

formatこの目的のためにClojureを使用できます。それはあなたの問題に対する解決策を提供するはずです。ここにいくつかの例とリファレンスがあります:

user=> (format "%.2f" 0.010)
"0.01"
user=> (format "%.2f" 0.010000)
"0.01"
user=> (format "%.2f" 00.010000000)


user=> (doc format)
-------------------------
clojure.core/format
([fmt & args])
  Formats a string using java.lang.String.format, see java.util.Formatter for format
  string syntax
于 2012-05-25T09:45:10.737 に答える
22

これは、 clojure-doc.orgの例を少し変更したものです。

(defn round2
  "Round a double to the given precision (number of significant digits)"
  [precision d]
  (let [factor (Math/pow 10 precision)]
    (/ (Math/round (* d factor)) factor)))

@ number23_cnの答えは、多くの場合正しい答えです。ただし、たとえば、すべての数値が丸められたシーケンスを表示する場合は、精度引数を使用した実際の丸め関数が役立つ場合があります。次に、シーケンスにマップするだけround2で、すべての数値を一度にフォーマットできます。

(map (partial round2 2) [0.001 10.123456 9.5556])

これは

(0.0 10.12 9.56)

もちろん、これは長いシーケンスの場合に便利です。


もう1つのオプションはcl-format、CommonLispのClojure実装であるを使用することformatです。formatこれはClojure(に基づいています)に似てjava.util.Formatterいますが、構文が異なり、いくつかのより巧妙なトリックが可能です。

(clojure.pprint/cl-format nil "~,2f" 23.456)
; => "23.46"

上記~{ ~}の最初の例のように、ディレクティブはシーケンスの処理を許可します。

(clojure.pprint/cl-format nil "~{ ~,2f~}" [0.001 10.123456 9.5556])
; => " 0.00 10.12 9.56"

~{ ~}~{シーケンスを引数として見ることを期待し、との間に表示されるディレクティブを使用して、シーケンスの要素を1つずつ食べます~}

(PeterSeibelのPracticalCommon Lispの章formatは、Common Lispの、したがってClojureのimoの最良の入門書です。通常のソースであるCommon Lisp HyperspecのCLに関するドキュメントは、使用するのが難しい場合があります。CLのセクションCommonLispでは言語は少し優れています。)formatcl-formatformatformat

于 2014-08-02T19:23:16.303 に答える
2

受け入れられた回答は推奨formatしていますが、丸められていformatません(コメントの1つで指摘されているように)。他の答え(火星による)はsでは機能しませんBigDecimalbigdecClojureでsを小数点以下の桁数に丸めるには、Java相互運用機能を使用するしかありません。

(defn round [s]
  (fn [n]
    (assert (bigdec? n))
    (.setScale n s RoundingMode/HALF_EVEN)))

(def round4 (round 4)) 
于 2017-09-09T21:45:56.973 に答える
1

Double/ParseDouble10進数で使用した後に関数を使用すると、を使用formatして記述された目的の小数に丸められた小数が返されformatます。そのようです:

user=> (Double/parseDouble (format "%.2f" 0.009) ) 
0.01

さらに計算するために丸められた数値が必要な場合は、Doubleを解析することが重要です。ただし、必要なのが丸められた数値の出力だけである場合は、の使用formatが適切です。

于 2019-04-10T18:23:14.980 に答える
1

これらの文字列を最初にBigDecimal値に変換することが重要です。のような数値リテラル0.0001または任意の数値は、doubleまたはfloatに推測される可能性があり、非常に大きなスケールを持つ数値の精度を失う可能性があります。

2つ目は、明示的にフォーマットするのではなく、名義尺度に再スケーリングすることです。

(defn round
  [n scale rm]
  (.setScale ^java.math.BigDecimal (bigdec n)
             (int scale)
             ^RoundingMode (if (instance? java.math.RoundingMode rm)
                             rm
                             (java.math.RoundingMode/valueOf
                              (str (if (ident? rm) (symbol rm) rm))))))

(round "12.345" 2 :UP)
12.35M

(round "12.345" 2 :DOWN)
12.34M

(round "12.345" 2 :HALF_UP)
12.35M

(round "12.3" 2 :HALF_EVEN)
12.30M

文字なしで印刷するには、または:Mを使用します。str.toPlainString

(str (round "0" 2 :HALF_EVEN))
"0.00"

(.toPlainString ^java.math.BigDecimal (round "1.2" 4 :UP))
"1.2000"

また、 Banksterライブラリ(通貨とお金で遊ぶため)で同様のことをどのように抽象化したかを確認できますapply。プロトコルメソッドを探してください。

https://github.com/randomseed-io/bankster/blob/main/src/io/randomseed/bankster/scale.clj

于 2021-07-17T14:08:58.550 に答える