Reputation: 2541
For the following code (Java):
double d = (double) m / n; //m and n are integers, n>0
int i = (int) (d * n);
i == m
Is the last expression always true? If it's not is this always true?:
i = (int) Math.round(d * n);
i == m
Upvotes: 5
Views: 1159
Reputation: 3761
The second question you ask concerns how large an ulp is in Java.
If the ulp exceeds 1/(n)
, then rounding the multiplication would not recover the original divided int. Typically, larger ulps are associated with larger double values. An ulp associated with a double starts to exceed 1 at around 9E15; if your recovered doubles were around there, then you might finding problems with round() not getting the expected answer. As you are working with int values, though, the largest value of the numerator of your division will be Integer.MAX_VALUE
.
The following program tests all the positive integer values of n
to see which one causes the largest potential for rounding error when trying to recover the divided int:
public static void main(String[] args)
{
// start with large number
int m = Integer.MAX_VALUE;
double d = 0;
double largestError = 0;
int bigErrorCause = -1;
for (int n = 1; n < Integer.MAX_VALUE; n++)
{
d = (double) m / n;
double possibleError = Math.ulp(d) * n;
if (possibleError > largestError)
{
largestError = possibleError;
bigErrorCause = n;
}
}
System.out.println("int " + bigErrorCause + " causes at most "
+ largestError + " error");
}
The output is:
int 1073741823 causes at most 4.768371577590358E-7 error
Rounding that using Math.round, then casting to int should recover the original int.
Upvotes: 4
Reputation: 18552
int i = (int) (d * n); i == m;
This is false for m=1, n=49.
i = (int) Math.round(d * n); i == m;
My intuition tells me it should be true, but it may be hard to prove rigorously.
Upvotes: 5
Reputation: 141917
The first on is definitely not always true. The second one I would say yes it's true, but only because I can't think of a counterexample.
If n is very large, it could possibly be false, I'm not sure really. I know it will be true at least 99% of the time though.
Upvotes: 1
Reputation: 36476
Mathematically it should be true. However you're likely going to get floating point rounding errors that will make it false. You should almost never compare floating point precision numbers using ==
.
You're much better off comparing them using a threshold like this:
Math.abs( d*n - m ) < 0.000001;
Note that the two statements should be equivalent
i = (int) (d * n);
i = (int) Math.round(d * n);
However for example, if d=3/2
and n=2
, floating point errors might result in i=2.999999999999
which after truncation/rounding is 2.
Upvotes: 1