- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我用 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
幸运的是,这个性能问题已经在 Java 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/
这个问题在这里已经有了答案: Isn't an Int64 equal to a long in C#? (2 个答案) 关闭 9 年前。 它不应该是一个整数类型吗? 这样,一些使用 int 的函数
当我遇到一些我想知道的事情时,我正忙着解析一个二进制文件。 Stream.Position属性的类型为Int64或long。为什么是这样?因为流中的位置不能为负,所以使用 UInt64 不是更有意义吗
所以第一部分是我从用户那里获得输入,在本例中,输入是“1”作为从另一个函数接收的字符值。 printf ("\nPlease enter 1, 2, 3 or q: "); option =
我正在尝试使用以下代码从 REST 服务返回 JSON: $categories = $categoriesController->listAll(); if($categories){ hea
我阅读了文档,它说 long 是 %li,但打印输出返回为 -2147024891。是什么赋予了? 最佳答案 您甚至没有提供要打印的号码,但我猜您已经无意中发现了签名打印和未签名打印之间的区别。 使用
我正在创建自定义购物车,我正在构建一个查询,该查询从检索我刚刚保存到购物车表中的 session_id 开始。我知道这个值被保存了,我在 mysql 命令行运行这个查询,它返回我需要的但我没有将值放入
我有一个包含 textView 的 scrollView。如果文本很长并且不适合屏幕,我想增加 textView 高度(我想我可以通过添加 NSLayoutConstraint outlet 并修改它
我有一个基本的数据库处理程序类,其中有一个使用 PDO::FETCH_ASSOC 参数返回结果集的公共(public)方法: public function resultSet() { $th
在后台线程中,我调用 PublishSubject.onNext(); 并在主线程中通过 subscribe(PublishSubject.filter(message -> message.getI
我想知道为什么 Amazon Web Services 控制台登录页面有这么长的 url?为什么不只发布数据而不显示其中包含大量数据的冗长 url。以这种方式实现有什么充分的理由吗? 最佳答案 我认为
这个问题在这里已经有了答案: Can I mix MySQL APIs in PHP? (4 个答案) 关闭 6 年前。 希望我犯了一个快速而明显的错误,我浏览了 previous question
我得到了答案:如果我禁用了cookie,那么使用URL重定向我可以传递JSESSIONID,但我的URL已经很长,因为我使用它有约束的GET方法。那怎么办我应该使用我的 session 吗?我希望我的
目前,当我使用 DOMDocument 对象并调用 saveHTML() 时,它会自动添加一些我不需要的 html 标签。我尝试了此处建议的解决方案 ( https://stackoverflow.c
我是一名优秀的程序员,十分优秀!