In my program i'm posting the payment amount value to controller and i'm converting that value to Integer. Because I need to convert this value to cents before calling web service.
I'm using java and convert String to Integer code given below
(int)(Double.parseDouble(httpRequest.getParameter(PAYMENT_AMOUNT).trim()) * 100);
payment.jsp
page look like this
Payment Amount: <input type="text" id="paymentAmount" name="paymentAmount" value="1.00" />
For many input values it gives the correct output.
But for some values like 8.03 as input it return 802 as output value . This happens in 9.03,9.04 ,10.03,10.04,11.03 etc ... what could be the reason for this issue?
You need to round the result. The problem you have is that floating point numbers are almost but not exactly the number it appears when printed as a string. This shows up as a problem when you perform calculations.
I suggest you try
(int) Math.round( Double.parseDouble( httpRequest.getParameter(PAYMENT_AMOUNT).trim()) * 100);
In your specific case, you can see with BigDecimal what the actual representation of a double is
double d = 8.03;
BigDecimal bd = new BigDecimal(d);
System.out.println("bd: " + bd);
double d100 = d * 100;
System.out.println("d100: " + d100);
int i100 = (int) d100;
System.out.println("i100: " + i100);
int r100 = (int) Math.round(d100);
System.out.println("r100: " + r100);
prints
bd: 8.0299999999999993605115378159098327159881591796875
d100: 802.9999999999999
i100: 802
r100: 803
So you can see the actual value of 8.03 is slightly less than 8.03 which means however that when you * 100 and round down it means that you get 802 not 803 as expected.
The best solution is to round the result which finds the closest representable value.
As a side note, you might want to reconsider using int types to store cent values esp when dealing with large numbers.
To add more to earlier answers on floating-point issues in Java, and the need for BigDecimal, refer to some explanation here:
http://www.drdobbs.com/jvm/javas-floating-point-imprecision/240168744
You can change your code to:
(new BigDecimal(httpRequest.getParameter(PAYMENT_AMOUNT).trim(), MathContext.DECIMAL64)).multiply(new BigDecimal(100, MathContext.DECIMAL64)).intValue()
Another note: I would be cautious about assuming that you will get a String object back in the getParameter() call above esp. if someone is attempting to call your service without passing the PAYMENT_AMOUNT parameter.
Related
I have a method which returns a double
public double getOdds() {
return odds;
}
This works completly fine. However, the problem is when the data is displayed, it automatically rounds the inserted value up. I want to prevant that, and get a value with 2 decimals.
Here are my JSP where I call the method. The ArrayList "bets" consist of all values entered by the user. But, as explained above, when the user enters 2.75 then it will return 3.0
ArrayList <bets> bets = betsDAO.getBets(x, y);
for (bets bet : bets) {
<td><%=bet.getOdds()%></td>
}
I'm still new to Java, and have tried looking for solutions, but unfortunatly I have not been able to solve the issue.
when the user enters 2.75 then it will return 3.0
The only reason for that to happen is if the value is limited to zero decimals at some point. Java only does that for int (or long or short or char or byte) values, and those are truncated, so result would be 2, not 3.0.
The only round-to-nearest I can envision is caused by the database or the JDBC driver:
The column type in the database is INTEGER or NUMBER(5,0) or something like that. Check your database schema.
The code reading the database (betsDAO) is calling getInt(...) and the JDBC driver rounds the value for you.
Anyway, the error is in code you haven't shown.
it depends on which data type you intend on working with, but this
should do the trick for you
public class Rounding {
public static void main(String[] args) {
//using string format
double input = 3.14159265359;
System.out.println("double : " + input);
System.out.println("double : " + String.format("%.2f", input));
//using Decimal format
double num = 1.34567;
DecimalFormat df = new DecimalFormat("#.###");
df.setRoundingMode(RoundingMode.CEILING);
System.out.println(df.format(num));
}
}
OUTPUT:
double : 3.14159265359
double : 3.14
double : 3.14
OUTPUT:
1.346
so you can be more specific here with the decimal point to return. it all depends on the importance of the decimal precision for your project
Couldn't Math.floor help with the rounding? it rounds down, and if you ever need to use rounding up then use Math.ceil.
hopefully this helps!
i am using following function to format the double value to x.xx , but after that the result value started to end up with exponential value ( i have already read the answers which are advising to use the DecimalFormat or to plain text () methods but every where the system is giving error to change the types ...return types i am lost a bit now
can some one please help me in following method tweaks so that the returning values can be displayed as normal number instead of 3.343E32
Please note that the following function FD is used many times in code so i want to change it here only so i dont have to apply the formatting each and every results / variable..
public double fd(double x) {
BigDecimal bd_tax = new BigDecimal(x);
BigDecimal formated = bd_tax.setScale(2, BigDecimal.ROUND_UP);
x = Double.valueOf(formated.doubleValue());
return x;
}
You say, "...to format the double value...", but there is no code in your example that formats anything. Your fd(x) function takes a double as its argument, and it returns a double. It doesn't do anything else.
If your numbers really are in the neighborhood of 3.343E32, Then they're going to have a lot of digits: 33 digits before the decimal point. Is that what you were expecting?
Suggest you look at String.format() if you are trying to turn the double value into human readable text. Something like this, perhaps:
public String fd(double x) {
return String.format("%.2f", x);
}
This seems BEYOND easy but I cant see to find a clear answer...
Say I have a string (volume) that has a percentage...(80, 50, etc), I want to get the number in DECIMAL format, and then use that to figure out the volume to set the phone at. I already get the maxVolume...so it's just getting the correct value that's killing me...
Integer theVolume=Integer.parseInt(volume);
double decimalNumber = theVolume/100;
int calc=(int) (maxVolume*decimalNumber);
mgr.setStreamVolume(AudioManager.STREAM_MUSIC,calc, 0);
The decimalNumber is only coming out as 0.0...no matter what number I give it...?
Try doing it like this:
double decimalNumber = theVolume / 100.0;
The .0 at the end converts it to a decimal number.
edit: And for reference, it behaves like this because Java is trying to divide two integers (when using 100) so it tries to output the result as an integer. The result is a fraction so Java rounds it down by default to the closest integer to that fraction (0 in this case) and then assigns that integer value to your double. By instead using 100.0, you are telling Java to divide the integer by a double, which is then knows it can keep the fraction result and not round down.
Parse the volume as a double
double theVolume=Double.parseDouble(volume);
double decimalNumber = theVolume/100;
int calc=(int) (maxVolume*decimalNumber);
mgr.setStreamVolume(AudioManager.STREAM_MUSIC,calc, 0);
I have been given the task of using java to produce a Sin table, however I seem to get some very weird results for some values of the input. I am using the below
System.out.println("| sin(" + currentPoint + ") = " + Math.sin(Math.toRadians(currentPoint)));
Where (int) currentPoint is a value in degrees (eg 90)
These are results I find weird
| sin(360) = -2.4492935982947064E-16
| sin(180) = 1.2246467991473532E-16
| sin(150) = 0.49999999999999994
| sin(120) = 0.8660254037844387
Expecting
sin(360) = 0
sin(180) = 0
sin(150) = 0.5
sin(120) = 0.866025404
Am I missing something?
You're dealing with floating point numbers, looking for exact answers isn't going to work for all values. Take a look at
What Every Computer Scientist Should Know About Floating-Point Arithmetic. You want your tests to be equivalent to your expectations within some delta. Note that the answers you're getting are pretty close. It's expressing values in bits that's biting you.
From the link:
Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation. Although there are infinitely many integers, in most programs the result of integer computations can be stored in 32 bits. In contrast, given any fixed number of bits, most calculations with real numbers will produce quantities that cannot be exactly represented using that many bits. Therefore the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. This rounding error is the characteristic feature of floating-point computation.
If your code was System.out.println("| sin(" + currentPoint + ") = " + Math.sin(currentPoint)); you would expect this:
sin(360) = 0.958915723
sin(180) = -0.801152636
sin(150) = -0.71487643
sin(120) = 0.580611184
In other words, the sine of 360 radians is 0.9589, but the sine of 360 degrees is 0.
EDIT:
The reason you're seeing unexpected results is just due to lack of precision in the calculations. If you just format the results so they have fewer decimal places, the rounding will take care of it. Do something like this:
System.out.printf("| sin(%d) = %.7f\n", currentPoint, Math.sin(Math.toRadians(currentPoint)));
Then you will get results closer to what you expect.
Your results are correct ... for approximation try this...
result=Math.sin(Math.toRadians(value));
result=format(result);
private double format(double value) {
return (double)Math.round(value * 1000000) / 1000000; //you can change this to round up the value(for two position use 100...)
}
As mentioned above it is not an error, just the aproximation of computer's floating point arithmetic.
To get the expected answer, as sin() & cos() are between -1, 0 , +1, try to add 1 round it to the accurancy needed and substract 1.
x = round15(Math.sin(toRad(angle))+1)-1;
where round15 is defined
public double round15(double x){
DecimalFormat twoDForm = new DecimalFormat("0.##############E0");
String str = twoDForm.format(x);
return Double.valueOf(str);
}
It works for me, hope future readers like it.
The posters above are right. The correct values you are expecting are:
Sin(360 degrees) = 0
Sin(180 degrees) = 0
Sin(150 degrees) = .5
Sin(120 degrees) = .866
The code is returning the correct answers. They just need to be rounded. Try this:
System.out.printf("%s%.3f","| sin(" + currentPoint + ") = ", (Math.sin(Math.toRadians(currentPoint))));
You can change the .3f value to different numbers if you want to improve or reduce decimal precision.
For some reason it displays the sin of 360 to be -0.00. I am sure there is a more elegant solution, but this should work.
EDIT: Beaten by seconds. Use the code above mine, it is easier to read.
Also note that Math.PI, which is a double value, is not PI, but just an approximation of PI, and Math.sin(Math.PI) gives you the double value which is the closest to actual mathematical value of sin(Math.PI).
Below is the API description of the Math.sin method. Note the part in asterix.
I would bet that the difference between your expected results and the once you get are defects of floatpoint calculation or rounding problems.
sin
public static double sin(double a)
Returns the trigonometric sine of an angle. Special cases:
* If the argument is NaN or an infinity, then the result is NaN.
* If the argument is zero, then the result is a zero with the
same sign as the argument.
A result must be within 1 **ulp** of the correctly rounded result. Results
must be semi-monotonic.
Parameters:
a - an angle, in radians.
Returns:
the sine of the argument.
You must convert the angle into radians like this
Math.sin(Math.toRadians(90)) and the result must be 1
This question already has answers here:
Retain precision with double in Java
(24 answers)
Closed 4 years ago.
Seems like the subtraction is triggering some kind of issue and the resulting value is wrong.
double tempCommission = targetPremium.doubleValue()*rate.doubleValue()/100d;
78.75 = 787.5 * 10.0/100d
double netToCompany = targetPremium.doubleValue() - tempCommission;
708.75 = 787.5 - 78.75
double dCommission = request.getPremium().doubleValue() - netToCompany;
877.8499999999999 = 1586.6 - 708.75
The resulting expected value would be 877.85.
What should be done to ensure the correct calculation?
To control the precision of floating point arithmetic, you should use java.math.BigDecimal. Read The need for BigDecimal by John Zukowski for more information.
Given your example, the last line would be as following using BigDecimal.
import java.math.BigDecimal;
BigDecimal premium = BigDecimal.valueOf("1586.6");
BigDecimal netToCompany = BigDecimal.valueOf("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);
This results in the following output.
877.85 = 1586.6 - 708.75
As the previous answers stated, this is a consequence of doing floating point arithmetic.
As a previous poster suggested, When you are doing numeric calculations, use java.math.BigDecimal.
However, there is a gotcha to using BigDecimal. When you are converting from the double value to a BigDecimal, you have a choice of using a new BigDecimal(double) constructor or the BigDecimal.valueOf(double) static factory method. Use the static factory method.
The double constructor converts the entire precision of the double to a BigDecimal while the static factory effectively converts it to a String, then converts that to a BigDecimal.
This becomes relevant when you are running into those subtle rounding errors. A number might display as .585, but internally its value is '0.58499999999999996447286321199499070644378662109375'. If you used the BigDecimal constructor, you would get the number that is NOT equal to 0.585, while the static method would give you a value equal to 0.585.
double value = 0.585;
System.out.println(new BigDecimal(value));
System.out.println(BigDecimal.valueOf(value));
on my system gives
0.58499999999999996447286321199499070644378662109375
0.585
Another example:
double d = 0;
for (int i = 1; i <= 10; i++) {
d += 0.1;
}
System.out.println(d); // prints 0.9999999999999999 not 1.0
Use BigDecimal instead.
EDIT:
Also, just to point out this isn't a 'Java' rounding issue. Other languages exhibit
similar (though not necessarily consistent) behaviour. Java at least guarantees consistent behaviour in this regard.
I would modify the example above as follows:
import java.math.BigDecimal;
BigDecimal premium = new BigDecimal("1586.6");
BigDecimal netToCompany = new BigDecimal("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);
This way you avoid the pitfalls of using string to begin with.
Another alternative:
import java.math.BigDecimal;
BigDecimal premium = BigDecimal.valueOf(158660, 2);
BigDecimal netToCompany = BigDecimal.valueOf(70875, 2);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);
I think these options are better than using doubles. In webapps numbers start out as strings anyways.
Any time you do calculations with doubles, this can happen. This code would give you 877.85:
double answer = Math.round(dCommission * 100000) / 100000.0;
Save the number of cents rather than dollars, and just do the format to dollars when you output it. That way you can use an integer which doesn't suffer from the precision issues.
See responses to this question. Essentially what you are seeing is a natural consequence of using floating point arithmetic.
You could pick some arbitrary precision (significant digits of your inputs?) and round your result to it, if you feel comfortable doing that.
This is a fun issue.
The idea behind Timons reply is you specify an epsilon which represents the smallest precision a legal double can be. If you know in your application that you will never need precision below 0.00000001 then what he suggests is sufficient to get a more precise result very close to the truth. Useful in applications where they know up front their maximum precision (for in instance finance for currency precisions, etc)
However the fundamental problem with trying to round it off is that when you divide by a factor to rescale it you actually introduce another possibility for precision problems. Any manipulation of doubles can introduce imprecision problems with varying frequency. Especially if you're trying to round at a very significant digit (so your operands are < 0) for instance if you run the following with Timons code:
System.out.println(round((1515476.0) * 0.00001) / 0.00001);
Will result in 1499999.9999999998 where the goal here is to round at the units of 500000 (i.e we want 1500000)
In fact the only way to be completely sure you've eliminated the imprecision is to go through a BigDecimal to scale off. e.g.
System.out.println(BigDecimal.valueOf(1515476.0).setScale(-5, RoundingMode.HALF_UP).doubleValue());
Using a mix of the epsilon strategy and the BigDecimal strategy will give you fine control over your precision. The idea being the epsilon gets you very close and then the BigDecimal will eliminate any imprecision caused by rescaling afterwards. Though using BigDecimal will reduce the expected performance of your application.
It has been pointed out to me that the final step of using BigDecimal to rescale it isn't always necessary for some uses cases when you can determine that there's no input value that the final division can reintroduce an error. Currently I don't know how to properly determine this so if anyone knows how then I'd be delighted to hear about it.
So far the most elegant and most efficient way to do that in Java:
double newNum = Math.floor(num * 100 + 0.5) / 100;
Better yet use JScience as BigDecimal is fairly limited (e.g., no sqrt function)
double dCommission = 1586.6 - 708.75;
System.out.println(dCommission);
> 877.8499999999999
Real dCommissionR = Real.valueOf(1586.6 - 708.75);
System.out.println(dCommissionR);
> 877.850000000000
double rounded = Math.rint(toround * 100) / 100;
Although you should not use doubles for precise calculations the following trick helped me if you are rounding the results anyway.
public static int round(Double i) {
return (int) Math.round(i + ((i > 0.0) ? 0.00000001 : -0.00000001));
}
Example:
Double foo = 0.0;
for (int i = 1; i <= 150; i++) {
foo += 0.00010;
}
System.out.println(foo);
System.out.println(Math.round(foo * 100.0) / 100.0);
System.out.println(round(foo*100.0) / 100.0);
Which prints:
0.014999999999999965
0.01
0.02
More info: http://en.wikipedia.org/wiki/Double_precision
It's quite simple.
Use the %.2f operator for output. Problem solved!
For example:
int a = 877.8499999999999;
System.out.printf("Formatted Output is: %.2f", a);
The above code results in a print output of:
877.85
The %.2f operator defines that only TWO decimal places should be used.