Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 双精度浮点比较_C++_Comparison_Floating Point_Double_Leveldb - Fatal编程技术网

C++ 双精度浮点比较

C++ 双精度浮点比较,c++,comparison,floating-point,double,leveldb,C++,Comparison,Floating Point,Double,Leveldb,我在这里有点困惑-当双精度存储为不透明(二进制)字段时,双精度的比较仍然正确吗?我面临的问题是,double包含符号的前导位(即正或负),当它们存储为二进制数据时,我不确定是否会正确比较: 我希望确保比较能够正确进行,因为我使用double作为a的一部分,并且我希望保留正数和负数的数据局部性。LevelDB只使用不透明字段作为键,但它允许用户指定自己的比较器。但是,我只想确保不指定比较器,除非我绝对需要: // Three-way comparison function: // if a

我在这里有点困惑-当双精度存储为不透明(二进制)字段时,双精度的比较仍然正确吗?我面临的问题是,double包含符号的前导位(即正或负),当它们存储为二进制数据时,我不确定是否会正确比较:

我希望确保比较能够正确进行,因为我使用double作为a的一部分,并且我希望保留正数和负数的数据局部性。LevelDB只使用不透明字段作为键,但它允许用户指定自己的比较器。但是,我只想确保不指定比较器,除非我绝对需要:

// Three-way comparison function:
//   if a < b: negative result
//   if a > b: positive result
//   else: zero result
inline int Compare(const unsigned char* a, const unsigned char* b) const 
{
    if (*(double*)a < *(double*)b) return -1;
    if (*(double*)a > *(double*)b) return +1;
    return 0;
}
//三向比较函数:
//如果ab:阳性结果
//否则:结果为零
内联整数比较(常量无符号字符*a,常量无符号字符*b)常量
{
如果(*(双*)a<*(双*)b)返回-1;
如果(*(双*)a>*(双*)b)返回+1;
返回0;
}

回答我的评论

有两件事可能会出错:

  • 如果其中一个(或两个)参数为
    NAN
    ,则比较将始终返回false。因此,即使二进制表示形式相同,
    NAN==NAN
    也将始终为false。此外,它违反了比较传递性

  • 如果任一参数没有正确对齐(因为它们是字符指针),则在不支持未对齐内存访问的计算机上可能会遇到问题。而对于那些这样做的人,你可能会遇到性能上的打击

  • 因此,为了解决这个问题,您需要添加一个陷阱案例,如果其中一个参数被证明是
    NAN
    ,那么将调用它。(我不确定
    INF
    的状态)


    由于需要此陷阱,您需要定义自己的比较运算符。

    是的,您必须指定自己的比较函数。这是因为double不一定存储为“big-endian”值。指数将不会驻留在尾数之前的内存中,即使在逻辑上,当值以big-endian格式写出时,它出现在尾数之前

    当然,如果您在同一数据库中的不同CPU架构之间共享数据,那么最终可能会出现奇怪的endian问题,因为您将数据存储为二进制blob

    最后,即使你能控制endianness,我仍然不相信它。例如,如果一个double未规范化,则当作为二进制数据进行比较时,它可能无法正确地与另一个double进行比较


    当然,在编写比较函数时,其他人所说的关于对齐和诸如NAN和INF之类的奇数值的所有内容都很重要。但是,至于你是否应该写一个,我不得不说这将是一个非常好的主意。

    我假设你的数字格式符合IEEE 754标准。如果是这种情况,那么简单的有符号整数比较将不起作用——如果两个数字都是负数,则比较的结果是相反的。因此,您必须提供自己的比较器。

    有两件事:如果两个参数都是
    NAN
    ,这将失败,因为
    NAN!=NAN
    。另一件事是要注意对齐。并非所有系统都支持错位访问。@神秘,感谢您的反馈。。。我将尝试找出如何处理
    NAN
    。那么我的假设是正确的?我必须为包含双精度的键指定一个比较运算符?嗯,我对leveldb一点也不熟悉。所以我不理解一半的问题,所以我没有把它作为一个答案。但是是的,如果你需要它返回true,如果它们在二进制中是相同的,那么你必须为NAN添加陷阱案例。此外,比较
    NAN
    s是不可传递的,因此您也必须处理它。为什么要使用
    const unsigned char*
    而不是
    const void*
    ?只要将双精度值作为双精度进行比较,表示(符号位等)就不相关。南是一个问题。对齐也可以,但如果
    a
    b
    被初始化为转换的指针,指向正确对齐的
    double
    对象。@Mystical:请详细说明第2点。具体是哪台机器,以及预期的性能影响有多大?当从内存访问多字节字(如8字节双精度)时,地址应该可以被字的大小整除。当您正常使用指针时,编译器会确保这一点。但是,当您开始执行指针强制转换时,一种类型(
    char
    )的对齐方式可能不适合另一种类型(
    double
    )。在不支持未对齐访问的计算机上,硬件将引发异常。(崩溃)在支持它的机器上,通常会有一个惩罚,因为硬件需要进行两次单独的访问,然后将它们合并并提取相关部分。由于我超过500个字符,因此继续:x86/x64将允许对除SIMD向量加载/存储外的所有内容进行未对齐的内存访问。对于这些,有一个单独的未对齐加载/存储指令。在许多RISC架构(如ARM、安腾等)上,需要对齐。在x86/x64的情况下,未对齐访问的性能影响很大程度上取决于体系结构,可以是缓存线拆分的50个周期(在Core 2上)到几乎空闲的(在Sandy Bridge上)。@mystical我无法控制键/值的转换方式。Google的LevelDB只接受指向类型
    char
    的指针的键/值,如果我的键最初是类型
    double
    或64位
    无符号
    整数,那么我必须将它们转换为
    char*
    (这是我主要使用的两种键)。LevelDB只是一个键/值嵌入式数据库,所以我不确定对齐会产生什么影响,我也不确定