weird results with IF - if-statement

Inspired by this question and it's answers, I did some testing.
One answer suggests, the numbers are too big (out of 32bit integer) and they get truncated, but this doesn't explain the results. Also obviously it doesn't compare both sides as strings (as I would have expected). It seems that if gets confused and thinks "well, I don't know - give it a TRUE". (Using neq, gtr, lss instead of equ, geq, leq always give FALSE).
The code works as expected, if any of a and/or b are within the borders of 32bit integer or contain any char out of [0-9].
#echo off
set a=333333333333
set b=444444444444
call :compare
set b=222222222222
call :compare
goto :eof
:compare
echo comparing %a% with %b%
if %a% geq %b% (echo a ^>= b) else (echo -)
if %b% geq %a% (echo b ^>= a) else (echo -)
if %a% leq %b% (echo a ^<= b) else (echo -)
if %b% leq %a% (echo b ^<= a) else (echo -)
if %a% equ %b% (echo a = b) else (echo -)
if %a% == %b% (echo a == b) else (echo -)
Is there any logical explanation for this, or is it just something we have to live with without thinking?

The reason for this result can be found in documentation of function strtol which is used first on using the comparison operators EQU, NEQ, LSS, LEQ, GTR, GEQ as explained in my answer on Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files.
Return Value
On success, the function returns the converted integral number as a long int value.
If no valid conversion could be performed, a zero value is returned (0L).
If the value read is out of the range of representable values by a long int, the function returns LONG_MAX or LONG_MIN (defined in <climits>), and errno is set to ERANGE.
The last sentence is most important here.
It looks like IF in cmd.exe is coded similar to this C code:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char* argv[])
{
const char csNo[] = "no";
const char csYes[] = "yes";
char* pcEndValue1;
char* pcEndValue2;
int iExitCode = 2;
int iErrorNumber1;
int iErrorNumber2;
int iStringResult1;
int iStringResult2;
long lIntegerValue1;
long lIntegerValue2;
if(argc > 2)
{
/* Convert the two arguments to 32-bit signed integers. */
lIntegerValue1 = strtol(argv[1],&pcEndValue1,0);
iErrorNumber1 = errno;
lIntegerValue2 = strtol(argv[2],&pcEndValue2,0);
iErrorNumber2 = errno;
/* Failed the conversion for any of the two arguments? */
if(((lIntegerValue1 == 0) && (*pcEndValue1 != '\0')) ||
((lIntegerValue2 == 0) && (*pcEndValue2 != '\0')))
{
/* Compare case-sensitive the two arguments as strings. */
iStringResult1 = strcmp(argv[1],argv[2]);
iStringResult2 = strcmp(argv[2],argv[1]);
printf("String comparing %s (a) with %s (b):\n\n",argv[1],argv[2]);
printf("a GEQ b: %s\n",(iStringResult1 >= 0) ? csYes : csNo);
printf("b GEQ a: %s\n",(iStringResult2 >= 0) ? csYes : csNo);
printf("a LEQ b: %s\n",(iStringResult1 <= 0) ? csYes : csNo);
printf("b LEQ a: %s\n",(iStringResult2 <= 0) ? csYes : csNo);
printf("a EQU b: %s\n",(iStringResult2 == 0) ? csYes : csNo);
iExitCode = 1;
}
else
{
/* Compare the values. */
printf("Value comparing %s/%ld (a) with %s/%ld (b):\n\n",argv[1],lIntegerValue1,argv[2],lIntegerValue2);
printf("a GEQ b: %s\n",(lIntegerValue1 >= lIntegerValue2) ? csYes : csNo);
printf("b GEQ a: %s\n",(lIntegerValue2 >= lIntegerValue1) ? csYes : csNo);
printf("a LEQ b: %s\n",(lIntegerValue1 <= lIntegerValue2) ? csYes : csNo);
printf("b LEQ a: %s\n",(lIntegerValue2 <= lIntegerValue1) ? csYes : csNo);
printf("a EQU b: %s\n",(lIntegerValue2 == lIntegerValue1) ? csYes : csNo);
iExitCode = 0;
}
printf("\nError number a: %d ... %s\n",iErrorNumber1,strerror(iErrorNumber1));
printf("Error number b: %d ... %s\n",iErrorNumber2,strerror(iErrorNumber2));
}
return iExitCode;
}
Compiling this C code as console application and running the executable with the parameters 333333333333 444444444444 results for example in output:
Value comparing 333333333333/2147483647 (a) with 444444444444/2147483647 (b):
a GEQ b: yes
b GEQ a: yes
a LEQ b: yes
b LEQ a: yes
a EQU b: yes
Error number a: 2 ... Output of function out of range (ERANGE)
Error number b: 2 ... Output of function out of range (ERANGE)
And running the executable with the parameters 333333333333 222222222222 results for example in output:
Value comparing 333333333333/2147483647 (a) with 222222222222/2147483647 (b):
a GEQ b: yes
b GEQ a: yes
a LEQ b: yes
b LEQ a: yes
a EQU b: yes
Error number a: 2 ... Output of function out of range (ERANGE)
Error number b: 2 ... Output of function out of range (ERANGE)
Note: The error number and the corresponding error string can differ depending on used C compiler respectively standard library.
In both test cases both arguments resulted in a 32-bit signed integer overflow on conversion from string to long int. Therefore strtol returned for all four values LONG_MAX and set errno to ERANGE. But the overflow condition is not evaluated by code of IF in cmd.exe. It is just checked the conversion result and on which character the end pointer points to for both arguments like by the C code above.
In other words IF processes on usage of comparison operators EQU, NEQ, LSS, LEQ, GTR, GEQ always an integer comparison as long as conversion from string to integer does not fail for any of the two arguments because of an invalid character in argument strings. An out of range condition is no reason for IF not doing an integer comparison.
A string comparison is done only if one of the two argument strings contains an invalid character for an integer.

It is a limit.
C:>set /A a=333333333333
Invalid number. Numbers are limited to 32-bits of precision.

Related

Could someone explain the difference between & and &&? [duplicate]

This question already has answers here:
Can I use bitwise operators instead of logical ones?
(5 answers)
Closed 6 years ago.
1st Semester Student here. I'm confused about the differences between the bitand (&) and the logical and (&&), and the same with the bitor (|), the logical or (||), and the Xor (^). Specifically, I've a bit of code that I thought required the || or && to function, but.. apparently not? Here's the code in question:
cout << "Please enter your biological sex (M or F): " << endl;
cin >> sex;
//Repetition Structure
while (toupper(sex) != 'M' && 'F')
{
cout << "Invalid entry. Please enter your biological sex (M or F): " << endl;
cin >> sex;
} //end while
I tried using || at first, but it gave me the "invalid entry" reply no matter how I answered it. I looked around on the forums, found that && would be better and tried using it. It worked - at first. Then, for no apparent reason, it stopped taking 'F' as an answer (the code wasn't changed).
To correct this, I tried using Xor (^) which failed, and then bitand (&, instead of &&), which apparently made it function correctly once more. But, I've seen warnings that you can still get the right answers using either & or &&, but one does not equal the other and could cause problems later. This is why I need clarification (also, it's just good stuff to know).
UPDATE: Since this was tagged as a duplicate, I'll clarify my intent: I want to know more about & and &&, why you use one and not the other, as well as the same info for ^, | and ||. The tagged thread has examples of using one versus another, but they don't explain the details of the operations themselves. As I'm struggling with understanding the very nature of the operations themselves, those explanations are crucial; examples alone won't clarify my understanding.
This isn't something you use bit operators for. You want to compare input string with a desired 'M' or 'F' so all you have to do is:
while (toupper(sex) != 'M' && toupper(sex) != 'F') {...
In your code you were missing the second toupper(sex) != part. You need to look at this statement as two requirements that have to be met in order for while to continue.
First one is: toupper(sex) != 'M'
Second on: toupper(sex) != 'F'
The reason why a &&(logical and) should be between those two is because you want the while loop to run if sex isn't M and at the same time it isn't F.
Operators like & and | are for comparing bits of a variable. For example if you want to use bit flags you set each of your flag to one bit and compare the resulting flag combination with &.
EDIT: So for bit flags, they compare the value you give them bit by bit. So what you do for bit flags is you can define them as powers of 2 (1, 2, 4, 8...) which each represents on position in binary (00000001, 00000010, 00000100, 00001000 ...). So for example when you have flags:
a = 1;
b = 2;
c = 4;
You can set them with ``| to your set of flags:
setFlags = setFlags | a | c;
This will compare the setFlags bit by bit with a and c.
00000000
|00000001 // a
|00000100 // c
=00000101 // result
So the | operator checks all the bits of the same position and if one of them is true, the result will be true just like logical OR.
Now to read them you use & like this:
if (setFlags & a)
which does:
00000101 // setFlags
&00000001 // a
=00000001 // result
this leaves only bits where they both are true (just like logical AND), therefore you can get true if the setFlags contains that flag.
00000101 // setFlags
&00000010 // b
=00000000 // result
in this case there are no bits set to true on same position so the result tells you that b isn't set in setFlags.
while (toupper(sex) != 'M' && 'F') is evaluated as:
while(true && (bool)'F'): while(true && true) // or
while(false && (bool)'F'): while(false && true)
because if you sex is assigned 'm' or 'M' then the condition is true and you used logical and && on a non-zero value 'f' the result is always true.
it is like: if( (bool)5 ) which is true because the bool values of any non-zero value is always true.
to correct you example:
while (toupper(sex) != 'M' && toupper(sex) != 'F')
logical operators like logical and &&, logical or ||,... return bool values true or false; 1 or 0 they evaluate expressions.
bitwise operators like bitwise and &, bitwise or |... return any value, the y work on bits:
unsigned char uc1 = 13; // 0x01 00001101
unsigned char uc2 = 11; // 0x03 00001011
unsigned char uc3 = (uc1 & uc2);// 00001001
as you can see 1 & 1 = 1, 0 & 1 = 0, 1 & 0 = 0, 1 & 1 = 1, 0 & 0 = 0...
the result us 00001001 which is in decimal 9

Are float inequalities guaranteed to be consistent

Assume a, b, c, and d are declared double (or float). Are the following expressions always true?
! ( (a >= b) && (c <= d) ) || ( (a-c) >= (b-d) )
! ( (a > b) && (c <= d) ) || ( (a-c) > (b-d) )
! ( (a >= b) && (c < d) ) || ( (a-c) > (b-d) )
Is there any guaranty from the IEEE 754 or the current C or C++ standard? And will any compiler optimize this as simply true at compile time? I am interested mostly in normal values, not so much in subnormal or special values.
Seems to me this should depend on round-off errors during subtraction mostly.
For the 3rd to produce false it should be sufficient to take large equal a and b and small unequal c and d, e.g. a=1e30, b=1e30, c=1e-31, d=1e-30.
EDIT: Ok, for the 2nd to produce false, by analogy to the 3rd, it should be sufficient to take small unequal a and b and large equal c and d, e.g. a=1e-30, b=1e-31, c=1e30, d = 1e30.
No idea about a counterexample for the 1st expression...
Serge Rogatch gave counterexamples to your second and third expressions.
The first one, !(a >= b && c <= d) || a-c >= b-d, is always true in IEEE 754 arithmetic, if a, b, c, and d must all be finite. Subtraction of finite numbers cannot produce a NaN. Thus a counterexample must satisfy a >= b && c <= d && a-c < b-d. However, a >= b implies that a-c >= b-c, whatever c is, and c <= d implies that b-c >= b-d, whatever b is. Transitivity of >= takes care of the rest.
You can take a = c = 1.0/0.0 and take arbitrary choices of b and d for a counterexample if you relax the condition that a, b, c, and d must all be finite. All counterexamples are of essentially this form.

Bool type True and False

I was playing around with the Bool type (Boolean Variable) and typed this:
#include <iostream>
int main(void)
{
using std::cout;
using std::cin;
using std::endl;
bool $ok = false & true;
if($ok == true)
{
cout << "The value is True." << endl;
}
else if($ok == false)
{
cout << "The value is false." << endl;
}
cin.get();
cin.get();
return 0;
}
I know the differences between using the bitwise operator & and the logical operator &&, but I do not see how this produces a false (0) value. I know if I swapped the bitwise operator and used a + the expression 0+1 would cause it to evaluate to true. Can someone explain why this:
bool $ok = false & true;
evaluates to false?
false=0(0x00000000)
true=1(0x00000001)
Now when we do bitwise and operator of (false & true)---(0&1=0).
0x00000000
& 0x00000001
-------------
0x00000000
Hence the result is 0(0x00000000)
Why would this be true? false converts to a 0-valued integer. true converts to a non-zero valued integer (normally 1, but this is not guaranteed). 0 & x for any x is always 0. 0 == false by definition of the integer/boolean interactions, thus the false branch is entered.
For what it's worth, over a domain of 0 and 1, with 0 as false and 1 as true, * maps to AND whereas + maps to OR. Given this, I'm not quite sure why you'd expect + and & to give the sameresults.
x * y != 0 iff x != 0 and y != 0
x + y != 0 iff x != 0 or y != 0
It's also worth mentioning that bit-wise operations on signed types tend to be a bad idea. If you're going to treat integers as bitfields, use unsigned integral types where the rules around the operations are much more natural and intuitive.
It's because false is 0 (when converted from boolean-land to integer-land), while true is 1 (when converted from boolean-land to integer-land).
false & true == 0 & 1 == 0 == false
false + true == 0 + 1 == 1 == true
If the magic of & is a mystery to you, there are lots of great resources on bitwise-and.

How can i avoid -0.0 in computation

two double values .
double a=-324.000000
double b= 0.000000
if(a*b<0)
{
//number is less than 0
}
else
{
//number is greater than zero
}
It always gives an output as 'number less than zero'.When i multiply both of them i get the result as `-0.000000 .However the result should be 0.000000 .
This is not the result that I get. Are you sure the problem isn't somewhere else?
You said in a comment "i tried if(a==0.0){/*but it never enters here!!*/ }." It really looks like the number is not actually 0.
Consider this code:
#include<iostream>
int main() {
double a=-324;
double b= 0;
double c = a * b;
std::cout<<std::boolalpha
<<"a : "<<a<<std::endl
<<"b : "<<b<<std::endl
<<"c : "<<c<<std::endl
<<"c < 0 : "<<(c < 0)<<std::endl
<<"c > 0 : "<<(c > 0)<<std::endl
<<"c == 0: "<<(c == 0)<<std::endl
;
}
With output:
a : -324
b : 0
c : -0
c < 0 : false
c > 0 : false
c == 0: true
According to the IEEE Standard for Floating Point Arithmetic (also known as IEEE 754):
Comparisons shall ignore the sign of zero (so +0 = -0)
(quote from Section 5.11)
Your problem is somewhere else.
Yes, it is possible to generate a value of -0.0. It does compare equal to positive 0.0 so you can do the following:
double c = a * b;
if (c == 0.0)
c = 0.0;
I've actually used this code in Visual Studio to fix a formatting bug. Make sure you comment it thoroughly so people don't think you're nuts.

Why is the complement operator not working when bool = true?

I have written this C++ program, and I am not able to understand why it is printing 1 in the third cout statement.
#include<iostream>
using namespace std;
int main()
{
bool b = false;
cout << b << "\n"; // Print 0
b = ~b;
cout << b << "\n"; // Print 1
b = ~b;
cout << b << "\n"; // Print 1 **Why?**
return 0;
}
Output:
0
1
1
Why is it not printing the following?
0
1
0
This is due to C legacy operator mechanization (also recalling that ~ is bitwise complement). Integral operands to ~ are promoted to int before doing the operation, then converted back to bool. So effectively what you're getting is (using unsigned 32 bit representation) false -> 0 -> 0xFFFFFFFF -> true. Then true -> 1 -> 0xFFFFFFFE -> 1 -> true.
You're looking for the ! operator to invert a boolean value.
You probably want to do this:
b = !b;
which is logical negation. What you did is bitwise negation of a bool cast to an integer. The second time the statement b = ~b; is executed, the prior value of b is true. Cast to an integer this gives 1 whose bitwise complement is -2 and hence cast back to bool true. Therefore, true values of b will remain true while false values will be assigned true. This is due to the C legacy.
As pretty much everyone else has said, the bool is getting promoted to an integer before the complement operator is getting its work done. ~ is a bitwise operator and thus inverts each individual bit of the integer; if you apply ~ to 00000001, the result is 11111110. When you apply this to a 32-bit signed integer, ~1 gives you -2. If you're confused why, just take a look at a binary converter. For example: http://www.binaryconvert.com/result_signed_int.html?decimal=045050
To your revised question:
False to true works for the same reason as above. If you flip 00000000 (out to 32 bits), you get 11111111... which I believe is -1 in integer. When comparing boolean values, anything that is -not- 0 is considered to be true, while 0 alone is false.
You should use logical operators, not binary operators. Use ! instead of ~.