How to convert negative zero to positive zero in C?
您好,我正在学习Objective C,并且正在做经典的Calculator示例。
问题是,当我将零乘以任何负数时会得到负零,然后将结果放入(双精度)类型!
要查看发生了什么,我玩了调试器,这就是我得到的:
(gdb) print -2*0
$1 = 0
(gdb) print (double) -2 * 0
$2 = -0
在第二种情况下,当我将其强制转换为双精度类型时,它将变为负零! 如何在应用程序中解决该问题? 我需要打双打。
如何修复结果,以便当结果应为零时得到零?
-
结果是正确的。负零有什么问题?
-
大概您的应用程序未在GDB中运行。当然,您将控制输出的格式。另外,还有一个问题:"如何解决结果,以便当结果应为零时得到零?"基于错误的前提-您确实得到了零。
-
幸运的是,-0.0 == +0.0,所以您的问题消失了。
-
我发现上述所有评论都没有响应,Arams也回答了。我假设这是一个小故障,因为零位双精度符号的符号位与正常零位的行为不同,而实际上它们代表相同的数量并且应以相同的方式显示。
-
@Jiminion这不是小故障。在某些情况下,-0.0与+0.0的行为不同-atan2()是常见情况。尽管它们表示相同的值,但-0.0的各个方面取决于实现的标准(如果遵循IEEE,则??不是)。
-
OP运行时遇到的故障。我相信IEEE标准有其做事的理由。
-
@Jiminion:IEEE浮点规范是一项非常受人尊敬的工作。其中的所有内容都是精心制作的,确实很糟糕,有些C编译器没有完全实现其所有细节和规定。 0.0和-0.0之间的主要区别在于它们作为商值的行为:1 0.0是正无穷大,而1 -0.0是负无穷大,这是非常不同的。
-
古兹(Guz),请注意,使用double x = -0.0000001; printf("%f
", x);也会使用-0.000000打印类似"负零"的输出。当然,查看-1.000000e-07的代码可能是printf("%e
", x);。
-
如何使负数变为正数的可能重复项
我做了一个简单的测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| double d = (double) -2.0 * 0;
if (d < 0)
printf("d is less than zero
");
if (d == 0)
printf("d is equal to zero
");
if (d > 0)
printf("d is greater than zero
");
printf("d is: %lf
", d ); |
它输出:
d is equal to zero
d is: -0.000000
因此,要解决此问题,您可以在应用程序中添加一个简单的if-check:
-
或者,如果您具有C99实现(if (signbit(d)) d *= -1;),请使用signbit()。
-
if (d == 0) d = 0; ...并非总是起作用,至少在Visual Studio 2008上不起作用。
-
@ThomasEding当然,非标准编译器会执行非标准操作。看起来它们违反了浮点的IEEE标准。
-
@ThomasEding double x = -0.0; if (x == 0.0) { x = 0.0; } char buf[100]; sprintf(buf,"d is: %lf
", x);和VS 2008正常工作。也许您设置/查看d的方式有误。
-
这个答案是所有特定于实现的;在PC上进行测试并不能保证一般情况
http://en.wikipedia.org/wiki/Signed_zero
The number 0 is usually encoded as +0, but can be represented by either +0 or ?0
它不应影响计算或UI输出。
-
-0.0在某些情况下会影响数值计算:+0.0和-0.0上的哪些运算和功能会给出不同的算术结果?
-
如果将其打印出来,对于人类读者来说,它看起来可能很奇怪且不合适。
-
@Jiminion在某些情况下,-0.0很有用-即使它看起来不合适,例如四舍五入到接近.0的值,但仍想显示0.0的哪一边,例如低于冻结值和财务四舍五入的值,以说仍然我想传达的是它的损失,尽管相对而言很小,如年终利润-0.0百万。
这里对运算符优先级存在误解:
被解析为
与(-2.0) * 0.0基本上相同。
C标准提供信息的附件J列出为非说明者行为,当某些操作符存储在对象中时,是否可以生成负零,以及负零是否会变为正常零(6.2.6.2)。
相反,(double)(-2 * 0)应该在大多数当前平台上生成正零0.0,因为乘法是使用整数算术执行的。 C标准确实支持区分正零和负零整数的体系结构,但是如今这些很少消失了。
如果要强制零为正,则此简单的解决方法应该起作用:
1 2 3
| if (d == 0) {
d = 0;
} |
您可以通过以下方式使意图更清晰:
1 2 3
| if (d == -0.0) {
d = +0.0;
} |
但是,如果d为正零,则测试也将成功。
Chux为符合IEC 60559的环境提供了一个更简单的解决方案:
1
| d = d + 0.0; // turn -0.0 to +0.0 |
-
不建议将==与浮点数或双精度字一起使用。
-
通常,这是正确的,但是在这种特殊情况下,您要检查d是恰好是0.0还是-0.0,而这与==运算符是无法区分的。与-DBL_EPSILON进行比较是不正确的,因为您会将许多小的负非零值转换为0.0。
-
刚意识到这是一个旧帖子!如果未给出删除的答案,可能不会注意到。 (稍后请删除此评论)
-
6.2.6.2仅引用整数负零(不能在2s补码中出现)
How can I fix that in my application?
代码确实没有损坏,因此无需"修复"任何内容。 @肯尼
How can I fix the result so I get a zero when the result should be zero?
要在结果为-0.0时轻松摆脱-,请添加0.0。遵循标准(IEC 60559浮点)规则的代码将产生-符号的掉落。
1 2 3 4 5 6 7 8 9 10 11 12 13
| double nzero = -0.0;
printf("%f
", nzero );
printf("%f
", nzero + 0.0);
printf("%f
", fabs(nzero )); // This has a side effect of changing all negative values
// pedantic code using <math.h>
if (signbit (nzero )) nzero = 0.0; // This has a side effect of changing all negative values
printf("%f
", nzero ); |
通常的输出。
1 2 3 4
| -0.000000
0.000000
0.000000
0.000000 |
但是对于可能具有任何价值的普通double x,很难超越以下条件。 @Richard J. Ross III @chqrlie x + 0.0方法的优点在于可能不会引入分支,但以下内容很清楚。
注意:fmax(-0.0, 0.0)可能产生-0.0。
-
如果nzero等于-2.0怎么办?
-
@Jiminion:nzero被初始化为-0.0。它可以是正零,也可以是负零,您想如何使nzero变为-2.0?
-
@chux:可以提供C标准的引用来支持您的主张吗?如果结果为-0.0时轻松摆脱-,请添加0.0?
-
@chqrlie,因为在实际的实现中,您可能不知道该值是0.0还是-0.0。只是它可能是-0.0;
-
@chqrlie不需要实现" ...-消除-当结果为-0.0时加0.0?",但是如果"定义__STDC_IEC_559__的实现应符合本附件中的规范" C11F。 1和" +,?,*和/运算符提供IEC 60559的加,减,乘和除运算。" F.3 1然后根据该标准进行。
-
@chqrlie如果nzero不是NaN,则nzero = nzero + 0.0不会更改nzero的值,但会导致-0.0变为+0.0-如果实现遵循STDC_IEC_559。实现通常遵循大多数STDC_IEC_559,即使没有__STDC_IEC_559__也是如此。当然,这可能不是一个极端情况。
-
@chux:很高兴知道。谢谢。每天学些新东西!
-
@Jiminion:如果nzero不为零,则nzero == 0将为false。
-
@chqrlie我知道它将是错误的,但是您的代码未显示该错误。
-
@Jiminion:你什么意思? if (d == 0) { d = 0; }很清楚。 Chux提出了一种无需任何测试的更好解决方案:d = d + 0.0;。如果编译器符合IEC 60559规范,则会将负零转换为正1,并使所有其他非Nan值保持不变。
-
@Jiminion关于您的代码并没有表明:您是在指这个答案吗?如果您引用其他答案,则指向该答案的链接或在该答案下发表评论会更有意义。
-
fabs显然是要走的路,它让我感到困惑,五年来没有人提到它:-)
-
@CiroSantilli新疆改造中心六四事件法轮功隐含的功能是如何将-0.0更改为0.0,而所有其他double保持与y = x+0.0相同的方式。 fabs()不提供此功能。 如果域x仅为0.0和-0.0,则y = 0.0甚至比y = fabs(x)更简单。
在我的代码中(在C MPI intel编译器上)-0.0和+0.0不相同。
举个例子:
1 2 3
| d = -0.0
if (d < 0.0)
do something... |
它正在做这个"事情"。
还添加了-0.0 + 0.0 = -0.0...