简体   繁体   English

浮点数的三向比较

[英]3-way comparison of floating-point numbers

Given a pair of floating-point numbers, what's the best way to perform a three-way comparison, that is, return negative, zero or positive, depending on whether the first number is less than, equal to or greater than the second number?给定一对浮点数,执行三路比较的最佳方法是什么,即返回负数、零或正数,具体取决于第一个数是小于、等于还是大于第二个数?

Some languages like Perl, Java and C++20, have this operator built-in, or in the standard library.一些语言,如 Perl、Java 和 C++20,内置了这个运算符,或者在标准库中。 However, I'm asking how to do this in plain C.但是,我问的是如何在普通的 C 中做到这一点。

If the inputs were integers, it would be a simple matter of writing a pair of two-way comparisons.如果输入是整数,那么编写一对双向比较将是一件简单的事情。 But it's more complicated with floating-point inputs because of the special behavior of NaNs in comparison.但是由于 NaN 的特殊行为,浮点输入更复杂。 What's the appropriate way to do it, taking that into account?考虑到这一点,这样做的适当方法是什么?

Returns -1, 0, 1 for less, equal and greater, plus some other value for not comparable:返回 -1, 0, 1 表示小于、等于和大于,加上一些其他值表示不可比较:

#include <math.h>

int cmp(double a, double b) {
    if (isunordered(a, b)) {
        /* at least one NaN, return whatever you feel is appropriate */
        return 42;
    }
    return (a>b) - (a<b);
}

If you want fuzzy comparisons with epsilon, feel free to make the < and > bit more complicated...如果您想与 epsilon 进行模糊比较,请随意使<>更复杂...

What's the appropriate way to do it, taking that (NAN) into account?考虑到(NAN),这样做的适当方法是什么?

Return a FP type to allow 4 different returns values: -1.0, 0.0, 1.0, NAN.返回一个 FP 类型以允许 4 个不同的返回值:-1.0、0.0、1.0、NAN。

Below also returns -0.0 in select cases involving -0.0.下面还在涉及 -0.0 的 select 案例中返回 -0.0。

#include <math.h>

double fcmp(double a, double b) {
  if (isunordered(a, b)) return NAN;
  if (a > b) return 1.0; 
  if (a < b) return -1.0; 
  return a - b;
} 

I'd even consider propagating the a or b when one is NAN to maintain the NAN payload.当一个是NAN时,我什至会考虑传播ab以维护 NAN 有效负载。 There may exist many different non-a-numbers.可能存在许多不同的非数字。

double fcmp(double a, double b) {
  if (isnan(a)) return a;
  if (isnan(b)) return b;
  ...
} 

But let us look at a 3-way used for sorting as with qsort() .但是让我们看一下用于排序的 3-way 与qsort()一样。 A question is where to put NANs?一个问题是在哪里放置 NAN? A common goal is to put them at the end is the list - that is all NAN are greater than others.一个共同的目标是将它们放在列表的最后——即所有的 NAN 都比其他的都大。 To do so, we need to consistently compare, even if both operands are NANs with different payloads.为此,我们需要持续进行比较,即使两个操作数都是具有不同有效负载的 NAN。

// All NAN considered greater than others
// return 0, a positive or negative int.
int fcmp_for_qsort(const void *ap, const void *bp) {
  double a = *(const double *) ap;
  double b = *(const double *) bp;
  if (isnan(a)) {
    if (isnan(b)) {
      return 0;
    }
    return 1;
  }
  if (isnan(b)) -1;
  return (a > b) - (a < b);
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM