What does "compares less than 0" mean? - c++

Context
While I was reading Consistent comparison, I have noticed a peculiar usage of the verb to compare:
There’s a new three-way comparison operator, <=>. The expression a <=> b
returns an object that compares <0 if a < b, compares >0 if a > b, and
compares ==0 if a and b are equal/equivalent.
Another example found on the internet (emphasis mine):
It returns a value that compares less than zero on failure. Otherwise,
the returned value can be used as the first argument on a later call
to get.
One last example, found in a on GitHub (emphasis mine):
// Perform a circular 16 bit compare.
// If the distance between the two numbers is larger than 32767,
// and the numbers are larger than 32768, subtract 65536
// Thus, 65535 compares less than 0, but greater than 65534
// This handles the 65535->0 wrap around case correctly
Of course, for experienced programmers the meaning is clear. But the way the verb to compare is used in these examples is not standard in any standardized forms of English.
Questions*
How does the programming jargon sentence "The object compares less than zero" translate into plain English?
Does it mean that if the object is compared with0 the result will be "less than zero"?
Why would be wrong to say "object is less than zero" instead of "object compares less than zero"?
* I asked for help on English Language Learners and English Language & Usage.

"compares <0" in plain English is "compares less than zero".
This is a common shorthand, I believe.
So to apply this onto the entire sentence gives:
The expression a <=> b returns an object that compares less than zero
if a is less than b, compares greater than zero if a is greater than
b, and compares equal to zero if a and b are equal/equivalent.
Which is quite a mouthful. I can see why the authors would choose to use symbols.

What I am interested in, more exactly, is an equivalent expression of "compares <0". Does "compares <0" mean "evaluates to a negative number"?
First, we need to understand the difference between what you quoted and actual wording for the standard. What you quoted was just an explanation for what would actually get put into the standard.
The standard wording in P0515 for the language feature operator<=> is that it returns one of 5 possible types. Those types are defined by the library wording in P0768.
Those types are not integers. Or even enumerations. They are class types. Which means they have exactly and only the operations that the library defines for them. And the library wording is very specific about them:
The comparison category types’ relational and equality friend functions are specified with an anonymous parameter of unspecified type. This type shall be selected by the implementation such that these parameters can accept literal 0
as a corresponding argument. [Example: nullptr_t satisfies this requirement. —
end example] In this context, the behaviour of a program that supplies an argument other than a literal 0 is undefined.
Therefore, Herb's text is translated directly into standard wording: it compares less than 0. No more, no less. Not "is a negative number"; it's a value type where the only thing you can do with it is comparing it to zero.
It's important to note how Herb's descriptive text "compares less than 0" translates to the actual standard text. The standard text in P0515 makes it clear that the result of 1 <=> 2 is strong_order::less. And the standard text in P0768 tells us that strong_order::less < 0 is true.
But it also tells us that all other comparisons are the functional equivalent of the descriptive phrase "compares less than 0".
For example, if -1 "compares less than 0", then that would also imply that it does not compare equal to zero. And that it does not compare greater than 0. It also implies that 0 does not compare less than -1. And so on.
P0768 tells us that the relationship between strong_order::less and the literal 0 fits all of the implications of the words "compares less than 0".

"acompares less than zero" means that a < 0 is true.
"a compares == 0 means that a == 0 is true.
The other expressions I'm sure make sense now right?

Yes, an "object compares less than 0" means that object < 0 will yield true. Likewise, compares equal to 0 means object == 0 will yield true, and compares greater than 0 means object > 0 will yield true.
As to why he doesn't use the phrase "is less than 0", I'd guess it's to emphasize that this is all that's guaranteed. For example, this could be essentially any arbitrary type, including one that doesn't really represent an actual value, but instead only supports comparison with 0.
Just, for example, let's consider a type something like this:
class comparison_result {
enum { LT, GT, EQ } res;
friend template <class Integer>
bool operator<(comparison_result c, Integer) { return c.res == LT; }
friend template <class Integer>
bool operator<(Integer, comparison_result c) { return c.res == GT; }
// and similarly for `>` and `==`
};
[For the moment, let's assume the friend template<...> stuff is all legit--I think you get the basic idea, anyway).
This doesn't really represent a value at all. It just represents the result of "if compared to 0, should the result be less than, equal to, or greater than". As such, it's not that it is less than 0, only that it produces true or false when compared to 0 (but produces the same results when compared to another value).
As to whether <0 being true means that >0 and ==0 must be false (and vice versa): there is no such restriction on the return type for the operator itself. The language doesn't even include a way to specify or enforce such a requirement. There's nothing in the spec to prevent them from all returning true. Returning true for all the comparisons is possible and seems to be allowed, but it's probably pretty far-fetched.
Returning false for all of them is entirely reasonable though--just, for example, any and all comparisons with floating point NaNs should normally return false. NaN means "Not a Number", and something that's not a number isn't less than, equal to or greater than a number. The two are incomparable, so in every case, the answer is (quite rightly) false.

I think the other answers so far have answered mostly what the result of the operation is, and that should be clear by now. #VTT's answer explains it best, IMO.
However, so far none have answered the English language behind it.
"The object compares less than zero." is simply not standard English, at best it is jargon or slang. Which makes it all the more confusing for non-native speakers.
An equivalent would be:
A comparison of the object using <0 (less than zero) always returns true.
That's quite lengthy, so I can understand why a "shortcut" was created:
The object compares less than zero.

It means that the expression will return an object that can be compared to <0 or >0 or ==0.
If a and b are integers, then the expression evaluates to a negative value (probably -1) if a is less than b.
The expression evaluates to 0 if a==b
And the expression will evaluates to a positive value (probably 1) if a is greater than b.

Related

Why is numeric_limits::infinity() misbehaving logically for integral types [duplicate]

I was reading Setting an int to Infinity in C++. I understand that when one needs true infinity, one is supposed to use numeric_limits<float>::infinity(); I guess the rationale behind it is that usually integral types have no values designated for representing special states like NaN, Inf, etc. like IEEE 754 floats do (again C++ doesn't mandate neither - int & float used are left to the implementation); but still it's misleading that max > infinity for a given type. I'm trying to understand the rationale behind this call in the standard. If having infinity doesn't make sense for a type, then shouldn't it be disallowed instead of having a flag to be checked for its validity?
The function numeric_limits<T>::infinity() makes sense for those T for which numeric_limits<T>::has_infinity returns true.
In case of T=int, it returns false. So that comparison doesn't make sense, because numeric_limits<int>::infinity() does not return any meaningful value to compare with.
If you read e.g. this reference you will see a table showing infinity to be zero for integer types. That's because integer types in C++ can't, by definition, be infinite.
Suppose, conversely, the standard did reserve some value to represent inifity, and that numeric_limits<int>::infinity() > numeric_limits<int>::max(). That means that there would be some value of int which is greater than max(), that is, some representable value of int is greater than the greatest representable value of int.
Clearly, whichever way the Standard specifies, some natural understanding is violated. Either inifinity() <= max(), or there exists x such that int(x) > max(). The Standard must choose which rule of nature to violate.
I believe they chose wisely.
numeric_limits<int>::infinity() returns the representation of positive infinity, if available.
In case of integers, positive infinity does not exists:
cout << "int has infinity: " << numeric_limits<int>::has_infinity << endl;
prints
int has infinity: false

Rigorous proof of the following C++ code's property?

Take the following C++14 code snippet:
unsigned int f(unsigned int a, unsigned int b){
if(a>b)return a;
return b;
}
Statement: the function f returns the maximum of its arguments.
Now, the statement is "obviously" true, yet I failed to prove it rigorously with respect to the ISO/IEC 14882:2014(E) specification.
First: I cannot state the property in a formal way.
A formalized version could be:
For every statement s, when the abstract machine (which is defined in the spec.) is in state P and s looks like "f(expr_a,expr_b)" and 'f' in s is resolved to the function in question, s(P).return=max(expr_a(P).return, expr_b(P).return).
Here for a state P and expression s, s(P) is the state of the machine after evaluation of s.
Question: What would be a correctly formalized version of the statement? How to prove the statement using the properties imposed by the above mentioned specification? For each deductive step please reference the applicable snippet from the standard allowing said step (the number of the segment is enough).
Edit: Maybe formalized in Coq
Please appologize for my approximate ageing mathematic knowledge.
Maximum for a closed subset of natural number (BN) can be defined as follow:
Max:(BN,BN) -> BN
(x ∊ BN)(a ∊ BN)(b ∊ BN)(x = Max(a,b)) => ( x=a & a>b | x=b )
where the symbol have the common mathemical signification.
While your function could be rewritten as follow, where UN is the ensemble of unsigned int:
f:(UN,UN) -> UN
(x ∊ UN)(a ∊ UN)(b ∊ UN)(x = f(a,b)) => ( x=a && a>b || x=b )
Where symbol = is operator==(unsigned int,unsigned int), etc...
So the question reduces to know if the standard specifies that the mathematical structure(s) formed by the unsigned integer with C++ arithmetic operators and comparison operator is isomorphic to the matematical structures (classes,categories) formed by a closed subset of N with the common arithemtic operation and relations. I think the answer is yes, this is expressed in plain english:
C++14 standard,[expr.rel]/5 (Relational Operators)
If both operands (after conversions) are of arithmetic or enumeration type, each of the operators shall yield true if the specified relationship is true and false if it is false.
C++14 standard, [basic.fundamental]/4 (Fundamental Types)
Unsigned integers shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.
Then you could also proove that ({true,false},&&,||) is also isomorphic to boolean arithmetic by analysing the text in [expr.log.and]
and [expr.log.or]
I do not think that you should go further than showing that there is this isomorphism because further would mean demonstrating axioms.
It appears to me that the easiest solution is to prove this backwards. If the first argument to f is the maximum argument, prove that the first argument is returned (fairly easy - the maximum argument a is by definition bigger than b). If the second argument is the maximum argument, prove that the second argument is returned. If the two are equal, show that there is no unique maximum element, so the second argument is still a maximum argument.
Finally, prove that these three options are exhaustive. If a unique maximum argument is passed, it must be passed either as the first or the second argument, since f is binary.
I am unsure about what you want. Looking at a previous version, N3337, we can easily see that almost everything is specified:
a and b starts with the calling values (Function 5.2.2 - 4)
Calling a function executes the compound statement of the function body (Obvious, but where?)
The statements are normally executed in order (Statements 6)
If-statements execute the first sub-statement if condition is true (The If Statement 6.4.1)
Relations actually work as expected (Relation operators 5.9 - 5)
The return-statement returns the value to the caller of the function (The return statement 6.6.3)
However, you attempt to start with f(expr_a, expr_b); and evaluating the arguments to f potentially requires a lot more; especially since they are not sequenced - and could be any function-call.

What does an exclamation mark in array index do?

While perusing through my organization's source repository I came across this little gem:
RawParameterStorage[!ParameterWorkingIdx][ParameterDataOffset] = ...
Is this valid code? (It compiles) What does the exclamation mark here do?
An invert ~ operator might make sense, since it's commonly confused with the not ! operator in boolean expressions. However, it doesn't seem to make logical sense to impose the not ! operator on an array index. Any Thoughts?
!ParameterWorkingIdx Means ParameterWorkingIdx is 0, If it is, !ParameterWorkingIdx evaluates as true which might be implicitly converted to the indexer type (For example, 1 for integer indexer as in an array), otherwise, it evaluates as false.
If ParameterWorkingIdx == 0 then [!ParameterWorkingIdx] == [1].
If ParameterWorkingIdx != 0 then [!ParameterWorkingIdx] == [0].
It also depends on other stuff like:
The type of ParameterWorkingIdx.
overloading of ! operator by the type of ParameterWorkingIdx.
indexer overloading by the type of RawParameterStorage.
etc...
Taking a bit of a guess here, but that looks like a double-buffer pattern. ParameterWorkingIdx would flip-flop between 0 and 1 (probably with ParameterWorkingIdx = !ParameterWorkingIdx;).
Then, at any time, RawParameterStorage[ParameterWorkingIdx] would be the current buffer, and RawParameterStorage[!ParameterWorkingIdx] would be the previous buffer.
it doesn't seem to make logical sense to impose the not ! operator on an array index
It might: all it does here is convert zero to one, and any other number to zero.
We can infer from this code that RawParameterStorage probably has two elements at the top level.
P. S. Here, I assume that RawParameterStorage is an array (as you say it is). Furthermore, I assume that ParameterWorkingIdx is an integer (as its name implies). If, for example, either is a class with overloaded operators than the semantics could be completely different.
Is this valid code?
Yes it is. Suppose ParameterWorkingIdx to be an int, for !ParameterWorkingIdx, when used with operators !, it'll be contextually convertible to bool,
The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.
Then integral promoted to be used as the array index.
the type bool can be converted to int with the value false becoming ​0​ and true becoming 1.
So !ParameterWorkingIdx is equivalent with ParameterWorkingIdx == 0 ? 1 : 0, which is much more clear IMO.

What datatype does the result of a binary comparison reduce to?

Relizing there's no such thing as a BOOL datatype, take the following:
std::cout << (1>2); //<<-- prints 0
Assuming this false comparison is a 0, what datatype deos the result of a comparison reduce to? Doing a quick google search doesn't yield any results. My best guess it that it's an unsigned char because it's the smallest most basic datatype where 0 truly represented as 0x00. I don't want to assume anything because I'm not sure what voodoo std::cout does to the value to make it a printable character.
The type of the result of all relational operators (<, >, <=, >=) is bool:
The operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) all yield false or true. The type of the result is bool.
An object of type bool has the values true or false.Under integral promotion, a bool can be converted to an int where false becomes 0 and true becomes 1:
A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.
bool is an integral type, which the standard says are represented by use of a "pure binary numeration system". The footnote that describes this representation is fairly unclear as to how it maps to the values true and false, but you could assume that they are implying that the value representation for 0 would be all 0 bits:
A positional representation for integers that uses the binary digits 0 and 1, in which the values represented by successive bits are additive, begin with 1, and are multiplied by successive integral power of 2, except perhaps for the bit with the highest position. (Adapted from the American National Dictionary for Information Processing Systems.)
There's no standard BOOL type, but bool is a standard fundamental type:
[C++11: 3.9.1/6]: Values of type bool are either true or false. [..]
As for the result of your relational comparison:
[C++11: 5.9/1]: The relational operators group left-to-right. [..] The operands shall have arithmetic, enumeration, or pointer type, or type std::nullptr_t. The operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) all yield false or true. The type of the result is bool.
Note that this is not the same in C, in which there is no built-in type bool and the result of relational comparisons is of type int:
[C99: 6.5/8]: Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false. The result has type int.
The C++ standard, section 5.9 Relational operators, paragraph 1 says:
The type of the result is bool.
This is not a direct answer to your question:
as said here it is bool in c++ and int in c but you i think the part which you would think of is how much memory it takes to save a comparison result ?
as you know a data type defines how much memory to be allocated.
Note: sometimes it(data type to memory size definition) is different from compiler/processor architecture to another for example in embedded systems environment people used to talk about and define data types in projects using number of bits e.g typedef unsigned char uint8; instead of using standard data types directly so it would be easy to port to another compiler/target processor
you should look at this: Why is a char and a bool the same size in c++?
you should look at this also http://www.cplusplus.com/doc/tutorial/variables under "Fundamental data types" section a table of each data type and its size and range but he noted :
The values of the columns Size and Range depend on the system the program is compiled for. The values shown above are those found on
most 32-bit systems. But for other systems, the general specification
is that int has the natural size suggested by the system architecture
(one "word") and the four integer types char, short, int and long must
each one be at least as large as the one preceding it, with char being
always one byte in size. The same applies to the floating point types
float, double and long double, where each one must provide at least as
much precision as the preceding one.
as noted by sftrabbit about the standard in his answer that the standard is abstract enough and not detailed thus i think that the size of bool in memory is an implementation specific which may be different from c++ compiler to another , check Nawazs' answer here: How a bool type variable is stored in memory? (C++)

Why is numeric_limits<int>::max() > numeric_limits<int>::infinity()?

I was reading Setting an int to Infinity in C++. I understand that when one needs true infinity, one is supposed to use numeric_limits<float>::infinity(); I guess the rationale behind it is that usually integral types have no values designated for representing special states like NaN, Inf, etc. like IEEE 754 floats do (again C++ doesn't mandate neither - int & float used are left to the implementation); but still it's misleading that max > infinity for a given type. I'm trying to understand the rationale behind this call in the standard. If having infinity doesn't make sense for a type, then shouldn't it be disallowed instead of having a flag to be checked for its validity?
The function numeric_limits<T>::infinity() makes sense for those T for which numeric_limits<T>::has_infinity returns true.
In case of T=int, it returns false. So that comparison doesn't make sense, because numeric_limits<int>::infinity() does not return any meaningful value to compare with.
If you read e.g. this reference you will see a table showing infinity to be zero for integer types. That's because integer types in C++ can't, by definition, be infinite.
Suppose, conversely, the standard did reserve some value to represent inifity, and that numeric_limits<int>::infinity() > numeric_limits<int>::max(). That means that there would be some value of int which is greater than max(), that is, some representable value of int is greater than the greatest representable value of int.
Clearly, whichever way the Standard specifies, some natural understanding is violated. Either inifinity() <= max(), or there exists x such that int(x) > max(). The Standard must choose which rule of nature to violate.
I believe they chose wisely.
numeric_limits<int>::infinity() returns the representation of positive infinity, if available.
In case of integers, positive infinity does not exists:
cout << "int has infinity: " << numeric_limits<int>::has_infinity << endl;
prints
int has infinity: false