Is there a limit of n bits when bit shifting? - c++

While trying to come up with a scheme for a bitboard class, I decided use global compile time variables to represent key bit board configurations, ex. the initial position of all black rooks.
constexpr uint64_t BLACK_ROOK_INIT = 0x1 | (0x1 << 56);
However I am getting compiler errors. The compiler appears to be treating this value as a 32 bit value and type casting or adding additional 0's does not seem to make a difference. The type definition is from .
As soon as I drop constexp from this expression it compiles, however still produces the equivalent warning. Why is this happening? I thought it might be a limitation of the pre-processor, but the problem persists without constexp.
chess.cpp:16:64: error: right operand of shift expression ‘(1 << 56)’ is >= than the precision of the left operand [-fpermissive]
FYI, this also does not compile
constexpr int64_t BLACK_ROOK_INIT = (int64_t)0x1 | (int64_t)(0x1 << 32);

This is what you want:
#include <iostream>
int main(){
constexpr uint64_t BLACK_ROOK_INIT = 0x1ULL | (0x1ULL << 56);
std::cout<<BLACK_ROOK_INIT<<std::endl;
}
Your 0x1 value is, by default, an int, which is usually implemented as a 32-bit integer.
The suffixes are discussed here. If they make you a bit uncomfortable, as they do me, you can cast as follows:
#include <iostream>
int main(){
constexpr uint64_t BLACK_ROOK_INIT = (uint64_t)(0x1) | ((uint64_t)(0x1) << 56);
std::cout<<BLACK_ROOK_INIT<<std::endl;
}

here 1 is int and after shifting it crosses the limit of int.
so firstly we need to convert int to long long int(a/c to your requirements)
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
ll l=(long long int)1<<n;
cout<<l<<endl;
}

Related

long long int bit representation, C++ [duplicate]

I want to use the following code in my program but gcc won't allow me to left shift my 1 beyond 31.
sizeof(long int) displays 8, so doesn't that mean I can left shift till 63?
#include <iostream>
using namespace std;
int main(){
long int x;
x=(~0 & ~(1<<63));
cout<<x<<endl;
return 0;
}
The compiling outputs the following warning:
left shift `count >= width` of type [enabled by default] `x=(~0 & ~(1<<63))`;
^
and the output is -1. Had I left shifted 31 bits I get 2147483647 as expected of int.
I am expecting all bits except the MSB to be turned on thus displaying the maximum value the datatype can hold.
Although your x is of type long int, the 1 is not. 1 is an int, so 1<<63 is indeed undefined.
Try (static_cast<long int>(1) << 63), or 1L << 63 as suggested by Wojtek.
You can't use 1 (int by default) to shift it beyond the int boundaries.
There's an easier way to get the "all bits except the MSB turned on" for a specific datatype
#include <iostream>
#include <limits>
using namespace std;
int main(){
unsigned long int max = std::numeric_limits<unsigned long int>::max();
unsigned long int max_without_MSB = max >> 1;
cout<< max_without_MSB <<endl;
return 0;
}
note the unsigned type. Without numeric_limits:
#include <iostream>
using namespace std;
int main() {
long int max = -1;
unsigned long int max_without_MSB = ((unsigned long int)max) >> 1;
cout << max_without_MSB << endl;
return 0;
}
Your title is misleading; a long can shift beyond 31 bits if a long is indeed that big. However your code shifts 1, which is an int.
In C++, the type of an expression is determined by the expression itself. An expression XXXXX has the same type regardless; if you later go double foo = XXXXX; it doesn't mean XXXXX is a double - it means a conversion happens from whatever XXXXX was, to double.
If you want to left-shift a long, then do that explicitly, e.g. 1L << 32, or ((long)1) << 32. Note that the size of long varies between platforms, so if you don't want your code to break when run on a different system then you'll have to take further measures, such as using fixed-width types, or shifting by CHAR_BIT * sizeof(long) - 1.
There is another issue with your intended code: 1L << 63 causes undefined behaviour if long is 64-bit or less. This is because of signed integer overflow; left-shift is defined the same as repeated multiplication of two, so attempting to "shift into the sign bit" causes an overflow.
To fix this, use unsigned types where it is fine to shift into the MSB, e.g. 1ul << 63.
Technically there is another issue in that ~0 doesn't do what you want if you are not on a 2's complement system, but these days it's pretty safe to ignore that case.
Looking at your overall intention with long x = ~0 & ~(1 << 63). A shorter way to write this is:
long x = LONG_MAX;
which is defined by <climits>. If you wanted 64-bit on all platforms then
int64_t x = INT64_MAX;
NB. If you do not intend to work with negative values then use unsigned long x and uint64_t respectively.
First let me state a few things about the shift, which is the source of your problem:
There is no guarantee that long int is actually 64 bit wide.
The most generic way I can think of is using std::numeric_limits:
static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1);
Now you can even make that a constexpr templated function:
template <typename Integer>
constexpr Integer foo()
{
return static_cast<Integer>(1) << (std::numeric_limits<Integer>::digits - 1);
}
So replacing the shift with static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1) will fix your issue, however there is a far better way:
std::numeric_limits includes a bunch of useful stuff, including:
std::numeric_limits<T>::max(); // the maximum value T can hold
std::numeric_limits<T>::min(); // the minimum value T can hold
std::numeric_limits<T>::digits; // the number of binary digits
std::numeric_limits<T>::is_signed(); // well, do I have to explain? ;-)
See cppreference.com for a complete list. You should prefer the facilities provided by the standard library, because it will most likely have fewer mistakes and other developers immediately know it.
The default datatype for a numeric value in C is integer unless explicitly mentioned.
Here you have to type cast the 1 as long int which would otherwise be an int.

Problem using for(int i=0; i< array.size();i++) [duplicate]

auto.cpp: In function ‘int autooo(unsigned int)’:
auto.cpp:33:25: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
im doing the makefile , and i already run the makefile and make an auto.o but still i get this error, below is my autooo.cpp , auto.h
i dont undestand what is unsigned and signed :\ please help
auto.h
#ifndef function_H_
#define function_H_
int autooo(unsigned);
int interr(unsigned);
#endif /* function_H_ */
autooo.cpp
#include <iostream>
#include <cstdlib> //for random functions
#include "prime.h"
#include "auto.h"
using namespace std;
#ifndef auto_CPP_
#define auto_CPP_
int autooo(unsigned);
int autooo(unsigned a)
{
int b=50;
unsigned numberFound = 0;
do
{
++a;
if (isPrime(a))
{
++numberFound;
cout << a << "is prime number" <<endl;
}
} while (numberFound < b);
return 0;
}
#endif
The compiler warns that the code contains comparison of unsigned int with a signed int in the line
while (numberFound < b);
This has nothing to do with makefiles or make.
You can fix that by changing
int b=50;
to
unsigned b = 50;
or by changing
unsigned numberFound = 0;
to
int numberFound = 0;
The problems you might run into when comparing signed int and unsigned int are explained in this answer to another SO question
At this line
while (numberFound < b);
The first is an unsigned int and the second an int. So you have to make them the same type, or if you are completely sure cast one of them.
As Etan commented:
"Blindly casting away a warning just to avoid the warning is a mistake. You need to understand what the warning is telling you and decide what the right fix is."
You are getting this warning about comparing signed and unsigned types because the ranges of signed and unsigned ints are different.
If you have to make such a comparison, you should explicitly cast one of the values to be compatible with the other, but a check is required to make sure value your cast is valid.
For e.g:-
int i = someIntValue();
if (i >= 0)
{
// i is non-negative, so it is safe to compare to unsigned value
if ((unsigned)i >= u)
// do something
}
It says you are comparing two different things. Most notably the range of one does not fit into the range of another.
I.e there. Exists a number in the unsigned range that cannot be expressed as a signed number
Type cast the code before you were comparing the signed and unsigned code to avoid warning
int a;
unsigned int b;
if(a==b) gives warning
if(a == (int)b)
will resolve your issue
EDIT
Blind casting will lead to some unexpected results
The warning is because ranges for signed and unsigned are different.
Casting will work fine when signed integer you were used for comparison was greater than zero.
so have check whether the signed integer is greater that zero before comparing
More info here

Understanding numerical overflow in C++

I am trying to understand better how overflows behaves in C++. Consider the following MWE (must check for integer literals):
#include <cstdint>
#include <iostream>
#include <iomanip>
int main() {
uint64_t known = 6049417284; // Known solution to operation.
uint32_t option_1 = 77778u; // Using 32 bits for operands.
uint64_t option_2 = 77778ull; // using 64 bits for operands.
uint64_t sol_option_1 = option_1*option_1;
uint64_t sol_option_2 = option_2*option_2;
std::cout << std::boolalpha << (sol_option_1 == known) << std::endl;
std::cout << (sol_option_2 == known) << std::endl;
}
Execution:
false
true
Why does it overflow with operands using 32 bits, even tough I explicitly request 64 bits to receive the solution?
My impression is that during run-time, C++ creates a temporary rvalue, whose precision is that from the operands, i.e. 32 bits. This overflows, and this result from an overflow is copied to the sol_option_1 variable, which receives the result from an overflow.
The answer is very simple: C++ doesn't care about what the result is being assigned to, it just takes the expression option_1 * option_1 and evaluates that. Then, it performs the assignment with the result. Note that you can also choose not to assign the result of an expression anywhere but that shouldn't affect the expression's evaluation.
The first argument determines the type of the result.
In the first line, it is option1 (32 bit).
In the 2nd line, it is option2 (64 bit).
You can solve the overflow of the first line with:
uint64_t sol_option_1 = (uint64_t) option_1*option_1;

Looping through bytes of a long prints out the bytes twice on 64-bit systems [duplicate]

I want to use the following code in my program but gcc won't allow me to left shift my 1 beyond 31.
sizeof(long int) displays 8, so doesn't that mean I can left shift till 63?
#include <iostream>
using namespace std;
int main(){
long int x;
x=(~0 & ~(1<<63));
cout<<x<<endl;
return 0;
}
The compiling outputs the following warning:
left shift `count >= width` of type [enabled by default] `x=(~0 & ~(1<<63))`;
^
and the output is -1. Had I left shifted 31 bits I get 2147483647 as expected of int.
I am expecting all bits except the MSB to be turned on thus displaying the maximum value the datatype can hold.
Although your x is of type long int, the 1 is not. 1 is an int, so 1<<63 is indeed undefined.
Try (static_cast<long int>(1) << 63), or 1L << 63 as suggested by Wojtek.
You can't use 1 (int by default) to shift it beyond the int boundaries.
There's an easier way to get the "all bits except the MSB turned on" for a specific datatype
#include <iostream>
#include <limits>
using namespace std;
int main(){
unsigned long int max = std::numeric_limits<unsigned long int>::max();
unsigned long int max_without_MSB = max >> 1;
cout<< max_without_MSB <<endl;
return 0;
}
note the unsigned type. Without numeric_limits:
#include <iostream>
using namespace std;
int main() {
long int max = -1;
unsigned long int max_without_MSB = ((unsigned long int)max) >> 1;
cout << max_without_MSB << endl;
return 0;
}
Your title is misleading; a long can shift beyond 31 bits if a long is indeed that big. However your code shifts 1, which is an int.
In C++, the type of an expression is determined by the expression itself. An expression XXXXX has the same type regardless; if you later go double foo = XXXXX; it doesn't mean XXXXX is a double - it means a conversion happens from whatever XXXXX was, to double.
If you want to left-shift a long, then do that explicitly, e.g. 1L << 32, or ((long)1) << 32. Note that the size of long varies between platforms, so if you don't want your code to break when run on a different system then you'll have to take further measures, such as using fixed-width types, or shifting by CHAR_BIT * sizeof(long) - 1.
There is another issue with your intended code: 1L << 63 causes undefined behaviour if long is 64-bit or less. This is because of signed integer overflow; left-shift is defined the same as repeated multiplication of two, so attempting to "shift into the sign bit" causes an overflow.
To fix this, use unsigned types where it is fine to shift into the MSB, e.g. 1ul << 63.
Technically there is another issue in that ~0 doesn't do what you want if you are not on a 2's complement system, but these days it's pretty safe to ignore that case.
Looking at your overall intention with long x = ~0 & ~(1 << 63). A shorter way to write this is:
long x = LONG_MAX;
which is defined by <climits>. If you wanted 64-bit on all platforms then
int64_t x = INT64_MAX;
NB. If you do not intend to work with negative values then use unsigned long x and uint64_t respectively.
First let me state a few things about the shift, which is the source of your problem:
There is no guarantee that long int is actually 64 bit wide.
The most generic way I can think of is using std::numeric_limits:
static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1);
Now you can even make that a constexpr templated function:
template <typename Integer>
constexpr Integer foo()
{
return static_cast<Integer>(1) << (std::numeric_limits<Integer>::digits - 1);
}
So replacing the shift with static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1) will fix your issue, however there is a far better way:
std::numeric_limits includes a bunch of useful stuff, including:
std::numeric_limits<T>::max(); // the maximum value T can hold
std::numeric_limits<T>::min(); // the minimum value T can hold
std::numeric_limits<T>::digits; // the number of binary digits
std::numeric_limits<T>::is_signed(); // well, do I have to explain? ;-)
See cppreference.com for a complete list. You should prefer the facilities provided by the standard library, because it will most likely have fewer mistakes and other developers immediately know it.
The default datatype for a numeric value in C is integer unless explicitly mentioned.
Here you have to type cast the 1 as long int which would otherwise be an int.

what does the signed/unsigned comparison warning mean?

auto.cpp: In function ‘int autooo(unsigned int)’:
auto.cpp:33:25: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
im doing the makefile , and i already run the makefile and make an auto.o but still i get this error, below is my autooo.cpp , auto.h
i dont undestand what is unsigned and signed :\ please help
auto.h
#ifndef function_H_
#define function_H_
int autooo(unsigned);
int interr(unsigned);
#endif /* function_H_ */
autooo.cpp
#include <iostream>
#include <cstdlib> //for random functions
#include "prime.h"
#include "auto.h"
using namespace std;
#ifndef auto_CPP_
#define auto_CPP_
int autooo(unsigned);
int autooo(unsigned a)
{
int b=50;
unsigned numberFound = 0;
do
{
++a;
if (isPrime(a))
{
++numberFound;
cout << a << "is prime number" <<endl;
}
} while (numberFound < b);
return 0;
}
#endif
The compiler warns that the code contains comparison of unsigned int with a signed int in the line
while (numberFound < b);
This has nothing to do with makefiles or make.
You can fix that by changing
int b=50;
to
unsigned b = 50;
or by changing
unsigned numberFound = 0;
to
int numberFound = 0;
The problems you might run into when comparing signed int and unsigned int are explained in this answer to another SO question
At this line
while (numberFound < b);
The first is an unsigned int and the second an int. So you have to make them the same type, or if you are completely sure cast one of them.
As Etan commented:
"Blindly casting away a warning just to avoid the warning is a mistake. You need to understand what the warning is telling you and decide what the right fix is."
You are getting this warning about comparing signed and unsigned types because the ranges of signed and unsigned ints are different.
If you have to make such a comparison, you should explicitly cast one of the values to be compatible with the other, but a check is required to make sure value your cast is valid.
For e.g:-
int i = someIntValue();
if (i >= 0)
{
// i is non-negative, so it is safe to compare to unsigned value
if ((unsigned)i >= u)
// do something
}
It says you are comparing two different things. Most notably the range of one does not fit into the range of another.
I.e there. Exists a number in the unsigned range that cannot be expressed as a signed number
Type cast the code before you were comparing the signed and unsigned code to avoid warning
int a;
unsigned int b;
if(a==b) gives warning
if(a == (int)b)
will resolve your issue
EDIT
Blind casting will lead to some unexpected results
The warning is because ranges for signed and unsigned are different.
Casting will work fine when signed integer you were used for comparison was greater than zero.
so have check whether the signed integer is greater that zero before comparing
More info here