2

Is there a way to calculate the maximum value representable by unsigned int without using limits.h (so no UINT_MAX) or without using

unsigned int z = 0;
z = z - 1;
JaMiT
  • 14,422
  • 4
  • 15
  • 31
Singh
  • 783
  • 1
  • 6
  • 24
  • 2
    It is not clear what you want. `static_cast(-1)` gives a compile-time constant. What could be better than that?.. – Evg Nov 13 '19 at 21:27
  • It's complicate to explain because for me that's the best way but my teacher don't accept it ... Idk what to do ... he said : the algorithm is made with the hypothesis that you don't know about variables... Idk what that means – Singh Nov 13 '19 at 21:30
  • Do you mean the highest number that can be stored in an unsigned int? – user11914177 Nov 13 '19 at 21:30
  • Yes sir @user11914177 – Singh Nov 13 '19 at 21:31
  • 3
    `~0u` is a good value. – Eljay Nov 13 '19 at 21:34
  • Try `z = ~z;` If he doesn't accept that, he should be fired, lol. Your solution already demonstrates a clear understanding of how unsigned integers work. – alteredinstance Nov 13 '19 at 21:34
  • @alteredinstance that's what I think ... He doesn't even like initializing variable in c like int x = 0 ... – Singh Nov 13 '19 at 21:36
  • I'd defer to @Eljay 's answer then, `~0u` is purely a number with the maximum value of a unsigned int. Or even, as one of the answers says, `unsigned int(-1)` should work. – alteredinstance Nov 13 '19 at 21:38
  • 1
    @Jason, I don't know about C, but in C++ it is perfectly defined. Unsigned types are 2's complement already, signed will be 2's complement in C++20. – Evg Nov 13 '19 at 21:42
  • What's wrong with using a standard header? (I'm guessing that this was a thought experiment given as a learning exercise. If that is the case, you might want to mention that in the question to spare your teacher accusations of being incompetent.) – JaMiT Nov 13 '19 at 21:43
  • @evg : you should not have deleted your answer IMO - it is valid and not at all "like" the solution in the question as Singh suggested. It is a compile time constant not a runtime calculation - that is fundamentally different. – Clifford Nov 13 '19 at 23:42

5 Answers5

3

The simplest way to do this is to simply assign -1 to an unsigned int. You could also assign ~0u to it.

If that's not acceptable, while inefficient, you could do something like this:

unsigned int i = 0;
while (i+1 > 0) 
  i++;
printf("i=%u\n", i);
dbush
  • 205,898
  • 23
  • 218
  • 273
  • Does, according to [this](https://stackoverflow.com/a/16728392/7151494), this snippet never terminate? – Fureeish Nov 13 '19 at 21:50
  • @Fureeish It does terminate. Unsigned integer types will wrap around, so eventually `i+1` will be 0. – dbush Nov 13 '19 at 21:52
  • True, my oversight. – Fureeish Nov 13 '19 at 21:54
  • i will accept this answer , i know this isn't the best solution but this do what i am looking for (my teacher is looking for). – Singh Nov 13 '19 at 21:59
  • @Singh : _"this isn't the best solution_" - on the contrary `~0u` is exactly the best solution. In fact I'd disagree with the assertion that `-1` is the simplest solution - `~0u` is the simpler, requiring neither implicit or explicit cast or any assumption about 2's complement representation. It also demonstrates an understanding of the fundamentals that the naive and unnecessary algorithm does nothing to reinforce. – Clifford Nov 13 '19 at 22:41
  • @Clifford Actually `-1` is better as it doesn't depend on the representation while `~0` does. – dbush Nov 13 '19 at 22:47
  • @Clifford I mean for the while loop – Singh Nov 13 '19 at 22:50
  • @Singh : but why would you submit that as the answer, when it demonstrates a complete lack of understanding that `~0u` exemplifies perfectly? – Clifford Nov 13 '19 at 23:09
  • @Clifford idk if I got your question but my answer was unsigned x = 0; x= x-1; but my teacher doesn't accepted and said that he wanted something without limits and without as like my solution , Actually I don't know why.He is strange, he doesn't even like the initialization of variables like x = 0 ... – Singh Nov 13 '19 at 23:19
  • @Singh : Because the initialisation to zero and calculation is unnecessary, you can assign `unsigned x = ~0u ;` directly. It is fundamentally different as it generated no code to "calculate" the value - the max is inserted as a literal constant value. That would be a good reason for him rejecting your answer, and not strange at all. However he is the one paid to teach you, so perhaps you should ask him!? – Clifford Nov 13 '19 at 23:36
  • This solution will take rather a long time in the event that `unsigned` is a 64-bit value! It is unworkable and unnecessary. it can be done in N rather than 2^N iterations. – Clifford Nov 13 '19 at 23:37
  • @Clifford I tried with ~0u but he wants an algorithm ... Like your answer with for loop – Singh Nov 13 '19 at 23:40
  • 1
    `-1` is definitely better than `~0`. The standard guarantees that `-1` will always give the largest possible value when converted to an unsigned type. `~0` gives no such guarantee. In fact, it only works when `~0` happens to produce `-1` (as a signed number), which then converts to the largest value of a unsigned type. – Jerry Coffin Nov 13 '19 at 23:50
  • @JerryCoffin : Fair point. In a ones-complement system all ones equals `-0`. I'd suggest that was an academic rather then practical distinction, but this is an academic question. – Clifford Nov 14 '19 at 00:20
  • @Clifford: It's a practical distinction as well though--as an unsigned it'll just become 0, which doesn't seem to be the desired result. – Jerry Coffin Nov 14 '19 at 00:42
  • @JerryCoffin I am not sure what you mean. My point is that an assumption of two's complement is not unreasonable. – Clifford Nov 14 '19 at 07:46
  • @Clifford: Fair enough--and yes, anymore 2's complement is pervasive. – Jerry Coffin Nov 14 '19 at 07:49
1

Your z = z - 1 determines the value at run-time arithmetically. It can be determined as a compile time constant without implicit or explicit casts:

unsigned int z = ~0u ;

That will be what your tutor is looking for if he has any credibility.

Otherwise if you really must provide an "algorithim" to get a grade in a clearly flawed assignment, then;

unsigned z = 1 ;
for( unsigned b = 1; 
     b != 0; 
     z = (z << 1) | 1, b <<= 1 ) ; 

printf( "z = %u\n", z ) ;

That is a somewhat terse way of writing:

unsigned z = 1 ;       // Initial set LSB of max-int to 1
for( unsigned b = 1;   // "Walk" a 1 through each bit of an unsigned
     b != 0;           // until the 1 falls of the end
     b <<= 1 )         // move the 1 right
{
     z = (z << 1) | 1 ; // shift max-int right and set LSB to 1
} 

Another alternative:

unsigned z = 1 ;
unsigned p = 0 ;
while( z != p )
{
    z = (z << 1) | 1 ;
    p = (p << 1) | 1 ;
}

In this solution p has one fewer bits than z until both are "all ones" when they are equal.

The only possible advantage of these loop methods is that by adding a counter you can simultaneously determine the maximum value and the bit width:

unsigned z = 1 ;
unsigned bits = 0 ;
for( unsigned b = 1; 
     b != 0; 
     z = (z << 1) | 1, b <<= 1, bits++ ) ; 

printf( "z = %u %u-bits\n", z, bits ) ;
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Can you explain me <<=1 and 1,b – Singh Nov 13 '19 at 23:40
  • Funny, I thought I'd edited that. Now corrected. `<<=` is _shift-right-and-assign_. `b <<= 1` is the same as `b = b << 1`. it moves all the bits right by 1. `z = (z << 1) | 1` shifts s right by 1 then sets the vacated LSB to 1 - filling z with 1's one bit at a time. the comma-operator, is simply a way of combining several independent sub-expressions where only a single expression is otherwise valid. It is deliberately terse code. I'll add a simplified expansion. – Clifford Nov 13 '19 at 23:55
  • Note @JerryCoffin's comment of `~0` vs `(unsigned)-1`. The former assumes a 2's complement system (only _almost_ universally true - but probably true for any hardware you are likely to ever be coding in C on). That said the bit shift method makes the same assumption, but at least it will finish in a reasonable time! – Clifford Nov 14 '19 at 00:30
0

(unsigned int)(-1) or static_cast<unsigned int>(-1) are guaranteed to give the maximum value representable by unsigned int. These are compile-time constants.

Evg
  • 25,259
  • 5
  • 41
  • 83
0

I am guessing that this is an academic question based on not knowing the underlying architecture of the computer that a program will run on. E.g. in the 80's we had 8 bit computers, then it moved to 16 bit, then 32 and now 64 bit. (think there may be 128 bit).

The formula below calculates the largest value

int max = pow(2, number of bits assigned to data type) — 1;

e.g. for 8 bits you get 2^8 - 1 = 255

To get the number of bytes available for the unsigned int type use sizeof. sizeof is part of the c core language so does not need limits.h

Paul McCarthy
  • 818
  • 9
  • 24
-1

So that is quite easy, C and C++ has the function sizeof. This will return the number of bytes a variable of this type needs. So for example on my system

sizeof(int) will return 4. So 4 bytes are needed to store a int value.

Now to calculate the highest number that can be fit in this variable you first need to make sure if the variable is signed or unsigned.

Why? A signed variable (meaning it also can store negative values) uses the first bit of its memory to indicate if it is positive or negative.

As the name suggest, a unsigned int is unsigned. So your calculation will look like this: 2^(sizeof(unsigned int) * 8) - 1.

Why? sizeof return the number of bytes the variable needs, but this calculation only works with bits. Because 1 Byte = 8 Bit you have to multiply by 8. Why the - 1? Your computer starts counting with 0 not with 1.

If you want to calculate the highest number storable in a signed variable you calculate like this: 2^(sizeof(int) * 8 - 1) - 1.

But this is only half, your signed variable stores from -some amount to +some amount right? So 2^(sizeof(int) * 8 - 1) - 1 is your upper bound and -2^(sizeof(int) * 8 - 1) + 1 is your lower bound.

user11914177
  • 885
  • 11
  • 33
  • 1
    `sizeof` does not tell you how many value bits are in an `unsigned int` because there may be padding bits and because there may be more than eight bits in a byte. – Eric Postpischil Nov 13 '19 at 21:51
  • Really? More than eight bits in a byte? Just because something extraordinary exists doesn't mean that there are no general cases! – user11914177 Nov 13 '19 at 21:52
  • 1
    tried this but doesnt work maybe im doing something wrong ... unsigned int j = 0 ; j = 2^(sizeof(unsigned int)*8)-1; printf("j = %u\n",j); – Singh Nov 13 '19 at 21:56
  • Oh sorry, so in C the `^` operator means xor, but in math, like I intended to use it means 2 to the power of sizeof... so you would need `pow(2, sizeof...)` – user11914177 Nov 13 '19 at 22:01
  • 1
    @user11914177 oh I forget about it ahha , my bad anyway thanks – Singh Nov 13 '19 at 22:04
  • @user11914177 - yest really, and not at all extraordinary. TI C2000 series microcontrollers for example. – Clifford Nov 13 '19 at 22:46
  • The question clearly states the type in question is `unsigned int` so the discussion of signed types is irrelevant. Your answer does not calculate the maximum value in a manner that can be coded. Your comment regarding `pow()` does not provide a solution because in the event that `sizeof(double) == sizeof(int)`, then `INT_MAX` will not be representable by the return type of `pow()`. So your "quite easy" is both rather complicated, unworkable and really not as easy as the obvious `~0u`. – Clifford Nov 13 '19 at 23:01
  • Since your exponential expressions are not in the language in question, the use of code tags/markup should be avoided - changed to ... HTML tags. – Clifford Nov 13 '19 at 23:04
  • Regarding the width of a `char`, that is defined in limits.h as `CHAR_BIT` - but limits.h is not allowed. – Clifford Nov 13 '19 at 23:07
  • 1
    Yes, really. This is an academic question—that is the reason for the constraint of not using ``, and a comment confirms it was posed by a teacher. That means the answer should be based on properties of the C standard, not on common implementations, and hence you should not assume either the lack of padding bits nor the number of bits in a byte. – Eric Postpischil Nov 13 '19 at 23:44