【问题标题】:convert extremely large decimal to bytes将非常大的十进制转换为字节
【发布时间】:2013-01-21 18:21:27
【问题描述】:

如何将超大 (>1MB) 十进制数转换为字节/十六进制/二进制?

例如,数字“300”应转换为 {0x01, 0x2C}。字节顺序无所谓,{0x2C, 0x01} 也可以。

源编号存储在一个准备好的文件中(没有标点符号、空格或换行符)。最大的是just over 17MB,虽然不排除以后会有100MB的号。目标也是一个文件。

有没有一种不需要很长时间的方法,或者在它确实需要很长时间的情况下是安全的?

我担心使用 BigInteger 会花费很长时间,并且不是故障保存(ie.如果出现问题,我无法中途恢复)

我并不反对实现我自己的算法,尽管我正在寻找比“检查奇数,除以 2”更有效的方法。我已经看到了一个非常有效的二进制到 BCD 的实现,Shift and Add-3 算法,并且正在寻找一个类似的高效实现。

对还支持定点数(1 位数字和其余小数,例如。 Pi)的实现的额外赞誉。

【问题讨论】:

  • 你为什么不试试 BigInt,看看它是否足够快?
  • 我可能会,但我只是一个高效算法的傻瓜
  • @Zom-B:每当您“担心”某些东西可能不够快时,您绝对应该在开始寻找其他地方之前对其进行测试。

标签: java binary numbers decimal converter


【解决方案1】:

对于我来说,BigInteger 在大约 39 秒内将 1M 位数字转换为 byte []。对你来说太过分了吗?

Random r = new Random ();

StringBuilder sb = new StringBuilder();

for (int i = 0; i < 1000000; i++)
    sb.append ("0123456789".charAt(r.nextInt(10)));

long t = System.currentTimeMillis();
BigInteger bi = new BigInteger (sb.toString());
byte [] bytes = bi.toByteArray();
System.out.println(System.currentTimeMillis() - t);

关于小数。假设你有一个大的小数形式&lt;n digits&gt;.&lt;m digits&gt;。您想将其转换为在点后使用k 位的二进制文件。你需要解一个方程:D/(10^m) = X/(2^k),其中 X 是整数。这里 D 是没有点的小数(小数的尾数),X 是没有点的二进制(二进制的尾数)。方程很容易求解:X ~ round(D*(2^k)/(10^m))。 X 必须是整数,所以我们添加了round()

例如,您需要将 12.34 转换为点后 3 位的二进制。

n = 2
m = 2
D = 1234
k = 3
X ~ round(D*(2^k)/(10^m)) = round(1234 * 8 / 100) = round(98.72) = 99 = 1100011b

请记住,我们需要点后 3 位,所以我们的答案是 12.34 ~ 1100.011b

所有这些计算都可以使用 BigInteger 完成。

【讨论】:

  • 好的,假设这个问题解决了,我该如何处理定点数? BigDecimal 没有 toByteArray() 方法或类似方法。
【解决方案2】:

有没有一种不需要很长时间的方法,或者在确实需要很长时间的情况下是安全的?

没有。

十进制数到二进制数的转换涉及将一个大数反复乘以 10。如果您有数百万位数,那么您就有数百万次乘法需要对非常大的数执行。

但是,听起来您实际上并没有对这些非常大的数字之一进行转换,您只是猜测这需要很长时间。在你继续之前,我强烈建议你对这个操作进行基准测试,看看它实际需要多长时间。 (米哈伊尔的回答说大约 39 秒,但他编写的代码没有考虑 JVM 预热。)

或者更好的是,使用 BigInteger 和 profile 对整个应用程序进行编码以确定是否存在性能问题,以及实际的性能瓶颈在哪里。

【讨论】:

  • 像 BigInteger 这样的朴素和通用(就基数而言)实现是二次时间 O(n²),所以我预计它需要很长时间,看来我是对的。一些统计测试和推断让我得出了这些数字:1MB:17 秒、10MB:1700 秒、100MB:170000 秒 = 1.96 天——现在就足够了,但将来不行。
  • 嗯,你可能被“搞砸了”......正如他们所说......除非你能找到一个数学突破,让你将一个 N 位数的二进制数乘以 10,而不是 O(N ) 时间。您可以期望的最好的结果是找到一个更快的“大整数”实现来减少C1 + C2 * N^2 中的C2。而且您可能需要切换到 C。无论您使用什么实现,O(N^2) 对于足够大的N 值都将是“年龄”。这个问题根本无法很好地扩展。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
  • 2010-10-31
  • 2013-09-12
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
相关资源
最近更新 更多