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。

奇怪的是,我在网络上的任何地方都没有找到任何提及这一点。我在这里吃疯药吗!?

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 != 1,1.0/(double)n不能完全表示,因此您不能使用 来计算 x 的第 n 个根pow(x, 1.0/(double)n)。因此pow(x, y)指定为负 x 和非整数 y 返回 NaN - 对于任何这些情况都没有适当的实际结果。

于 2013-01-16T20:47:06.637 回答
3

这里的问题是“第七根”的数学定义是一个多值函数。虽然这是真的

(-2) 7 = -128

这并不意味着-2 是 (-128) 1/7的唯一答案。在复平面中,七次方根函数是多值的并且有许多可能的答案(就像 4 的平方根可以被认为是 +2 或 -2,但 +2 是通常的答案)。

为了简化此类表达式的数学处理,按照惯例为所讨论的函数选择主值,以便函数变为单值。在七根的情况下,主要值是Wolfram Alpha 为 (-128) 1/7给出的值。

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。

注意:由于双浮点精度限制,它适用于大多数(但不是全部)小数指数。

下面是我编写的 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 ,我使用 Rational 可以准确表示 Microsoft.SolverFoundation.Common 中的 1/3 。请参阅:https ://msdn.microsoft.com/en-us/library/microsoft.solverfoundation.common .rational%28v=vs.93%29.aspx?f=255&MSPPError=-2147217396

而且我可以捕获 1/3 的奇数根链接,因为我可以获得分母。

如果我得到一个根是斧头,我使用代码获取分子和分母。

            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 的 pow 使得 powerBase 为正。

与 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 回答