我有一些从Java到C ++的端口代码
// since this point is a vector from (0,0,0), we can just take the
// dot product and compare
double r = point.dot(normal);
return (r>=0.0);
但是在C ++中,r
可以是+0.0
或-0.0
,当r
等于-0.0
时,检查失败。
我已尝试在下面的代码中调整负零,但它从未达到DEBUG("负零")行。但是r2
的打印输出等于+0.0
。
// since this point is a vector from (0,0,0), we can just take the
// dot product and compare
double r = point.dot(normal);
if (std::signbit(r)){
double r2 = r*-1;
DEBUG("r=%f r=%f", r,r2);
if (r2==0.0) {
DEBUG("Negative zero");
r = 0.0; //Handle negative zero
}
}
return (r>=0.0);
有什么建议吗?
测试代码:
DEBUG("point=%s", point.toString().c_str());
DEBUG("normal=%s", normal->toString().c_str());
double r = point.dot(normal);
DEBUG("r=%f", r);
bool b = (r>=0.0);
DEBUG("b=%u", b);
测试结果:
DEBUG - point=Vector3D[ x=1,y=0,z=0 ]
DEBUG - normal=Vector3D[ x=0,y=-0.0348995,z=0.0348782 ]
DEBUG - r=0.000000
DEBUG - b=1
DEBUG - point=Vector3D[ x=1,y=0,z=0 ]
DEBUG - normal=Vector3D[ x=-2.78269e-07,y=0.0174577,z=-0.0174391 ]
DEBUG - r=-0.000000
DEBUG - b=0
GCC
Target: x86_64-linux-gnu
--enable-languages=c,c++,fortran,objc,obj-c++
--prefix=/usr
--program-suffix=-4.6
--enable-shared
--enable-linker-build-id
--with-system-zlib
--libexecdir=/usr/lib
--without-included-gettext
--enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.6
--libdir=/usr/lib
--enable-nls
--with-sysroot=/
--enable-clocale=gnu
--enable-libstdcxx-debug
--enable-libstdcxx-time=yes
--enable-gnu-unique-object
--enable-plugin
--enable-objc-gc
--disable-werror
--with-arch-32=i686
--with-tune=generic
--enable-checking=release
--build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
FLAGS:
CXXFLAGS += -g -Wall -fPIC
解答:
我已经使用@ amit的答案来执行以下操作。
return (r>=(0.0-std::numeric_limits<double>::epsilon()));
这似乎有用。
答案 0 :(得分:10)
嗯,使用double
时的一般建议是记住它们并不准确。因此,如果平等很重要 - 通常建议使用一些容差因子。
在你的情况下:
if (|r - 0.0| >= EPSILON)
其中EPSILON
是您的容差因子,如果r
不是0.0,且至少EPSILON
间隔,则会生成true。
答案 1 :(得分:7)
在某些较旧的系统(即IEE754之前版本)上,您可能会发现针对0的等式检查失败为负0:
if (a == 0.0) // when a==-0.0, fails
你可以通过在比较前将值加0.0来解决这个问题:
if ((a+0.0) == 0.0) // when a == -0.0, succeeds
因此,如果您在Fortran中编写了一个例程并从Pascal调用它,则可能会遇到此问题,并在进行比较之前通过添加0.0来阻止它。
我会很好地承认你的问题并非真正源于与负零的比较。我所知道的所有合理的现代硬件都是完全自动处理的,因此软件根本不需要考虑它。
答案 2 :(得分:3)
据推测,你的意思是if (r2==-0.0)
。尽管如此,负0和正0都将相等。出于所有意图和目的,两者之间没有区别。您可能不需要为负0设置特殊情况。您的比较r >= 0
should be true表示否定或正数为0.
答案 3 :(得分:1)
考虑:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
double const x = -2.78269e-07;
printf( "printf: x=%f\n", x );
cout << "cout: x=" << x << endl;
}
使用结果(使用Visual C ++ 11.0):
[D:\dev\test] > cl foo.cpp foo.cpp [D:\dev\test] > foo printf: x=-0.000000 cout: x=-2.78269e-007 [D:\dev\test] > _
这似乎与问题中的神秘结果非常相似。
我的考虑是,它像问题的结果一样嘎嘎作响,看起来问题的结果和像问题的结果一样摇摇欲坠。
所以,我相信未显示的计算代码产生了值2.78269e-007
。
因此,总的来说,显然只是描述的行为,关于“负零”比较不等于零,这是非标准的。实际上,显然没有负零,只是一个非常小的负值。对于给定的输出格式,将其显示为前面带有减号的所有零数字。
答案 4 :(得分:0)
这是一个很小的负数,控制台无法为您打印它
您可以尝试根据自己的精度进行检查,以便将其替换为纯零。
std::cout << std::setprecision(7) << (abs(value) < 0.0000005f ? 0 : value);
注意,我如何按照std::setprecision()
指定的浮动精度添加7个位置。
这取决于您要多精确地打印浮点数/双精度点。
答案 5 :(得分:0)
OP在他的问题中提到了std::signbit
,但是应该很快就能找到答案,所以这里是:
从C ++ 11开始,这可以区分-0.0
和+0.0
:
#include <cmath>
std::signbit(x) // true iif sign bit of x is set i.e. x is negative