【问题标题】:Regarding Big Decimal关于大十进制
【发布时间】:2010-03-01 01:34:09
【问题描述】:

我有一个 csv 文件,其中除了标题和尾记录之外,每个详细记录中都存在金额和数量字段。拖车记录有一个总费用值,即数量的总和乘以明细记录中的金额字段。我需要检查拖车总费用值是否等于我计算的金额和数量字段的值。我对所有这些计算都使用双精度数据类型

在 csv 文件中,金额字段显示为“10.12”或“10”或“10.0”或“10.456”或“10.4555”或“-10.12”。金额也可以有正值或负值。

在 csv 文件中

H,ABC.....

"D",....,"1","12.23"

"D",.....,"3","-13.334"

"D",......,"2","12"

T,csd,123,12.345

------------------ 验证时我有以下代码 --------- ------------

              double detChargeCount =0; 

              //From csv file i am reading trailer records charge value 
              String totChargeValue = items[3].replaceAll("\"","").trim(); 

              if (null != totChargeValue && !totChargeValue.equals("")) { 
                  detChargeCount = new Double(totChargeValue).doubleValue(); 

              if(detChargeCount==calChargeCount) 
                  validflag=true; 

-----------------------在阅读 CSV 文件时,我有以下代码

               if (null != chargeQuan && !chargeQuan.equals("")) { 
                      tmpChargeQuan=Long(chargeQuan).longValue(); 
                     } 

                if (null != chargeAmount && !chargeAmount.equals("")) { 
                      tmpChargeAmt=new Double(chargeAmount).doubleValue(); 
                          calChargeCount=calChargeCount+(tmpChargeQuan*tmpChargeAmt); 
                          } 

我已将变量 tmpChargeQuan、tmpChargeAmt、calChargeCount 声明为 double

当我在网上搜索时,我知道 double 可能会给财务计算带来问题,因此需要使用 BIGDECIMAL。但我想知道这种情况是否适用于我的计算。在我的情况下,金额值在小数点后最多可以有 5 或 6 位”我可以使用双数据类型进行此计算吗?我使用它进行验证。如果我使用上述代码和使用双倍的乘法会产生问题吗?

【问题讨论】:

    标签: java double bigdecimal


    【解决方案1】:

    我将扩展 Adeel 已经简洁回答的内容。您可以将这些数字放入双数据类型。问题是当数字被计算出来时,它们会被正确计算吗?答案是否定的——他们不会。一般来说,如果你用 delta 来解释这个问题,那并不是什么大问题,也就是说,你可以假设一个 double 值是否等于另一个 double 值。但是对于涉及精确数字的计算,例如货币计算,您必须使用 BigDecimal 等类型来保存值。

    当你有这个号码时: 1.23445 作为双倍,它可能看起来像 1.23445 但实际上可能是这样的 1.234450000003400345543034

    当您对诸如此类的数字执行多次计算时,通常那些多余的地方并不重要 - 但是,随着时间的推移,它们会产生不准确的结果。使用 BigDecimal,当一个数字被指定为其字符串表示形式时,它就是那个数字 - 它不会遭受双打的“几乎一样好”的问题。

    我正在更新此答案以包含来自 BigDecimal 的双重构造函数的一些注释,可在此 address 找到。

    这个构造函数的结果可以是 有点不可预测。一个可能 假设写新的 Java 中的 BigDecimal(0.1) 创建一个 BigDecimal 完全等于 0.1(未缩放的值 1,缩放为 1),但实际上是相等的 到 0.10000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能 完全表示为双精度(或, 就此而言,作为二进制分数 任何有限长度)。因此,价值 正在传递给 构造函数不完全等于 0.1,尽管出现了。

    String 构造函数,另一方面 手,是完全可以预测的: 编写 new BigDecimal("0.1") 创建 一个 BigDecimal 完全等于 0.1,正如人们所期望的那样。因此,一般建议将 字符串构造函数用于 偏爱这个。

    当必须使用双精度作为源时 对于 BigDecimal,请注意,这 构造函数提供了一个精确的 转换;它不一样 结果将双精度转换为 字符串使用 Double.toString(double) 方法和 然后使用 BigDecimal(String) 构造函数。要获得该结果,请使用 静态 valueOf(double) 方法。

    【讨论】:

    • 非常感谢所以即使我在小数点后有 4 位数字(低精度),您也会这么说。乘法时我可能会出错。我还注意到 bigdecimal 有一个 setscale 方法来设置小数点后的位数和舍入方法。就我而言,我不需要进行任何舍入,因为我只是在验证值。此外,我的输入有时可能在小数点后有 2 或 3 或 0 位数字。 BigDecimal 是否有任何默认舍入。我将按以下方式分配 BigDecimal aa =new BigDecimal("11.2359");
    • BigDecimal 没有默认舍入,除非您已将数字指定为双精度数。你输入的字符串就是你得到的。如果您的比例比当前结果短,则绝对需要 setScale 上的舍入模式 - 假设您有 6.35,并且您说 setScale(1) - 根据您选择的舍入模式,它将使其变为 6.3 或 6.4。跨度>
    • 非常感谢。所以你说如果我将它包含在字符串 BigDecimal("11.2359") 中并与另一个 BigDecimal ("12") 类型相乘,它不会对结果进行四舍五入吗?如果我将它作为 double BigDecimal(11.2359) 给出,那么当我进行乘法或任何其他操作时它会进行什么样的默认舍入。如果我想比较两个大小数的值,看看它们是否相等,我需要得到双值和两者并检查吗?
    • 乘法可能会扩大规模,因此不需要四舍五入。除法可能会缩小比例,因此如果原始比例不足以容纳真实结果,则可能必须进行四舍五入。当您在 BigDecimal 中使用双精度时,它会将其存储为实际的双精度表示形式 - 从上面链接的 Javadoc 关于双精度构造函数java.sun.com/j2se/1.5.0/docs/api/java/math/… 0.1 在存储为双精度时是 not 0.1,而是新的BigDecimal("0.1") 就是你想的那样。
    • String cd="12.234" double abc =12.234;如果我执行 new BigDecimal(cd) 或 new BigDecimal(BigDecimal.valueof(abc) 并将其用于计算是否都给我相同的结果?我还假设 valueof 方法使用 Double.toString(double) 方法,所以它与给 new BigDecimal(Double.toString(abc)); 我浏览了文档。我也没有得到 unscaled 、 scaled 和precision 之间的区别。你能发布一个例子 Bigdecimal 如何存储正/负值以及正在发生的事情存储在未缩放、缩放、精度值中
    【解决方案2】:

    这不是大小的问题,而是准确表达浮点数的问题。 How the BigDecimal Class Helps Java Get its arithmetic right.

    【讨论】:

    • 非常感谢您的链接。在 BIGDECIMAL 中默认舍入是什么。我不希望发生任何舍入,因为我在这里进行验证。将每条记录的(数量*金额)相加,最后检查总费用金额。如果匹配,我会将值添加到表中。
    • 阅读文档并没有什么坏处。 :) 它将回答您关于舍入的所有问题:java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 2018-01-05
    相关资源
    最近更新 更多