0

So I have this division between doubles (from values it gets in a database);

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

There is no case where either of the values can be blank. They HAVE to be something here.

Well I get this crazy long number sometimes, so I convert it to BigDecimal like so:

 bdRatio = new BigDecimal(indPayRatio[i]);

At this line, I get the following stack trace from many users. I am unable to replicate it so I am unsure of the value.

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

My first hunch, is that I should be using BigDecimal to multiply at the first line, but if that is the issue, why am I getting the error when I convert it to BigDecimal?

TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259
  • What if debt_total is 0? It would explain your case? BigDecimal constructor: `NumberFormatException - if val is infinite or NaN.` – jn1kk Mar 23 '15 at 15:42
  • I have never thought of that. Though from the amount of errors I have gotten, and that value would only be very rarely "0" in that case. I think I just need to do the hard division with `BigDecimal` so I get a good value, not a value that double would fail on. – TheLettuceMaster Mar 23 '15 at 15:47
  • There are no good/bad values. If the divisor is 0, for doubles you get Infinity, for BigDecimals you get an exception - using BigDecimal will not solve the problem. You need to come up with a decision on what to do when the divisor is 0. This is the only way I see that this exception gets thrown at you. – jn1kk Mar 23 '15 at 15:50
  • Verify that the denominator is not zero: http://stackoverflow.com/questions/2259190/try-catch-for-division-by-zero – Ravi Yenugu Mar 23 '15 at 15:51

1 Answers1

0

So I did two things to help fix this. Most importantly, I no longer do heavy division with double but now BigDecimal. I beleive the old way was causing NaN values. Like mentioned above, I also found passing in 0 crashed the BigDecimal division.

I changed this:

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

to:

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);
} 
TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259
  • Unless you `indPayRatio[loadCounter]` is a BigDecimal too, you are wasting computation cycles doing heavy BigDecimal calculations. – jn1kk Mar 23 '15 at 19:49
  • @jsn down in the code, later on, I was eventually converting `indPayRatio[loadCounter]` into a `BigDecimal` anyway so I think I just saved a step. – TheLettuceMaster Mar 23 '15 at 19:51
  • If indPayRatio is a double/float you are losing precision from BigDecimal most likely, so when you convert indPayRatio to BigDecimal later on, original BD and new BD will not be equal most likely. If you are going to use BD, use it all the time, until data needs to be saved/presented. – jn1kk Mar 23 '15 at 20:03
  • So what I am doing now, appears to be a better idea. I am immediately taking value out of DB and putting into a `BigDecimal` instead of a quick (pointless) trip as a double then to a `BigDecimal`, as I was doing. To put this in context. This is for a financial app. I had everything as a `double`. Now I am converting it to `BigDecimal` like is recommended for finances. That is why there are leftover `double` instances that have yet to be converted. – TheLettuceMaster Mar 23 '15 at 20:17
  • 1
    Yes, keep it in BigDecimal until you need to present it or save it in database. BigDecimal helps immensely when dealing with money. However, do note that certain point you do need to round stuff. You (obviously) cannot charge a customer $3.50000001112222222 – jn1kk Mar 23 '15 at 20:21