baobab's blog

By baobab, history, 8 years ago, In English

This is a common subtask in many geometry problems. Today I was unable to solve 1059D because my point-to-point distance calculation is not accurate enough. To summarize the problem, "Find the smallest circle which encompasses all the points, such that its border touches the x axis." I understand there are other ways to solve the problem, but I really want to learn to complete this subtask accurately, since it's recurring in many different problems.

Here's how I would usually calculate it:

double xDist = Math.abs(x1 - x2)
double yDist = Math.abs(y1 - y2)
double dist = Math.sqrt(xDist*xDist + yDist*yDist)

However, this was failing test #4 due to double precision issues. I got some help with this and refactored the calculation into:

double dist = Math.sqrt(xDist) * Math.sqrt(yDist) * Math.sqrt(xDist/yDist + yDist/xDist);

Somehow, this was still not enough. I don't understand how I could possibly calculate distance between 2 points more accurately with Java doubles. Can you help me out? I condensed the failing test case into very little code here.

  • Vote: I like it
  • +28
  • Vote: I do not like it

| Write comment?
»
8 years ago, hide # |
 
Vote: I like it +15 Vote: I do not like it

If you just want to compare distances, you can compare squared distances. That way you have no precision error. Often you can solve problems while only taking one sqrt of the squared distance at the end. I'm not sure if this is applicable here though.

»
8 years ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Why the downvotes?

»
8 years ago, hide # |
 
Vote: I like it +10 Vote: I do not like it

using doubles and calculating the dist like you did is perfectly fine for this problem... the precision loss probalby happens somewhere else... (a solution which uses doubles: https://mirror.codeforces.com/contest/1059/submission/44052169)

  • »
    »
    8 years ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Did you look at the condensed example case https://pastebin.com/bgDKxiJe ? It shows that the precision loss does indeed occur at the distance calculation. I'm not entirely sure what's going on in the solution you linked, but many solutions to this problem use doubles to do different calculations than point-to-point distances. It looks to me like that solution is also doing something else, not calculating point-to-point distances.

»
8 years ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

I tried a ton of tweaks, and I was able to reduce the error by half!

https://mirror.codeforces.com/contest/1059/submission/44053130

Unfortunately it's still not enough to pass.

The only advice I have for you is switch to C++.

»
8 years ago, hide # |
 
Vote: I like it +10 Vote: I do not like it

I tried looking at your could but couldn't manage to find the problem. However, I believe that even if you managed to find the precision problem you'd still receive a TLE verdict with this solution, since you do a binary search on the radius and, for every radius, a ternary search on the X coordinate of the center of the circle. It's possible to exclude that ternary search by finding, for every point, an interval of X coordinates of where the center of the circle could be and simply check if the intersection of such intervals is empty or not.

»
8 years ago, hide # |
 
Vote: I like it -28 Vote: I do not like it

If you're having precision issues when measuring distances, first of all you should buy a ruler with a smaller scale. If you're still having trouble, wear glasses and take some medications to prevent your hand from shaking when holding the ruler.

»
8 years ago, hide # |
 
Vote: I like it +18 Vote: I do not like it

I was able to get it to test 6 but I have no idea on how to make it more precise (I eliminated the need for ternary search inside the binary search and some other changes). https://mirror.codeforces.com/contest/1059/submission/44082804

Also, why do you have 1400 lines of template?

»
8 years ago, hide # |
 
Vote: I like it +1 Vote: I do not like it

Hey, as someone who had similar issues to you, my advice is to not do a<=b to compare very large floating point values.

Why? Because the mantissa will easily cut it off.

Instead of something like a < b, try something like a-b < epsilon where the epsilon is 1e-8 or something. Good luck!