为什么负零很重要?


64

我对为什么我们关心正零和负零的不同表示感到困惑。

我隐约记得阅读过的说法,即负零表示在涉及复数的编程中极为重要。我从来没有机会编写涉及复数的代码,所以我对为什么会这样感到困惑。

Wikipedia关于该概念的文章并不是特别有用。如果我理解正确的话,它只会使带符号的零的含糊的说法使某些数学运算在浮点中变得更简单。该答案列出了几个功能不同的函数,如果您熟悉它们的用法,则可以从示例中推断出一些东西。(尽管复杂的平方根的特定示例看起来完全错了,因为这两个数字在数学上是等价的,除非我有误解。)但我一直无法找到一个清晰的陈述,说明如果不存在该陈述会遇到的麻烦。我能够找到的更多数学资源表明,从数学角度看,两者之间没有区别,并且Wikipedia文章似乎暗示,除了描述限制之外,在计算之外很少见到这一点。

那么为什么负零在计算中有价值呢?我确定我只是想念一些东西。


6
负零可以表示IEEE浮点数发生下溢,但是除此之外,它的使用似乎是有争议且晦涩的。如果我猜的话,我会说,零负在IEEE代表浮点因为......嗯,你可以的。 对于更有趣的旅程,请查找有关浮点信号NaN的信息。
罗伯特·哈维

1
如果特定示例是“ 1 / 0.0” /“ 1 / -0.0”,则0是1 / x的分支剪切,并且限制取决于您是从下方还是上方进行操作。
瓦汀2015年

@Vatine不,具体示例是sqrt(-1+0i) = isqrt(-1-0i) = -i,尽管我相信它为某些编程语言配备了适当的语法。我将进行更清晰的编辑。
jpmc26 2015年

3
我搜索了程序员堆栈溢出计算机科学数学工程学。我唯一能找到的问题是用于负零浮点值?。这不仅是第二次出现!

我真的很惊讶,答案中根本没有出现复数,特别是考虑到我指出的平方根示例。
jpmc26 2015年

Answers:


69

您需要牢记,在FPU算术中,0不一定必须精确地表示零,而且值太小而无法使用给定的数据类型表示,例如

a = -1 / 1000000000000000000.0

a太小,无法用浮点数(32位)正确表示,因此将其“舍入”为-0。

现在,让我们继续计算:

b = 1 / a

因为a为浮点数,将导致-infinity,与-1000000000000000000.0的正确答案相差很远

现在让我们计算b是否不存在-​​0(因此a舍入为+0):

b = 1 / +0
b = +infinity

由于四舍五入,结果再次是错误的,但现在它是“更错误的”-不仅在数值上,而且更重要的是因为符号不同(计算结果为+无限,正确结果为-1000000000000000000.0)。

您仍然可以说这并不重要,因为两者都是错误的。重要的是,在许多数值应用中,计算的最重要结果是符号-例如,当使用某种机器学习算法确定在十字路口处向左还是向右转时,您可以解释正值=>左,负值=>右转,该值的实际“幅值”仅为“置信系数”。


您是否对下溢的符号在虚/复数计算中是否特别重要有任何想法?
jpmc26

@qbd:您知道那些数字应用是什么吗?我要说的是,触发和使用+inf-inf在正常操作下运行的程序是错误的。
比昂·林德奎斯特

@BjörnLindqvist如果您需要具体的可下载应用程序-那么我什么都不知道。我认为这不一定是越野车-可以使用BigDecimal之类的东西以无限精度代替float / double。但是,当程序将给出与具有float / double的结果完全相同但性能却差得多的结果时,是否值得?
qbd16年

您可以编写“数字应用程序,其中最重要的计算结果是符号”,但我无法相信有任何写得很好的应用程序都依赖-0且依赖于是+inf-inf。如果您的程序导致浮点下溢,那就是bug,然后发生的事情就没那么有趣了,恕我直言。我们仍然缺少-0有用的实际示例。
比昂·林德奎斯特

1
@BjörnLindqvistx265的大部分是在组装中完成的,这取决于很少有人以性能为名而知道的模糊细节(取决于CPU体系结构)。这是错的吗?依靠广泛使用的30年历史的标准(现在仍然存在),以性能为名的一个简单易懂的功能似乎并不那么糟糕。
qbd

8

首先,如何创建-0?有两种方法:(1)执行浮点运算,其中数学结果为负,但非常接近零,因此四舍五入为零而不是非零数。该计算将得出-0。(b)某些涉及零的运算:将正零乘以负数,或将正零除以负数,或取反正零。

负零会稍微简化乘法和除法,x * y或x / y的符号始终是x的符号,异或是y的符号。如果没有负零,则必须进行一些额外的检查才能将-0替换为+0。

在某些非常罕见的情况下它很有用。您可以检查乘法或除法的结果在数学上是否大于或小于零,即使存在下溢(只要您知道结果不是数学上的零)即可。我不记得曾经写过代码,可以有所作为。

优化编译器讨厌-0。例如,您不能将x + 0.0替换为x,因为如果x为-0.0,则结果不应为x。您不能将x * 0.0替换为0.0,因为如果x <0或x为-0.0,则结果应为-0.0。


7
我希望IEEE-754包含四个零:“精确”,正无穷小,负无穷小和无符号(后者是无法区分的值之间的差)。这样做会使很多浮点公理工作-其中包括x + 0.0等效x-0.0等效x,xy等效x +(-1.0)* y和1.0 / x等效-1.0 /(-1.0 * x)[如果x为正零,则两者均为pos-inf;如果为负零,则均为负。如果准确或未签名,则均为NaN]。
2015年

我能够通过传递得到一个负零-55fmod()。对于我的用例而言,这很烦人。
亚伦·弗兰克

6

C#Double符合IEEE 754

    double a = 3.0;
    double b = 0.0;
    double c = -0.0;

    Console.WriteLine(a / b);
    Console.WriteLine(a / c);

印刷品:

Infinity
-Infinity

其实要解释一下...

Double d = -0.0; 

这意味着更接近d = The Limit of x as x approaches 0-或的东西 The Limit of x as x approaches 0 from the negatives


为了表达Philipp的评论...

基本上为负零表示下溢。

负零几乎没有实际用途...

例如,此代码(再次为C#):

double a = -0.0;
double b = 0.0;

Console.WriteLine(a.Equals(b));
Console.WriteLine(a==b);
Console.WriteLine(Math.Sign(a));

产生以下结果:

True
True
0

非正式地讲,IEEE 754浮点可以具有的所有特殊值(正无穷大,负无穷大,NAN,-0.0)在实际意义上没有意义。它们不能代表任何物理价值,也不能代表在“现实世界”计算中有意义的任何价值。他们的意思基本上是这样的:

  • 正无穷大表示在浮点可以表示的正端溢出
  • 负无穷大表示在浮点可以表示的正端溢出
  • 负零表示下溢且操作数具有相反的符号
  • 正零可能意味着下溢并且操作数具有相同的符号
  • NAN意味着你的计算是得意不确定的,像sqrt(-7),或者它没有限制一样 0/0或类似PositiveInfinity/PositiveInfinity

7
是的,但是为什么这很重要?您能否提供一个实际的,实际的例子来说明差异的重要性?
菲利普

5

关于这与复数计算的关系的问题真正成为了为什么+0和-0都存在于浮点中的核心。如果您完全研究复杂分析,您会很快发现,从复杂到复杂的连续函数通常不能被视为“单值”,除非人们采用“礼貌的虚构”,即输出形成所谓的“黎曼曲面”。例如,复数对数为每个输入分配无限多个输出;当您“将它们连接起来”以形成连续的输出时,最终所有的真实零件都会在原点周围形成一个“无限的开瓶器”表面。一条连续的曲线“从正-假想侧向下”穿过实轴,而另一条曲线“围绕极点”并穿过“实轴”。

现在将其应用于使用复数浮点进行计算的数值程序。根据程序当前在哪个“工作表”上,在给定计算之后采取的操作可能会有很大的不同,最后计算结果的符号可能会告诉您哪个“工作表”。现在假设结果为零?请记住,这里的“零”实际上意味着“太小而无法正确表示”。但是如果结果为零时,如果计算可以安排-保存符号-(即记住哪个“工作表”),那么即使在这种情况下,代码也可以检查符号并执行正确的操作。


1

原因比平常简单

当然,有很多看起来很不错的hack,它们非常有用(例如四舍五入-0.0+0.0假设我们在开始时都有带减号/加号的带符号int的表示(我知道这是由U2二进制代码解决的)通常以整数表示,但假设使用不太复杂的double表示形式:

0 111 = 7
^ sign

如果有负数怎么办?

1 111 = -7

好吧,那很简单。因此,让我们代表0:

0 000 = 0

也可以 但是呢1 000?它必须是一个禁止的号码吗?更好不。

因此,我们假设有两种类型的零:

0 000 = +0
1 000 = -0

好吧,这将简化我们的计算并幸运地给出一些附加功能。因此+0-0来自二进制表示形式问题。


6
如果我没看错的话,您实际上只是在说定义或实施标准的人们不想麻烦您放弃它。我认为这种推论不支持这样一个事实,即2的补码使用“负零”表示一个完全不同的数字,而没有负零的表示。请参阅我链接的维基百科文章。
jpmc26 2015年

1
@ jpmc26我认为实际上有一些道理,因为不禁止它意味着不需要实现具有特殊情况。实际上,每个数字都有一个符号位,可以通过切换符号位来取反。甚至NaN都是经过签名的,实现可以(但不是必须)在生成NaN时选择适当的符号。如果负零并不存在,每一个结果为0计算将需要做额外的工作来修复符号位,等等
霍布斯

4
@ jpmc26(即,在每个其他两个数的乘法中,结果的符号是被乘数的符号的异或,而大小是两个大小的乘积。在现实生活中,这适用于-1 * 0 =- 0。但是如果符号位被翻转的零是某个特殊的非零值,那么每个可能产生0的产品都必须检查并确保它不会错误地产生该特殊值。)
霍布斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.