Issues with commutative property of && operator - c++

The code below that I have been having strange issues with is meant to trim off the unused portion of an integer array, and then convert it into a string.
Ex:
_ABC__DE______ would become _ABC__DE.
The problems show up when the input is filled with the default character. ("_" in the example).
sLength is the length of the integer array chars
The problematic code:
int inputLength = sLength - 1;
while (chars[inputLength] == defaultChar && inputLength >= 0) {
inputLength--;
}
inputLength++;
Serial.println("input length: " + String(inputLength));
// (in)sanity check
Serial.println(inputLength);
Serial.println(String(inputLength));
Serial.println(inputLength <= 0);
Serial.println(0 <= 0);
Serial.println(inputLength == 0);
Serial.println(0 == 0);
if (inputLength <= 0) {
//reset cursor position
Serial.println("index set to 0");
index = 0;
} else {
output = "";
for (int i = 0; i < inputLength; i++) {
char c = charSet[chars[i]];
if (c == '_') {
c = ' ';
}
output += c;
}
done = true;
}
The output when given an array filled with defaultChar:
input length: 0
0
0
0
1
0
1
If I'm interpreting correctly, the output means that 0 > 0 and 0 =/= 0 on even lines, but 0 <= 0 and 0 = 0 on odd lines.
The workaround I've come up with is replacing
while (chars[inputLength] == defaultChar && inputLength >= 0) {
inputLength--;
}
with one of the following
while (inputLength >= 0 && chars[inputLength] == defaultChar) {
inputLength--;
}
.
while (chars[inputLength] == defaultChar) {
inputLength--;
if (inputLength < 0) {
break;
}
}
which both result in an output of:
input length: 0
0
0
1
1
1
1
index set to 0
Why does this change the result?
As far as I knew until now, the && operator was commutative.
Is there something that I am missing that makes
chars[inputLength] == defaultChar && inputLength >= 0
not equal to
inputLength >= 0 && chars[inputLength] == defaultChar?
If It's relevant, this is being run on an 328P Arduino Nano with the old bootloader using IDE 1.8.8

&& is not commutative. It evaluates the left operand first and then stops if the left operand evaluated to 0.
Your original code fails because at some point it evaluates chars[-1] (which causes undefined behaviour if chars is an array). The alternative version does not have that problem because it performs the >= 0 test before using inputLength as an array index.

&& is commutative in the sense that the result of a && b is same as the result of b && a. But the built-in operator && has a short-circuiting behavior. This means that if the result of a && b can be decided by evaluating the first operand alone, the second one is not evaluated.
So when the first operand is chars[inputLength] == defaultChar and inputLength is -1, you enter the territory of undefined behavior which means the behavior of the program is unpredictable. But with the workarounds, you avoid undefined behavior because of the inputLength >= 0 and inputLength < 0 checks and therefore the code works as intended.
As #PeteBecker notes: a() && b() is not commutative if either a() or b() has side effects.

Related

postfix evaluation using stack(problem with adding zeros for multidigit postfix expression)

the problem is that this code works perfectly except with numbers that inculde number (0) in them
the code was written in a way that it accepts multiple digits and because of this piece of code, 0 is pushed whenever a space is encountered.
else if (expression[i] == ' ') {
push(digit);
digit = 0;
}
so i wrote this:
else if (expression[i] == ' ') {
if (digit == 0) {
continue;
}
push(digit);
digit = 0;
}
and it works perfectly! problem is when an expression has 0 in it such as
12 0 -
result would be = -12
when i check operands operand one is 0 and two is 12
which is supposed to be the opposite.
so what i've tried also to do was to include a counter(which i honestly don't know how it works but it works)
and the code now looks like this
else if (expression[i] == ' ') {
if (digit == 0 && counter <= 1) {
continue;
}
push(digit);
digit = 0;
counter--;
}
counter is incremented when an operand is encountered, and is decremented when digit is pushed. Now the problem with this is that 12 0 - = 12 but 0 12 - = 0 although op1 = 0 and op2 = 12
any idea how i could go around fixing this?
how can i differentiate between zero because of finished multidigit number and actual zeros?

how to fix hamming weight invariants

I am learning Dafny, attempting to write a specification for the hamming weight problem, aka the number of 1 bits in a number. I believe I have gotten the specification correct, but it still doesn't verify. For speed of verification I limited it to 8 bit numbers;
problem definition: https://leetcode.com/problems/number-of-1-bits/
function method twoPow(x: bv16): bv16
requires 0 <= x <= 16
{
1 << x
}
function method oneMask(n: bv16): bv16
requires 0 <= n <= 16
ensures oneMask(n) == twoPow(n)-1
{
twoPow(n)-1
}
function countOneBits(n:bv8): bv8 {
if n == 0 then 0 else (n & 1) + countOneBits(n >> 1)
}
method hammingWeight(n: bv8) returns (count: bv8 )
ensures count == countOneBits(n)
{
count := 0;
var i := 0;
var n' := n;
assert oneMask(8) as bv8 == 255; //passes
while i < 8
invariant 0 <= i <= 8
invariant n' == n >> i
invariant count == countOneBits(n & oneMask(i) as bv8);
{
count := count + n' & 1;
n' := n' >> 1;
i := i + 1;
}
}
I have written the same code in javascript to test the behavior and example the invariant values before and after the loop. I don't seen any problems.
function twoPow(x) {
return 1 << x;
}
function oneMask(n) {
return twoPow(n)-1;
}
function countOneBits(n) {
return n === 0 ? 0 : (n & 1) + countOneBits(n >> 1)
}
function hammingWeight(n) {
if(n < 0 || n > 256) throw new Error("out of range")
console.log(`n: ${n} also ${n.toString(2)}`)
let count = 0;
let i = 0;
let nprime = n;
console.log("beforeloop",`i: ${i}`, `n' = ${nprime}`, `count: ${count}`, `oneMask: ${oneMask(i)}`, `cb: ${countOneBits(n & oneMask(i))}`)
console.log("invariants", i >= 0 && i <= 8, nprime == n >> i, count == countOneBits(n & oneMask(i)));
while (i < 8) {
console.log("");
console.log('before',`i: ${i}`, `n' = ${nprime}`, `count: ${count}`, `oneMask: ${oneMask(i)}`, `cb: ${countOneBits(n & oneMask(i))}`)
console.log("invariants", i >= 0 && i <= 8, nprime == n >> i, count == countOneBits(n & oneMask(i)));
count += nprime & 1;
nprime = nprime >> 1;
i++;
console.log('Afterloop',`i: ${i}`, `n' = ${nprime}`, `count: ${count}`, `oneMask: ${oneMask(i)}`, `cb: ${countOneBits(n & oneMask(i))}`)
console.log("invariants", i >= 0 && i <= 8, nprime == n >> i, count == countOneBits(n & oneMask(i)));
}
return count;
};
hammingWeight(128);
All invariants evaluate as true. I must be missing something. it says invariant count == countOneBits(n & oneMask(i) as bv8); might not be maintained by the loop. Running the javascript shows that they are all true. Is it due to the cast of oneMask to bv8?
edit:
I replaced the mask function with one that didn't require casting and that still not resolve the problem.
function method oneMaskOr(n: bv8): bv8
requires 0 <= n <= 8
ensures oneMaskOr(n) as bv16 == oneMask(n as bv16)
{
if n == 0 then 0 else (1 << (n-1)) | oneMaskOr(n-1)
}
One interesting thing I found is that it shows me a counter example where it has reached the end of the loop and the final bit of the input variable n is set, so values 128 or greater. But when I add an assertion above the loop that value equals the count at the end of the loop it then shows me the another value of n.
assert 1 == countOneBits(128 & OneMaskOr(8)); //counterexample -> 192
assert 2 == countOneBits(192 & OneMaskOr(8)); //counterexample -> 160
So it seems like it isn't evaluating the loop invariant after the end of loop? I thought the whole point of the invariants was to evaluate after the end of loop.
Edit 2:
I figured it out, apparently adding the explicit decreases clause to the while loop fixed it. I don't get it though. I thought Dafny could figure this out.
while i < 8
invariant 0 <= i <= 8
invariant n' == n >> i
invariant count == countOneBits(n & oneMask(i) as bv8);
decreases 8 - i
{
I see one line in the docs for loop termination saying
If the decreases clause of a loop specifies *, then no termination check will be performed. Use of this feature is sound only with respect to partial correctness.
So is if the decreases clause is missing does it default to *?
After playing around, I did find a version which passes though it required reworking countOneBits() so that its recursion followed the order of iteration:
function countOneBits(n:bv8, i: int, j:int): bv8
requires i ≥ 0 ∧ i ≤ j ∧ j ≤ 8
decreases 8-i {
if i == j then 0
else (n&1) + countOneBits(n >> 1, i+1, j)
}
method hammingWeight(n: bv8) returns (count: bv8 )
ensures count == countOneBits(n,0,8)
{
count ≔ 0;
var i ≔ 0;
var n' ≔ n;
//
assert count == countOneBits(n,0,i);
//
while i < 8
invariant 0 ≤ i ≤ 8;
invariant n' == n >> i;
invariant count == countOneBits(n,0,i);
{
count ≔ (n' & 1) + count;
n' ≔ n' >> 1;
i ≔ i + 1;
}
}
The intuition here is that countOneBits(n,i,j) returns the number of 1 bits between i (inclusive) and j (exclusive). This then reflects what the loop is doing as we increase i.

C++ comparison of integers with float [duplicate]

This question already has answers here:
Checking if a value is within a range in if statment [duplicate]
(2 answers)
Closed 6 years ago.
I have the following code.that demonstrates the problem I am having. How come the comparison is not evaluating to true? Is this a limitation of integer and floating point comparisons?
#include <iostream>
int main(){
double m = -0.625;
if((-1)<=m<=0){
std::cout << "Enter here" <<std::endl;
}
return 0;
}
You can't do three way comparison like that in C. Change it to the following and it'll work:
if((-1) <= m && m <= 0){
std::cout << "Enter here" <<std::endl;
}
The condition in this if statement
if( ( -1 ) <= m <= 0 ){
is equivalent to
if( ( -1 <= m ) < = 0 ){
as -1 is less than m then the subexpression ( -1 <= m ) yields 1 in C and true in C++ that then is converted to 1 and the subexpression 1 <= 0 yields 0 in C and false in C++..
To get the expected result you should write instead
if( -1 <= m && m <= 0 ){
In C++ -1 <= m <= 0 is equivalent to (-1 <= m) <= 0.
In this example, -1 is implicitly converted to a float in order to use the <= operator with m. The result of this expression is a bool. This result is then implicitly converted to an int in order to use the <= operator with 0. Since a bool is converted to either 0 or 1 (false or true), this conditional statement will only be true when m is less than -1.
It makes sense from a math standpoint to structure the if statement like that, however you must break it up explicitly so the compiler knows what you want.
Try this
-1 <= m && m <= 0

Check if C-style array equals other (compile-time) array

I've got a double[9] and want to check if it contains the values (1,0,0,0,1,0,0,0,1). Is there a cleaner way than this?
if (ornt1[0] == 1 && ornt1[1] == 0 && ornt1[2] == 0
&& ornt1[3] == 0 && ornt1[4] == 1 && ornt1[5] == 0
&& ornt1[6] == 0 && ornt1[7] == 0 && ornt1[8] == 1 )
I'm using C++.
It is not a good idea to compare double values strictly. I would recommend you create a constant array to compare against and then use a cycle and also use a tolerance(e.g. 1e-9):
bool doublesEqual(double a, double b) {
return fabs(a - b) < 1e-9;
}
const double expected[9] = {1,0,0,0,1, 0, 0, 0, 1};
bool equal = true;
for (int i = 0; i< 9; ++i) {
if (!doublesEqual(expected[i], ornt1[i])) {
equal = false;
break;
}
}
if (equal) { // do smth
EDIT: as suggested by John Zwinck I have edited the code to be able to handle the case when the array we compare contains only NAN. I have edited his suggestion a bit to make the code more readable. Please refer to his comment below for clarification why this is needed.

Matching nulls(0) in int [c++]

I have a problem with checking on 0, i trying to get numbers from file(and i get it) but if is 0 then said me >
0 maybe its not found!(0 | 0)
0 maybe its not found!(1 | 1)
0 maybe its not found!(2 | 2)
0 maybe its not found!(3 | 3)
0 maybe its not found!(4 | 4)
if i want 1 and i gets the correct line from line:
0 maybe its not found!(0 | 0)
[Line0]: 1 1 1 200 150 6 1 10000000 1
[Line1]: 1 1 13 14
0 maybe its not found!(2 | 2)
0 maybe its not found!(3 | 3)
0 maybe its not found!(4 | 4)
Check func is :
int myClass = 0; //'\0'
for(int i=0; i < Show.line0 && Show.line1; i++)
{
if( Show.Get[i].m_Class0 && Show.Get[i].m_Class1 == myClass )
{
........
}
else
{
cout << myClass; cout << " maybe its not found!";
cout << "(";
cout << Show.Get[i].m_Class0;
cout << " | ";
cout << Show.Get[i].m_Class1;
cout << ")";
cout << endl;
}
m_class0/1 are int and the value its getted from the loaded file.
in other value on myClass bigger then 0 i gets the same line lines from file begining with wanted number, but doesnt works with 0.
Your error lies in the following line:
if( Show.Get[i].m_Class0 && Show.Get[i].m_Class1 == myClass )
Here, the compiler evaluates:
Show.Get[i].m_class0
If this is true, the compiler goes on to evaluate:
Show.Get[i].m_Class1 == myClass
If this is true (the other one must be true at this point, unless && was overloaded), then the if block executes.
The problem lies within the first condition. It will be true when Show.Get[i].m_Class0 does not equal 0.
What you really want is the opposite in this case (since myClass is 0):
if( Show.Get[i].m_Class0 == myClass && Show.Get[i].m_Class1 == myClass )
Now I mentioned a couple of things in there. The first is that the second part will only be evaluated if the first is true. This is called short circuit evaluation, and is used to save time. However, if one were to overload operator&&, the short circuit no longer kicks in. That is the second, and this is why it's generally a bad idea to do so, as it can give unexpected side effects from the second condition.
For example:
if (false && ++x)
would leave x if the && is native, but increment x if it is an overloaded version.
if( Show.Get[i].m_Class0 && Show.Get[i].m_Class1 == myClass )
As #chris commented, this is not doing what you seem to think.
if (A && B == 0) does not mean "if A and B are both equal to zero"
It means "if A is true, and B is equal to zero" and that fails when A is zero, because zero is false
You want if (A == 0 && B == 0) which means "if A is equal to zero and B is equal to zero"