parseDouble of Double class adds extra zero - java

public static double centsToDollars(Number cents, int precision) {
return BigDecimal.valueOf(cents.doubleValue() / 100).setScale(precision, RoundingMode.DOWN).doubleValue();
}
Code above works completely fine when I want to display cents value in dollars. For example, for 1 cent, it returns 0.01 dollar.
assertEquals("$0.01", FormatUtils.centsToDollars(1, 3))
assertEquals("$0.012", FormatUtils.centsToDollars(1.2345, 3))
assertEquals("$0.327", FormatUtils.centsToDollars(32.7, 3))
But I can't figure out, why FormatUtils.centsToDollars(0.65, 3) returns $0.0060. I expect to receive 0.006 instead. What is the latest zero about ?
Update
Looks like the root cause of the issue is invocation of doubleValue() of BigDecimal
System.out.println(Double.parseDouble("0.006"));
System.out.println(BigDecimal.valueOf(0.006).doubleValue());
returns 0.0060 for me
Any clue why this happens ?

parseDouble of Double class adds extra zero
There is a bug id:4428022 in Java 1.4 to 6 which means it adds an extra zero you don't need. This happens for values 0.001 to 0.009 only. Java 7 doesn't have this bug.
for (int i = 1; i <= 9; i++)
System.out.println(i / 1000.0);
in Java 6 prints
0.0010
0.0020
0.0030
0.0040
0.0050
0.0060
0.0070
0.0080
0.0090
but in Java 7 prints
0.001
0.002
0.003
0.004
0.005
0.006
0.007
0.008
0.009
I suspect that 0.65 is actually slightly less in reality. When you divide it by 100 you get something like 0.006499999999999 which when rounded drops to 0.006
I suspect what you wanted was
public static String centsToDollars(Number cents, int precision) {
return "$" + BigDecimal.valueOf(cents.doubleValue())
.divide(BigDecimal.valueOf(100))
.setScale(precision, RoundingMode.HALF_UP);
}
Try
System.out.println(new BigDecimal(0.65 / 100));
This is how I would write it
public static String centsToDollars(double cents) {
double rounded = Math.round(cents * 100) / 1e4;
return "$" + rounded;
}
This assumes two decimal places of cents.

parseDouble of Double class adds extra zero
No it doesn't. The methods you are using to format the double is doing that. Doubles don't contain trailing decimal zeros. They don't contain decimal anything.

Related

Calculation gives different results

I'm trying to calculate a formula in Android:
percent = absence/(week*(37/period))*100;
The value for absence is 4, week is 2, and period is 2. percent returns 11.111111.
But if I do the same in Excel with formula 4/(2*(37/2))*100, it returns 10.81.
Can anyone explain me what might be wrong?
It's because of integer division.
The value for absence is 4, week is 2, and period is 2. percent returns 11.111111.
This is because 37 / 2 is 18.5, and the fractional part is thrown out because of integer division. That gives 18, which multiplied by 2 is 36. Next we divide 4 by 36, which is 0.111... That multiplied by 100 is 11.111....
But if I do the same in Excel with formula 4/(2*(37/2))*100, it returns 10.81.
This is because Excel doesn't use integer division. 37 / 2 is 18.5, 18.5 * 2 is 37. 4 / 37 is 0.108108108... Thus multiplying by 100 gives approximately 10.81.
Explanation
The reason it's doing integer division is because you have an integer period. Java sees that there are two integers and are being divided so it uses integer division. This causes all fractional parts to be erased, meaning the 0.5 from 18.5 resulting from 37 / 2 is removed, making the results different.
Fix
You can 'fix' this by making at least one of the operands in the division float or double:
double percent = absence/(week*((double) 37/period))*100;
What this will do is achieve floating-point division giving 10.8108...
Declare all of the variables as double and it will work as you expect:
public static void main(String[] args) {
double period = 2;
double absence = 4;
double week = 2;
double percent = absence /(week *(37/period ))*100;
System.out.println("percent: " + percent);
}
Gives the output:
percent: 10.81081081081081
If your period variable is declared as an int, your output will change to:
percent: 11.11111111111111
This is becuase you're losing precision due to rounding down when you divide 37 by the int period. If you change it to double, it will give you the expected result.

Multiply percantage values

I need to multiply a double value by 12%, how can I do so?
public class AnnualMaintenanceFee {
public void GetTotal(int TotalND) {
double software=1500;
double TNDWithSof= 1500+TotalND;
double AMF= TNDWithSof 12;
System.out.println("New Total: "+AMF);
}
}
Simply do this,
double AMF= TNDWithSof * 0.12; // 0.12 means 12/100(12%), you can use 0.12 directly
System.out.println("New Total: "+AMF);
Here you go :
(yourDouble * 12) / 100
The % in 12% is no more than an operator that divides by 100 (or equivalently from a mathematical perspective, multiplies by 0.01).
So 12% can be written as 12 * 0.01. I prefer that to writing 12 / 100 since the latter, unless you're careful, will be performed in integer division with any fractional part being discarded.
Do consider using a currency type though for money values: floating point numbers are not designed to represent exact money amounts.
For multiplication use *, for percent 12% you can use 12/100 like:
double AMF= TNDWithSof*(12/100);
System.out.println("New Total: "+AMF);
Because the division(12/100) be evaluated in first because it's inside bracket, and finally evaluate TNDWithSof*0.12.

Floating point precision with Math.Ceil (Java)

I'm implementing a business rule to calculate a percentage increase on a stock level:
Stock level | Percentage Increase | Expected output
100 | 93 | 193
As decimal stock levels are not well defined the rule is to round up the output:
public int calculateStockLevel(int rawStockLevel, double percentageIncrease) {
return Math.ceil(rawStockLevel * (1 + (percentageIncrease / 100));
}
Actual output for the situation above: 194 (The test fails)
This looks like a floating point precision error, whats an elegant & readable way to get this test to pass?
You should use BigDecimal to specify what precision you want, but for your case you could do something simpler: just divide by 100 at the end.
public int calculateStockLevel(int rawStockLevel, double percentageIncrease) {
return Math.ceil(rawStockLevel * (100 + percentageIncrease) / 100);
}
Binary floating-point types can't represent exactly every value in decimal. So percentageIncrease / 100 will get the closest representation in binary. In your case the exact value of 0.93 in double precision is 0.930000000000000048849813083507, which is slightly more than the true decimal value. Therefore after ceil it'll be rounded up to 0.94
If you want exact decimal output you must use decimal arithmetic, like BigDecimal. But in your case you can just do it in plain integer, utilizing the fact that the fractional part of the result must be larger than 0 if remainder of the division is non-zero.
int temp = rawStockLevel * (100 + percentageIncrease);
int result = temp/100;
if (temp % 100 != 0)
result++; // round up if not divisible by 100
return result;

How to round to the nearest 0.05? [duplicate]

This question already has an answer here:
Java rounding to nearest 0.05
(1 answer)
Closed 8 years ago.
I'm trying to find a way on how to round to the nearest 0.05 in java. Let's say that I have the following numbers:
0.33
0.02
0.874
0.876
This should become:
0.35
0.00
0.85
0.90
I tried many things and I can only get it to round to n places behind the comma by using BigDecimal, but I can't seem to find a way for this one.
Can someone help me?
EDIT: Thank you for all your help, I am amazed at how easy this could be done. And how do I get the double converted into a string properly? I can't use Double.toString(double d) because for example the string will be "0.9" instead of "0.90"?
0.05 == 1/20, right? Therefore, what you need is just the nearest number with dividing by 1/20, so, you may multiply this number by 20, get the nearest number with dividing by 1, then get the initial things.
TL;DR: you just may just multiply it by 20, round and divide by 20 again:
public double customRound(double num) {
return Math.round(num * 20) / 20.0;
}
A simple way would be:
double d = 0.33;
double roundedTimes20 = Math.round(d * 20);
double rounded = roundedTimes20 / 20; //0.35
but note that the resulting double is not necessarily the exact representation of the rounded number (usual floating point caveat) and that the method assumes that your original double times 20 can fit in a long.
Try a function:
public static double round05(double num) {
return Math.round(num * 20) / 20.0;
}
You can use String.format to format value to String
String s = String.format("%.2f", 0.9);

generate ill-conditioned data for testing floating point summation

I have implemented a Kahan floating point summation algorithm in Java. I want to compare it against the built-in floating point addition in Java and infinite precision addition in Mathematica. However the data set I have is not good for testing, because the numbers are close to each other. (Condition number ~= 1)
Running Kahan on my data set gives all most the same result as the built-in +.
Could anyone suggest how to generate a large amount of data that can potentially cause serious rounding off error?
However the data set I have is not good for testing, because the numbers are close to each other.
It sounds like you already know what the problem is. Get to it =)
There are a few things that you will want:
Numbers of wildly different magnitudes, so that most of the precision of the smaller number is lost with naive summation.
Numbers with different signs and nearly equal (or equal) magnitudes, such that catastrophic cancellation occurs.
Numbers that have some low-order bits set, to increase the effects of rounding.
To get you started, you could try some simple three-term sums, which should show the effect clearly:
1.0 + 1.0e-20 - 1.0
Evaluated with simple summation, this will give 0.0; clearly incorrect. You might also look at sums of the form:
a0 + a1 + a2 + ... + an - b
Where b is the sum a0 + ... + an evaluated naively.
You want a heap of high precision numbers? Try this:
double[] nums = new double[SIZE];
for (int i = 0; i < SIZE; i++)
nums[i] = Math.rand();
Are we talking about number pairs or sequences?
If pairs, start with 1 for both numbers, then in every iteration divide one by 3, multiply the other by 3. It's easy to calculate the theoretical sums of those pairs and you'll get a whole host of rounding errors. (Some from the division and some from the addition. If you don't want division errors, then use 2 instead of 3.)
By experiment, I found following pattern:
public static void main(String[] args) {
System.out.println(1.0 / 3 - 0.01 / 3);
System.out.println(1.0 / 7 - 0.01 / 7);
System.out.println(1.0 / 9 - 0.001 / 9);
}
I've subtracted close negative powers of prime numbers (which should not have exact representation in binary form). However, there are cases then such expression evaluates correctly, for example
System.out.println(1.0 / 9 - 0.01 / 9);
You can automate this approach by iterating power of subtrahend and stopping when multiplication by appropriate value doesn't yield integer number, for example:
System.out.println((1.0 / 9 - 0.001 / 9) * 9000);
if (1000 - (1.0 / 9 - 0.001 / 9) * 9000 > 1.0)
System.out.println("Found it!");
Scalacheck might be something for you. Here is a short sample:
cat DoubleSpecification.scala
import org.scalacheck._
object DoubleSpecification extends Properties ("Doubles") {
/*
(a/1000 + b/1000) = (a+b) / 1000
(a/x + b/x ) = (a+b) / x
*/
property ("distributive") = Prop.forAll { (a: Int, b: Int, c: Int) =>
(c == 0 || a*1.0/c + b*1.0/c == (a+b) * 1.0 / c) }
}
object Runner {
def main (args: Array[String]) {
DoubleSpecification.check
println ("...done")
}
}
To run it, you need scala, and the schalacheck-jar. I used version 2.8 (I don't have to say, that your c-path will vary):
scalac -cp /opt/scala/lib/scalacheck.jar:. DoubleSpecification.scala
scala -cp /opt/scala/lib/scalacheck.jar:. DoubleSpecification
! Doubles.distributive: Falsified after 6 passed tests.
> ARG_0: 28 (orig arg: 1030341)
> ARG_1: 9 (orig arg: 2147483647)
> ARG_2: 5
Scalacheck takes some random values (orig args) and tries to simplify these, if the test fails, in order to find simple examples.

Categories

Resources