Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does std::totally_ordered<float> return true?

The cpp reference (https://en.cppreference.com/w/cpp/concepts/totally_ordered) says std::totally_ordered<T> is modeled only if, given lvalues a, b and c of type const std::remove_reference_t<T>:

  • Exactly one of bool(a < b), bool(a > b) and bool(a == b) is true;
  • If bool(a < b) and bool(b < c) are both true, then bool(a < c) is true;
  • bool(a > b) == bool(b < a)
  • bool(a >= b) == !bool(a < b)
  • bool(a <= b) == !bool(b < a)

So I considered about NaN, and found that float does not fit with the sentence bool(a > b) == bool(b < a). But std::totally_ordered<float> is true. Did I make anything wrong?

=======

I use this macro to create NaN,

#define NAN        ((float)(INFINITY * 0.0F))

and this is my code:

#include <iostream>
#include <concepts>

using namespace std;

int main(int argc, char* argv[])
{
    /*
    1) std::totally_ordered<T> is modeled only if, given lvalues a, b and c of type const std::remove_reference_t<T>:
    Exactly one of bool(a < b), bool(a > b) and bool(a == b) is true;
    If bool(a < b) and bool(b < c) are both true, then bool(a < c) is true;
    bool(a > b) == bool(b < a)
    bool(a >= b) == !bool(a < b)
    bool(a <= b) == !bool(b < a)
    */
    constexpr bool b = totally_ordered<float>; // true
    cout << typeid(NAN).name() << endl;        // float
    cout << NAN << endl;
    cout << b << endl;

    cout << "Exactly one of bool(a < b), bool(a > b) and bool(a == b) is true;" << endl;
    cout << (NAN < NAN) << endl;
    cout << (NAN > NAN) << endl;
    cout << (NAN == NAN) << endl;

    cout << " If bool(a < b) and bool(b < c) are both true, then bool(a < c) is true;" << endl;
    cout << (1.f < 2.f) << endl;
    cout << (2.f < NAN) << endl;
    cout << (1.f < NAN) << endl;

    cout << "bool(a > b) == bool(b < a)" << endl; ////// IT IS FALSE //////
    cout << (NAN > 1.f) << endl;
    cout << (1.f < NAN) << endl;

    cout << "bool(a >= b) == !bool(a < b)" << endl;
    cout << (NAN >= 1.f) << endl;
    cout << (NAN < 1.f) << endl;

    cout << "bool(a <= b) == !bool(b < a)" << endl;
    cout << (NAN <= 1.f) << endl;
    cout << (NAN > 1.f) << endl;
    cout << endl;
}
like image 694
yqZhang4480 Avatar asked Dec 25 '21 09:12

yqZhang4480


1 Answers

Concepts have syntactic requirements, that some set of expressions exist and are of a type that provides certain behavior. The concept feature of C++20 can detect these.

Concepts also have semantic requirements, requirements about the meaning of expressions, possibly relative to one another. The concept feature cannot (usually) detect these. A type is said to "model" a concept if it fulfills both the syntactic and semantic requirements.

For totally_ordered, float fulfills the syntactic requirements of the concept, but an IEEE754 float it does not fulfill the semantic requirements. Indeed, C++20 uses totally_ordered<float> as an example of this syntactic vs. semantic divide in a notation.

Some concepts try to work around this by requiring the user to explicitly opt-into a semantic requirement. But totally_ordered is not one of them.

like image 128
Nicol Bolas Avatar answered Oct 24 '22 04:10

Nicol Bolas