views:

915

answers:

3

I'm trying to take two 7 digit numbers (source and target record counts) and calculate the percentage of missing records in the target count.

For example, my record counts could be 4084094 for the source, and 4081313 for the target. I'm also using the follow formula to calc the percentage: ((1 - (target / source)) * 100)

For my example, I should get the value of about .0681%

I'm am new to Java and JSP, and I'm not able to get the percentage to display correctly. I seem to only get a value rounded down to 0.

I've also tried BigDecimal, to no avail.

Even the following simple code displays the value of 1-1, so I obviously am doing somthing seriously wrong:

<%
BigDecimal percentMiss;
long tmp = 600/500;
percentMiss = BigDecimal.valueOf(tmp);
%>
<%=percentMiss.toString()%>-<%=tmp%>
+2  A: 

The problem is in the following line

long tmp = 600/500;

You cannot store floating point numbers in a long, instead you should consider using the following code:

double tmp = (double)600 / (double)500;

and then display tmp, which should have a value somewhere between 0 and 1 (in your case 1.2, because you have to change your calculation to 500 / 600)

Homes2001
You don't have to cast the second value to double too, but I usually do it because it makes the code more readable (at least imo...)
Homes2001
Why not 600D and 500D
Adeel Ansari
in this case the D would be shorter, that's true... I wanted to give an example which can be used with variables too (as you can't add D at the end of a variable to cast it to a double ... ;) ...)
Homes2001
Fair enough. But its good to write D instead of d. See Java Puzzler for that. Consider the case of long, where the small l pretty much looks like 1. So, for this very reason its good to practice caps for all.
Adeel Ansari
+1  A: 

The problem is obviously that you are dividing two long numbers.

I would recommend using DecimalFormat to display the number. If you are using JSTL, then an even better solution is to use the format tags:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<fmt:formatNumber value="${value}" minFractionDigits="2" maxFractionDigits="2"/>
kgiannakakis
No he is actually dividing two ints. :)
Adeel Ansari
+1  A: 

Your problem is that 600 and 500 are integer values, and a division between them will have an integer result, which you assign to a long integer. After this, the fractional part of the result is gone (twice) and you can't get it back.

In order to get a fractional result, at least one of the input values of the division needs to be non-integer. You can achieve this by casting them to double or float, or by making the literals explicitly double or float like this:

500.0 // implicitly double
500f // float literal
500d // double literal

However, printing the result of a double/float divison will often have more decimal places than you want even if they shouldn't be in the result (e.g. 1/10 can result in 0.100000001490116119384765625), due to the way these numbers are stored as binary fractions.

You can eliminate these unwanted digits by using java.lang.DecimalFormat, but BigDecimal is a better option, since it internally uses decimal fractions and will therefore deliver the actually correct results while offering exact control over rounding modes. Of course, this requires you to use BigDecimal for the calculation itself, rather than as "voodoo ingredient" to fix an already broken result.

new BigDecimal(600).divide(new BigDecimal(500))

Read the API documentation for BigDecimal for more information.

Michael Borgwardt
Wrong. integers use integer division, with an integer result.
Michael Borgwardt
You are right. +1
Adeel Ansari