gpt4 book ai didi

java - BigDecimal toPlainString 生成字符串需要很长时间

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:40:10 25 4
gpt4 key购买 nike

我用 Java 编写了一个程序来计算像 100 万这样的极端阶乘。它所做的本质上是从 1 开始到 n 的循环,每次迭代,将 BigDecimal 与循环中计数器变量的值相乘。循环完成后,它会调用 BigDecimal#toPlainString() 返回生成的数字作为字符串。但是,调用此方法需要很长时间才能执行。例如,在下面的代码中:

public static void main(String[] args) {
BigDecimal number = new BigDecimal(1);
long startTime = System.currentTimeMillis();
for (int i = 1; i < 500000; i++) {
number = number.multiply(new BigDecimal(i));
}
System.out.println("Generating took: " + (System.currentTimeMillis() - startTime) + "ms. Creating String.");
startTime = System.currentTimeMillis();
String result = number.toPlainString();
System.out.println("String generation took: " + (System.currentTimeMillis() - startTime) + "ms");
FileUtils.writeStringToFile(new File("Path/To/File"), result);
}

控制台的输出是:

Generating took: 181324ms. Creating String.
String generation took: 710498ms

它演示了方法 toPlainString() 花费了多长时间。

我知道我们正在处理巨大的数字(在上面的示例中大约有数百万位数字),但我想知道是否有任何方法可以加快此方法的速度,我应该如何去做?

谢谢!

编辑#1:在帖子中添加毫秒时间计算的唯一原因是将“长”带入预期,并可能展示代码,以防所有读者都无法重现问题。我想做的是确定为什么我的情况需要这么长时间,最重要的是如何加快转换为字符串的过程。

最佳答案

为什么BigDecimal#PlainString的原因使用 Java 7 生成字符串需要很长时间:它在 Java 7 中的实现效率很低。幸运的是,它在 Java 8 中的速度

在这里,可能需要注意的是在这种特殊情况下,它实际上并不是BigDecimal 中的字符串创建。 , 但在 BigInteger .在给定示例中计算的值是一个大阶乘,因此实际上是一个整数值。内部scale BigDecimal 的领域将是 0然后,看看 toPlainString方法表明,在这种情况下,内部的字符串值 intVal将返回字段:

public String toPlainString() {
if(scale==0) {
if(intCompact!=INFLATED) {
return Long.toString(intCompact);
} else {
return intVal.toString();
}
}
...
}

intVal字段是 BigInteger ,这才是真正的罪魁祸首。

以下程序旨在作为适当的“微基准测试”,而只是应该给出性能估计:它创建多个阶乘,并生成这些阶乘的字符串表示形式:

import java.math.BigDecimal;

public class BigDecimalToPlainStringPerformance
{
public static void main(String[] args)
{
for (int n = 10000; n <= 50000; n += 5000)
{
BigDecimal number = factorial(n);
long before = System.nanoTime();
String result = number.toPlainString();
long after = System.nanoTime();

double ms = (after - before) / 1e6;
System.out.println(n + "! took " + ms +
" ms, length " + result.length());
}
}

private static BigDecimal factorial(int n)
{
BigDecimal number = new BigDecimal(1);
for (int i = 1; i < n; i++)
{
number = number.multiply(new BigDecimal(i));
}
return number;
}

}

使用 Java 7 (u07),在我的(旧)PC 上,输出是这样的

10000! took 514.98249 ms, length 35656
15000! took 1232.86507 ms, length 56126
20000! took 2364.799995 ms, length 77333
25000! took 3877.565724 ms, length 99090
30000! took 5814.925361 ms, length 121283
35000! took 8231.13608 ms, length 143841
40000! took 11088.823021 ms, length 166709
45000! took 14344.778177 ms, length 189850
50000! took 18155.089823 ms, length 213232

幸运的是,这个性能问题已经在 J​​ava 8 中得到修复。对于 Java 8 (u45),输出是

10000! took 77.20227 ms, length 35656
15000! took 113.811951 ms, length 56126
20000! took 188.293764 ms, length 77333
25000! took 261.328745 ms, length 99090
30000! took 355.001264 ms, length 121283
35000! took 481.912925 ms, length 143841
40000! took 610.812827 ms, length 166709
45000! took 698.80725 ms, length 189850
50000! took 840.87391 ms, length 213232

表明性能得到了显着的改进。

通过快速浏览 OpenJDK 中的提交日志,有一个提交可能与此处最相关:

Accelerate conversion to string by means of Schoenhage recursive base conversion

(我没有验证这一点,但它似乎是唯一一个致力于提高 toString 性能的)

关于java - BigDecimal toPlainString 生成字符串需要很长时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41754262/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com