在C#中一直在玩复杂的数字,我发现了一些有趣的东西。不确定它是否是一个错误,或者我是否错过了什么,但是当我运行以下代码时:
var num = new Complex(0, 1);
var complexPow = Complex.Pow(num, 2);
var numTimesNum = num * num;
Console.WriteLine("Complex.Pow(num, 2) = {0} num*num = {1}", complexPow.ToString(), numTimesNum.ToString());
我得到以下输出:
Complex.Pow(num, 2) = (-1, 1.22460635382238E-16) num*num = (-1, 0)
如果内存服务,复数本身应该只有-1而没有虚部(或者更确切地说是0的虚部)。那么为什么Complex.Pow(num,2)不给-1? 1.22460635382238E-16来自哪里?
如果重要,我使用单声道,因为我不在Windows atm。认为它可能是64位,因为我运行的是64位操作系统,但我不确定在哪里检查。
保重, 克尔。
编辑:
好的,我解释得很差。我当然意味着我的平方是-1,而不是任何复数的平方。谢谢你指出来。现在有点累,所以我的大脑不能很好地工作,哈哈。
编辑2:
为了澄清一些事情,我最近一直在读一些数学,并决定制作一个小脚本语言以获得乐趣。好的,“脚本语言”是一个过度语句,它只是评估方程式而已。
答案 0 :(得分:7)
你看到浮点不精确。
1.22460635382238E-16
实际上是0.00000000000000012...
。
Complex.Pow()
可能是通过De Moivre's formula实现的,使用三角函数计算任意幂
因此,浮点运算和trig都会出现不准确的情况
它显然没有任何特殊情况代码的整体权力,这可以更简单。
普通complex multiplication只涉及简单算术,因此当数字为整数时,它不会受到浮点不准确的影响。
答案 1 :(得分:7)
那么为什么Complex.Pow(num,2)不给-1? 1.22460635382238E-16来自哪里?
我怀疑这是一个舍入错误,基本上。毕竟,这是一个非常小的数字。我不知道Complex.Pow
的详细信息,但我发现它在某处使用了一些三角函数并不会感到惊讶 - 你可能正在观察pi / 2不能完全代表双重的事实
*
操作可以通过更简单的定义来避免这种情况 - Complex.Pow
可以专门用于只使用x * x
的权力2,但我希望还没有完成。相反,使用了一种通用算法,它给出假设的答案非常接近,但这会导致很小的错误。
答案 2 :(得分:3)
那么为什么Complex.Pow(num,2)不给-1? 1.22460635382238E-16来自哪里?
floating point representations的标准问题,以及用于计算Complex.Pow
的算法(它并不像您想象的那么简单)。请注意,1.22460635382238E-16
非常小,接近机器epsilon。此外,这里的一个关键事实是(0, 1)
在极坐标中确实是(1, pi / 2)
,而pi / 2
在浮点中没有精确的表示。
如果您对此感到不舒服,我建议您阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic。 应该需要阅读大学CS课程。