处理负底数和非整数指数的幂函数

4
无论是被称为Math.pow()还是pow(),许多语言(以及计算器)都有一些内置函数来计算浮点数(或双精度数)的x=a^b。特殊情况是a为负数且b不是整数。有些会返回NaN,有些会给出复杂结果(咳咳 Python)。但有些实际上能够给出实际结果,所以我想知道的是如何做到这一点。为了解释我的困惑:
假设b是有理数:b=c/d。现在我们看一下c和d的奇偶性:
- d为偶数:没有实数x-> NaN或错误 - d是奇数,c是偶数:正x - d是奇数,c是奇数:负x
浮点数存储在特定格式中,这意味着如果它被字面解释,它将始终是偶数d(实际上是2的幂)。由于这些信息在计算中丢失,无法知道c和d的实际奇偶性。只能猜测。
因此,我的猜测是-它试图找到一个接近于b的有理数c/d,其中d是奇数,且c和d都小于某个阈值t。更小的t意味着它可以更确定它是正确的,但它将在较少的数字上工作。如果成功,则使用c的奇偶性。否则,假装d是偶数。毕竟,浮点数可以是任何东西,数学库不想通过假设它可能不是有理数而给出可能错误的结果。
这只是我的猜测。如果有人真正看到了这些幂函数中的代码(或规范,也一样好),并能提供见解,那就太好了。

1
如果您提供哪些语言和计算器“实际上能够给出真实结果”的示例,那将非常有帮助。我所知道的唯一一个是TI Nspire CX手持图形计算器,而且我相信德州仪器以保持其计算器源代码不公开而臭名昭著(尽管他们会公开一些使用计算器的软件)。 - Rory Daulton
对于非整数次幂,您会得到复数根;对于无理数次幂,您将得到无穷多个根。您可以使用数学恒等式来克服Math.pow的限制-请参见欧拉公式De Moivre定理 - meowgoesthedog
2
你能给出具体的例子吗?我觉得这个问题很困惑。正如所指出的,所有数字二进制浮点数都是有理数(即分数),其中 d 是偶数(即 2 的幂)。如果“奇偶性”指的是整数是奇数还是偶数的属性,那么我们就知道 d 是偶数,并且浮点数的位模式告诉我们 c 是奇数还是偶数。因此,我不理解“无法知道 c 和 d 的真实奇偶性,因为该信息已丢失”的说法。 - njuffa
1
如果你用它准确表示的分数替换一个浮点数,那么它要么是整数,要么分母必须是偶数,分子必须是奇数(思考简化)。因此,你不可能得到一个真实的结果返回... - aka.nice
请查看此链接 基于复数域数学的真实域幂 - Spektre
2个回答

1

首先看一下:负指数幂的平方法

现在假设一个情况:x^y,其中x<0,且y不是整数。如果你使用

x^y = exp2(y*log2(x))

如果你受到log2定义范围的限制,那么你将受到NaN|x|^y的影响。如果你想要更好的结果,可以尝试将y分解为以下形式:

y = a/b

其中a,b为整数。如果可能(或应用四舍五入),则将问题更改为:

x^y = (x^a)^(1/b)

现在你可以处理更多的情况(正如你所建议的):
  1. 如果 a 是偶数,则子结果不再为负数,因为 x^a>=0,所以 (x^a)^(1/b)>=0
  2. 如果 a,b 都是奇数,则结果为负数
  3. 否则结果为 NaN 或使用 |x|^y
现在回到你的 float 问题,数字总是以这种形式出现:
y = mantissa*exp2(exponent)

所以是的,b 是偶数(除非 exponent!=0,这意味着数字是整数)。由于 mantissa 存储为整数,您可以通过检查其 LSB 来获得其奇偶性。不要忘记,在 floats 中,MSB 缺失并且始终应该是 1,除非存在像非规格化或 Nan/Inf 数字这样的特殊情况。

0

如果你准备作弊,这里是如何将负数提高到任意幂的方法:

x^(b/c)=x^(2b/2c)=(x^2b)^(1/2c)

x^2b 是正数,所以取 2c 次方根没有问题


你的代码没有找到实数x的正确幂,而是找到了|x|的幂。这不是同一件事。例如,你的代码声称(-1)^(1/3)1,但它应该给出-1(正如OP想要的)或者1/2 + sqrt(3)/2*j(正如Python近似返回的)。 - Rory Daulton
当然,这就是为什么它被称为作弊 ;) 这个愚蠢的回答的灵感来自于浮点数有效数字奇偶性的论文:一旦分数被约分,分子将是奇数(除非浮点表示是整数)。此外,将其提高至分数的定义有些随意。 - aka.nice

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