2012-05-25 16 views
18

tengo cadenas que representa los valores decimales, ex: "0,010", "" "0,0100000 00,01000"Clojure redondeo de cifras decimales

les quiero redondear al formato especificado, por ejemplo: # ##.

en Java tenemos:

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

¿Cuál es la mejor manera de lograr esto en Clojure en lugar de utilizar la interoperabilidad?

Respuesta

26

Puede usar Clojure's format para este fin. Debería proporcionarle una solución a su problema. He aquí algunos ejemplos y una referencia:

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 
+0

CL-formato debe ser utilizado en lugar de - formato es sólo una envoltura delgada alrededor del java. util.Formatter y por eso no maneja BigInt de Clojure, por ejemplo. A partir de Clojure 1.3, si su número es demasiado grande durante un tiempo, se desbordará en un BigInt, que es la implementación de Clojure, en lugar de BigInteger, que es la implementación de Java. Como es de suponer, java.util.Formatter no maneja la implementación de Clojure y arroja una excepción. – Unknown

+2

no redondea, simplemente lo aplasta. – celwell

18

Ésta es una versión ligeramente modificada de un ejemplo en 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))) 

@ respuesta de number23_cn es el más adecuado para muchos casos. Sin embargo, una función real de redondeo con un argumento de precisión puede ser útil si, por ejemplo, desea visualizar una secuencia con cada número redondeado. A continuación, puede asignar round2 sobre la secuencia para dar formato a cada número a la vez:

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

que devuelve

(0.0 10.12 9.56) 

Esto es más útil para una secuencia más larga, por supuesto.


Otra opción es utilizar cl-format, que es una implementación de Common Lisp Clojure de format. Es similar al format de Clojure (que se basa en java.util.Formatter) pero tiene una sintaxis diferente y permite algunos trucos más extravagantes.

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

La directiva ~{ ~} permite secuencias de procesamiento, como en el primer ejemplo anterior:

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

~{ ~} espera ver una secuencia como un argumento, y comerá elementos de la secuencia de uno en uno utilizando cualquier las directivas aparecen entre ~{ y ~}.

(El chapter on format de Peter Seibel de Practical Common Lisp es la mejor introducción a Common Lisp de format, y por lo tanto a Clojure de cl-format, la OMI. El documentation on CL's format en la fuente de costumbre, el Common Lisp Hyperspec, puede ser difícil de utilizar a veces. El section on CL's format en Common Lisp The Language es un poco mejor.)

+0

La función docstring en round2 indica incorrectamente que el parámetro de precisión hace referencia al número si hay dígitos significativos. https://en.wikipedia.org/wiki/Significant_figures debe decir "número de dígitos fraccionarios" – antonmos

1

La respuesta aceptada recomienda format, pero format no redondea (como se indicó en uno de los comentarios). La otra respuesta (por parte de Marte) no funcionará para BigDecimal s.Para redondear bigdec s de una serie de cifras decimales en Clojure la única solución que he encontrado es utilizar Java interoperabilidad:

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

(def round4 (round 4))