如何使用Math.Pow(等等)函数?

4

我搜索了很长时间,几乎找不到任何信息。我在这个链接中找到了一些关于Math.Pow可能实现的信息,但它们是不准确的,例如这段代码

public static double PowerA(double a, double b)
{
    int tmp = (int)(BitConverter.DoubleToInt64Bits(a) >> 32);
    int tmp2 = (int)(b * (tmp - 1072632447) + 1072632447);
    return BitConverter.Int64BitsToDouble(((long)tmp2) << 32);
}
static void Main(string[] args)
{
    double x = 12.53, y = 16.45;
    Console.WriteLine(Math.Pow(x, y));
    Console.WriteLine(PowerA(x, y));
}

提供输出:
1,15158266266297E+18
8,9966384455562E+17

很不精确...

我认为它的工作方式类似于一系列的总和,但我并不确定。


3
必读资料:《计算机科学家应了解的浮点数算术知识》(What Every Computer Scientist Should Know About Floating-Point Arithmetic)。我相信这篇论文中有你不知道的浮点数知识。 - ppeterka
1
我建议PowerA是不准确的。PowerA(12.0, 5.0)返回不正确的227008.5,而Math.Pow(12.0, 5.0)返回正确的248832,足够小以进行测试。此外,一个整数double乘以另一个整数double应该返回另一个整数double,而不是以.5结尾的数字! - Rick Davin
2
@RickDavin 我理解为OP的意思是他现在的方法没有正确地模拟Math.Pow,它是错误的,他正在寻找一个能够正确模拟Math.Pow的实现。 - Servy
给Tim S:在提问之前,我已经阅读过相关内容,但只有解释说这是原生的C++代码,所以才发布了这个问题。给ppeterka 66:我已经阅读了一篇基于你提供的链接的文章。所以我对其中大部分内容都很了解,但我肯定会去阅读原文。但是它如何帮助我呢?提供反汇编器手册的链接应该更实用一些 :) - Alex Zhukovskiy
显示剩余3条评论
1个回答

7

pow通常使用以下公式进行计算:

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

函数exp2(x),log2(x)直接在FPU中实现。如果您想要实现bignums,则可以通过使用预先计算的sqrt-powers表格和基本运算符来进行评估。

2^1/2, 2^1/4, 2^1/8, 2^1/16, 2^1/32 ...

为了加速这个过程

如果您需要处理负数底数求根,请参考以下内容:


函数exp2(x),log2(x)直接在FPU中实现 - 这是我不知道的最重要的信息。谢谢。 - Alex Zhukovskiy
函数exp2(x),log2(x)直接在FPU中实现 - 您确定您不是指* FP库*,因为FPU是硬件实体,其与CPU架构差异巨大(问题中未明确),并且可能不一定实现此类高阶函数。 - Eight-Bit Guru
@Eight-BitGuru 我在 x87 FPU 上工作,这些函数在那里本来就存在,所以我的意思是它们是在 FPU 中实现的,而不是在 FP 库中。 - Spektre
@Eight-BitGuru 看看像 f2xm1,fyl2x,fyl2xp1 这样的指令... "work on" 的意思是 "我使用" 当然... 我刚想到了错误的翻译 :) - Spektre
@Spektre,我认为你错过了我的观点的核心 - 并非所有FPU架构都实现了这种类型的高阶函数,因此断言“函数exp2(x),log2(x)直接在FPU中实现”是对硬件性质进行了未明确指定的假设。 - Eight-Bit Guru
显示剩余4条评论

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