如何计算椭圆的周长

How to calculate the perimeter of an ellipse

我想用给定的短轴和长轴值计算椭圆的周长。我目前正在使用 Python.

我计算了椭圆的短轴和长轴长度,即 ab

面积很容易计算,但是我想计算椭圆的周长来计算四舍五入的长度。你有什么想法吗?

根据Ramanujan求椭圆周长的第一个近似公式->

>>> import math
>>>
>>> def calculate_perimeter(a,b):
...     perimeter = math.pi * ( 3*(a+b) - math.sqrt( (3*a + b) * (a + 3*b) ) )
...     return perimeter
...
>>> calculate_perimeter(2,3)
15.865437575563961

您也可以将结果与 google calculator 进行比较

一个定义问题:长轴、短轴不同于semi-major、semi-minor
OP应该很清楚,那些抓取的,与在线解决方案相比应该也是

你可以同情(数字)解决问题,我使用的是完整的轴定义

from sympy import *
a, b, w = symbols('a b w')

x = a/2 * cos(w)
y = b/2 * sin(w)

dx = diff(x, w)
dy = diff(y, w)

ds = sqrt(dx**2 + dy**2)

def perimeter(majr, minr):
    return Integral(ds.subs([(a,majr),(b,minr)]), (w, 0, 2*pi)).evalf().doit()

print('test1: a, b = 1 gives dia = 1 circle,  perimeter/pi = ',
      perimeter(1, 1)/pi.evalf())

print('test2: a, b = 4,6 ellipse perimeter = ', perimeter(4,6))

test1: a, b = 1 gives dia = 1 circle,  perimeter/pi =  1.00000000000000
test2: a, b = 4,6 ellipse perimeter =  15.8654395892906

也可以将符号 ds 方程导出为函数以尝试使用其他 Python 库集成函数

func_dw = lambdify((w, a, b), ds)

from scipy import integrate

print(integrate.quad(func_dw, 0, 2*np.pi, args=(4, 6)))

(15.865439589290586, 2.23277254813499e-12)  

scipy.integrate.quad(func, a, b, args=()...
Returns:
y : float, The integral of func from a to b.
abserr : float, An estimate of the absolute error in the result

正如马克所说 , you can simply use scipy.special.ellipe. This implementation uses the complete elliptic integral of the second kind as approximated in the original C function ellpe.c。如 scipy 的文档所述:

the computation uses the approximation,

E(m) ~ P(1-m) - (1-m) log(1-m) Q(1-m)

where P and Q are tenth-order polynomials

from scipy.special import ellipe

a = 3.5
b = 2.1
# eccentricity squared
e_sq = 1.0 - b**2/a**2
# circumference formula
C = 4 * a * ellipe(e_sq)
17.868899204378693

这是比较上述答案的一种元答案。

实际上,Ramanujan 的第二个近似值比 Rezwan4029 的答案(使用 Ramanujan 的第一个近似值)中的公式更准确,也更复杂一些。第二个近似值是:

π * ((a+b) + (3(a-b)²) / (10*(a+b) + sqrt(a² + 14ab + b²)))

但是我查看了上面所有的答案并比较了他们的结果。出于充分的理由,稍后会变得很明显,我选择加布里埃尔的版本作为真实来源,即与其他版本进行比较的价值。

对于 Rezwan4029 给出的答案,我在 2**(-10) .. 2**9 的网格上绘制了百分比误差。这是结果(两个轴都是幂,所以点 (3|5) 显示了半径为 2**3, 2**5 的椭圆的误差):

很明显,只有功率的差异与错误有关,所以我也绘制了这个:

无论如何出现的是,误差范围从圆的 0 到极度偏心的椭圆的 0.45%。根据您的应用程序,这可能是完全可以接受的或使解决方案无法使用。

对于Ramanujan的第二个近似公式,情况非常相似,误差约为前者的1/10:

Mark Dickinson 的 sympy 解法和 Gabriel 的 scipy 解法还是有一些区别,但最多在 1e-6 的范围内,所以是一个不同的球场。但是 sympy 解决方案非常慢,所以在大多数情况下可能应该使用 scipy 版本。

为了完整起见,这里给出一个误差的分布(这次误差的对数在z轴上,否则就不能告诉我们太多,所以高度和负数大致对应有效数字的个数):

结论:使用scipy方法。它速度快,而且很可能非常准确,甚至可能是所提出的三种方法中最准确的。

有一些很好的答案,但我想在 exact/approximate 计算以及计算速度方面澄清一些事情。

  • 对于使用纯 python 的精确圆周,查看我的 pyellipse 代码 https://gist.github.com/TimSC/4be20baeac7890e15773d31efb752d23 我实现的方法是由 Adlaj 2012 提出的(如@[=37= 所建议的) ]).

  • 或者,对于精确的周长,使用@Gabriel 所描述的 scipy.special.ellipe。这比 Adlaj 2012 慢两倍。

  • 对于计算速度快且没有 scipy 依赖性的良好近似值,请参阅@Alfe

    描述的 Ramanujan 的第二个近似值
  • 对于另一个计算速度快的好近似值(避免使用平方根),请使用 Jacobsen 和 Waadeland 1985 年提出的 Padé 近似值 http://www.numericana.com/answer/ellipse.htm#hudson

h = pow(a-b, 2.0) / pow(a+b, 2.0)
C = (math.pi * (a+b) * (256.0 - 48.0 * h - 21.0 * h*h)
       /(256.0 - 112.0 * h + 3.0 * h*h))

还有许多其他方法,但这些方法对普通应用程序最有用。

使用俄罗斯数学家几年前的改进(不是无限级数计算而是使用AGM和MAGM的收敛计算)http://www.ams.org/notices/201208/rtx120801094p.pdf
https://indico-hlit.jinr.ru/event/187/contributions/1769/attachments/543/931/SAdlaj.pdf 那里有一个用途:surface plots in matplotlib using a function z = f(x,y) where f cannot be written in standard functions. HowTo?(用于绘制包含等周曲线的曲面的脚本:这意味着曲线的所有 X-Y 都是具有相同周长的所有椭圆的半参数)。或直接联系数学家,或在 springernature.com 购买文章“第三类算术几何平均数!”,Semjon Adlaj,俄罗斯科学院“信息学与控制”联邦研究中心,Vavilov St. 44, 莫斯科 119333, 俄罗斯 SemjonAdlaj@gmail.com