Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numerically approximate ellipse perimeter #383

Merged
merged 23 commits into from
Oct 6, 2024

Conversation

tomcur
Copy link
Member

@tomcur tomcur commented Oct 1, 2024

This implements the (truncated) infinite series for the ellipse perimeter as described by Kummer (1837) and rediscovered by Linderholm and Segal (1995), and the iterative arithmetic-geometric mean method.

In the common case of ellipses that are only moderately eccentric and for "normal" accuracy (say, 0.001), the infinite series converges quickly. The series is known at compile-time, truncated to the 6th power. For a given ellipse and accuracy, a quick check is performed at runtime, to determine whether the truncated series' approximation is within the desired accuracy. If so, the truncated series is evaluated.

If the check determines the approximation is not good enough, the problem is handed to the iterative arithmetic-geometric mean method. This method converges quadratically for all cases.

This uses the infinite series for the ellipse perimeter as described by
Kummer (1837) and rediscovered by Linderholm and Segal (1995).

It converges quadratically in the worst case, and in the common case of
ellipses that are nearly circular or moderately eccentric, it converges
very fast.
@tomcur
Copy link
Member Author

tomcur commented Oct 1, 2024

This solves the general case up to arbitrary precision.

For ellipses that are only moderately eccentric, the series converges very quickly, such that only a few terms are needed for normal accuracy. Even for practically infinite accuracy (i.e., for Kurbo's case: within machine precision of an f64), only a few terms are needed when ellipses are just slightly eccentric.

Wikipedia states terms up to and including the 4th power are enough for eccentricities of 0.5 or less to reach the limits of f64 precision. With a back-of-the-envelope calculation that seems about right: the next term would be 49 * 0.005^5 / 65536, log2 of that is -48, so 48 bits away from the first term of 1.

We could expand the first few terms explicitly, only starting iteration when necessary. Though we'd have to benchmark whether that really is faster.

@tomcur tomcur changed the title Numerically calculate ellipse perimeter Numerically approximate ellipse perimeter Oct 1, 2024
@tomcur
Copy link
Member Author

tomcur commented Oct 2, 2024

The method I first added (kummer_elliptic_perimeter, based on a series with binomial coefficients in n=1/2) only converges quadratically for ellipses that are not too eccentric. I've added an iterative method based on the arithmetic-geometric mean that actually does converge quadratically for all cases, requiring 7 iterations even in the case of an ellipse with radii (0.000_000_1, 1.) and desired accuracy 0.000_001. The binomial series required 355 terms, with the difference increasing rapidly with higher eccentricity or better accuracy (with an accuracy of 0.000_000_01, it's 8 iterations vs. 3534 terms).

The method based on binomial coefficients is still nice, in the sense that the coefficients can be known at compile-time. We can expand that series up to some number of terms, evaluating that in the case the approximation is good enough for the given eccentricity and accuracy. Wikipedia states terms up to and including the 4th power are enough for eccentricities of 0.5 or less to reach the limits of f64 precision. With a back-of-the-envelope calculation that seems about right: the next term would be 49 * 0.005^5 / 65536, log2 of that is -48, so 48 bits away from the first term of 1.

That allows a loopless approximation for the most common cases, using the quadratically converging iterative arithmetic-geometric mean method for very high eccentricity or very precise accuracy.

@tomcur tomcur marked this pull request as draft October 2, 2024 15:11
@tomcur
Copy link
Member Author

tomcur commented Oct 2, 2024

That allows a loopless approximation for the most common cases, using the quadratically converging iterative arithmetic-geometric mean method for very high eccentricity or very precise accuracy.

Done, and PR text updated. Perhaps we should benchmark whether this is actually enough of a performance improvement for common ellipses, to justify the additional lines of code.

@tomcur tomcur force-pushed the numerical-ellipse-perimeter branch from 021bbca to 395a4dc Compare October 2, 2024 16:43
@tomcur tomcur force-pushed the numerical-ellipse-perimeter branch from 1381f88 to 9fffb75 Compare October 2, 2024 19:08
@tomcur tomcur marked this pull request as ready for review October 2, 2024 19:13
Copy link
Contributor

@raphlinus raphlinus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool, from what I can see the math checks out.

I think the AGM algorithm is probably very good, but for one other possibility that seems to work well in the high eccentricity case, see "Cayley" in The Perimeter of an Ellipse. That formula requires logarithms, though, so it's not clear it will be better than AGM. Also, I suspect the accuracy of table 1, as perimeter is not monotonic.

src/ellipse.rs Outdated Show resolved Hide resolved
src/ellipse.rs Outdated Show resolved Hide resolved
src/ellipse.rs Outdated Show resolved Hide resolved
src/ellipse.rs Outdated Show resolved Hide resolved
@tomcur
Copy link
Member Author

tomcur commented Oct 4, 2024

one other possibility that seems to work well in the high eccentricity case, see "Cayley" in The Perimeter of an Ellipse. That formula requires logarithms, though, so it's not clear it will be better than AGM.

Very nice, that does seem to work well. It only requires evaluating ln(4/k), so the cost is constant. At the very least it's a good candidate to handle the same way as kummer_elliptic_perimeter, as the coefficients are known at compile-time, requiring just a few additions and multiplications per term.

I wonder if the overlap between Kummer and Cayley is enough to guarantee machine precision for all eccentricities, without too many terms.

Also, I suspect the accuracy of table 1, as perimeter is not monotonic.

Well-spotted. Having checked a few, it seems from b=0.002 onwards the reported perimeter decimals are accidentally shifted left by one. The decimals are otherwise correct.

@tomcur tomcur added this pull request to the merge queue Oct 6, 2024
Merged via the queue into linebender:main with commit e8fa6c0 Oct 6, 2024
15 checks passed
@tomcur tomcur deleted the numerical-ellipse-perimeter branch October 6, 2024 14:06
@tomcur
Copy link
Member Author

tomcur commented Oct 6, 2024

I think the Cayley formula is worth exploring, but will leave that for another PR. I haven't looked into it yet. In the meantime this is an improvement and is useful also for #381.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants