轻量级Java小数类

15
我正在考虑写两个有限精度的BigDecimal替代方案,即DecimalInt和DecimalLong。它们能够处理实际int和long边界内的数字,并可以创建可变和不可变形式,带有任意数量的小数位。我的计划是使DecimalInt支持+/-999,999,999到+/-0.999999999,DecimalLong也相同,但最多18位数字。
这将通过维护DecimalInt的0-9位小数数字计数值和DecimalLong的0-18位小数数字计数值以及与之匹配的缩放整数或长整数来实现。通常用于小数(例如货币和股票价格),通常为2-4个小数位。
必要的要求是(a)占用空间小(2个类,加上OverflowException),并且(b)完全支持所有基本操作和所有有意义的数学操作。
搜索结果没有明显的命中项-它们似乎都与任意小数有关。
我的问题是:这已经做过了吗?其中是否存在隐藏的微妙之处,这就是为什么它还没有被完成的原因?是否有人听说过Java支持类似DotNet的十进制类型的传言?
编辑:这与BigDecimal不同,因为它应该(a)更高效地处理不涉及int数组的情况,(b)不会包装BigInteger,因此在内存上更精简,并且(c)它将具有可变选项,因此在这方面速度会更快。总之-对于简单用例(例如“我想存储银行余额而不带BigDecimal的开销和double的不准确性”)的开销较小。
编辑:我打算使用int或long进行所有数学计算,以避免经典问题:1586.60-708.75=877.8499999999999,而不是877.85。

"这个已经完成了吗?" 你提出的类和BigDecimal有什么不同? - matt b
当你说“任意数量的小数位”时,你是指你有一个固定的小数位数在脑海中,还是希望能够支持任意数量的小数位? - DJClayworth
可能编写代码会比在这里处理人们误解你的问题要快。 - jmucchiello
5个回答

13
我强烈怀疑之所以没有这样做的原因是BigDecimal和BigInteger的开销并不像你想象的那么重要,避免使用它不值得付出努力,并且存在某些微妙错误的风险。以您的例子为例:对于任何财务应用程序,节省几十个字节都不是问题,而有限的精度则会成为制约因素(美国的股票价格可能通常只有2-4位数字,但如果你想处理新兴市场,你将遇到通货膨胀失控的货币,在那里15位数字的总和仅能购买半个面包)。基本上,这听起来就像另一种过早优化的情况。

4
你曾经见过一个使用高通胀货币进行产品交易的系统吗?我建议你远离这些系统。 - Peter Lawrey

0

如果您正在处理货币并且需要处理固定、小数点后的位数,通常可以使用整数(必要时为长整型)来表示分或百分之一美分。

如果您在处理货币,则需要注意如何处理四舍五入。如果您的计算将接受审计,则有关于此类操作的规则。而且,请注意有些运算无法精确进行(例如除法)。


准确地说,我希望将这个逻辑捆绑到一个类中,该类意识到其值的规模,因此可以与其他类似数字进行操作。 - Lawrence Dol

0

大多数特别关注舍入误差的人使用BigDecimal和BigInteger,在大多数情况下表现良好。

然而,在性能更为关键的情况下,使用带有舍入的double可以胜任。这经常被新手忽略,但是你不能只取一个没有合理舍入的double结果并期望得到一个明智的答案。

在绝大多数情况下,带有舍入的double就足够了。

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

打印

877.85

-1

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

还有一个有趣的库,可以看看构造实数。虽然它不轻巧。

关于下面的评论,您不能使用Apache Commons Math Library处理分数吗? 有什么原因不能使用吗?


真的看起来不错,但是...它是GPL许可的,所以不能商业使用,而且它仍然使用浮点数运算,因此会遇到无法在二进制中表示的十进制小数问题。 - Lawrence Dol
我没有意识到你有许可证要求。 - WolfmanDragon

-1

如果您需要任意精度,那么您需要一些未定义的位数来表示尾数。这意味着需要某种数组分配策略来处理尾数。您可以自己编写代码实现,但BigInteger可以高效地完成这项工作。

您需要指定要表示的最小(非零)值是多少。这将是10^-(2^n),其中n+1是您为指数分配的位数。对于BigDecimal,这是10^-(2^31)。您可以使用任意大小的指数,但该范围应该足够满足您的需求。

因此,您需要一个无限整数尾数来提供任意精度,并且需要一个固定大小的指数,具体取决于您想要表示的最小值。本质上,这就是BigDecimal;唯一的区别是您将使用一些比BigDecimal使用的int更小的对象。我怀疑节省空间是否值得。我认为BigDecimal将以几乎与您自己编写的任何解决方案相同的内存使用量完成您所需的工作。

当然,您可以选择需要的最大有效数字数量;然后,您需要为尾数和指数使用固定大小的存储空间,这样可以节省很多存储空间。只需使用固定数量的long作为尾数即可。


这就是为什么我的问题说“有限精度”,而不是“任意精度”的原因。 - Lawrence Dol
并且指出每个变量的精度将受到int和long的限制,而一个单独的值将保存小数点后的位数,以消除BigInteger所需的复杂计算。 - Lawrence Dol
你的问题中提到了“任意数量的小数位”。请明确你的意思。 - DJClayworth
任意的,但限制为0-9或0-19位小数。 - Lawrence Dol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接