This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 7 years ago.
public double hypotenuse()
{
//return Math.hypot(leg, leg); //returns 7.0710678118654755
//return 0.1 * Math.floor(Math.hypot(leg, leg) * 10); //returns 7.0
//return 0.1 * Math.ceil(Math.hypot(leg, leg) * 10); //returns 7.1000000000000005
return 0.1 * Math.round(Math.hypot(leg, leg) * 10); //returns 7.1000000000000005
}
I am trying to round to the nearest 10th place, so this number should round up to 7.1. Why does this method work with Math.floor but not with Math.round? Does anyone have any insight?
Thanks,
Sky
In regards to your answer to yourself, you don't want to convert an object of type A to type B, operate on it, and then convert it back to type A. Not if you can do anything else.
The following does what you want it to do:
public double hypotenuse()
{
return Math.round(Math.hypot(leg, leg) * 10) / 10.0;
}
I'm not entirely sure why. It would take some digging into what this compiles down to at the assembly level.
The real problem is that each double in Java only has a limited number of bits to store its decimal portion. There are an infinite number of possible real numbers in real life. There is no way you can represent every single real number with only 64 bits. This is why you should avoid floating point calculations in banking apps and software that requires the number to be exact. Multiplying a few doubles together can introduce quite a significant error margin in the calculation. See this explanation on another SO answer, which does a great job of explaining this further.
If you really need it to be exact, use BigDecimal.
Nevermind, this is what I found that works.
public double hypotenuse()
{
double hypot = Math.hypot(leg, leg);
String str = String.format("%1.1f", hypot);
hypot = Double.valueOf(str);
return hypot;
}
If this is for JS:
The Math.round() function returns the value of a number rounded to the nearest integer.
Related
This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 2 years ago.
I want to round up a double value in java. Always to round up the value in ispite that matematecally correct way, sometimes, is round down the value. For example:
value = 6.5817
I want to round up, keeping two decimals. So I need the value will be like this:
value = 6.59
The important thing here is always keep two decimals and always round up the second decimal if the value have more two decimals.
Have someone idea how I can to do this in java?
Since double values are inexact, e.g. it cannot store a number like 0.07 exactly, you need to use BigDecimal to help round up a double value, with the least probability of getting the wrong value.
To round to 2 decimals, use:
double value = 6.5817;
double roundedUp = BigDecimal.valueOf(value).setScale(2, RoundingMode.UP).doubleValue();
System.out.println(roundedUp); // prints 6.59
Note that this code prints 0.07 when value = 0.07, unlike e.g. Math.ceil(value * 100.0) / 100.0, which incorrectly prints 0.08.
Try the following:
double a = 6.5817;
Math.ceil(a * 100.0) / 100.0;
This question already has answers here:
Why not use Double or Float to represent currency?
(16 answers)
Is floating point math broken?
(31 answers)
Closed 7 years ago.
I am working on a project where we are calculating prices of items with 8 places of decimal points.
But sometime calculation results are different.
I tried some samples but getting different calculation results:
public static void main(String[] args) {
double value1 = 0.999939f * 0.987792f;
double value2 = 0.999939 * 0.987792;
double value3 = (double)0.999939f * 0.987792f;
System.out.println("value 1 : "+ value1);
System.out.println("value 2: "+ value2);
System.out.println("value 3 : "+ value3);
}
Outputs are:
value 1 : 0.9877317547798157
value 2 : 0.9877317446880001
value 3 : 0.9877317839126931
These three are different results.
I am confused. Can anyone please clarify me what is happening here?
Thanks.
I went through some already answered, But I just want some ways where I can calculate with float and doubles only. otherwise I have to change many places. It will be painful.
Because of how floats and decimals are represented, the casts could be causing different results.
For: double value1 = 0.999939f * 0.987792f you are multiplying two floats and then casting it to a double. The resulting float representation is the one being converted to a double.
For: double value2 = 0.999939 * 0.987792; you are multiply two doubles and saving it in a double. This is time there is no casting so the representation never changes (ie. no potential data loss from change in data representation).
For: double value3 = (double)0.999939f * 0.987792f; you are multiplying a double that is casted from a float, times a float. Because of how the Java math works, that second float is probably also being casted to a double, so now you are multiplying two doubles that were once floats causing a third set of representations.
Because float and doubles have different precisions each of these will get a different result. For more info about floating point arithmetic, see here.
When you write a number with the "f" character, it is taken as float, meaning it is encoded with 32bits, whereas without it, it is a double, encoded with 64bits.
The more bits, the more accurately you will represent decimal numbers. This does not make a difference for number with few decimals, but in your case it is significant.
In conclusion, use exclusively double variables in your code.
I have a float-based storage of decimal by their nature numbers. The precision of float is fine for my needs. Now I want is to perform some more precise calculations with these numbers using double.
An example:
float f = 0.1f;
double d = f; //d = 0.10000000149011612d
// but I want some code that will convert 0.1f to 0.1d;
Update 1:
I know very well that 0.1f != 0.1d. This question is not about precise decimal calculations. Sadly, the question was downvoted. I will try to explain it again...
Let's say I work with an API that returns float numbers for decimal MSFT stock prices. Believe or not, this API exists:
interface Stock {
float[] getDayPrices();
int[] getDayVolumesInHundreds();
}
It is known that the price of a MSFT share is a decimal number with no more than 5 digits, e.g. 31.455, 50.12, 45.888. Obviously the API does not work with BigDecimal because it would be a big overhead for the purpose to just pass the price.
Let's also say I want to calculate a weighted average of these prices with double precision:
float[] prices = msft.getDayPrices();
int[] volumes = msft.getDayVolumesInHundreds();
double priceVolumeSum = 0.0;
long volumeSum = 0;
for (int i = 0; i < prices.length; i++) {
double doublePrice = decimalFloatToDouble(prices[i]);
priceVolumeSum += doublePrice * volumes[i];
volumeSum += volumes[i];
}
System.out.println(priceVolumeSum / volumeSum);
I need a performant implemetation of decimalFloatToDouble.
Now I use the following code, but I need a something more clever:
double decimalFloatToDouble(float f) {
return Double.parseDouble(Float.toString(f));
}
EDIT: this answer corresponds to the question as initially phrased.
When you convert 0.1f to double, you obtain the same number, the imprecise representation of the rational 1/10 (which cannot be represented in binary at any precision) in single-precision. The only thing that changes is the behavior of the printing function. The digits that you see, 0.10000000149011612, were already there in the float variable f. They simply were not printed because these digits aren't printed when printing a float.
Ignore these digits and compute with double as you wish. The problem is not in the conversion, it is in the printing function.
As I understand you, you know that the float is within one float-ulp of an integer number of hundredths, and you know that you're well inside the range where no two integer numbers of hundredths map to the same float. So the information isn't gone at all; you just need to figure out which integer you had.
To get two decimal places, you can multiply by 100, rint/Math.round the result, and multiply by 0.01 to get a close-by double as you wanted. (To get the closest, divide by 100.0 instead.) But I suspect you knew this already and are looking for something that goes a little faster. Try ((9007199254740992 + 100.0 * x) - 9007199254740992) * 0.01 and don't mess with the parentheses. Maybe strictfp that hack for good measure.
You said five significant figures, and apparently your question isn't limited to MSFT share prices. Up until doubles can't represent powers of 10 exactly, this isn't too bad. (And maybe this works beyond that threshold too.) The exponent field of a float narrows down the needed power of ten down to two things, and there are 256 possibilities. (Except in the case of subnormals.) Getting the right power of ten just needs a conditional, and the rounding trick is straightforward enough.
All of this is all going to be a mess, and I'd recommend you stick with the toString approach for all the weird cases.
If your goal is to have a double whose canonical representation will match the canonical representation of a float converting the float to string and converting the result back to double would probably be the most accurate way of achieving that result, at least when it's possible (I don't know for certain whether Java's double-to-string logic would guarantee that there won't be a pair of consecutive double values which report themselves as just above and just-below a number with five significant figures).
If your goal is to round to five significant figures a value which is known to have been rounded to five significant figures while in float form, I would suggest that the simplest approach is probably to simply round to five significant figures. If your magnitude of your numbers will be roughly within the range 1E+/-12, start by finding the smallest power of ten which is smaller than your number, multiply that by 100,000, multiply your number by that, round to the nearest unit, and divide by that power of ten. Because division is often much slower than multiplication, if performance is critical, you might keep a table with powers of ten and their reciprocals. To avoid the possibility of rounding errors, your table should store for each power of then the closest power-of-two double to its reciprocal, and then the closest double to the difference between the first double and the actual reciprocal. Thus, the reciprocal of 100 would be stored as 0.0078125 + 0.0021875; the value n/100 would be computed as n*0.0078125 + n*0.0021875. The first term would never have any round-off error (multiplying by a power of two), and the second value would have precision beyond that needed for the final result, so the final result should thus be rounded accurately.
I have weird decimal calculation that really surprise me, I have two big decimal number, one is a normal proce and the other one is an offer price. Then I want to calculate discount percentage and ceil it to the nearest integer.
Here are the code:
BigDecimal listPrice = new BigDecimal(510000);
BigDecimal offerPrice = new BigDecimal(433500);
int itemDiscount = (int)Math.ceil(((listPrice.longValue() - offerPrice.longValue()) / (float) listPrice.longValue()) * 100);
I expect it would set 15 as value of itemDiscount, but surprisingly it has 16, wow. Then i print each calculation to show in which statement is the problem, so i put System.out.println for each statement as below :
System.out.println(listPrice.longValue() - offerPrice.longValue()); //==> show 76500
System.out.println((listPrice.longValue() - offerPrice.longValue()) / (float) listPrice.longValue()); // ==> 0.15
System.out.println((listPrice.longValue() - offerPrice.longValue()) * 100 / (float) listPrice.longValue()); // ==> 15.000001
the problem is in above statement, istead of returning 15.0, it return 15.000001. And when i ceil it, it will of course return 16 instead of 15.
What is the explanation if this case? is this the way it is or it is a bug?
What is the explanation if this case? is this the way it is or it is a bug?
It is the way it is. It is not a bug.
You are doing the calculation using floating point types (float) and floating point arithmetic is imprecise.
I'm not sure what the best fix is here. Maybe doing the computation using BigDecimal arithmetic methods would give a better result, but it is by no means guaranteed that you won't get similar problems in this calculation with different inputs ...
However, I suspect that the real problem is that you should not be using ceil in that calculation. Even BigDecimal will give you rounding errors; e.g. if your computation involves dividing by 3, the intermediate result cannot be precisely represented using a base-10 representation.
The correct way to do calculations using Real numbers is to properly take account of the error bars in the calculation.
Try using the divide method directly from the BigDecimal class. If you are casting to a float then you are not using the benefit of BigDecimal .
http://www.roseindia.net/java/java-bigdecimal/bigDecimal-divide-int.shtml
This question already has answers here:
Rounding Errors?
(9 answers)
Closed 10 years ago.
Why does this code print 2.4099999999999997, instead of just 2.41
public class Main
{
public static void main(String args[])
{
double d = 5.55%3.14;
System.out.println(d);
}
}
The problem is not the modulo operator, but rather the nature of floating point numbers. A double cannot hold the precise value of either 5.55, 3.14 or 2.41, so you get an approximate answer.
To understand this better, try to write down the value of 1/3 as a decimal, when you only have limited space on the paper to write it. You'll end up with something like 0.33333, which is an approximation of the actual value. The same happens to 5.55 when you write it in binary - it turns into 101.10001100110011001100110011... which gets cut off somewhere to fit the space of the double.
import java.text.DecimalFormat;
double d = 5.55%3.14;
DecimalFormat df = new DecimalFormat("#.##");
System.out.println( df.format( d ));
Add DecimalFormat
Edit:
You can also
double d = 5.55%3.14;
System.out.printf("%1$.2f", d);
Java double can have precision issues.
Why don't you try BigDecimal ?
the reason is that java doesn't do math the way we do. java uses binary numbers (from chapter 4 of Horstmann's big java book) so to a computer, 435 = 4 * 10^2 + 3 * 10^1 + 5 * 10^0
it does this because binary numbers (1 or 0) are easier to manipulate since switches in the computer are either on or off (1 or 0).
this results in occassional rounding issues. if you want to force it to round, then do things like use a decimal format, or if you just need the displayed value rounded you can use String.format or printf