Is ~i really equivalent to i != -1? - c++

How does ~i work in C++?
I just noticed it is equivalent to i != -1, but I'm not certain about that.
int arr[3] {1, 2, 3};
int n = 3;
for (int i = n - 1; ~i; i--) {
cout << arr[i] << ' ';
}
It printed the array in reverse.

~ is the bitwise NOT operator. ~i is 0 if and only if i has 1 in all its bits. Whether -1 has all bits 1 depends on how signed numbers are represented on the system. In two's complement representation, -1 is represented with all bits 1, so on such systems ~(-1) == 0. Neither in one's complement, nor in sign-and-magnitude does that hold true.
Therefore, the answer is no; not on all systems. That said, two's complement is fairly ubiquitous in modern machines (everything made since the 90's), and on such systems, the answer is yes. Regardless of the sign representation however, i != -1 is much more readable.

~i is bitwise NOT operator. I.e. it inverts every bit in i.
-1 is represented binary as every bit of number being set to 1, inverting every bit to 0 gets you 0. And when checking integer in place where bool is expected 0 is treated as false and any other number as true.
So, in this particular case yes, ~i is equivalent with i != -1.

Because your i variable from for loop is of type int, which is defined as signed integer, and as such in twos complement, its binary representation of value -1 is all bits set, what means all bits are 1. On other side, bitwise negation of all ones is all zeros, and that is what you need, loop to execute until i>=0 or i!=-1, since you decrementing i. In that context of bitwise operations on sign values on system has twos complement binary representation of int, yes, it is the same.

Related

Why does ~n give -(n+1)?

I wanted to test what happens when I write this code. I can not explain the following case:
Input: 5
Output: -6
#include <iostream>
int lastBit(int n){ return ~(n); }
int main() { std::cout << lastBit(5); }
Computers express negative numbers in quite a specific way. Values are always stored as series of bits and there is no way of introducing negative sign, so this has to be solved differently: one of bits plays role of a negative sign.
But this is not all - the system must be designed to handle maths properly (and ideally, the same way as for positive numbers).
So for instance 0 == 0b00000000. If you subtract 1 from 0, you get -1, but from the binary perspective, due to "binary underflow", 0b00000000 - 0b00000001 == 0b11111111, hence 0b11111111 == -1.
If you then subtract 1 from -1, you get 0b11111111 - 0b00000001 == 0b11111110 == -2. But 2 == 0b00000010, which shows, why -2 != ~2 (and the same rule applies to next values).
The very short, but maybe more intuitive answer might be: "-5 != ~5, because there is only one zero binarily (eg. 0 == -0), so there is always one more negative value than positive ones"
Not on all systems but on systems that use complement of two for signed values. By definition there, the binary representation of negative X = -n, where n is a positive integer, is ~n + 1, which allows signed and unsigned addition operations to be same.
Until C++20 result of ~(n) for signed negative n here would be undefined, because it depends on platform and compiler. In C++20 it's required to behave as if complement of two is used.
I found out the following
5 = 0101
Therefore, ~(5) = 1010
The 1 at the most significant bit denotes negativee (-)
010 = 6
Therefore, output is -6
Since this is a 2's complement machine

What is the purpose of "int mask = ~0;"?

I saw the following line of code here in C.
int mask = ~0;
I have printed the value of mask in C and C++. It always prints -1.
So I do have some questions:
Why assigning value ~0 to the mask variable?
What is the purpose of ~0?
Can we use -1 instead of ~0?
It's a portable way to set all the binary bits in an integer to 1 bits without having to know how many bits are in the integer on the current architecture.
C and C++ allow 3 different signed integer formats: sign-magnitude, one's complement and two's complement
~0 will produce all-one bits regardless of the sign format the system uses. So it's more portable than -1
You can add the U suffix (i.e. -1U) to generate an all-one bit pattern portably1. However ~0 indicates the intention clearer: invert all the bits in the value 0 whereas -1 will show that a value of minus one is needed, not its binary representation
1 because unsigned operations are always reduced modulo the number that is one greater than the largest value that can be represented by the resulting type
That on a 2's complement platform (that is assumed) gives you -1, but writing -1 directly is forbidden by the rules (only integers 0..255, unary !, ~ and binary &, ^, |, +, << and >> are allowed).
You are studying a coding challenge with a number of restrictions on operators and language constructions to perform given tasks.
The first problem is return the value -1 without the use of the - operator.
On machines that represent negative numbers with two's complement, the value -1 is represented with all bits set to 1, so ~0 evaluates to -1:
/*
* minusOne - return a value of -1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 2
* Rating: 1
*/
int minusOne(void) {
// ~0 = 111...111 = -1
return ~0;
}
Other problems in the file are not always implemented correctly. The second problem, returning a boolean value representing the fact the an int value would fit in a 16 bit signed short has a flaw:
/*
* fitsShort - return 1 if x can be represented as a
* 16-bit, two's complement integer.
* Examples: fitsShort(33000) = 0, fitsShort(-32768) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 1
*/
int fitsShort(int x) {
/*
* after left shift 16 and right shift 16, the left 16 of x is 00000..00 or 111...1111
* so after shift, if x remains the same, then it means that x can be represent as 16-bit
*/
return !(((x << 16) >> 16) ^ x);
}
Left shifting a negative value or a number whose shifted value is beyond the range of int has undefined behavior, right shifting a negative value is implementation defined, so the above solution is incorrect (although it is probably the expected solution).
Loooong ago this was how you saved memory on extremely limited equipment such as the 1K ZX 80 or ZX 81 computer. In BASIC, you would
Let X = NOT PI
rather than
LET X = 0
Since numbers were stored as 4 byte floating points, the latter takes 2 bytes more than the first NOT PI alternative, where each of NOT and PI takes up a single byte.
There are multiple ways of encoding numbers across all computer architectures. When using 2's complement this will always be true:~0 == -1. On the other hand, some computers use 1's complement for encoding negative numbers for which the above example is untrue, because ~0 == -0. Yup, 1s complement has negative zero, and that is why it is not very intuitive.
So to your questions
the ~0 is assigned to mask so all the bits in mask are equal 1 -> making mask & sth == sth
the ~0 is used to make all bits equal to 1 regardless of the platform used
you can use -1 instead of ~0 if you are sure that your computer platform uses 2's complement number encoding
My personal thought - make your code as much platform-independent as you can. The cost is relatively small and the code becomes fail proof

What does ~ exactly do when used in bit wise operations?

What is the difference between ~i and INT_MAX^i
Both give the same no. in binary but when we print the no. the output is different as shown in the code below
#include <bits/stdc++.h>
using namespace std;
void binary(int x)
{
int i=30;
while(i>=0)
{
if(x&(1<<i))
cout<<'1';
else
cout<<'0';
i--;
}
cout<<endl;
}
int main() {
int i=31;
int j=INT_MAX;
int k=j^i;
int g=~i;
binary(j);
binary(i);
binary(k);
binary(g);
cout<<k<<endl<<g;
return 0;
}
I get the output as
1111111111111111111111111111111
0000000000000000000000000011111
1111111111111111111111111100000
1111111111111111111111111100000
2147483616
-32
Why are k and g different?
K and g are different - the most significant bit is different. You do not display it since you show only 31 bits. In k the most significant bit is 0 (as the result of XOR of two 0's). In g it is 1 as the result of negation of 0 (the most significant bit of i).
Your test is flawed. If you output all of the integer's bits, you'll see that the values are not the same.
You'll also now see that NOT and XOR are not the same operation.
Try setting i = 31 in your binary function; it is not printing the whole number. You will then see that k and g are not the same; g has the 'negative' flag (1) on the end.
Integers use the 32nd bit to indicate if the number is positive or negative. You are only printing 31 bits.
~ is bitwise NOT; ~11100 = ~00011
^ is bitwise XOR, or true if only one or the other
~ is bitwise NOT, it will flip all the bits
Example
a: 010101
~a: 101010
^ is XOR, it means that a bit will be 1 iff one bit is 0 and the other is 1, otherwise it will set to 0.
a: 010101
b: 001100
a^b: 011001
You want UINT_MAX. And you want to use unsigned int's INT_MAX only does not have the signed bit set. ~ will flip all the bits, but ^ will leave the sign bit alone because it is not set in INT_MAX.
This statement is false:
~i and INT_MAX^i ... Both give the same no. in binary
The reason it appears that they give the same number in binary
is because you printed out only 31 of the 32 bits of each number.
You did not print the sign bit.
The sign bit of INT_MAX is 0 (indicating a positive signed integer)
and is is not changed during INT_MAX^i
because the sign bit of i also is 0,
and the XOR of two zeros is 0.
The sign bit of ~i is 1 because the sign bit of i was 0 and the
~ operation flipped it.
If you printed all 32 bits you would see this difference in the binary output.

Negation of -2147483648 not possible in C/C++?

#include <iostream>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int num=-2147483648;
int positivenum=-num;
int absval=abs(num);
std::cout<<positivenum<<"\n";
std::cout<<absval<<"\n";
return 0;
}
Hi I am quite curious why the output of the above code is
-2147483648
-2147483648
Now I know that -2147483648 is the smallest represntable number among signed ints, (assuming an int is 32 bits). I would have assumed that one would get garbage answers only after we went below this number. But in this case, +2147483648 IS covered by the 32 bit system of integers. So why the negative answer in both cases?
But in this case, +2147483648 IS covered by the 32 bit system of integers.
Not quite correct. It only goes up to +2147483647. So your assumption isn't right.
Negating -2147483648 will indeed produce 2147483648, but it will overflow back to -2147483648.
Furthermore, signed integer overflow is technically undefined behavior.
The value -(-2147483648) is not possible in 32-bit signed int. The range of signed 32-bit int is –2147483648 to 2147483647
Ahhh, but its not... remember 0, largest signed is actually 2147483647
Because the 2's complement representation of signed integers isn't symmetric and the minimum 32-bit signed integer is -2147483648 while the maximum is +2147483647. That -2147483648 is its own counterpart just as 0 is (in the 2's complement representation there's only one 0, there're no distinct +0 and -0).
Here's some explanation.
A negative number -X when represented as N-bit 2's complement, is effectively represented as unsigned number that's equal to 2N-X. So, for 32-bit integers:
if X = 1, then -X = 232 - 1 = 4294967295
if X = 2147483647, then -X = 232 - 2147483647 = 2147483649
if X = 2147483648, then -X = 232 - 2147483648 = 2147483648
if X = -2147483648, then -X = 232 + 2147483648 = 2147483648 (because we only keep low 32 bits)
So, -2147483648 = +2147483648. Welcome to the world of 2's complement values.
The previous answers have all pointed out that the result is UB (Undefined Behaviour) because 2147483648 is not a valid int32_t value. And we all know, UB means anything can happen, including having daemons flying out of your nose. The question is, why does the cout behavior print out a negative value, which seems to be the worst value it could have chosen randomly ?
I'll try to justify it on a two's complement system. Negation on a CPU is actually somewhat of a tricky operation. You can't do it in one step. One way of implementing negation, i.e. int32_t positivenum = -num is to do a bit inversion followed by adding 1, i.e. int32_t positivenum = ~num + 1, where ~ is the bitwise negation operator and the +1 is to fix the off-by-one error. For example, negation of 0x00000000 is 0xFFFFFFFF + 1 which is 0x00000000 (after roll over which is what most CPUs do). You can verify that this works for most integers... except for 2147483648. 2147483648 is stored as 0x80000000 in two's complement. When you invert and add one, you get
- (min) = -(0x80000000)
= ~(0x80000000) + 1
= 0x7FFFFFFF + 1
= 0x80000000
= min
So magically, the unary operator - operating on min gives you back min!
One thing that is not obvious is that two-complement CPUs' arithmetic have no concept of positive or negative numbers! It treats all numbers as unsigned under the hood. There is just one adder circuit, and one multiplier circuit. The adder circuit works for positive and negative numbers, and the multiplier circuit works for positive and negative number.
Example: -1 * -1
= -1 * -1
= (cast both to uint32_t)
= 0xFFFFFFFF * 0xFFFFFFFF
= FFFFFFFE00000001 // if you do the result to 64 bit precision
= 0x00000001 // after you truncate to 32 bit precision
= 1
The only time you care about signed vs unsigned is for comparisons, like < or >.

Using tilde to get MAX value for int

I tryed to get MAX value for int, using tilde.But output is not what I have expected.
When I run this:
#include <stdio.h>
#include <limits.h>
int main(){
int a=0;
a=~a;
printf("\nMax value: %d",-a);
printf("\nMax value: %d",INT_MAX);
return 0;
}
I get output:
Max value: 1
Max value: 2147483647
I thought,(for exemple) if i have 0000 in RAM (i know that first bit shows is number pozitiv or negativ).After ~ 0000 => 1111 and after -(1111) => 0111 ,that I would get MAX value.
You have a 32-bit two's complement system. So - a = 0 is straightforward. ~a is 0xffffffff. In a 32-bit two's complement representation, 0xffffffff is -1. Basic algebra explains that -(-1) is 1, so that's where your first printout comes from. INT_MAX is 0x7fffffff.
Your logical error is in this statement: "-(1111) => 0111", which is not true. The arithmetic negation operation for a two's complement number is equivalent to ~x+1 - for your example:
~x + 1 = ~(0xffffffff) + 1
= 0x00000000 + 1
= 0x00000001
Is there a reason you can't use std::numeric_limits<int>::max()? Much easier and impossible to make simple mistakes.
In your case, assuming 32 bit int:
int a = 0; // a = 0
a = ~a; // a = 0xffffffff = -1 in any twos-comp system
a = -a; // a = 1
So that math is an incorrect way of computer the max. I can't see a formulaic way to compute the max: Just use numeric_limits (or INT_MAX if you're in a C-only codebase).
Your trick of using '~' to get maximum value works with unsigned integers. As others have pointed out, it doesn't work for signed integers.
Your posting shows an int which is equivalent to signed int. Try changing the type to unsigned int and see what happens.
There is no formula to compute the max value of a signed integer type in C. You simply must use the INT_MAX, etc. macros from limits.h and stdint.h.
binary 1...1111 would always represent -1. Simple math says -1 * -1 = 1!
Always remember there's just one zero: 0...0000. If you'd now swap the MSB and you'd be right, then you'd have 10...0000 which would then be -0 which can't be true (as 0 = -0 in math, but your binary numbers would be different).
Getting the negative value of a number isn't just about swapping the MSB.
It's not quite as straightforward as the top-bit indicating the sign. If it were, you could have both +0 and -0. You should read up on two's complement.
The correct answer is
max = (~0) >> 1;
I'm not a C/C++ expert, so you might need >>> instead. You need the shift operator that does NOT do sign extension.
In 2's complement notation 111111... is -1; now, the unary minus operator does not simply change the sign bit (otherwise it would provide strange results in every normal context), but computes correctly the opposite of the number, i.e. +1.
If you want to change the MSB you could use bitwise operators to simply set it to zero. Notice that however this way of finding the maximum value for the int type is not portable, since you're making assumptions about how the number is represented that are not required by the standard.