Java Atan2() Sort violates general contract? - java

I'm having trouble with a comparison method being used in Java/Processing.
It says it violates its general contract, which I understand means it doesn't work on the relationships between the items consistently...
But I don't understand why. Since it just returns the angle, theta, based on the ratio of ycor to xcor (like sin to cos), shouldn't it sort them consistently based on their positions from 0 to 360 degrees?
public int compareTo(Orb other) {
double X = Math.atan2(ycor,xcor);
if (Math.atan2(other.ycor,other.xcor) > X) {
return -1;
}
if (Math.atan2(other.ycor,other.xcor) == X) {
return 0;
}
return 1;
}
Any help is very appreciated, thanks!
The specific context is that the error occurs when a Collection.Sort() is run.

EDIT: See Louis Wasserman's comment above:
Is it possible that xcor and ycor are both zero for some of these? I suspect that would result in NaN. Switching to Double.compare(Math.atan2(ycor, xcor), Math.atan2(other.ycor, other.xcor)) ought to work.
THE BELOW WAS THE CONTENT OF THIS POST; IT IS PROBABLY WRONG
It's not well-defined whether one angle is "greater" than another - if I'm clockwise of you by 170 degrees, then I'm also counterclockwise of you by 190 degrees.
Even if you choose to use "within 180 degrees of" as greater-than, you still don't have the triangle inequality satisfied.

Related

Sorting by (x,y) coordinates with an offset causes violation of comparator contract

I'm trying to sort a collection of x and y points with an offset on x such that p.x-q.x should be treated equal IF p.x==q.x OR ABS(p.x-q.x) < offset.
Note that I'm taking the absolute value here, so I shouldn't be getting any negative values. My comparator is below:
private static class XYOrder implements Comparator<ExtractPojo> {
public int compare(ExtractPojo p, ExtractPojo q) {
Integer a=p.x.intValue();
Integer b=q.x.intValue();
Integer c=p.y.intValue();
Integer d=q.y.intValue();
int offset=Math.abs(a-b); //calculate offset from x
if(offset < 15 || a == b) //if x is the same, sort by y coordinate
return c-d;
else return a-b; //if x is not same sort by x coordinate
}
}
This code works for some cases, but I get the following error message on others:
Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:868)
at java.util.TimSort.mergeAt(TimSort.java:485)
at java.util.TimSort.mergeForceCollapse(TimSort.java:426)
at java.util.TimSort.sort(TimSort.java:223)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
I have a feeling I'm violating a transivity rule as I've searched extensively through this site for an answer, but I'm not exactly sure how to test what I'm missing here.
I've tested this code without the offset and I don't get this error message, so I know it has to do with how I'm implementing the offset. I've Been trying to solve this for a few weeks with no luck.
I was hoping to get some tips or suggestions on this. Thank you very much.
So the only fix I can think of is first sorting by x position, then going through each x and adjusting the x's to be the same based on the offset, then doing the sort again by the x,y mentioned above without the offset. Just seems like a hack to do it that way, but I've never used a comparator before and I'm having difficulty solving this issue.
I have a feeling I'm violating a transivity rule
Indeed you are. Under your comparator, we have (0, 20) > (10, 10) > (20, 0) > (0, 20). (Also, it's spelled "transitivity".)
Generally, compare, compareTo, and equals methods shouldn't use tolerances, because tolerances are inherently intransitive. Two differences that both fall beneath a tolerance may add up to a difference above the tolerance.
Check your code again. This is what the Java docs have to say regarding the implementation of the compare() method.
The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.
Did you override the equals() method for your ExtractPojo class? You can find the doc here.
Also, you shouldn't be using code like a == b. Here, you have variables of type Integer. As such, it will only be checking whether the 2 variables point to the same object (which could be false in this case. More on that here). Use a.equals(b) instead.
So I did a few more tests and I believe found your issue: Overflows.
I made your compare method very simple and I was still getting that error:
public int compare(ExtractPojo p, ExtractPojo q) {
Integer x1 = p.x.intValue();
Integer x2 = q.x.intValue();
return x1 - x2;
}
This is because in some situations x1 - x2 will cause an overflow violating transitivity. To check for this do something like:
public int compare(ExtractPojo p, ExtractPojo q) {
Integer x1 = p.x.intValue();
Integer x2 = q.x.intValue();
checkSubtractionOverflow(x1, x2);
return x1 - x2;
}
//This will throw an exception if there is an overflow
public static void checkSubtractionOverflow(int left, int right) {
Math.subtractExact(left, right);
}
If you see the exception:
Exception in thread "main" java.lang.ArithmeticException: integer overflow
at java.lang.Math.subtractExact(Unknown Source)
Then you know you have overflow issues which will need to be addressed.
Basically, your code is saying this:
If the x coordinates are within 15 units of each other, use the y coordinates for comparison.
If the x coordinates are 15 or more units from each other, use the x coordinates for comparison
The x coordinates are equal case can go to either side without affecting the issue at hand.
I suspect the transitivity issue is going to be hit, for example, when:
P.x is within 15 units of Q.x and P < Q (because P.y < Q.y)
Q.x is within 15 units of R.x and Q < R (because Q.y < R.y)
AND P.x is beyond 15 units from R.x and P > R (because P.x > R.x)
Also, you are doing some unnecessary boxing/unboxing with the .intValue() calls. Integer a = P.x is an Integer to Integer assignment.

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.

How to understand Newton's method for square root in Java?

public static double sqrt(double c)
{
if (c < 0) return Double.NaN;
double t = c; // line 1
double err = 1e-15; // line 2
while (Math.abs(t - c/t) > err * t) // line 3
t = (c/t + t) / 2.0; // line 4
return t;
}
Q1: I am confused by the variable t in line1 and line 4:
since t = c, then c/t = 1, what does line 4 mean?
Q2: In line 3, what's the purpose to check?
I searched "Newton's method" and got several explanation, but I still could not understand. May I request an straight forward explanation here?
Q1: Note that t changes with each iteration of the loop, so while c/t==1 initially, it won't after that.
Q2: We want the loop to continue until we get an answer "close enough", as defined by err.
The Newton's method is used to approximate real valued functions' roots. See here.
When you are calculating the root to a double value you are actually trying to solve for F(x) = X^2 - C where C is the double and you would be trying to find the x that makes the equation zero.
Now the Newton's Method approximates this by a series of guesses. By each guess(as this function has the appropriate properties), we get closer to the square root. The incremental approximation is actually calculating the tangent to the graph at each guess(t) and then choosing that as a guess at that point and moves closer in steps(c/t + t)/2. At a certain point we get very close and we don't want the function to go on forever so we have line 3 to check that our next estimation has a certain distance from the current approximation. If the next approximation is closer than err*t we don't bother continuing. We are close enough.

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!)

Problems with NaN

I've been having problems with my code for two weeks, and have been unsuccessful in debugging it. I've come here in the hope that someone can help. I've written a program that utilizes the Barnes-Hut algorithm for n-body gravitational simulation. My problem is that one or more 'particles' will have the position of {NaN, NaN, NaN} assigned to them (using three doubles to represent x, y, z of 3-d space). This, in turn, causes the other particles to have an acceleration of {NaN, NaN, NaN}, and in turn, a velocity and position of {NaN, NaN, NaN} as well. Basically, after a frame or two, everything disappears. It seems to be occurring in the updateAcc method, but I have a feeling that this isn't so. I understand that this is a huge undertaking, and am very grateful for anyone that helps me.
What I've checked:
There are no negative square roots, and all the values seem to be within their limits.
The source code is available here. Thanks again.
Code that seems to produce NaN:
private static void getAcc(particle particle, node node)
{
if ((node.particle == null && node.children == null) || node.particle == particle)
{
//Geting gravity to a node that is either empty or the same node...
}
else if (distance(node.centerOfMass, particle.position) / node.sideLength > theta && node.children != null)
{
for (int i = 0; i < node.children.length; i++)
{
if (node.children[i] != null)
{
getAcc(particle, node.children[i]);
}
}
}
else
{
particle.acceleration = vecAdd(particle.acceleration, vecDiv(getForce(particle.position, particle.mass, node.centerOfMass, node.containedMass), particle.mass));
}
}
private static double sumDeltaSquare(double[] pos1, double[] pos2)
{
return Math.pow(pos1[0]-pos2[0],2)+Math.pow(pos1[1]-pos2[1],2)+Math.pow(pos1[2]-pos2[2],2);
}
private static double[] getForce(double[] pos1, double m1, double[] pos2, double m2)
{
double ratio = G*m1*m2;
ratio /= sumDeltaSquare(pos1, pos2);
ratio /= Math.sqrt(sumDeltaSquare(pos1,pos2));
return vecMul(vecSub(pos2, pos1), ratio);
}
private static double distance(double[] position, double[] center)
{
double distance = Math.sqrt(Math.pow(position[0]-center[0],2) + Math.pow(position[1]-center[1],2) + Math.pow(position[2]-center[2],2));
return distance;
}
I'm not sure if this is the only problem, but it is a start.
sumDeltaSquare will sometimes return 0 which means when the value is used in getForce ratio /= sumDeltaSquare(pos1, pos2); it will produce Infinity and start causing issues.
This is a serious problem that you need to debug and work out what everything means. I enjoyed looking at the dots though.
Firstly, why aren't you using Java's Vecmath library? (It's distributed as a part of Java3D. Download Java3D's binary build and then just use vecmath.jar) Your problem is, very likely, somewhere in your custom vector functions. If not, #pimaster is probably right in that your translation magnitude method sumDeltaSquare might be returning 0 if two of your masses occupy a single space. Which means, unless you're inside a black hole, you're doing it wrong :P. Or you need to come up with a quantum gravity theory before you can do this simulation.
If you can't use vecmath (i.e. this is a homework assignment) I would suggest you use a regex to find every instance of return * and then replace it with assert !Double.isNan(*) && Double.isFinite(*);\nreturn *, except substitute * for whatever regex finds a "match group". I've forgotten exactly what that is, but I got you started on Google. I also suggest you avoid optimizations until after you have working code.
I'm not going to debug your code. But NaN values are the result of mathematically invalid operations on floating point numbers. The most famous of those is division by 0 (does not throw an exception with floating point).
How can this happen?
If your computation produces very small numbers, they might become too small to be represented as 64-bit floating point numbers (they require more bits than are available), and Java will return 0.0 instead.
In the other direction, if you get an overflow (the magnitude of the number requires too many bits), Java turns this into infinity. Doing math with infinity and 0 can quickly lead to NaN, and NaN propagates through every operation you apply to it.
For details, see sections 4.2 and 15.17 of the Java language spec.

Categories

Resources