如何计算给定三个点的抛物线的顶点
我有三个 X/Y 点,形成一条抛物线。 我只需要计算经过这三个点的抛物线的顶点是什么。 最好是一种快速的方法,因为我必须做很多这样的计算!
“询问科学家”网站提供了这个答案:
抛物线的一般形式由以下方程给出:A * x^2 + B * x + C = y 其中 A、B 和 C 是任意实数常数。 您有三对点,它们是 (x,y) 有序对。 将每个点的 x 和 y 值代入抛物线方程。 您将得到三个未知数(三个常数)的三个线性方程。 然后,您可以轻松地求解这个由三个方程组组成的 A、B 和 C 值,并且您将得到与 3 个点相交的抛物线方程。 顶点是一阶导数为 0 的地方,一点代数给出: ( -B/2A , C - B^2/4A ) 顶点。
很高兴看到用 C# 或 C++ 执行此计算的实际代码。 有人吗?
I have three X/Y points that form a parabola. I simply need to calculate what the vertex of the parabola is that goes through these three points. Preferably a quick way as I have to do a LOT of these calculations!
The "Ask A Scientist" website provides this answer:
The general form of a parabola is given by the equation: A * x^2 + B * x + C = y where A, B, and C are arbitrary Real constants. You have three pairs of points that are (x,y) ordered pairs. Substitute the x and y values of each point into the equation for a parabola. You will get three LINEAR equations in three unknowns, the three constants. You can then easily solve this system of three equations for the values of A, B, and C, and you'll have the equation of the parabola that intersects your 3 points. The vertex is where the first derivative is 0, a little algebra gives: ( -B/2A , C - B^2/4A ) for the vertex.
It would be nice to see actual code that does this calculation in C# or C++. Anybody?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
谢谢 David,我将您的伪代码转换为以下 C# 代码:
这就是我想要的。 抛物线顶点的简单计算。 稍后我将处理整数溢出。
Thanks David, I converted your pseudocode to the following C# code:
This is what I wanted. A simple calculation of the parabola's vertex. I'll handle integer overflow later.
这实际上只是一个简单的线性代数问题,因此您可以用符号进行计算。 当您代入三个点的 x 和 y 值时,您将得到三个未知数的三个线性方程。
解决这个问题的直接方法是反转矩阵
并将其乘以向量,
结果是......好吧,并不完全那么简单;-)我在 Mathematica 中做到了,这里是伪代码中的公式
: ,如果您想以数字方式进行矩阵数学,您通常会转向线性代数系统(例如 ATLAS,虽然我不确定它是否有 C#/C++ 绑定)。
无论如何,一旦您获得了通过这些公式计算出的
A
、B
和C
的值,您只需将它们代入问题中给出的表达式-B / 2A
和C - B^2/4A
来计算顶点的坐标。1请注意,如果原始三个点的坐标使 denom 成为一个非常大或非常小的数字,则直接进行计算可能会出现严重的数值误差。 在这种情况下,最好稍微修改一下,以避免除以分母,无论如何它们都会抵消:
然后顶点的坐标是
-b / 2a
和( c - b^2 / 4a) / denom
。 还有各种其他情况可能会受益于这样的“技巧”,例如如果A
非常大或非常小,或者如果C
几乎等于B^2 / 4A
因此它们的差异非常小,但我认为这些情况差异很大,最好针对具体情况的后续问题进行全面讨论。将所有这些转换为您选择的语言的代码留给读者作为练习。 (对于任何使用标准中缀运算符语法的语言来说,这应该是相当简单的,例如 AZDean 在 C# 中显示。)
1在答案的最初版本中,我认为这是显而易见的,但似乎有很多人喜欢明确提及它。
This is really just a simple linear algebra problem, so you can do the calculation symbolically. When you substitute in the x and y values of your three points, you'll get three linear equations in three unknowns.
The straightforward way to solve this is to invert the matrix
and multiply it by the vector
The result of this is... okay, not exactly all that simple ;-) I did it in Mathematica, and here are the formulas in pseudocode:
Alternatively, if you wanted to do the matrix math numerically, you'd typically turn to a linear algebra system (like ATLAS, though I'm not sure if it has C#/C++ bindings).
In any case, once you have the values of
A
,B
, andC
as calculated by these formulas, you just have to plug them into the expressions given in the question,-B / 2A
andC - B^2/4A
, to calculate the coordinates of the vertex.1Note that if the original three points have coordinates that make
denom
a very large or very small number, doing the calculation directly might be susceptible to significant numerical error. In that case it might be better to modify it a bit, to avoid dividing by the denominators where they would cancel out anyway:and then the coordinates of the vertex are
-b / 2a
and(c - b^2 / 4a) / denom
. There are various other situations that might benefit from "tricks" like this, such as ifA
is very large or very small, or ifC
is nearly equal toB^2 / 4A
so that their difference is very small, but I think those situations vary enough that a full discussion would be better left for case-by-case followup questions.Converting all of this to code in the language of your choice is left as an exercise for the reader. (It should be pretty trivial in any language that uses standard infix operator syntax, e.g. as AZDean showed in C#.)
1In the initial version of the answer I thought this would be obvious, but it seems there are a lot of people who like having it mentioned explicitly.
通过直接代入,您可以得到以下三个方程:
您可以通过注意到这相当于矩阵乘积来解决这个问题:
因此,您可以通过对矩阵求逆并将逆矩阵与右侧向量相乘来得到 A、B 和 C。
我发现,当我发布这篇文章时,John Rasch 已链接到更深入地实际求解矩阵方程的教程,因此您可以按照这些说明来获得答案。 反转 3x3 矩阵非常容易,所以这应该不会太难。
You get the following three equations by direct substitution:
You can solve this by noting that this is equivalent to the matrix product:
So you can get A,B, and C by inverting the matrix and multiplying the inverse with the vector on the right.
I see that while I've been posting this John Rasch has linked to tutorial that goes into more depth on actually solving the matrix equation, so you can follow those instructions to get the answer. Inverting a 3x3 matrix is quite easy, so this shouldn't be too tough.
下面是一个 Fortran 代码,它实现了 @david-z 和 @AZDean 的解决方案:
Here is a code in Fortran that implements @david-z and @AZDean's solution:
我做了一些类似于 @piSHOCK 的答案,也是基于 @AZDean 的代码。 如果您需要大量运行它(或者像我一样在 Matlab 中使用它),这可能是最快的。
我的假设是
x1 == -1, x2 == 0, x3 == 1
。I've done something similar to @piSHOCK's answer, also based on @AZDean's code. If you need to run it heavily (or to use it in Matlab like me), this might be the fastest one.
My assumption is that
x1 == -1, x2 == 0, x3 == 1
.这闻起来像家庭作业。 “问科学家”是正确的。 假设您的 3 个点是 (x1, y1)、(x2, y2) 和 (x3, y3)。 然后,您将得到三个线性方程:
其中 M11 = x12、M12 = x1,M13 = 1,Z1 = y1,对于其他两行类似地使用 (x2, y2) 和 (x3, y3) 代替 (x1, y1)。
求解这个由 3 个方程组组成的方程组将得到 A、B 和 C 的解。
This smells like homework. "Ask a Scientist" is right on. Say your 3 points are (x1, y1), (x2, y2), and (x3, y3). Then, you get three linear equations:
Where M11 = x12, M12 = x1, M13 = 1, Z1 = y1, and similarly for the other two rows using (x2, y2) and (x3, y3) in place of (x1, y1).
Solving this system of 3 equations will give you a solution for A, B, and C.
在 https://ideone.com/y0SxKU 运行,
我添加了一些针对负向峰值的单元测试:在 https://ideone.com/WGK90S 上实时运行
Running at https://ideone.com/y0SxKU
I have added a couple of unit tests for negative going peaks: running live at https://ideone.com/WGK90S