Find largest unsigned int .... Why doesn't this work? - c++

Couldn't you initialize an unsigned int and then increment it until it doesn't increment anymore? That's what I tried to do and I got a runtime error "Timeout." Any idea why this doesn't work? Any idea how to do it correctly?
#include
int main() {
unsigned int i(0), j(1);
while (i != j) {
++i;
++j;
}
std::cout << i;
return 0;
}

Unsigned arithmetic is defined as modulo 2^n in C++ (where n is
the number of bits). So when you increment the maximum value,
you get 0.
Because of this, the simplest way to get the maximum value is to
use -1:
unsigned int i = -1;
std::cout << i;
(If the compiler gives you a warning, and this bothers you, you
can use 0U - 1, or initialize with 0, and then decrement.)

Since i will never be equal to j, you have an infinite loop.
Additionally, this is a very inefficient method for determining the maximum value of an unsigned int. numeric_limits gives you the result without looping for 2^(16, 32, 64, or however many bits are in your unsigned int) iterations. If you didn't want to do that, you could write a much smaller loop:
unsigned int shifts = sizeof(unsigned int) * 8; // or CHAR_BITS
unsigned int maximum_value = 1;
for (int i = 1; i < shifts; ++i)
{
maximum_value <<= 1;
++maximum_value;
}
Or simply do
unsigned int maximum = (unsigned int)-1;

i will always be different than j, so you have entered an endless loop. If you want to take this approach, your code should look like this:
unsigned int i(0), j(1);
while (i < j) {
++i;
++j;
}
std::cout << i;
return 0;
Notice I changed it to while (i<j). Once j overflows i will be greater than j.
When an overflow happens, the value doesn't just stay at the highest, it wraps back abound to the lowest possible number.

i and j will be never equal to each other. When an unsigned integral value achieves its maximum adding to it 1 will result in that the next value will be the minimum that is 0.
For example if to consider unsigned char then its maximum is 255. After adding 1 you will get 0.
So your loop is infinite.

I assume you're trying to find the maximum limit that an unsigned integer can store (which is 65,535 in decimal). The reason that the program will time out is because when the int hits the maximum value it can store, it "Goes off the end." The next time j increments, it will be 65,535; i will be 0.
This means that the way you're going about it, i would NEVER equal j, and the loop would run indefinitely. If you changed it to what Damien has, you'd have i == 65,535; j equal to 0.

Couldn't you initialize an unsigned int and then increment it until it doesn't increment anymore?
No. Unsigned arithmetic is modular, so it wraps around to zero after the maximum value. You can carry on incrementing it forever, as your loop does.
Any idea how to do it correctly?
unsigned int max = -1; // or
unsigned int max = std::numeric_limits<unsigned int>::max();
or, if you want to use a loop to calculate it, change your condition to (j != 0) or (i < j) to stop when j wraps. Since i is one behind j, that will contain the maximum value. Note that this might not work for signed types - they give undefined behaviour when they overflow.

Related

Sum signed 32-bit int with unsigned 64bit int

On my application, I receive two signed 32-bit int and I have to store them. I have to create a sort of counter and I don't know when it will be reset, but I'll receive big values and frequently. Beacause of that, in order to store these values, I decided to use two unsigned 64-bit int.
The following could be a simple version of the counter.
struct Counter
{
unsigned int elementNr;
unsigned __int64 totalLen1;
unsigned __int64 totalLen2;
void UpdateCounter(int len1, int len2)
{
if(len1 > 0 && len2 > 0)
{
++elementNr;
totalLen1 += len1;
totalLen2 += len2;
}
}
}
I know that if a smaller type is casted to a bigger one (e.g. int to long) there should be no issues. However, passing from 32 bit rappresentation to 64 bit rappresentation and from signed to unsigned at the same time, is something new for me.
Reading around, I undertood that len1 should be expanded from 32 bit to 64 bit and then applied sign extension. Because the unsigned int and signen int have the same rank (Section 4.13), the latter should be converted.
If len1 stores a negative value, passing from signed to unsigned will return a wrong value, this is why I check the positivy at the beginning of the function. However, for positive values, there
should be no issues I think.
For clarity I could revrite UpdateCounter(int len1, int len2) like this
void UpdateCounter(int len1, int len2)
{
if(len1 > 0 && len2 > 0)
{
++elementNr;
__int64 tmp = len1;
totalLen1 += static_cast<unsigned __int64>(tmp);
tmp = len2;
totalLen2 += static_cast<unsigned __int64>(tmp);
}
}
Might there be some side effects that I have not considered.
Is there another better and safer way to do that?
A little background, just for reference: binary operators such arithmetic addition work on operands of the same type (the specific CPU instruction to which is translated depends on the number representation that must be the same for both instruction operands).
When you write something like this (using fixed width integer types to be explicit):
int32_t a = <some value>;
uint64_t sum = 0;
sum += a;
As you already know this involves an implicit conversion, more specifically an
integral promotion according to integer conversion rank.
So the expression sum += a; is equivalent to sum += static_cast<uint64_t>(a);, so a is promoted having the lesser rank.
Let's see what happens in this example:
int32_t a = 60;
uint64_t sum = 100;
sum += static_cast<uint64_t>(a);
std::cout << "a=" << static_cast<uint64_t>(a) << " sum=" << sum << '\n';
The output is:
a=60 sum=160
So all is all ok as expected. Let's se what happens adding a negative number:
int32_t a = -60;
uint64_t sum = 100;
sum += static_cast<uint64_t>(a);
std::cout << "a=" << static_cast<uint64_t>(a) << " sum=" << sum << '\n';
The output is:
a=18446744073709551556 sum=40
The result is 40 as expected: this relies on the two's complement integer representation (note: unsigned integer overflow is not undefined behaviour) and all is ok, of course as long as you ensure that the sum does not become negative.
Coming back to your question you won't have any surprises if you always add positive numbers or at least ensuring that sum will never be negative... until you reach the maximum representable value std::numeric_limits<uint64_t>::max() (2^64-1 = 18446744073709551615 ~ 1.8E19).
If you continue to add numbers indefinitely sooner or later you'll reach that limit (this is valid also for your counter elementNr).
You'll overflow the 64 bit unsigned integer by adding 2^31-1 (2147483647) every millisecond for approximately three months, so in this case it may be advisable to check:
#include <limits>
//...
void UpdateCounter(const int32_t len1, const int32_t len2)
{
if( len1>0 )
{
if( static_cast<decltype(totalLen1)>(len1) <= std::numeric_limits<decltype(totalLen1)>::max()-totalLen1 )
{
totalLen1 += len1;
}
else
{// Would overflow!!
// Do something
}
}
}
When I have to accumulate numbers and I don't have particular requirements about accuracy I often use double because the maximum representable value is incredibly high (std::numeric_limits<double>::max() 1.79769E+308) and to reach overflow I would need to add 2^32-1=4294967295 every picoseconds for 1E+279 years.

Returning a big number in for loop

I was working on a problem and got stuck into this silly error and I can't solve it.
Basically I am using a for loop and reading a character from stream. When the character is '-' I am decreasing my integer by one and when it is '+' I am increasing it by one.
I used an unsigned int because I don't want negative numbers. Here is an example of code:
char x;
unsigned int number = 0;
for (int i = 0; i < n; i++){
cin >> x;
if (x == '-'){
number--;
}else if (x == '+'){
number++;
}
}
cout << number;
And it shows a number something like this 4294967293.
Where is the problem?
If your problem statement says that final resultant number will not be negative, it does not mean that the intermediate numbers will also be positive only. Because, there can be a sequence of streams with characters like - + + which leads to values like: 0, -1, 0, 1. Here, final answer is positive but intermediate numbers are still negative.
Now, you are trying to hold both positive and negative numbers in unsigned int datatype which is leads to wrong output here in above example. Because, if number is 0 and you try to apply negation, it will be 4294967295 (maximum value for a variable of type unsigned int) instead of being -1.
So, instead of using unsigned int datatype , you can use int datatype as suggested by Kaidul.
This is due to wrapping around of unsigned data type. Since it's unsigned, it can't be negative. So negation operation wraps around and yields boundary values of 32 bit integer.
Replace
unsigned int number = 0;
with
int number = 0;

Auto failed for vector size

I am trying use auto to infer the type.
for (auto i = remaining_group.size() - 1; i >= 0; --i) {
std::cout << i;
}
I get very large number like 18446744073709534800 which is not expected. When I change auto to int it is the number I expected between 0 and 39.
Is there any reason auto will fail here?
remaining_group's type is a std::vector<lidar_point> and lidar_point is struct like:
struct LidarPoint {
float x;
float y;
float z;
uint8_t field1;
double field2;
uint8_t field3;
uint16_t field4;
}
When using auto the type of i would be std::vector::size_type, which is an unsigned integer type. That means the condition i >= 0; would be always true, and if overflow happens you'll get some large numbers.
Unsigned integer arithmetic is always performed modulo 2n
where n is the number of bits in that particular integer. E.g. for unsigned int, adding one to UINT_MAX gives ​0​, and subtracting one from ​0​ gives UINT_MAX.
Simple reproduction of problem:
#include <iostream>
size_t size() {return 1;}
int main() {
for (auto i = size() - 1; i >= 0; --i) {
std::cout << i << std::endl;
}
}
size() got type size_t and literal constant 1 would be promoted to size_t, in result auto would become size_t, which cannot be less than zero, resulting in infinite loop and underflow of i.
If you need a reverse index loop, use operator -->
When you write a normal index loop, you write it with 0, size, and <.
When you write a normal reverse index loop, things become a bit wonky: you need size - 1, >=, 0, and you can't use unsigned index, because unsigned i is always >= 0 so your check i >= 0 always returns true, your loop could run forever.
With fake operator "goes to", you can use 0, size, and > to write the reverse index loop, and it doesn't matter if i is signed or unsigned:
for (auto i = a.size(); i --> 0; ) //or just i--, or i --> 1, i --> 10...
std::cout << i << ' ';

casting int to unsigned long long

I was solving a problem wherein the task was to output the result of a pascal triangle at a given row mentioned by a user.
https://leetcode.com/problems/pascals-triangle-ii/
I wrote my solution which had issues storing huge factorial results.
vector<int> getRow(int rowIndex) {
vector<int> v;
int C = 1;
v.push_back(1);
for (int i = 1; i <= rowIndex; i++)
{
printf("%d ", C);
C = C * (rowIndex +1 - i) / i;
v.push_back(C);
}
return v;
}
On going through these questions,
What range of values can integer types store in C++
How many bytes is unsigned long long?
and going through some other sources, i made the following change which gave me the required result.
C = (unsigned long long)C * (rowIndex +1 - i) / i;
Since "C" is of type int and my vector v stores int, i wanted to know why would a cast unsigned long long still give me valid results.
The sub-expression C * (rowIndex +1 - i) can overflow before your division. By casting C to a larger data-type then the whole expression becomes that type, so the multiplication will not overflow. Then after the division with i the result is converted to an int again, but because of the division it is within range of an int.
Note that this is only for the values you currently have. If you continue with even higher values then sooner or later you will have overflows that can't be fixed by such a cast.
When you say
(unsigned long long)C
you are not making actual variable C a unsigned long long. You are just saying when doing this
C * (rowIndex +1 - i) / i;
treat C (at the right side) as unsigned long long. That is, only the temporary space to hold C, then hold its multiplication with (rowIndex +1 - i), and then its division with i is done at a space that big. If the whole result was bigger than a value that integer can have, this would not work either.

Converting a size_t into an integer (c++)

I've been trying to make a for loop that will iterate based off of the length of a network packet. In the API there exists a variable (size_t) by event.packet->dataLength. I want to iterate from 0 to event.packet->dataLength - 7 increasing i by 10 each time it iterates but I am having a world of trouble.
I looked for solutions but have been unable to find anything useful. I tried converting the size_t to an unsigned int and doing the arithmetic with that but unfortunately it didn't work. Basically all I want is this:
for (int i = 0; i < event.packet->dataLength - 7; i+=10) { }
Though every time I do something like this or attempt at my conversions the i < # part is a huge number. They gave a printf statement in a tutorial for the API which used "%u" to print the actual number however when I convert it to an unsigned int it is still incorrect. I'm not sure where to go from here. Any help would be greatly appreciated :)
Why don't you change the type of i?
for (size_t i = 0; i < event.packet->dataLength - 7; i+=10) { }
Try to keep the types of all variables used together the same type; casts should be avoided.
There is no format specifier for size_t in C++03, you have to cast to the largest unsigned integer type you can and print that. (The format specifier for size_t in C++0x is %zu). However, you shouldn't be using printf anyway:
std::cout << i; // print i, even if it's a size_t
While streams may be more verbose, they're more type safe and don't require you to memorize anything.
Keep in mind your actual loop logic may be flawed. (What happens, as genpfault notes, when dataLength - 7 is negative?)
Do everything with signed arithmetic. Try:
for (int i = 0; i < int(event.packet->dataLength) - 7; i+=10) { }
Once you start using unsigned arithmetic with values that may be negative, and using comparison operators like <, you're in trouble. Much easier to keep things signed.
Is dataLength >= 7? If the result of dataLength-7 is negative, if you interpret it as unsigned, the result is a very large integer.
Use size_t for i.
For printf, if you don't have C99, only C90, cast to unsigned long, or unsigned long long. E.g.:
for (size_t i = 0; i < 10; ++i)
//printf("%llu\n", (unsigned long long)i);
printf("%lu\n", (unsigned long)i);
Otherwise use %zu
You should first check if event.packet->dataLength < 7. Now if it's less then 7 you get values less than 0 used as unsigned: e.g. 0 = 0x00000000; -1 = 0 - 1 = 0xFFFFFFFF.
Again, the check:
if (event.packet->dataLength < 7) {
...
} else {
for (size_t i = 0; i < event.packet->dataLength - 7; i+=10) { }
}
"every time I do something like this or attempt at my conversions the i < # part is a huge number."
That indicates that original packet length is less than 7 (you're subtracting 7).
One fix is to use an in-practice-large-enough signed integer type, and the standard library provides ptrdiff_t for that purpose. Like,
#include <stdlib.h> // Not sure, but I think it was this one.
typedef ptrdiff_t Size;
typedef Size Index;
void foo()
{
// ...
for( Index i = 0; i < Size( event.packet->dataLength ) - 7; i += 10 )
{
// ...
}
}
A more cumbersome workaround is to embed the whole thing in an if that checks that the size is at least 7.
Cheers & hth.,
Since event.packet->dataLength returns an unsigned type size_t:
1) Use size_t as the index variable type.
2) Insure math does not underflow. #beldaz. Rather than subtract 7 from event.packet->dataLength, add 7 to i.
// for (int i = 0; i < event.packet->dataLength - 7; i+=10) { }
for (size_t i = 0; i + 7 < event.packet->dataLength; i += 10) { }