代码之家  ›  专栏  ›  技术社区  ›  geejay

Scala和Java BigDimple

  •  28
  • geejay  · 技术社区  · 14 年前

    我想把Java从脚本语言转换成应用程序中基于数学的模块。这是因为MathJava的可读性和功能限制。

    例如,在Java中,我有:

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

    如您所见,如果不使用bigdecimal运算符重载,简单的公式很快就会变得复杂起来。

    双打看起来不错,但我需要精准度。

    我希望在斯卡拉我能做到:

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

    默认情况下,我会得到类似十进制的行为,唉,scala默认情况下不使用十进制计算。

    然后我在scala中这样做:

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

    我仍然得到一个不精确的结果。

    在斯卡拉有什么事情我做得不对吗?

    也许我应该使用groovy来最大化可读性(默认情况下它使用小数)?

    6 回复  |  直到 13 年前
        1
  •  38
  •   Joachim Sauer    14 年前

    我不认识斯卡拉,但在爪哇 new BigDecimal(1.1) 初始化 BigDecimal 用一个 double 价值,因此它不是 确切地 等于1.1。在爪哇你必须使用 new BigDecimal("1.1") 相反。也许这对斯卡拉也有帮助。

        2
  •  31
  •   Jesper    14 年前

    将scala代码更改为:

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

    它将像Java一样工作。

        3
  •  13
  •   Kevin Wright    14 年前

    Scala在这方面与Java绝对是相同的。

    根据约阿希姆的回答,写 val x = BigDecimal(1.1)

    相当于写作

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

    当然,问题在于 d 已经有舍入错误,所以您正在用错误数据初始化X。

    使用接受字符串的构造函数,一切都会好起来。

    举个例子,你最好使用 val S而不是 var 在scala中也可以安全地去掉分号。

        4
  •  6
  •   Alexander Azarov    14 年前

    您可以在内部将值存储为整数/字符串(无精度),并使用 scale (这是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)
    

    或者,如果要分析字符串,可以控制舍入:

    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
    
        5
  •  5
  •   Eastsun    14 年前
    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>
    
        6
  •  2
  •   overthink    13 年前

    我知道这个问题由来已久并得到了解答,但如果你对不同的语言开放(就像OP看起来那样),另一个选择是使用clojure。在我看来,Clojure有一些 BigDecimal 数学(注意后面 M S——表示 双小数 ):

    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
    

    我喜欢Clojure的数学,因为它在许多情况下都默认为精确,例如使用 Ratio :

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