有没有办法使BigDecimal的速度比我在这里快? [英] Is there a way to make BigDecimal faster than I have here?

查看:137
本文介绍了有没有办法使BigDecimal的速度比我在这里快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一些财务分析软件,该软件将需要处理大量(ish)数据.我想使用BigDecimal来提高准确性(一些定价信息会在小数点后四到五位),但我担心速度.

I'm working on some financial analysis software that will need to process large (ish) volumes of data. I'd like to use BigDecimal for the accuracy (some pricing info goes to four or five digits to the right of the decimal) but I was concerned about speed.

我编写了以下测试应用程序,看来BigDecimal的速度可能比Doubles慢90到100倍.我知道会有一个增量,但这超出了我的预期.这是经过多次试验的典型输出.

I wrote the following test app and it appears that BigDecimal can be 90 to 100 times slower than Doubles. I knew there would be a delta, but that's more than I was expecting. Here's a typical output after many trials.

BigDecimal took 17944 ms
Double took 181 ms

我想念什么吗?

这是代码.我试图使其代表现实世界.我创建了一个可以在其中(pi)进行操作的常量,但是还进行了一些内联数字运算,这些运算会因数据行而异,例如pi * BigDecimal(i)+ BigDecimal(1).我的观点是避免构造函数不是唯一的答案.

Here is the code. I tried to make it representative of real world. I created a constant where I could (pi) but also did some inline math of numbers that would vary from data row to data row - such as pi * BigDecimal(i) + BigDecimal(1). My point being that avoiding constructors can't be the only answer.

幸运的是,由于数字通常采用00000.00000格式,因此Double仍然具有足够的精度.但是,我应该知道任何隐藏的陷阱吗?人们是否将Double用于财务分析软件?

Fortunately, it appears Double has enough precision anyway since numbers will be typically in the format 00000.00000. Any hidden gotchas I should know about, though? Do people use Double for financial analysis software?

import java.math.BigDecimal

object Stopwatch {
    inline fun elapse(f: () -> Unit):Long {
        val start = System.currentTimeMillis()
        f()
        return System.currentTimeMillis() - start
    }
}


fun tryBigDecimal() {
    val arr: MutableList<BigDecimal> = arrayListOf()

    for (i in 1..10000000) {
        arr.add(BigDecimal(i))
    }

    val pi = BigDecimal(3.14159)

    for (i in 0..arr.size - 1) {
        arr[i] = arr[i] * pi / (pi * BigDecimal(i) + BigDecimal(1))
    }

    //arr.forEachIndexed { i, bigDecimal ->  println("$i, ${bigDecimal.toString()}")}
}

fun tryDouble() {
    val arr: MutableList<Double> = arrayListOf()

    for (i in 1..10000000) {
        arr.add(i.toDouble())
    }

    val pi = 3.14159

    for (i in 0..arr.size - 1) {
        arr[i] = arr[i] * pi / (pi * i + 1)
    }

    //arr.forEachIndexed { i, bigDecimal ->  println("$i, ${bigDecimal.toString()}")}

}

fun main(args: Array<String>) {
    val bigdecimalTime = Stopwatch.elapse(::tryBigDecimal)
    println("BigDecimal took $bigdecimalTime ms")

    val doubleTime = Stopwatch.elapse(::tryDouble)
    println("Double took $doubleTime ms")
}

推荐答案

您可以尝试 Moneta ,即JSR 354参考实现(JavaMoney RI).它具有FastMoney实现:

You can try Moneta, the JSR 354 reference implementation (JavaMoney RI). It has a FastMoney implementation:

FastMoney表示针对速度进行了优化的数字表示.它仅将货币金额表示为类型long的整数,因此使用的数字刻度为100'000(10 ^ 5).

FastMoney represents numeric representation that was optimized for speed. It represents a monetary amount only as a integral number of type long, hereby using a number scale of 100'000 (10^5).

例如

operator fun MonetaryAmount.times(multiplicand: Double): MonetaryAmount {
    return multiply(multiplicand)
}

operator fun MonetaryAmount.div(divisor: Double): MonetaryAmount {
    return divide(divisor)
}

fun tryFastMoney() {
    val currency = Monetary.getCurrency("USD")
    val arr: MutableList<MonetaryAmount> = arrayListOf()

    for (i in 1..10000000) {
        arr.add(FastMoney.of(i, currency))
    }

    val pi = 3.14159

    for (i in 0..arr.size - 1) {
        arr[i] = arr[i] * pi / (pi * i + 1)
    }
}

fun main(args: Array<String>) {
    val fastMoneyTime = Stopwatch.elapse(::tryFastMoney)
    println("FastMoney took $fastMoneyTime ms")
    val doubleTime = Stopwatch.elapse(::tryDouble)
    println("Double took $doubleTime ms")
}

FastMoney took 7040 ms
Double took 4319 ms

这篇关于有没有办法使BigDecimal的速度比我在这里快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆