How to determine if two doubles are nearly equal - java

I'm trying to find some Java code to determine if two doubles are nearly equal. I did a lot of Googling and found bits and pieces that I've put together here. Where it starts to escape me is the use of a "relative epsilon". This approach seems like what I'm looking for. I don't want to have to specify the epsilon directly but want to use an epsilon based on the magnitudes of the two arguments. Here is the code I put together, I need a sanity check on it. (P.S. I know just enough math to be dangerous.)
public class MathUtils
{
// http://stackoverflow.com/questions/3728246/what-should-be-the-
// epsilon-value-when-performing-double-value-equal-comparison
// ULP = Unit in Last Place
public static double relativeEpsilon( double a, double b )
{
return Math.max( Math.ulp( a ), Math.ulp( b ) );
}
public static boolean nearlyEqual( double a, double b )
{
return nearlyEqual( a, b, relativeEpsilon( a, b ) );
}
// http://floating-point-gui.de/errors/comparison/
public static boolean nearlyEqual( double a, double b, double epsilon )
{
final double absA = Math.abs( a );
final double absB = Math.abs( b );
final double diff = Math.abs( a - b );
if( a == b )
{
// shortcut, handles infinities
return true;
}
else if( a == 0 || b == 0 || absA + absB < Double.MIN_NORMAL )
{
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
// NOT SURE HOW RELATIVE EPSILON WORKS IN THIS CASE
return diff < ( epsilon * Double.MIN_NORMAL );
}
else
{
// use relative error
return diff / Math.min( ( absA + absB ), Double.MAX_VALUE ) < epsilon;
}
}
}

I would use a library for this, the one I normally use is DoubleMath fro Googles Guava library. https://google.github.io/guava/releases/19.0/api/docs/com/google/common/math/DoubleMath.html
if (DoubleMath.fuzzyEquals(a, b, epsilon)) {
// a and b are equal within the tolerance given
}
there is also a fuzzyCompare.

The usual way to compare 2 floating values a,b is:
if ( Math.abs(a-b) <= epsilon ) do_stuff_if_equal;
else do_stuff_if_different;
where Math.abs() is absolute value. As I do not code in JAVA you need to use double variant if that is not the case. The epsilon is your difference. As mentioned ulp is too small for this. You need to use value that makes sense for the values you are comparing. So how to compute epsilon?
That is a bit tricky and yes it is possible to use magnitude of a,b but that is not robust way because if exponents of a,b are too different you can obtain false positives easily. Instead you should use a meaning-full value. For example if you are comparing position coordinates then the epsilon should be fraction of min detail or minimal distance you consider as the same point. For angles some minimal angle that is small enough like 1e-6 deg but the value depends on ranges and accuracy you work with. For normalized <-1,1> ranges I usually use 1e-10 or 1e-30.
As you can see the epsilon depends mostly on target accuracy and magnitude and change very from case to case so creating some uniform way (to get rid of epsilon like you want) is not safe and only would lead to head aches later on.
To ease up this I usually define a _zero constant or variable (in case of computational classes) that can be changed. Set it on default to value that is good enough for most cases and if cause problems at some point I know I can easily change it ...
If you want to do it your way anyway (ignoring above text) then you can do this:
if (Math.abs(a)>=Math.abs(b)) epsilon=1e-30*Math.abs(b);
else epsilon=1e-30*Math.abs(a);
but as I said this may lead to wrong results. If you persist on using ulp then I would use Min instead of Max.

You can use the class org.apache.commons.math3.util.Precision from the Apache Commons Math. Example:
if (Precision.equals(sum, price, 0.009)) {
// arguments are equal or within the range of allowed error (inclusive)
}

Related

Why is Java's Math.min so slow in my Android app?

I had some code I was profiling and was surprised at how much time was being spent on Math.min(float, float).
In my use case I needed to get the min of 3 float values, each value is guaranteed to not be NAN or another edge case float value.
My original method was:
private static float min2(float v1, float v2, float v3) {
return Math.min(Math.min(v1,v2),v3);
}
But I found that this was about 5x faster:
private static float min1(float v1, float v2, float v3) {
if (v1 < v2 && v1 < v3) {
return v1;
}
else if (v2 < v3) {
return v2;
}
else {
return v3;
}
}
For reference this is the code for Math.min:
public static float min(float f1, float f2) {
if (f1 > f2) {
return f2;
}
if (f1 < f2) {
return f1;
}
/* if either arg is NaN, return NaN */
if (f1 != f2) {
return Float.NaN;
}
/* min(+0.0,-0.0) == -0.0 */
/* 0x80000000 == Float.floatToRawIntBits(-0.0f) */
if (Float.floatToRawIntBits(f1) == 0x80000000) {
return -0.0f;
}
return f2;
}
Note: My use case was symmetric and the above was all true for max instead of min.
EDIT1:
It turns out ~5x was an overstatement, but I am still seeing a speed difference inside my application. Although I suspect that may be due to not having a proper timing test.
After posting this question I wrote a proper micro optimization speed test in a separate project. Tested each method 1000 times on random floats and they both took the same amount of time. I don't think it would be useful to post that code as it's just confirming what we all already thought.
There must be something specific to the project I'm working on causing the speed difference.
I'm doing some graphic work in an Android app, and I was finding the min/max of the values from 3 touch events. Again, edge cases like -0.0f and the different infinities are not an issue here. Values range between 0.0f and say 3000f.
Originally I profiled my code using the Android Device Monitor's Method Profiling tool, which did show a ~5x difference. But, this isn't the best way to micro-profile code as I have now learned.
I added the below code inside my application to attempt to get better data:
long min1Times = 0L;
long min2Times = 0L;
...
// loop assigning touch values to v1, v2, v3
long start1 = System.nanoTime();
float min1 = min1(v1, v2, v3);
long end1 = System.nanoTime();
min1Times += end1 - start1;
long start2 = System.nanoTime();
float min2 = min2(v1, v2, v3);
long end2 = System.nanoTime();
min2Times += end2 - start2;
double ratio = (double) (min1Times) / (double) (min2Times);
Log.d("", "ratio: " + ratio);
This prints a running ratio with each new touch event. As I swirl my finger on the screen, the first ratios logged are either 0.0 or Infinity or NaN. Which makes me think this test isn't very accurately measuring the time. As more data is collected the ratio tends to vary between .85 and 1.15.
The problem is about the precision of float values.
If you would call your method with the arguments (0.0f, -0.0f, 0.0f), it will return you 0.0f to be the smallest float - which it isn't (float-wise, -0.0f is smaller)
the nested Min-Method will return the expected result.
So, to answer your question: If two methods are not 100% equal - there is no point in comparing their performance :-)
Java will handle 0.0f == -0.0f as true, but: new Float(0.0)).equals(new Float(-0.0)) will be false! Math.Min will consider this, your method not.
When working with float values, you should never use smaller or equal to operators. Instead you should compare numbers based on your preselected delta to consider them smaller, greater or equal.
float delta = 0.005
if (Math.abs(f1 - f2) < delta) //Consider them equal.
if (Math.abs(f1 - f2) > delta) // not equal.
And that's what's happening at the end of the Math.min method - JUST in a very very precise manner by actually checking if one number is -0.0f - bitwise.
So the drawback in performance is just the more prcise result beeing calculated.
However, if you compared float values like "10", "5", and "8" - there shouldnt be a performance difference, cause the 0-check is never hit.
A problem with the performance of the built-in Math.min function stems from some unfortunate-in-retrospect decisions that were made when formulating the IEEE-754 Standard, especially the behavior of comparison and relational operators. The specified behavior was suitable for some purposes, but unsuitable for some other common purposes.
Most notably, if computation x would yield a positive number that is too small to represent, and computation y would yield a negative number that is too small to represent, then there is no way to directly compare the two values, they're not equivalent. Computation of 1.0/x would be interpreted as division by an infinitesimal positive number, while "1.0/y" behaves as division by an infinitesimal negative number. Thus, even though x and y are infinitesimal, and are close enough that comparison and relational operators report them as equal, both Math.min(x,y) and Math.min(y,x) should return y because it's infinitesimally smaller than x.
It strikes me as crazy that people are still designing hardware and programming languages which lack any nice means of comparing floating-point values in such a way that all pairs of values which aren't fully equivalent to each other from each other will be transitively ranked, but that has unfortunately the state of floating-point math for the last several decades. If one needs a function that will return the minimum of x and y in cases where they represent numbers with a non-zero difference, and otherwise arbitrarily return either x or y, such a function could be written more efficiently than one which has to handle the tricky cases involving positive and negative infinitesimal values.
Your implementation should lead to some really tight bytecode, which is easily turned into equally fast assembly language by a JIT compiler. The version using Math.min has two subroutine calls, and so may not be inlined like yours is. I think the results are to be expected.

If two lines intersect using cross product

I am trying to figure out if two lines are intersecting in a planar. I have been trying to use the cross product of vectors but have been getting wrong answers with large numbers. I realized that some of it was down to not having everything as long but even after this change I have still been finding intersections that don't exist. Can anyone notice were I have slipped up. I have been trying to figure out for quite some time.
My code is as followed:
public static boolean intersecting_segments ( Line_Segment A, Line_Segment B)
{
float side_one;, side_two ,side_three, side_four ;
side_one = cross_product( A, B.p) ;
side_two = cross_product( A, B.q) ;
side_three = cross_product( B, A.p) ;
side_four = cross_product( B, A.q) ;
return ( side_one >0 && side_two <0)|| ( side_one <0 && side_two >0) &&
( side_three >0 && side_four <0)|| ( side_three <0 && side_four >0);
}
public static long cross_product ( Line_Segment S, End_point r )
{
return (long)(((long)r.x -(long)S.p.x)*((long)S.q.y-(long)S.p.y)) -(((long)r.y- (long)S.p.y)*((long)S.q.x-(long)S.p.x));
}
You should make the side_XX variables long as well, which will likely fix your problem. If these variables have to have a decimal, use a double instead of a float.
The reason being though the cross_product function returns a long, the variables they are being assigned to (side_one, side_two, etc) are floats. This will force a conversion from long to float, which would lose precision and be inaccurate with large numbers.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
I can't be 100% sure of this without seeing your Line_Segment code, but based on what you've posted here, I'm guessing the x and y fields are ints, which you're casting to longs in your cross_product() method.
If that's the case, then your casts here aren't doing what you think they are: If, for instance you create a Line_Segment called p with an x value that overflows to 50 (i.e. it is 50 more than the max integer value, which means it gets stored as 50), then p.x is 50, and all you do by casting it to long is to make it 50L - it's not going to "undo" the overflow.
You need to change the types on these variables to long so they're stored properly, and lose the casts. (er, you don't technically have to lose the casts, but they're pointless)

Comparing double values for equality in Java.

I would like some advice from people who have more experience working with primitive double equality in Java. Using d1 == d2 for two doubles d1 and d2 is not sufficient due to possible rounding errors.
My questions are:
Is Java's Double.compare(d1,d2) == 0 handling rounding errors to some degree? As explained in the 1.7 documentation it returns value 0 if d1 is numerically equal to d2. Is anyone certain what exactly they mean by numerically equal?
Using relative error calculation against some delta value, is there a generic (not application specific) value of delta you would recommend? Please see example below.
Below is a generic function for checking equality considering relative error. What value of delta would you recommend to capture the majority of rounding errors from simple operations +,-,/,* operations?
public static boolean isEqual(double d1, double d2) {
return d1 == d2 || isRelativelyEqual(d1,d2);
}
private static boolean isRelativelyEqual(double d1, double d2) {
return delta > Math.abs(d1- d2) / Math.max(Math.abs(d1), Math.abs(d2));
}
You could experiment with delta values in the order of 10-15 but you will notice that some calculations give a larger rounding error. Furthermore, the more operations you make the larger will be the accumulated rounding error.
One particularly bad case is if you subtract two almost equal numbers, for example 1.0000000001 - 1.0 and compare the result to 0.0000000001
So there is little hope to find a generic method that would be applicable in all situations. You always have to calculate the accuracy you can expect in a certain application and then consider results equal if they are closer than this accuracy.
For example the output of
public class Main {
public static double delta(double d1, double d2) {
return Math.abs(d1- d2) / Math.max(Math.abs(d1), Math.abs(d2));
}
public static void main(String[] args) {
System.out.println(delta(0.1*0.1, 0.01));
System.out.println(delta(1.0000000001 - 1.0, 0.0000000001));
}
}
is
1.7347234759768068E-16
8.274036411668976E-8
Interval arithmetic can be used to keep track of the accumulated rounding errors. However in practise the error intervals come out too pessimistic, because sometimes rounding errors also cancel each other.
You could try something like this (not tested):
public static int sortaClose(double d1, double d2, int bits) {
long bitMask = 0xFFFFFFFFFFFFFFFFL << bits;
long thisBits = Double.doubleToLongBits(d1) & bitMask;
long anotherBits = Double.doubleToLongBits(d2) & bitMask;
if (thisBits < anotherBits) return -1;
if (thisBits > anotherBits) return 1;
return 0;
}
"bits" would typically be from 1 to 4 or so, depending on how precise you wanted the cutoff.
A refinement would be to add 1 to the position of the first bit to be zeroed before masking (for "rounding"), but then you have to worry about ripple all the way up past the most significant bit.
From the javadoc for compareTo
Double.NaN is considered by this method to be equal to itself and greater than all other double values (including Double.POSITIVE_INFINITY).
0.0d is considered by this method to be greater than -0.0d.
You may find this article very helpful
If you want you can check like
double epsilon = 0.0000001;
if ( d <= ( 0 - epsilon ) ) { .. }
else if ( d >= ( 0 + epsilon ) ) { .. }
else { /* d "equals" zero */ }

Math.pow and Math.sqrt work differently for large values?

I'm using Heron's formula to find the area of a triangle. Given sides a, b, and c, A = √(s(s-a)(s-b)(s-c)) where s is the semiperimeter (a+b+c)/2. This formula should work perfectly, but I noticed that Math.pow() and Math.sqrt() give different results. Why does this happen and how can I fix it?
I wrote two methods that find the area and determine if it is an integer.
In this first method, I take the square roots and then multiply them:
public static boolean isAreaIntegral(long a, long b, long c)
{
double s = (a+b+c)/2.0;
double area = Math.sqrt(s)*Math.sqrt(s-a)*Math.sqrt(s-b)*Math.sqrt(s-c);
return area%1.0==0.0 && area > 0.0;
}
In this second method, I find the product and then take the square root:
public static boolean isAreaIntegral(long a, long b, long c)
{
double s = (a+b+c)/2.0;
double area = Math.pow(s*(s-a)*(s-b)*(s-c),0.5);
return area%1.0==0.0 && area > 0.0;
}
Can anyone explain why these two methods that are mathematically equivalent give different Values? I'm working on Project Euler Problem 94. My answer comes out to 999990060 the first way and 996784416 the second way. (I know that both answers are very far off the actual)
I would certainly vote for "rounding issues", as you multiply the results of multiple method call in the first method (where every method result gets rounded) compared to the single method call in the second method, where you round only once.
The difference between the answers is larger than I'd expect. Or maybe it isn't. It's late and my mathematical mind crashed a while ago.
I think your issue is with rounding. When you multiply a load of roots together, your answer falls further from the true value.
The second method will be more accurate.
Though, not necessarily as accurate as Euler is asking for.
A calculator is a good bet.
Both methods are problematic. You should in general be very careful when comparing floating point values (that is, also double precision floating point values). Particularly, comparing the result of a computation with == or != is nearly always questionable (and quite often it is just wrong). Comparing two floating point values for "equality" should be done with a method like
private static boolean isEqual(double x, double y)
{
double epsilon = 1e-8;
return Math.abs(x - y) <= epsilon * Math.abs(x);
// see Knuth section 4.2.2 pages 217-218
}
In this case, the floating-point remainder operator will also not have the desired result. Consider the following, classic example
public class PrecisionAgain
{
public static void main(String[] args)
{
double d = 0;
for (int i=0; i<20; i++)
{
d += 0.1;
}
System.out.println(d);
double r = d%1.0;
System.out.println(r);
}
}
Output:
2.0000000000000004
4.440892098500626E-16
In your case, in order to rule out these rounding errors, the return statement could probably (!) something simple like
return (area - Math.round(area) < 1e8);
But in other situations, you should definitely read more about floating point operations. (The site http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html is often recommended, but might be a tough one to start with...)
This still does not really answer your actual question: WHY are the results different? In doubt, the answer is this simple: Because they make different errors (but they both make errors - that's in fact more important here!)

How to alter a float by its smallest increment in Java?

I have a double value d and would like a way to nudge it very slightly larger (or smaller) to get a new value that will be as close as possible to the original but still strictly greater than (or less than) the original.
It doesn't have to be close down to the last bit—it's more important that whatever change I make is guaranteed to produce a different value and not round back to the original.
(This question has been asked and answered for C, C++)
The reason I need this, is that I'm mapping from Double to (something), and I may have multiple items with the save double 'value', but they all need to go individually into the map.
My current code (which does the job) looks like this:
private void putUniqueScoreIntoMap(TreeMap map, Double score,
A entry) {
int exponent = 15;
while (map.containsKey(score)) {
Double newScore = score;
while (newScore.equals(score) && exponent != 0) {
newScore = score + (1.0d / (10 * exponent));
exponent--;
}
if (exponent == 0) {
throw new IllegalArgumentException("Failed to find unique new double value");
}
score = newScore;
}
map.put(score, entry);
}
In Java 1.6 and later, the Math.nextAfter(double, double) method is the cleanest way to get the next double value after a given double value.
The second parameter is the direction that you want. Alternatively you can use Math.nextUp(double) (Java 1.6 and later) to get the next larger number and since Java 1.8 you can also use Math.nextDown(double) to get the next smaller number. These two methods are equivalent to using nextAfter with Positive or Negative infinity as the direction double.
Specifically, Math.nextAfter(score, Double.MAX_VALUE) will give you the answer in this case.
Use Double.doubleToRawLongBits and Double.longBitsToDouble:
double d = // your existing value;
long bits = Double.doubleToLongBits(d);
bits++;
d = Double.longBitsToDouble(bits);
The way IEEE-754 works, that will give you exactly the next viable double, i.e. the smallest amount greater than the existing value.
(Eventually it'll hit NaN and probably stay there, but it should work for sensible values.)
Have you considered using a data structure which would allow multiple values stored under the same key (e.g. a binary tree) instead of trying to hack the key value?
What about using Double.MIN_VALUE?
d += Double.MIN_VALUE
(or -= if you want to take away)
Use Double.MIN_VALUE.
The javadoc for it:
A constant holding the smallest positive nonzero value of type double, 2-1074. It is equal to the hexadecimal floating-point literal 0x0.0000000000001P-1022 and also equal to Double.longBitsToDouble(0x1L).

Categories

Resources