3

私はPython 2と、ウィキペディアの記事「3次関数」に記載されているかなり単純な方法を使用しています。これは、タイトルに記載されている関数を作成するために定義しなければならない立方根関数にも問題がある可能性があります。

# Cube root and cubic equation solver
#
# Copyright (c) 2013 user2330618
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at http://www.mozilla.org/MPL/2.0/.

from __future__ import division
import cmath
from cmath import log, sqrt

def cbrt(x):
    """Computes the cube root of a number."""
    if x.imag != 0:
        return cmath.exp(log(x) / 3)
    else:
        if x < 0:
            d = (-x) ** (1 / 3)
            return -d
        elif x >= 0:
            return x ** (1 / 3)

def cubic(a, b, c, d):
    """Returns the real roots to cubic equations in expanded form."""
    # Define the discriminants
    D = (18 * a * b * c * d) - (4 * (b ** 3) * d) + ((b ** 2) * (c ** 2)) - \
    (4 * a * (c ** 3)) - (27 * (a ** 2) * d ** 2)
    D0 = (b ** 2) - (3 * a * c)
    i = 1j  # Because I prefer i over j
    # Test for some special cases
    if D == 0 and D0 == 0:
        return -(b / (3 * a))
    elif D == 0 and D0 != 0:
        return [((b * c) - (9 * a * d)) / (-2 * D0), ((b ** 3) - (4 * a * b * c)
        + (9 * (a ** 2) * d)) / (-a * D0)]
        else:
            D1 = (2 * (b ** 3)) - (9 * a * b * c) + (27 * (a ** 2) * d)
            # More special cases
            if D != 0 and D0 == 0 and D1 < 0:
                C = cbrt((D1 - sqrt((D1 ** 2) - (4 * (D0 ** 3)))) / 2)
            else:
                C = cbrt((D1 + sqrt((D1 ** 2) - (4 * (D0 ** 3)))) / 2)
                u_2 = (-1 + (i * sqrt(3))) / 2
                u_3 = (-1 - (i * sqrt(3))) / 2
                x_1 = (-(b + C + (D0 / C))) / (3 * a)
                x_2 = (-(b + (u_2 * C) + (D0 / (u_2 * C)))) / (3 * a)
                x_3 = (-(b + (u_3 * C) + (D0 / (u_3 * C)))) / (3 * a)
                if D > 0:
                    return [x_1, x_2, x_3]
                else:
                    return x_1

この関数はいくつかの単純な 3 次方程式を解くことができることがわかりました。

print cubic(1, 3, 3, 1)
-1.0

そして少し前に、2 つの根を持つ方程式を解けるようになりました。書き直したばかりで、今はおかしくなっています。たとえば、これらの係数は (2x - 4)(x + 4)(x + 2) の展開された形式であり、[4.0, -4.0, -2.0] などを返す必要があります。

print cubic(2, 8, -8, -32)
[(-4+1.4802973661668753e-16j), (2+2.9605947323337506e-16j), (-2.0000000000000004-1.1842378929335002e-15j)]

これは、私がしている数学的な間違いですか、それともプログラミングの間違いですか?

更新:皆さん、ご回答ありがとうございます。しかし、この関数には、これまで繰り返してきたよりも多くの問題があります。たとえば、立方根関数に関連するエラーがよく発生します。

print cubic(1, 2, 3, 4)  # Correct solution: about -1.65
...
    if x > 0:
TypeError: no ordering relation is defined for complex numbers
print cubic(1, -3, -3, -1)  # Correct solution: about 3.8473
    if x > 0:
TypeError: no ordering relation is defined for complex numbers
4

3 に答える 3

7

Wolfram Alphaは、最後の立方体の根が実際に

(-4, -2, 2)

そしてあなたが言うようではありません

...それは戻るはずです[4.0, -4.0, -2.0]

その(私は推測する)タイプミスにもかかわらず、あなたのプログラムは

[(-4+1.4802973661668753e-16j), (2+2.9605947323337506e-16j), (-2.0000000000000004-1.1842378929335002e-15j)]

正確に10**(-15)は、正しい解とまったく同じルーツです。他の人が言ったように、小さな虚数部分はおそらく丸めによるものです。

Cardano. MAPLEこれは、プログラムが好きまたは存在する理由の1つでありMathematica、式から実装への切断がしばしばあります。

純粋な python で数値の実数部分のみを取得するには、 を呼び出します.real。例:

a = 3.0+4.0j
print a.real
>> 3.0
于 2013-04-29T05:16:51.043 に答える
3

これを数値的に行いたい場合は、Hookedの答えが最適です。sympyを使用してシンボリックに実行することもできます:

>>> from sympy import roots
>>> roots('2*x**3 + 8*x**2 - 8*x - 32')
{2: 1, -4: 1, -2: 1} 

これにより、根とその多重度が得られます。

于 2013-04-29T15:18:30.813 に答える