【问题标题】:Getting NaN / Infinity Error when converting Double to BigDecimal将 Double 转换为 BigDecimal 时出现 NaN / Infinity 错误
【发布时间】:2015-03-24 02:53:08
【问题描述】:

所以我在doubles 之间进行了这种划分(从它在数据库中获取的值);

 indPayRatio[loadCounter] = c.getDouble(c.getColumnIndex("payment")) / c.getDouble(c.getColumnIndex("debt_total"));

没有任何一个值可以为空的情况。他们必须在这里。

嗯,有时我会得到这个疯狂的长数字,所以我将它转换为BigDecimal,如下所示:

 bdRatio = new BigDecimal(indPayRatio[i]);

在这一行,我从许多用户那里得到了以下堆栈跟踪。我无法复制它,所以我不确定它的价值。

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.NumberFormatException: Infinity or NaN: NaN
at java.math.BigDecimal.<init>(BigDecimal.java:465)
at com.---.---.DebtDataSource.payoffDebt(DebtDataSource.java:544)
at com.---.---.PlannerFragment$PlannerTask.doInBackground(PlannerFragment.java:177)
at com.---.---.PlannerFragment$PlannerTask.doInBackground(PlannerFragment.java:143)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
... 4 more

我的第一个预感是,我应该在第一行使用 BigDecimal 进行乘法运算,但如果这是问题所在,为什么在将其转换为 BigDecimal 时会出现错误?

【问题讨论】:

  • 如果debt_total 为0怎么办?它会解释你的情况吗? BigDecimal 构造函数:NumberFormatException - if val is infinite or NaN.
  • 我从来没想过。尽管从我得到的错误数量来看,在这种情况下,这个值很少会是“0”。我想我只需要用BigDecimal 进行硬除法,这样我就能得到一个很好的价值,而不是一个双倍会失败的价值。
  • 没有好/坏的值。如果除数为 0,对于双精度数,您会得到 Infinity,对于 BigDecimals,您会得到一个异常 - 使用 BigDecimal 不会解决问题。您需要决定当除数为 0 时该怎么做。这是我看到此异常被抛出的唯一方法。
  • 验证分母不为零:stackoverflow.com/questions/2259190/…

标签: java double bigdecimal


【解决方案1】:

所以我做了两件事来帮助解决这个问题。最重要的是,我不再使用double 进行重除,而是使用BigDecimal。我相信旧方法导致NaN 值。如上所述,我还发现传入 0 会使 BigDecimal 部门崩溃。

我改变了这个:

indPayRatio[loadCounter] = c.getDouble(c.getColumnIndex("payment")) / c.getDouble(c.getColumnIndex("debt_total"));

到:

BigDecimal dPayment = new BigDecimal(c.getDouble(c.getColumnIndex("payment")));
BigDecimal dTotal = new BigDecimal(c.getDouble(c.getColumnIndex("debt_total")));
if (dPayment.equals(BigDecimal.ZERO) || dTotal.equals(BigDecimal.ZERO)) {
    indPayRatio[loadCounter] = BigDecimal.ZERO;
} else {
    MathContext mc = new MathContext(2, RoundingMode.HALF_EVEN);
    indPayRatio[loadCounter] = dPayment.divide(dTotal, mc);
} 

【讨论】:

  • 除非你 indPayRatio[loadCounter] 也是一个 BigDecimal,否则你正在浪费计算周期来进行繁重的 BigDecimal 计算。
  • @jsn 在代码中,后来,我最终将indPayRatio[loadCounter] 转换为BigDecimal,所以我想我只是省了一步。
  • 如果 indPayRatio 是双精度/浮点数,您很可能会失去 BigDecimal 的精度,因此当您稍后将 indPayRatio 转换为 BigDecimal 时,原始 BD 和新 BD 很可能不相等。如果您要使用 BD,请一直使用它,直到需要保存/呈现数据。
  • 所以我现在所做的似乎是一个更好的主意。我立即从 DB 中取出价值并放入BigDecimal,而不是像我正在做的那样快速(毫无意义)作为双倍然后到BigDecimal。把它放在上下文中。这是一个金融应用程序。我拥有double 的所有内容。现在我将它转换为BigDecimal,就像推荐用于财务一样。这就是为什么还有剩余的 double 实例尚未转换的原因。
  • 是的,将它保存在 BigDecimal 中,直到您需要呈现它或将其保存在数据库中。 BigDecimal 在处理金钱方面有很大帮助。但是,请注意,您确实需要对某些内容进行舍入。您(显然)不能向客户收取 3.50000001112222222 美元
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-05
  • 1970-01-01
  • 1970-01-01
  • 2015-03-31
  • 1970-01-01
  • 2018-10-05
相关资源
最近更新 更多