Is the test of "Area of Two Circles' Intersection" correct?
Difference between en18 and en19, changed 10 character(s)
### TL;DR↵
[problem:600D] requires careful treatment of loss of significance, more than the geometry itself. The test is plagued by the numerical errors, and rejects "more accurate" solution.↵
↵
↵
### Geometry ↵
Let's review the geometry, first. We need three numbers $(r_1, r_2, d)$; where $d$ is the distance between two centers,↵
↵
$$ d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}. $$↵
↵
When two circles do not intersect, which is the case $d > r_1 + r_2$, the area of intersection is zero.↵
↵
When one circle is contained in the other, which is the case $\max(r_1, r_2) >= d + \min(r_1, r_2)$, the intersection  equals to the smaller circle.↵
↵
![ ](http://i.imgur.com/ObIOka0.png)↵
↵
Otherwise, intersection of two circles is determined from two circular sectors subtracted by two triangles, yielding↵
↵
$$ \mathrm{Intersection} = r_1^2 ( \theta_1 - \sin \theta_1 \cos \theta_1) +  r_2^2 ( \theta_2 - \sin \theta_2 \cos \theta_2). $$↵
↵
where angles $\theta_1$ and $\theta_2$ are determined from the cosine formula↵
↵
$$\theta_1 = \cos^{-1} \left( \frac{r_1^2 + d^2 - r_2^2}{2 r_1 d} \right),$$↵
↵
$$\theta_2 = \cos^{-1} \left( \frac{r_2^2 + d^2 - r_1^2}{2 r_2 d} \right).$$↵
↵
So far, so good. I wrote Python code (with `double` representation), and failed. Rewrote in C++ using `long double`, and succeeded. But..., what was wrong?↵
↵
↵
### Loss of significance↵
The culprit is [loss of significance (wikipedia)](https://en.wikipedia.org/wiki/Loss_of_significance). It occurs when you take difference $(y - x)$ of two close numbers $x \approx y$. For example, ↵
↵
$$1.0023 - 1.0019 = 0.0004$$  ↵
↵
The difference has only one significant digit although you started with numbers of five significant digits!↵
↵
↵
This type of numerical error can happen in two parts. One in inside of $\arccos()$, the other in the function $(\theta - \sin\theta \cos \theta )$ when $\theta$ is small $\theta \ll 1$.↵
↵
Inside of the $\arccos$ is just arithmetic operations so we can represent numbers as 
f`Fractions` to avoid the error. ($d$ is a floating point number but I still convert it into a fraction as well.)↵
↵
$(\theta - \sin\theta \cos \theta )$ involves non-arithmetic operation, so I use [Taylor expansion](https://en.wikipedia.org/wiki/Taylor_series). Wolfram|Alpha [tells](http://www.wolframalpha.com/input/?i=lim+%28x+-+sin+x+cos+x%29+as+x-%3E0) me like this.↵
↵
$$ f(x) = x - \sin x \cos x = \frac{2}{3} x^3  - \frac{2}{15} x^5 + \frac{4}{315} x^7 + O(x^9) $$↵
↵
The first three terms 
isare good enough. I replaced the function $f(x)$ with this form when $\lvert x \rvert| < 0.001$.↵
↵
↵
### Am I wrong, or test is wrong?↵
↵
Here is my Python implementation. ↵
↵
```python↵
"""↵
Codeforces Educational Round 2↵
↵
Problem 600 D. Area of Two Circles' Intersection↵
↵
@author yamaton↵
@date 2015-11-30↵
      2015-12-02↵
"""↵
import math↵
import fractions↵
↵
↵
def f(x):↵
    """↵
    compute  x - sin(x) cos(x) ↵
    without loss of significance↵
    """↵
    cos = math.cos↵
    sin = math.sin↵
↵
    if abs(x) < 0.001:↵
        return 2 * x**3 / 3 - 2 * x**5 / 15 + 4 * x**7 / 315↵
    return x - sin(x) * cos(x)↵
↵
↵
def solve(r1, r2, d):↵
    acos = math.acos↵
↵
    r1, r2 = min(r1, r2), max(r1, r2)↵
    if d >= r1 + r2:  # circles are far apart↵
        return 0.0     ↵
    if r2 >= d + r1:  # whole circle is contained in the other↵
        return math.pi * r1 ** 2↵
↵
    # Convert numbers into fractions before calculation.↵
    # Numbers are fractions until `acos()` is applied.↵
    r1f, r2f, df = map(fractions.Fraction, [r1, r2, d])↵
    r1sq, r2sq, dsq = map(lambda i: i * i, [r1f, r2f, df])↵
    theta1 = acos((r1sq + dsq - r2sq) / (2 * r1f * df))↵
    theta2 = acos((r2sq + dsq - r1sq) / (2 * r2f * df))↵
↵
    return r1 * r1 * f(theta1) + r2 * r2 * f(theta2)↵
↵
↵
def main():↵
    x1, y1, r1 = map(int, input().split())↵
    x2, y2, r2 = map(int, input().split())↵
    d = math.hypot(x1-x2, y1-y2)↵
    result = solve(r1, r2, d)↵
    print("%.20f" % result)↵
↵
↵
if __name__ == '__main__':↵
    main()↵
```↵
↵
But this **STILL** fails on test 36. Here is a screenshot.↵
↵
![ ](http://i.imgur.com/sSlsWYI.png)↵
↵
Am I wrong? Or, the test is wrong?↵

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en28 English yamaton 2015-12-05 17:51:41 30
en27 English yamaton 2015-12-05 17:44:25 2 Tiny change: '. (**EDIT2:** I was wro' -
en26 English yamaton 2015-12-05 17:42:43 93
en25 English yamaton 2015-12-05 17:39:25 11
en24 English yamaton 2015-12-05 17:37:30 20 Tiny change: 'icient in computing `acos`.\n\n2. `a' -> 'icient in significance.\n\n2. `a'
en23 English yamaton 2015-12-05 17:36:34 24 Tiny change: 'lly got AC: [submiss' -> 'lly got AC with `double` precision: [submiss'
en22 English yamaton 2015-12-05 17:35:44 1176 Tiny change: '21].\n\n** Lesson Learned: **\n\n- Ju' -
en21 English yamaton 2015-12-03 03:18:13 12 Tiny change: 'imgur.com/ObIOka0.png)\n\nO' -> 'imgur.com/NrqhykS.png)\n\nO'
en20 English yamaton 2015-12-03 03:00:55 391 Edited and modified
en19 English yamaton 2015-12-03 01:06:00 10 Fixed typos
en18 English yamaton 2015-12-03 00:52:35 0 (published)
en17 English yamaton 2015-12-03 00:49:27 24 Tiny change: 'n test 36.\n![ ](htt' -> 'n test 36. Here is a screenshot.\n\n![ ](htt'
en16 English yamaton 2015-12-03 00:47:48 1594
en15 English yamaton 2015-12-03 00:31:43 302
en14 English yamaton 2015-12-03 00:24:19 826
en13 English yamaton 2015-12-03 00:10:46 51
en12 English yamaton 2015-12-03 00:10:08 220
en11 English yamaton 2015-12-03 00:05:29 28
en10 English yamaton 2015-12-03 00:03:52 99
en9 English yamaton 2015-12-03 00:01:11 131
en8 English yamaton 2015-12-02 23:56:18 538
en7 English yamaton 2015-12-02 23:40:10 8 Tiny change: ' geometry problem itself.\n' -> ' geometry itself.\n'
en6 English yamaton 2015-12-02 23:39:47 150
en5 English yamaton 2015-12-02 23:33:39 27
en4 English yamaton 2015-12-02 23:32:04 283
en3 English yamaton 2015-12-02 23:29:53 15
en2 English yamaton 2015-12-02 23:28:55 476
en1 English yamaton 2015-12-02 23:24:53 858 Initial revision (saved to drafts)