Scala et Java BigDecimal

je veux passer de Java à un langage de script pour les modules mathématiques de mon application. Cela est dû à la lisibilité, et les limitations fonctionnelles de mathy Java.

Pour l'e.g, en Java, j'ai ceci:

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

comme vous pouvez le voir, sans surcharge de l'opérateur BigDecimal, les formules simples se compliquent très rapidement.

avec les doubles, ça a l'air bien, mais j'ai besoin de précision.

j'espérais Qu'à Scala je pourrais faire ceci:

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

et par défaut j'obtiendrais un comportement de type décimal, hélas Scala n'utilise pas le calcul décimal par défaut.

Puis-je faire cela en Scala:

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

Et j'obtiens toujours un résultat imprécis.

y a-t-il quelque chose que je ne fais pas bien à Scala?

peut-être que je devrais utiliser Groovy pour maximiser la lisibilité (il utilise des décimales par défaut)?

24
demandé sur Jonas 2010-04-23 13:57:42

6 réponses

je ne sais pas Scala, mais en Java new BigDecimal(1.1) initialise le BigDecimal avec un double valeur et donc il n'est pas exactement égale à 1.1. En Java, vous devez utiliser new BigDecimal("1.1") à la place. Peut-être que ça aidera aussi à Scala.

37
répondu Joachim Sauer 2010-04-23 10:01:48

changez votre code Scala en ceci:

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

et il va travailler comme il le fait en Java.

30
répondu Jesper 2010-04-23 10:04:51

Scala est certainement le même que Java à cet égard.

selon la réponse de Joachim, écrire val x = BigDecimal(1.1)

est équivalent à l'écriture

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

Le problème, bien sûr, est que le Double d a déjà l'erreur d'arrondi, donc vous initialisez x avec de mauvaises données.

utilisez le constructeur qui accepte une chaîne à la place, et tout ira bien.

Donné à votre exemple, vous seriez mieux d'utiliser vals au lieu de var s, et vous pouvez laisser le point-virgule éteint en toute sécurité à Scala aussi bien.

13
répondu Kevin Wright 2010-05-13 10:09:01

vous pouvez stocker des valeurs comme entier/chaîne (sans précision) en interne et utiliser scale (c'est une transcription de la 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)

Ou si vous souhaitez analyser une chaîne de caractères, vous pouvez contrôler l'arrondissement:

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
6
répondu Alexander Azarov 2011-02-27 20:01:35
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>
5
répondu Eastsun 2010-04-23 10:28:35

je sais que cette question Est ancienne et qu'on y répond, mais une autre option, si vous êtes ouvert à différentes langues (comme L'OP semblait être), serait D'utiliser Clojure. Clojure a, IMO, une syntaxe simple pour BigDecimal math (notez le résultat Ms -- qui indique 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

J'aime Clojure pour les maths car il est par défaut précis dans de nombreux cas, par exemple son utilisation de Ratio:

user=> (/ 60 14)
30/7
user=> (type (/ 60 14))
clojure.lang.Ratio
2
répondu overthink 2011-06-06 13:56:04