5

いいえ、これは (私の理解では) 整数除算や浮動小数点の丸めの問題を伴いません。

私の正確なコードは次のとおりです。

    static void Main(string[] args)
    {
        double power = (double)1.0 / (double)7.0;
        double expBase = -128.0;
        System.Console.WriteLine("sanity check: expected: -128 ^ 0.142857142857143 = -2.    actual: " + expBase + " ^ " + power + " = " + Math.Pow(expBase, power));
        System.Console.ReadLine();
    }

出力は次のとおりです。

sanity check: expected: -128 ^ 0.142857142857143 = -2. actual: -128 ^ 0.14285 7142857143 = NaN

このコードのターゲット フレームワークは、(ソリューション プロパティによると) .NET Framework 4.0 Client Profile です。

奇妙なことに、私は Web のどこにもこれについての言及を見つけませんでした。私はここでクレイジーな薬を飲んでいます!?

4

6 に答える 6

18

指定どおりのようです。Math.Pow() の備考セクションからPow(x,y);

パラメータ
x < 0 ですが、NegativeInfinity ではありません。y が整数、NegativeInfinity、または PositiveInfinity ではありません。

結果
NaN

于 2013-01-16T20:46:23.443 に答える
12

Joachimの答えは、 pow がその仕様に従って動作していることを説明しています。

pow( ) がそのように指定されているのはなぜですか? 1.0/7.0は 1/7 に等しくないからです。0.14285714285714285の累乗を求めていますが-128.0、そのプロパティには実数がないため、結果は正しく NaN になります。すべての奇数についてn != 11.0/(double)nは正確に表現できるわけではないため、 を使用して x の n 乗根を計算することはできませんpow(x, 1.0/(double)n)。したがってpow(x, y)、負の x および非整数の y に対して NaN を返すように指定されています。これらのケースのいずれにも、適切な実際の結果はありません。

于 2013-01-16T20:47:06.637 に答える
3

ここでの問題は、「7番目のルート」の数学的定義が多値関数であるということです。それは本当ですが

(-2)7 = -128

これは、-2が(-128) 1/7に対する唯一の答えであることを意味するものではありませ。複素平面では、7番目の根の関数は多値であり、多くの可能な答えがあります(4の平方根が+2または-2のいずれかであると見なすことができるのと同じように、+ 2が通常の答えです)。

このような式の数学的処理を単純化するために、関数が単一値になるように、問題の関数の慣例により主値が選択されます。7番目のルートの場合、主値は(-128) 1/7に対してWolframAlphaによって与えられた値です。

C#のMath.Pow()関数は、関数の主値を返そうとしpowます。結果の主値が複素数になる場合は、を返しますNaN

于 2013-01-16T21:08:23.930 に答える
1

負の実数の分数べき乗は複素数です (詳細な説明については、数学フォーラムを参照してください)。

于 2013-01-16T20:49:45.150 に答える
0

Math.Pow() を修正しました。

現在はより大きな許容ドメインを持ち (つまり、パラメーター: x < 0 であり、NegativeInfinity ではありません。y は分子が 1 で分母が奇数の分数です)、新しいドメイン領域の実数の結果を返します。

つまり、(-128)^(1/7) は -2 を返します。

注: double float の精度制限により、すべてではありませんが、ほとんどの小数指数で機能します。

以下は、私が書いた Math.Pow() のラッパーのコードです。

public class MathUtil
{
    /// <summary>
    /// Wrapper for Math.Pow()
    /// Can handle cases like (-8)^(1/3) or  (-1/64)^(1/3)
    /// </summary>
    public static double Pow(double expBase, double power)
    {
        bool sign = (expBase < 0);
        if (sign && HasEvenDenominator(power)) 
            return double.NaN;  //sqrt(-1) = i
        else
        {
            if (sign && HasOddDenominator(power))
                return -1 * Math.Pow(Math.Abs(expBase), power);
            else
                return Math.Pow(expBase, power);
        }
    }

    private static bool HasEvenDenominator(double input)
    {
        if(input == 0)
            return false;
        else if (input % 1 == 0)
            return false;

        double inverse = 1 / input;
        if (inverse % 2 < double.Epsilon)
            return true;
        else
            return false;
    }

    private static bool HasOddDenominator(double input)
    {
        if (input == 0)
            return false;
        else if (input % 1 == 0)
            return false;

        double inverse = 1 / input;
        if ((inverse + 1) % 2 < double.Epsilon)
            return true;
        else
            return false;
    }
}
于 2013-01-24T21:09:32.963 に答える
0

1.0/3 != 1/3 の場合、Microsoft.SolverFoundation.Common で 1/3 を正確に表すことができる Rational を使用します。 .rational%28v=vs.93%29.aspx?f=255&MSPPError=-2147217396

そして、分母を取得できるため、奇数根リンク 1/3 をキャッチできます。

ルートが ax である場合は、コードを使用して分子と分母を取得します。

            var at = (double)ax.Numerator;
            var down = (double)ax.Denominator;

有理数は 2/6=1/3 を作ることができます。

しかし、Rational.Pow は powerBase を計算できません。

powerBase が正ではなく、分母が偶数で、分子が奇数であることがわかりました。

             if (at % 2 == 1 && down % 2 == 0)
            {
                return Double.NaN;
            }

分母が奇数の場合、使用しますx = x * -1

            if (at % 2 == 1 && down % 2 == 1)
            {
                x = Math.Pow(x, (int)at);
                x = x * -1;
                return -1 * Math.Pow(x, 1.0 / (int)down);
            }

Numerator が偶数の場合、Numerator make powerBase の pow は正になります。

pow(x,2/3) のように、x が正でない場合、pow(x,2) を使用すると正になります。

            x = Math.Pow(x, (int)at);
            return Math.Pow(x, 1.0 / (int)down);

使用できるコード

       if (x < 0)
        {                
            var at = (double)ax.Numerator;
            var down = (double)ax.Denominator;

            if (at % 2 == 1 && down % 2 == 0)
            {
                return Double.NaN;
            }
            if (at % 2 == 1 && down % 2 == 1)
            {
                x = Math.Pow(x, (int)at);
                x = x * -1;
                return -1 * Math.Pow(x, 1.0 / (int)down);
            }
            x = Math.Pow(x, (int)at);
            return Math.Pow(x, 1.0 / (int)down);
        }
        else
        {
            return Math.Pow(x, a);
        }
于 2017-04-21T10:09:49.857 に答える