Java Math.pow() Rounding Error - java

I'm having trouble with (what I suspect is) a rounding error.
I have a string, 0.686357E-01, which I'm trying to convert to a double. I've been able to split it up using the Pattern.split() function, and I'm capturing the base and the exponent values just fine. However, once I try to multiply them appropriately, I get this as a result: 0.06863570000000001.
Here's my relevant code:
pattern = Pattern.compile("E\\+?");
String[] number = pattern.split(string);
double base = Double.parseDouble(number[0]);
int exponent = Integer.parseInt(number[1]);
number= base*Math.pow(10, exponent);
So, how do I avoid the rounding error? (There are ways that I can work around it, but if it's possible to do, then I'd like to know how to fix the issue)
Thanks.

You don't need to split it, Double.parseDouble can handle those kinds of numbers just fine.
double number = Double.parseDouble("0.686357E-01");
See? It works!

0.0686357 is not exactly representable as a double-precision value.
Two solutions:
Use e.g. BigDecimal.
Limit the displayed precision to a certain number of significant figures when converting back to human-readable.

Floating point numbers do not have perfect precision. If that is an issue, use BigDecimal:
String string = "0.686357E-01";
BigDecimal number = new BigDecimal(string);
System.out.println(number);

Double will print always like that, but the value will remain correct. You'll need to format the output to get the correct value. See DecimalFormat class.

Related

BigDecimal Java. How to append zeros in front

My question is basically the following:
When I use a value with BigDecimal, how do I append zeros in front of a random number?
Say I want to have a number <10 following an entirely random pattern. Now i want to add zeros in front of the number, so the actual amount adds up to 10 numbers.
Here's an example:
BigDecimal num = new BigDecimal(2353);
Now I want to have that ouput:
0000002353
Is there a function that appends numbers to a BigDecimal type?
I couldn't find any.
I tried using a while loop that checks whether the number is less than ten. But I don't understand the Big Decimal well enough to actually compare integral values to the BigDecimal types.
Thanks for any help in advance!
If you use a BigInteger instead (or any integer type, such as int or long) you can format the value with
String.format("%010d", BigInteger.valueOf(2353))
The leading 0 in the format strings means pad with 0, the following 10 is the desired length...
BigDecimal is meant to be used for storing large floating point numbers. Since in a floating-point number there isn't any difference between 0000002353 and 2353, there is no reasonable way to append leading 0's to a BigDecimal just as there is no reasonable way to append leading 0's to a normal float. According to the behavior you're looking for, I would suggest using a String to store your number, and then convert to and from BigDecimal when you want to perform any operations.
To compare an integral type to a BigDecimal, first convert the variable to a BigDecimal and then call BigDecimal's compareTo method. More info is in this question.
Since you're interested in formatting the number, you might want to look at DecimalFormat class, which allows to format floating point and integer numbers according to the specified pattern.
BigDecimal num = new BigDecimal(2353);
DecimalFormat f1 = new DecimalFormat("0000000000");
DecimalFormat f2 = new DecimalFormat("0,000,000,000");
System.out.println(f1.format(num));
System.out.println(f2.format(num));
Output:
0000002353
0,000,002,353
If the maximum number of digits is 10 and only whole numbers are allowed you don't need anything more than to use long with standard formatting:
long myNumber = 123456;
System.out.printf("%010d%n", myNumber);

decimal points precision is lost for some munbers in case of double data type

I am suprise to see the below program please advise how it is behaving like this as i aam very much concerened with poitn to precison after decimal point , below is the progrmam
double fixedRate = 0.997500000000; //**output --->0.9975
// BigDecimal fixedRate = new BigDecimal("0.997500000000");
double fixedRate1 = 0.1234567890123456789;
System.out.println(fixedRate);
System.out.println(fixedRate1);
and the output is
0.9975
0.12345678901234568
now please advise for the first the ouput is 0.9975 but late on for next it is not truncating after decimal points but why for first then.
The precision is not lost. It is just not printed because you do not need more digits to distinguish the printed value from any other double value.
If you do want to force a certain number of fractional digits, take a look at System.out.printf() or String.format().
See https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html for more details and possible formats.
The result may look like this:
System.out.printf("%.19f%n",fixedRate);
System.out.printf("%.19f%n", fixedRate1);
This is a printing problem.Please use this format to print your values and tell me the result:
double fixedRate = 0.997500000000;
double fixedRate1 = 0.1234567890123456789;
System.out.println(String.format("%.19f", fixedRate ));
System.out.println(String.format("%.19f", fixedRate1 ));
Good Luck !
According to your question
for the first the ouput is 0.9975 but late on for next it is not
truncating after decimal points but why for first then
Since double is numeric datatype and hence cannot hold the leading and trailing zeros.
A double doesn't care about formatting - it's about storage only. When you print it, it is converted to a String (using Double's static toString method).
In simple terms the value 0.9975 is not different from 0.997500000000or it is same as 0.997500000000 as zeros after a number will not have any value.
But consider if you had value like this 0.9975000000001 then all the numbers will be printed. Check it here.
If you want to format the value then you can see this question : How to properly display a price up to two decimals (cents) including trailing zeros in Java?

Arithmetic expression calculates 6.135157E-6 instead of zero

I have the below code somewhere in my app
float private myMethod(float c){
result = (float) (c+273.15);
}
When "c" gets the value something like -273.1455 the result is something very near to zero like 0.0044.
But when it gets the value -273.15 i get this instead of zero: 6.1035157E-6
Why does this happen?
The problem is that 273.15 is a double, not a float, and neither of them can represent 273.15 exactly. However, since they have different precision they will round actually store different numbers. When the addition is done the c is converted to a double which will be able store the float representation of 273.15. So now you have two doubles with almost the same value and the difference will be non zero.
To get "more predictable" result, use 273.15f to ensure you have floats through the calculations. That should solve this problem but what you need to do is to read up on binary floating point arithmetics and how that differs from decimal arithmetic that we are taught in school.
Wiki on floating point is a good place to start.
Floating point calculations in computers are not accurate. You should read something about floating point arithmetics to prevent such errors.
The problem is not with the value, but with the display to the user.
I'm assuming you are converting it into a String. The way this is done is detailed in http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Double.html#toString(double)
To Display a correct value use the NumberFormat class http://docs.oracle.com/javase/1.4.2/docs/api/java/text/NumberFormat.html
Example :
NumberFormat formater = NumberFormat.getNumberInstance()
formatter.setMaximumFractionDigits(4);
formater.format(myMethod(-273.15))
Now you should get 0.

Formatting decimal places in Java

I'm trying to format a double to just 2 decimal places in Java.
I've read the following post:
How to round a number to n decimal places in Java
For some reason, every one of those methods fails to work on certain numbers I have..
For example:
DecimalFormat df = new DecimalFormat("#.##");
normalizedValue = Double.valueOf(df.format(normalizedValue));
If I print normalizedValue I get result similar to the following:
-78.64000000000001
18.97
59.469999999999985
-63.120000000000005
(Note: some are formatted correctly... some aren't)
So, these methods seem to round, but I need something that will remove all decimals after 2 decimal places... Any suggestions?
Thank you.
The string representation given by DecimalFormat.format(...) does indeed have only 2 digits in your example. But as soon as you reconvert it into a double those accuracy issues occur. A binary base format like double will always show such effects when you try to represent "exakt" decimal fractions. You may change to BigDecimal to get rid of such effects.

How to always display a BigDecimal object in full decimal format instead of scientific notation?

I have a BigDecimal object, myNumber, with unknown length. For example: 12345678.
I always want to divide this number by 1 million, so I do:
myNumber.divide(BigDecimal.valueOf(1000000))
I get 12.345678.
I want to display this as a string "12.345678", without cutting off ANY decimal places.
So I do
myNumber.divide(BigDecimal.valueOf(1000000)).toString()
This works fine with the above example. But if myNumber is something ridiculously small or big, such as:
0.00000001
After dividing 0.00000001 by a million and converting to string, it displays as scientific notation, which is not what I want. I want it to always display in full decimal format (in this case, 0.00000000000001).
Any ideas?
You have to perform the division using the variant of divide() that includes a rounding mode and a scale, and set the scale large enough to include all the fractional digits.
int s = myNumber.scale();
BigDecimal result = myNumber.divide(BigDecimal.valueOf(1000000), s+6, RoundingMode.UNNECESSARY);
Then use toPlainString() to format.
I think that BigDecimal.toPlainString() is the method you need. However, note that the division itself will throw an exception when the decimal representation is infinite, such as with 1/3.
BigDecimal.toString or toPlainString would help.
You can use BigDecimal.toPlainString() to return "a string representation of this BigDecimal without an exponent field".
The scientific notation on the other hand is returned by BigDecimal.toEngineeringString().

Categories

Resources