What is the difference between ! ( x < y ) and x >= y in C++? - c++

Going through EASTL, I stumbled across a peculiar line of code. The following link shows the file with the line number of interest at 1870.
https://github.com/paulhodge/EASTL/blob/master/include/EASTL/algorithm.h
The code at that line is if(!(value < *i)). The comment says that "we always express value comparisons in terms of < or ==" without any explanation as to why this is so. There are also a few other areas where the same comment is placed but without any explanation.
Is there any benefit whatsoever to writing a comparison like that (maybe some context that I am overlooking)? If not, why did the author of EASTL deliberately wrote it in this particular fashion and even took the care to comment about it? Is consistency the only reason here?

It means you only need to provide < and == for container value types. It also means you reduce the amount of variability for those types (as all the algorithms use !(a<b) to mean a>=b and !(a==b) for a!=b); otherwise, you could have >= and != return inconsistent results.

In C++, you can overload the < operator so that it behaves differently than the opposite of >=, so they are not guaranteed to be equivalent.
Additionally, in any IEEE floating-point implementation, NaN < NaN is false, but so is NaN >= NaN, so !(NaN < NaN) is true even though NaN >= NaN is false.

I see at least one difference. If one of the numbers was QNAN (floating-point 0/0) then !(a < b) would've always return TRUE if any of a or b were QNAN, while it would've always returned false for a>=b

Using just the less-than operator, you can simulate all the other comparison operators. This makes it more consistent and allows you to use a single template parameter when you need to parameterize the comparison. The standard sorted containers and algorithms use std::less<T> as the default template comparator for example.
operation equivalent
x < y x < y
x > y y < x
x <= y !(y < x)
x >= y !(x < y)
x == y !(x < y) && !(y < x)
x != y (x < y) || (y < x)
For those operations where ordering is not important it's simpler and more efficient to use operator == instead.

Related

If else condition precedence in Verilog

I have noticed that there is a precedence of assignment while using if-else conditionals in Verilog. For example as in the code below:
if(counter < 6)
z <= 1;
else if(counter < 12)
z <= 2;
else
z <= 3;
I noticed that until the counter is less than 6, the value of z is assigned the value of 1 (z <= 1) and as soon as the value of the counter exceeds 6 and is less than 12, z is assigned the value 2 (z <= 2).
What if there are different variables used inside the conditionals as in the code below?
if(wire1_is_enabled)
z <= 1;
else if(wire2_is_enabled)
z <= 0;
What happens when both conditions are true? What is the behaviour of the assignment operator here?
I believe this is poor programming habit.
Yes, nested if-else branching statements naturally assume a priority in the order of execution. Think about using a case statement instead of deeply nesting if statements which are much more readable.
There is nothing wrong with this coding style unless you have code like:
if(counter < 6)
z <= 1;
else if(counter < 2)
z <= 2; // unreachable
else
z <= 3;
Then the statement z <= 2; becomes unreachable because when the first condition is false, the second condition can never be true. Fortunately there are a number of tools that can flag this problem for you.
Both if and case statements assume priority logic. However, you have an option to explicitly add a priority or unique keyword before the if or case keywords to declare and check your intent. See sections 12.4 and 12.5 in the IEEE 1800-2017 SystemVerilog LRM.
The 2 if/else statements behave the same way; the first condition to be true has the highest priority. Once a condition evaluates to true, all the following else clauses are ignored. Therefore, z <= 1 if both wire1_is_enabled and wire2_is_enabled are true. This is easy to prove to yourself with a simple simulation.
This is not a poor coding habit. This situation is common in Verilog. When you say programming, perhaps you are thinking of software languages. Keep in mind that these are hardware signals instead of software variables.

Sort Lambda Expression C++ by two condition

I am trying to sort data which I have in list.
And I need that kind of sort
if a>b sort by a,b
else if a==b sort by c,d
I done this by it is not working.
l_name->sort([](type*& s1, type*& s2)
{
if (s1->a() > s2->b())
return s1->a() > s2->b()
else if(s1->a() == s2->b())
return s1->c() > s2->d();
});
You cannot sort with a comparison function like that, because the sorting rules it defines are internally inconsistent. In order to sort, X < Y must imply that Y < X is false.
Consider these two objects:
Name a b
---- - -
X 2 1
Y 2 1
No matter how you compare them, X > Y or Y > X, you would get true, because X.a > Y.b and Y.a > X.b.
Even X > X and Y > Y would produce true, which must never happen.
For that reason, you should define your comparison rules in terms of comparing the same attributes. Otherwise, you will break reflexivity and transitivity rules.
What if a < b? You can solve this problem more robustly and concisely:
l_name->sort([](type*& s1, type*& s2)
{
if (s1->a() != s2->b())
return s1->a() < s2->b();
return s1->c() < s2->d();
});

Equalities in C/C++

In C++, the usual way of determining if some value, x, is between two limits is to:
//This is (A)
double x = 0.0d;
double lower = -1.0d;
double upper = +1.0d;
if(x > lower && x < upper){
// Do some stuff
}
But today I discovered by accident that I can do this:
// This is (B)
double x = 0.0d;
double lower = -1.0d;
double upper = +1.0d;
if(lower < x < upper){
// Do some stuff
}
It seems to work fine, but I've never heard of this being done before, with "lower < x < upper". Does this produce executable code as you would expect it to? IE, is (A) equivalent to (B)?
I think a lot of people won't know about this, and I suspect that might be because the compiler interprets (A) differently to (B). It this right?
No, A and B are not equivalent, you cannot do this.
Or, obviously you can (as you discovered) but you're not doing what you think you're doing.
You're evaluating (lower < x) < upper, i.e. the value of lower < x (which is false or true, but which convert to int for the comparison) is compared to upper.
See this table of operator precedence for more information.
They are definitely not equivalent. Your expression lower < x < upper will first evaluate lower < x to either true or false, and then do true < x or false < x respectively.
It doesn't work fine. In fact, it's dead wrong, and only works by accident.
lower < x < upper is parsed as (lower < x) < upper; (lower < x) has type bool, and its value is either true or false, depending on the value of x. To compare that bool value to upper the compiler converts the bool to a float with the value 1.0 for true and 0.0 for false.
Well, yes. In either cases x is between the value range.
For example:
lower = 4;
upper = 9;
x = 7;
If you do: 7 > 4 && 7 < 9 is the same as saying 4 < 7 < 9.
This is basic arithmetics, by the way.

Is it safe to sort a container which may contain infinities using quicksort?

I have realized that in order for quicksort to work, all the infinities need to be equal.
In other words, such a criterium is not enough:
class Entity
{
public:
float value() const;
bool valueIsInfinite() const;
};
class Criterium
{
bool operator()(Entity left, Entity right)const
{
if (left.valueIsInfinite())
return false;
return left.value() < right.value();
}
}
const Criterium criterium;
QVector<Entity> container;
qSort<container.begin(), container .end(), criterium>
This sorting fails, because not all infinities are equal according to the criterium. The unequalness depends on the order in which the entities enter the operator. I found out, that such a ordering fails.
I need something like this:
class Criterium
{
bool operator()(Entity left, Entity right)const
{
if (left.valueIsInfinite() && right.valueIsInfinite())
return false;
if (left.valueIsInfinite() && !right.valueIsInfinite())
return false;
if (!left.valueIsInfinite() && right.valueIsInfinite())
return true;
return left.value() < right.value();
}
}
But suppose that instead of
float Entity::value() const;
bool Entity::valueIsInfinite() const;
methods, I would like to use just
float Entity::value() const;
And have it return
std::numeric_limits<float>::infinity();
in cases where
bool Entity::valueIsInfinite() const;
would return true.
Now I tested this approach and it seems to work. But I am concerned about other ways in which an infinity may arise. For example:
float otherInfinity = exp(std::numeric_limits<float>::infinity());
This infinity seems to be the same. But I want to be sure. I know that C++ standard does not mention details of floating point arithmetic implementation, but if I use gcc, is it safe in all cases? I mean are all infinities created equal in gcc? Is it safe to sort a container of floats, which may contain infinities which have arisen on different occasions?
Without the presence of NaNs, infinities are fine with the regular operator <:
+∞ < +∞ is false: < is irreflexive;
if +∞ < x is true then x < +∞ is false for non-infinity values: < is antisymmetric;
if +∞ < x is true and x < y is true, then +∞ < y is true: < is transitive;
if +∞ is incomparable (not less, not greater) with x, and x is incomparable with y, then +∞ is incomparable with y: < displays transivity of equivalence.
(similar properties are valid for -∞)
Given those properties operator< on floats without NaNs is a strict weak ordering, and thus suitable for standard library style ordering operations.
However, with NaNs, the antisymmetry property is broken: NaN < 1 is false, and 1 < NaN is false too. You can solve this by ordering all NaNs either before or after all non-NaNs, in a manner similar to your proposed strategy:
struct Criterion
{
bool operator()(Entity left, Entity right)const
{
// NaNs come before non-NaNs
if (isnan(left.value()) && isnan(right.value()))
return false;
if (!isnan(left.value()) && isnan(right.value()))
return false;
if (isnan(left.value()) && !isnan(right.value()))
return true;
return left.value() < right.value();
}
}
(isnan can be found on the C++11 standard library, or implemented quite easily as return x != x;)
With this, we get NaN < 1 as true, and 1 < NaN as false, while the other properties still hold.
If you use this:
bool operator()(Entity left, Entity right)const
{
return !(left.valueIsInfinite() && right.valueIsInfinite())
&& left.value() < right.value();
}
Then the infinites are considered of the same order, since none comes before another one...

if(x==y==z) works, if(x!=y!=z) does not

Why is:
if(x!=y!=z)
handled as:
x=1
y=1
z=2
??
I just noticed it today.
x != y and x == y return booleans.
You're comparing z to those booleans.
Neither of them will work they way you want them to.
It probably is parsed as if ((x!=y) !=z) which does not do what you think if (x!=y!=z) should do (but does not).
Likewise if (x==y==z) probably means if ((x==y)==z) to the compiler which is not what you want.
Enable the warnings given by your compiler. With GCC, that means gcc -Wall and it would tell you warning: suggest parentheses around comparison in operand of '=='
Recall that a boolean expression like x==y gives a zero (when false) or non-zero (when true) result. Writing ((x==y) + (z==t)) is very poor taste, but makes sense for the compiler.
x == y == z is equivalent to (x == y) == z. In this case, (1 == 1) == 2, or true == 2, which is false because true == 1, not 2.
x != y != z is equivalent to (x != y) != z. In this case, (1 != 1) != 2, or false != 2, which is true because false == 0, not 2.
C(++) relational operators aren't chained like in Python. If you want to check whether three numbers are all equal to each other, use (x == y) && (y == z).
if(x==y==z)
will not work untill the value u will use for z be 1 or 0 but u can take the value of x and y anything
As when u try with the value 1 or 0 then the if will take its parameters as
if((x==y)==z)
this is happening because it first evaluate whatever the value in x and y and the answer will be in boolean and then it checks with z which it expects to be boolean. so if (x==y) be and z is 1(true) then code will be executed else it wont.Same thing will happen with (x!=y!=z). try with z=1 or 0 and x,y be anything.