-1
{
   printf("%lld\n", -9223372036854775807ull - 1);

}  

expected output : 9223372036854775808

actual output : -9223372036854775808

i know about wrapping around of unsigned integer but why subtracting 1 from an unsigned long long which wraps up to 9223372036854775809 did not give the result 9223372036854775808.

Can you give me a step by step explanation what happens here?

Thanks in advance

RJ Ruhan
  • 63
  • 4

3 Answers3

2

Also the result goes beyond the range of a signed long long.

The actual output suggest that it does not.

Most architectures use two's complement to represent negative numbers in binary.

The range of a signed 64 bit width value in twos complement is from -9223372036854775808 to 9223372036854775807 including. The number -9223372036854775808 is just in range.

The -9223372036854775807 is equal to 0x8000000000000001. Minus 1 that's 0x8000000000000000, which is equal to -9223372036854775808.

If your code would overflow (underflow) an integer of type long long, then the behavior of your program would be undefined. Signed integer overflow is undefined behavior according to the C standard. In C you can't have expectations for any behavior from a code that does underflow an signed integer (or you should be aware of your compiler that allows such behavior).

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • why does this statement `printf("%lld",-9223372036854775808)` prints **-1** though it is in range – RJ Ruhan Mar 20 '20 at 02:21
  • That's a funny one. `-9223372036854775808` is interpreted as `-` with `9223372036854775808`. Then number `9223372036854775808` is too big to fit into `long long` so `unsinged long long` is used. Then `-` is applied, and `unsigned long long` is converted to a `long long` value. Which result's in conversion. You could also read [cppreference integer constant](https://en.cppreference.com/w/c/language/integer_constant) the examples below. – KamilCuk Mar 20 '20 at 02:30
  • "... and `unsigned long long` is converted to a `long long` value" --> There is no proper conversion. – chux - Reinstate Monica Mar 20 '20 at 03:21
1

"Fundamentally, what the computer is presented with is a pattern of bits." If you choose to interpret the leftmost bit as a "sign bit," then you might get a "negative" number. Whereas, if you don't, you will get a (much larger) "positive" number. The computer really doesn't care.

"The pattern of bits does not change." If you choose to interpret them as a two's complement signed value, that's fine. Likewise if MSB=1 doesn't matter to you, that's fine too. You can format your printed output either way.

Mike Robinson
  • 8,490
  • 5
  • 28
  • 41
  • doesnt the expression -9223372036854775807ull wraps up to 9223372036854775809 and so subtracting 1 from it yields to 9223372036854775808 ? – RJ Ruhan Mar 20 '20 at 02:07
1

-9223372036854775807ull - 1 becomes 9223372036854775808ull due to wrap-around of the (supoosed) 64-bit unsigned long long. This is well defined. Nothing to do with 2's complement.

// like
(ULLONG_MAX + 1) - 9223372036854775807 - 1 --> 9223372036854775808

Printing with non-matching specifiers is usual undefined behavior (UB), except for corresponding integers of the same positive range. C17dr §6.5.2.2 6

Output is UB as 9223372036854775808ull is outside the positive range for long long and "%lld".

It appears to have wrapped, but that is UB.

If you want to print the unsigned long long result of -9223372036854775807ull - 1, use:

//  not  lld
printf("%llu\n", -9223372036854775807ull - 1);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256