14

我正在考虑为 BigDecimal 编写两个有限精度的替代方案,即 DecimalInt 和 DecimalLong。这些将能够处理 int 和 long 的实际范围内的数字,具有任意数量的小数位,可以以可变和不可变的形式创建。我的计划是让 DecimalInt 支持 +/-999,999,999 到 +/- 0.999999999 和 DecimalLong 相同,但最多支持 18 位数字。

这将通过将 DecimalInt 的十进制数字计数值 0-9 和 DecimalLong 的 0-18 与存储为缩放的 int 或 long 的实际值一起维护来完成。通常用于小数位数,例如货币和股票价格,通常为 2-4 位小数。

基本要求是 (a) 精简足迹(2 个类,加上 OverflowException),以及 (b) 完全支持所有基本操作以及所有有意义的数学。

谷歌搜索结果没有返回任何明显的命中——它们似乎都与任意小数有关。

我的问题是:这已经完成了吗?这是否有隐藏的微妙之处,这就是为什么它还没有完成?有没有人听说过 Java 支持像 DotNet 的十进制类型的传闻。

编辑:这与 BigDecimal 不同,因为它应该(a)不处理整数数组的效率要高得多,并且(b)它不会包装 BigInteger,因此它也会更精简内存,并且(c) 它将有一个可变选项,因此在那里它也会更快。总而言之 - 像“我想存储银行余额而不需要 BigDecimal 的开销和 double 的不准确性”这样的简单用例的开销更少。

编辑:我打算使用 int 或 long 进行所有数学运算,以避免经典问题:1586.60-708.75=877.8499999999999 而不是 877.85

4

5 回答 5

13

我强烈怀疑没有这样做的原因是 BigDecimal 和 BigInteger 的开销并不像您想象的那么相关,并且避免它不值得付出努力和以某种微妙的方式出错的风险。

以您的示例为例:对于任何金融应用程序,保存几十个字节都不是问题,而且精度有限,会破坏交易(美国的股票价格通常为 2-4 位数,但如果您想与新兴市场打交道,你会遇到通货膨胀失控的货币,15 位数的总和可以为你买半条面包)。

基本上,这听起来像是另一种过早优化的情况。

于 2008-12-11T10:39:45.230 回答
1

大多数特别关心舍入错误的人使用 BigDecimal 和 BigInteger,它们在大多数情况下都表现得很好。

但是,在性能更为关键的情况下,使用带舍入的 double 可以完成这项工作。新手经常忘记这一点,但你不能在没有明智的回合的情况下获得双重结果并期望得到明智的答案。

在绝大多数情况下,您只需要四舍五入即可。

System.out.printf("%.2f%n", 1586.60-708.75);

印刷

877.85
于 2010-11-23T23:03:13.630 回答
0

如果您正在寻找一个固定的、小数位数的小数位数来处理货币,那么这通常是通过持有整数(必要时长)美分或百分之一美分来完成的。

如果您正在处理金钱,那么您将需要注意如何处理舍入。如果要审核您的计算,则有一些关于如何完成此类事情的规则。另外我假设您知道某些操作无法精确完成(除法是明显的例子)。

于 2008-12-10T14:38:26.763 回答
0

如果您的重点是便携式设备,请查看Real。Real 允许将数字的精度设置为 0 到 16。它是为 MIDP 手机设计的。

同样有趣的是,看看建设性的 reals图书馆。虽然它不是轻量级的。

参考下面的评论,您不能使用Apache Commons 数学库来处理分数吗?有什么不可行的原因吗?

于 2008-12-09T20:31:18.503 回答
-1

在我看来,如果您想要任意精度,那么您将需要未定义的位数来表示尾数。这意味着尾数需要某种数组分配策略。你可以在这里制作你自己的,但是 BigInteger 做得相当有效并且它有效

您需要指定您需要表示的最小(非零)值是什么。这将是 10^-(2^n),其中 n+1 是您分配给指数的位数。使用 BigDecimal,这是 10^-(2^31)。您可以使用任意大小的指数,但该范围对任何人都应该足够了。

因此,您需要一个无界整数尾数来为您提供任意精度和一个固定大小的指数,具体取决于您希望最小可表示值是什么。本质上这是 BigDecimal;唯一的变化是您将使用一些较小的对象,而不是 BigDecimal 使用的 int。我怀疑节省空间是否值得。我认为 BigDecimal 会做你需要的事情,几乎不会比你自己制作的任何解决方案更多的内存使用量。

当然,您可以选择所需的最大有效数字数;那么你需要固定大小的尾数和指数存储,而这要少得多。只需使用固定数量的 long 作为尾数。

于 2008-12-09T22:43:45.287 回答