C语言中使用pow函数求负数的立方根

12

在现实世界中,负数的立方根应该存在:

cuberoot(-1)=-1,意味着 (-1)*(-1)*(-1)=-1 或者 cuberoot(-27)=-3,意味着 (-3)*(-3)*(-3)=-27

但是当我在C语言中使用pow函数计算负数的立方根时,却得到了一个nan(不是一个数字)。

double cuber;
cuber=pow((-27.),(1./3.));
printf("cuber=%f\n",cuber);

输出:cuber=nan

在C语言中有没有计算负数立方根的方法?

4个回答

20

7.12.7.1 cbrt函数

概要

#include <math.h>
double cbrt(double x);
float cbrtf(float x);
long double cbrtl(long double x);

描述

cbrt函数计算给定数值x的实数立方根。


如果您好奇,pow函数不能用于计算立方根,因为1/3不能表示为浮点数。 实际上,你正在请求pow函数将-27.0提高到一个接近于1/3的有理数幂次方; 没有适当的实数结果。


3
pow函数可以计算一个正数的0.333333333333333314829616256247390992939472198486328125次方,通常(但不总是)在四舍五入后与立方根相同。 - Stephen Canon
这与 C 标准保证 cbrt 的接近程度相同(这根本不是保证)。但如果 IEEE 754 可以保证 cbrt 的精度,则可能会有其他说法。 - Steve Jessop
@SteveJessop:没错。我并不是建议你使用cbrt来获得精度。在某些平台上,你应该使用它来提高速度,但真正使用它的原因是因为它可以为负数输入提供“你想要的答案”——pow无法做到这一点,因为不存在负数的0.333333333333333314829616256247390992939472198486328125次方。 - Stephen Canon
@SteveJessop:可以推测,既然它已经出现在C++中,MSVC最终也会加入它。 - Stephen Canon
@DanielFischer:不,那不是问题(尽管它与此密切相关)。不能通过简单地返回exp(y * log(x))来实现C标准库中的pow,因为这会得到许多边缘情况错误的结果。例如,尝试一下pow(-27.0, -1.0) - Stephen Canon
显示剩余6条评论

6

这里有一个要记住的公式:x^(1/3) = -(-x)^(1/3)。因此,下面的内容可以解决它:

double cubeRoot(double d) {
  if (d < 0.0) {
    return -cubeRoot(-d);
  }
  else {
    return pow(d,1.0/3.0);
  }
}

未经编译的编写,因此可能会存在语法错误。

问候, Jost


这并不像标准的cbrt()函数那样精确。 - phuclv

1

正如Stephen Canon所回答的那样,在这种情况下使用的正确函数是cbrt()。如果您不知道指数,可以查看cpow()函数。


#include <stdio.h>
#include <math.h>
#include <complex.h>
int main(void) { printf("立方根 cbrt: %g\n", cbrt(-27.)); printf("立方根 pow: %g\n", pow(-27., 1./3.)); double complex a, b, c; a = -27.; b = 1. / 3; c = cpow(a, b); printf("立方根 cpow: (%g, %g), abs: %g\n", creal(c), cimag(c), cabs(c)); return 0; }

输出结果为:

立方根 cbrt: -3
立方根 pow: -nan
立方根 cpow: (1.5, 2.59808), abs: 3

请记住复杂幂的定义:cpow(a, b) = cexp(b* clog(a))。


0

使用牛顿法:

def cubicroot(num):
  flag = 1
  if num < 0:
    flag = -1
    num = num - num - num
  x0 = num / 2.
  x1 = x0 - (((x0 * x0 * x0) - num) / (3. * x0 * x0))
  while(round(x0) != round(x1)):
    x0 = x1
    x1 = x0 - (((x0 * x0 * x0) - num) / (3. * x0 * x0))
  return x1 * flag

print cubicroot(27)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接