I have strings which represents the decimal values,
ex: "0.010", "0.0100000" "00.01000"
I want to round them to specified format,
ex: #.##
In Java we have:
public BigDecimal setScale(int newScale, RoundingMode roundingMode) {
return setScale(newScale, roundingMode.oldMode);
}
What is the best approach to achieve this in Clojure rather than using interop?
You can use Clojure's format
for this purpose. It should provide you a solution to your problem. Here are some examples and a reference:
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
This is a slightly modified version of an example at 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's answer is the right one for many cases. However, a real rounding function with a precision argument may be useful if, for example, you want to display a sequence with every number rounded. Then you can simply map round2
over the sequence to format every number at once:
(map (partial round2 2) [0.001 10.123456 9.5556])
which returns
(0.0 10.12 9.56)
This is more useful for a longer sequence, of course.
Another option is to use cl-format
, which is a Clojure implementation of Common Lisp's format
. It's similar to Clojure's format
(which is based on java.util.Formatter
) but has a different syntax, and allows some fancier tricks.
(clojure.pprint/cl-format nil "~,2f" 23.456)
; => "23.46"
The ~{ ~}
directive allows processing sequences, as in the first example above:
(clojure.pprint/cl-format nil "~{ ~,2f~}" [0.001 10.123456 9.5556])
; => " 0.00 10.12 9.56"
~{ ~}
expects to see a sequence as an argument, and will eat elements of the sequence one by one using whatever directives appear between ~{
and ~}
.
(The chapter on format
from Peter Seibel's Practical Common Lisp is the best introduction to Common Lisp's format
, and therefore to Clojure's cl-format
, imo. The documentation on CL's format
in the usual source, the Common Lisp Hyperspec, can be difficult to use sometimes. The section on CL's format
in Common Lisp The Language is slightly better.)
The accepted answer recommends format
, yet format
does not round (as pointed out in one of the comments). The other answer (by Mars) will not work for BigDecimal
s. To round bigdec
s to a number of decimal places in Clojure the only solution I have found is to use Java interop:
(defn round [s]
(fn [n]
(assert (bigdec? n))
(.setScale n s RoundingMode/HALF_EVEN)))
(def round4 (round 4))
Using the function Double/ParseDouble
after using format
on the decimal number will return a decimal rounded to the desired number of decimals described by using format
. Like so:
user=> (Double/parseDouble (format "%.2f" 0.009) )
0.01
If the rounded number is needed for further calculations, parsing a Double is important. However, if outputting a rounded number is all that is needed, then the use of format
is appropriate.