首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加倍我的钱:我的框架使用双倍的货币金额

加倍我的钱:我的框架使用双倍的货币金额
EN

Stack Overflow用户
提问于 2010-10-06 04:27:39
回答 5查看 668关注 0票数 9

我继承了一个项目,其中货币金额使用双精度类型。

更糟糕的是,它使用的框架,以及框架自己的类,都使用double来赚钱。

框架ORM还处理从数据库中检索值(以及将值存储到数据库中)。在数据库中,钱的值是类型number(19,7),但是框架ORM将它们映射为双精度。

除了完全绕过框架类和ORM之外,我还能做些什么来精确地计算货币价值呢?

编辑:是的,我知道应该使用BigDecimal。问题是,我与一个框架紧密相关,例如,类framework.commerce.pricing.ItemPriceInfo具有成员double mRawTotalPrice;和double mListPrice。我公司的应用程序自己的代码扩展了,例如,这个ItemPriceInfoClass。

实际上,我不能对我的公司说,“放弃两年的工作,花费数十万美元,基于这个框架的代码,因为四舍五入误差。”

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-10-06 04:31:53

如果可以接受,请将货币类型视为整型。换句话说,如果你在美国工作,跟踪美分而不是美元,如果美分提供了你需要的粒度。Double可以精确地表示直到a very large value (2^53)的整数(在该值之前没有舍入误差)。

但实际上,正确的做法是完全绕过框架,使用更合理的东西。对于这个框架来说,这是一个业余的错误--谁知道还潜伏着什么呢?

票数 10
EN

Stack Overflow用户

发布于 2010-10-06 04:29:54

我没看到你提到重构。我认为这是你最好的选择。与其拼凑一些技巧来让事情现在运行得更好,为什么不以正确的方式修复它呢?

这里有一些关于double vs BigDecimal的信息。这篇文章建议使用BigDecimal,尽管它更慢。

票数 6
EN

Stack Overflow用户

发布于 2010-10-06 04:55:39

很多人会建议使用BigDecimal,如果你不知道如何在你的项目中使用舍入,那就是你应该做的。

如果您知道如何正确使用小数舍入,请使用double。它的数量级更快,更清晰,更简单,因此不太容易出错。如果您使用美元和美分(或需要两位小数点),您可以获得高达70万亿美元的准确结果。

基本上,如果你使用适当的舍入来修正它,你就不会得到舍入误差。

顺便说一下:舍入错误的想法让许多开发人员感到恐惧,但它们不是随机错误,您可以相当容易地管理它们。

编辑:考虑这个舍入误差的简单示例。

代码语言:javascript
复制
    double a = 100000000.01;
    double b = 100000000.09;
    System.out.println(a+b); // prints 2.0000000010000002E8

有许多可能的舍入策略。您可以在打印/显示时对结果进行舍入。例如:

代码语言:javascript
复制
    System.out.printf("%.2f%n", a+b); // prints 200000000.10

或者对结果进行数学取整。

代码语言:javascript
复制
    double c = a + b;
    double r= (double)((long)(c * 100 + 0.5))/100;
    System.out.println(r); // prints 2.000000001E8

在我的例子中,我在从服务器发送(写入套接字和文件)时舍入结果,但是使用我自己的例程来避免创建任何对象。

一个更通用的舍入函数如下所示,但如果您可以使用printf或DecimalFormat,可能会更简单。

代码语言:javascript
复制
private static long TENS[] = new long[19]; static { 
    TENS[0] = 1; 
    for (int i = 1; i < TENS.length; i++) TENS[i] = 10 * TENS[i - 1]; 
} 

public static double round(double v, int precision) { 
    assert precision >= 0 && precision < TENS.length; 
    double unscaled = v * TENS[precision]; 
    assert unscaled > Long.MIN_VALUE && unscaled < Long.MAX_VALUE; 
    long unscaledLong = (long) (unscaled + (v < 0 ? -0.5 : 0.5)); 
    return (double) unscaledLong / TENS[precision]; 
}

注意:您可以使用BigDecimal来执行最后的舍入。如果您需要特定的舍入方法,请使用esp。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3867445

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档