setscale round ejemplo decimals java math scala groovy bigdecimal

round - default scale bigdecimal java



Scala y Java BigDecimal (6)

Quiero pasar de Java a un lenguaje de scripting para los módulos basados ​​en Math en mi aplicación. Esto se debe a la legibilidad y las limitaciones funcionales de mathy Java.

Por ejemplo, en Java tengo esto:

BigDecimal x = new BigDecimal("1.1"); BigDecimal y = new BigDecimal("1.1"); BigDecimal z = x.multiply(y.exp(new BigDecimal("2"));

Como puede ver, sin la sobrecarga del operador BigDecimal, las fórmulas simples se complican muy rápido.

Con los dobles, esto se ve bien, pero necesito la precisión.

Esperaba en Scala que podría hacer esto:

var x = 1.1; var y = 0.1; print(x + y);

Y de forma predeterminada, obtendría un comportamiento de tipo decimal, por desgracia, Scala no usa el cálculo decimal de forma predeterminada.

Entonces hago esto en Scala:

var x = BigDecimal(1.1); var y = BigDecimal(0.1); println(x + y);

Y todavía obtengo un resultado impreciso.

¿Hay algo que no estoy haciendo bien en Scala?

¿Tal vez debería usar Groovy para maximizar la legibilidad (usa decimales por defecto)?


Cambie su código de Scala a esto:

var x = BigDecimal("1.1"); // note the double quotes var y = BigDecimal("0.1"); println(x + y);

y funcionará como lo hace en Java.


No conozco a Scala, pero en Java, el new BigDecimal(1.1) inicializa el BigDecimal con un valor double y, por lo tanto, no es exactamente igual a 1.1. En Java, debe usar el new BigDecimal("1.1") . Tal vez eso ayude en Scala también.


Puede almacenar valores como Integer / String (sin precisión) internamente y usar scale (esto es una transcripción de Scala REPL):

scala> val Scale = 2 Scale: Int = 2 scala> val x = BigDecimal(110, Scale) x: scala.math.BigDecimal = 1.10 scala> val y = BigDecimal(303, Scale) y: scala.math.BigDecimal = 3.03 scala> (x+y, (x+y).scale) res0: (scala.math.BigDecimal, Int) = (4.13,2) scala> (x*2, (x*2).scale) res1: (scala.math.BigDecimal, Int) = (2.20,2)

O si desea analizar una cadena, puede controlar el redondeo:

scala> val z = BigDecimal("8.937").setScale(Scale, BigDecimal.RoundingMode.FLOOR) z: scala.math.BigDecimal = 8.93 scala> val z = BigDecimal("8.937").setScale(Scale, BigDecimal.RoundingMode.CEILING) z: scala.math.BigDecimal = 8.94


Sé que esta pregunta es vieja y respondida, pero otra opción, si está abierto a diferentes idiomas (como el OP parecía ser), sería usar Clojure. Clojure tiene, IMO, algunas de las sintaxis más simples para la matemática BigDecimal ( BigDecimal en la M s posterior, que indica BigDecimal ):

user=> (def x 1.1M) #''user/x user=> (def y 1.1M) #''user/y user=> (def z (* x (.pow y 2))) #''user/z user=> z 1.331M user=> (type z) java.math.BigDecimal

Me gusta Clojure para las matemáticas, ya que por defecto en muchos casos es la precisión, por ejemplo, su uso de Ratio :

user=> (/ 60 14) 30/7 user=> (type (/ 60 14)) clojure.lang.Ratio


Scala es definitivamente el mismo que Java en este sentido.

Según la respuesta de Joachim, escribiendo val x = BigDecimal(1.1)

es equivalente a escribir

val d : Double = 1.1 val x = BigDecimal(d)

El problema, por supuesto, es que el Double d YA tiene el error de redondeo, por lo que está inicializando x con datos incorrectos.

Use el constructor que acepta una cadena en su lugar, y todo estará bien.

Dado su ejemplo, también sería mejor usar val s en lugar de var s, y también puede dejar los puntos y coma de forma segura en Scala.


scala> implicit def str2tbd(str: String) = new { | def toBD = BigDecimal(str) | } str2tbd: (str: String)java.lang.Object{def toBD: scala.math.BigDecimal} scala> var x = "1.1".toBD x: scala.math.BigDecimal = 1.1 scala> var y = "0.1".toBD y: scala.math.BigDecimal = 0.1 scala> x + y res0: scala.math.BigDecimal = 1.2 scala> implicit def str2bd(str: String) = BigDecimal(str) str2bd: (str: String)scala.math.BigDecimal scala> x + y + "1.2345566" res1: scala.math.BigDecimal = 2.4345566 scala>