计算C中的小数指数

时间:2014-07-04 03:22:12

标签: c newtons-method exponent

我试图评估一个^ n,其中a和n是有理数。 我不想使用任何预定义的功能,例如sqrt()pow()

所以我尝试使用Newton的方法来使用这种方法获得近似解决方案:

  

3 ^ 0.2 = 3 ^(1/5),所以如果x = 3 ^ 0.2,则x ^ 5 = 3.

     

可能是解决这个问题的最佳方式(没有计算器但仍然如此)   使用基本算术运算)是使用"牛顿法"。   牛顿求解方程f(x)= 0的方法是建立a   通过将x0作为一些初始"猜测"定义的数字序列xn。   然后xn + 1 = xn-f(xn / f'(xn)其中f'(x)是f的导数。

张贴于physicsforums

该方法的问题在于,如果我想计算5.2^0.33333,我需要找到此等式x^10000 - 5.2^33333 = 0的根。我最终得到了大量的数字,并且大部分时间都会出现infnan错误。

有人可以就如何解决这个问题给我建议吗?或者,有人可以提供另一种算法来计算^ n吗?

3 个答案:

答案 0 :(得分:5)

似乎你的任务是计算

⎛ xN ⎞(aN / aD)
⎜⎼⎼⎼⎼⎟           where xN,xD,aN,aD ∈ ℤ,  xD,aD ≠ 0
⎝ xD ⎠

仅使用乘法,除法,加法和减法,Newton's method作为建议的实施方法。

我们试图解决的等式( y )是

             (aN / aD)
y = (xN / xD)            where y ∈ ℝ

Newton的方法找到函数的根。如果我们想用它来解决上述问题,我们从左侧减去右侧,得到一个函数,其零值给出了我们想要的 y

                  (aN/aD)
f(y) = y - (xN/xD)        = 0

没什么帮助。我想这就是你得到的?这里的要点是暂时还没有形成这个功能,因为我们没有办法计算有理数的理性幂!

首先,让我们确定 aD xD 都是正面的。如果 aD 为负数,我们可以简单地通过否定 aN aD 来做到这一点(所以 aN / <的符号如果 xD 为负,则em> aD 不会改变,并且否定 xN xD 。请记住,根据定义, xD aD 均为零。然后,我们可以简单地将双方都提升到 aD '的权力:

 aD            aN     aN     aN
y   = (xN / xD)   = xN   / xD

我们甚至可以通过将双方乘以最后一个词来消除分裂:

 aD     aN     aN
y   × xD   = xN

现在,这看起来很有希望!我们从中获得的功能是

        aD   aN     aN
f(y) = y   xD   - xN
牛顿的方法也需要衍生物,显然是

f(y)            aD   aN
⎼⎼⎼⎼ = df(y) = y   xD   y / aD
 dy

牛顿方法本身依赖于迭代

             f(y)
y    = y  - ⎼⎼⎼⎼⎼⎼
 i+1    i    df(y)

如果计算出数学,你会发现迭代只是

                                 aD
                y[i]      y[i] xN
y[i+1] = y[i] - ⎼⎼⎼⎼ + ⎼⎼⎼⎼⎼⎼⎼⎼⎼⎼⎼⎼⎼⎼
                 aD           aD   aN
                       aD y[i]   xD

您无需将所有 y 值保留在内存中;它足以记住最后一个,并在它们的差异足够小时停止迭代。

你仍然有上面的取幂,但现在它们只是整数取幂,即

  aD
xN   = xN × xN × .. × xN
       ╰───────┬───────╯
              aD times

你可以非常简单地做,例如只需将参数乘以所需的次数,例如,在C,

double ipow(const double base, const int exponent)
{
    double result = 1.0;
    int    i;
    for (i = 0; i < exponent; i++)
        result *= base;
    return result;
}

有更有效的方法integer exponentiation,但上述功能应完全可以接受。

最后一个问题是选择初始 y 以便收敛。你不能使用0,因为(幂) y 被用作分区中的分母;你会得到零除错误。就个人而言,我会检查结果是正面的还是负面的,小于或大于一个;总共有两条规则可以选择一个安全的初始 y

有问题吗?

答案 1 :(得分:2)

您可以使用generalized binomial theorem。替换y=1x=a-1。您可能希望根据所需的准确度在足够的术语后截断无限级数。为了能够将术语数量与准确性相关联,您需要确保x^r项的绝对值正在下降。因此,根据an的值,您应该应用公式来计算a^na^(-n)中的一个,并使用它来获得所需的结果。

答案 2 :(得分:2)

将整数提升为幂的解决方案是:

int poweri (int x, unsigned int y)
{
    int temp;
    if (y == 0)
        return 1;

    temp = poweri (x, y / 2);
    if ((y % 2) == 0)
        return temp * temp;
    else
        return x * temp * temp;
}

然而,平方根并不能提供封闭解决方案的清洁。在wikipedia-square rootWolfram Mathworks Square Root Algorithms处可以找到很多背景资料。两者都提供了几种满足您需求的方法,您只需选择适合您目的的方法。

稍作修改,来自维基百科的这个例程(修改为返回平方根并提高精度)返回一个令人惊讶的准确平方根。是的,关于联合的使用会有嚎叫,它只在整数和浮点存储等价的情况下有效,但是如果你正在攻击你自己的平方根,这是相对有效的:

float sqrt_f (float x)
{
        float xhalf = 0.5f*x;
        union
        {
            float x;
            int i;
        } u;
        u.x = x;
        u.i = 0x5f3759df - (u.i >> 1);
        /* The next line can be repeated any number of times to increase accuracy */
        // u.x = u.x * (1.5f - xhalf * u.x * u.x);
        int i = 10;
        while (i--)
            u.x *= 1.5f - xhalf * u.x * u.x;

        return 1.0f / u.x;
}