How can a 32-bit structure represent a negative 64-bit value? - c

In a 32-bit C programming environment without any built-in native 64-bit support, but some parts of the operating system API's do support 64-bit numbers, I have to represent a negative value (range -8192 upto and including -1). Presumably I have to do the maths myself.
typedef struct _LONGLONG {ULONG lo;LONG hi} LONGLONG;
LONGLONG x;
How can I assign such a negative value to x.lo and x.hi, and (less important) perhaps how can I verify it's the right number?
I've read about "What's wrong with quadpart?", but apparently there's no such thing available.

Bits represent values only according to some type scheme. The question does not state what scheme is used to make the bits in lo and hi represent values. For the purposes of this answer, we will suppose:
LONG hi is a 32-bit two’s complement integer.
ULONG lo is a 32-bit unsigned integer.
The API using this LONGLONG structure interprets lo and hi as a 64-bit two’s complement number formed with the bits of hi as the high 32 bits of the 64-bit number and the bits of low as the low 32 bits.
In this case, if n is a value in [−8192, −1], the upper 32 bits of a 64-bit two’s complement representation are all ones, and the lower 32 bits are the same as the 32 bits of a 32-bit two’s complement representation of n. Therefore, the desired bit patterns of the LONGLONG x can be set with:
x.hi = -1;
x.lo = n;
Note that, since x.lo is unsigned, the assignment x.lo = n will convert the signed n to unsigned. This conversion will be done by wrapping modulo 232, and the resulting 32-bit unsigned value for x.lo has the same bit pattern as the 32-bit two’s complement value for n, so the desired result is achieved.

Related

Does signed to unsigned casting in C changes the bit values

I've done some quick tests that a signed int to unsigned int cast in C does not change the bit values (on an online debugger).
What I want to know is whether it is guaranteed by a C standard or just the common (but not 100% sure) behaviour ?
Conversion from signed int to unsigned int does not change the bit representation in two’s-complement C implementations, which are the most common, but will change the bit representation for negative numbers, including possible negative zeroes on one’s complement or sign-and-magnitude systems.
This is because the cast (unsigned int) a is not defined to retain the bits but the result is the positive remainder of dividing a by UINT_MAX + 1 (or as the C standard (C11 6.3.1.3p2) says,
the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
The two’s complement representation for negative numbers is the most commonly used representation for signed numbers exactly because it has this property of negative value n mapping to the same bit pattern as the mathematical value n + UINT_MAX + 1 – it makes it possible to use the same machine instruction for signed and unsigned addition, and the negative numbers will work because of wraparound.
Casting from a signed to an unsigned integer is required to generate the correct arithmetic result (the same number), modulo the size of the unsigned integer, so to speak. That is, after
int i = anything;
unsigned int u = (unsigned int)i;
and on a machine with 32-bit ints, the requirement is that u is equal to i, modulo 232.
(We could also try to say that u receives the value i % 0x100000000, except it turns out that's not quite right, because the C rules say that when you divide a negative integer by a positive integer, you get a quotient rounded towards 0 and a negative remainder, which isn't the kind of modulus we want here.)
If i is 0 or positive, it's not hard to see that u will have the same bit pattern.
If i is negative, and if you're on a 2's complement machine, it turns out the result is also guaranteed to have the same bit pattern. (I'd love to present a nice proof of that result here, but I don't have time just now to try to construct it.)
The vast majority of today's machines use 2's complement. But if you were on a 1's complement or sign/magnitude machine, I'm pretty sure the bit patterns would not always be the same.
So, bottom line, the sameness of the bit patterns is not guaranteed by the C Standard, but arises due to a combination of the C Standard's requirements, and the particulars of 2's complement arithmetic.

short int Integer wrap around / short int inversion in c not understood, difference between assignment and prints

The following code fragment
short int k = -32768;
printf("%d \n", -k);
k=-k;
printf("%d \n", k);
prints
32768
-32768
I would assume that both prints are equal.
Can somebody explain what the difference is and why the assignment k=-k causes a wrap around? It was hard to find a explanation online, as i don't really know what to google.
Well, to print a short, you need to use a length modifier.
Change the format string to %hd.
Because SHRT_MIN = -32768 and SHRT_MAX = +32767. Check out how 2's complement work.
Edit
Actually, according to the international standard of the C programming language (i.e. Committee Draft — May 6, 2005, pp. 50-51) regarding signed integers:
For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit.
There need not be any padding bits; there shall be exactly one sign bit.
Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M <= N).
If the sign bit is zero, it shall not affect the resulting value.
If the sign bit is one, the value shall be modified in one of the following ways:
the corresponding value with sign bit 0 is negated (sign and magnitude);
the sign bit has the value −(2N ) (two's complement);
the sign bit has the value −(2N − 1) (ones' complement).
Which of these applies is implementation-defined, as is whether the value with sign bit 1 and all value bits zero (for the first two), or with sign bit and all value bits 1 (for ones' complement), is a trap representation or a normal value. In the case of sign and magnitude and ones' complement, if this representation is a normal value it is called a negative zero.
So, in other words, in your case it's seems that 2's complement is being used, but this should not be assumed to be in all platforms and compilers.
-32768 is 8000 in hexadecimal notation. 32768 can not be represented as a signed 16 bit number, therefore the compiler promotes -k to an int with the hex value 00008000. When this number is assigned to the 16-bit variable, the high bits are truncated, resulting in 8000 or -32768 again.

Signed int range confusion

This question might be very basic but i post here only after days of googling and for my proper basic understanding of signed integers in C.
Actually some say signed int has range
-32767 to 32767 and others say it has range
-32768 to 32767
Let us have int a=5 (signed / let us consider just 1 byte)
*the 1st representation of a=5 is represented as 00000101 as a positive number and a=-5 is represented as 10000101 (so range -32767 to 32767 justified)
(here the msb/sign bit is 1/0 the number will be positive/negative and rest(magnitude bits) are unchanged )
*the 2nd representation of a=5 is represented as 00000101 as a positive number and a=-5 is represented as 11111011
(the msb is considered as -128 and the rest of bits are manipulated to obtain -5) (so range -32768 to 32767 justified)
So I confuse between these two things. My doubt is what is the actual range of signed int in c ,1) or 2)
It depends on your environment and typically int can store -2147483648 to 2147483647 if it is 32-bit long and two's complement is used, but C specification says that int can store at least -32767 to 32767.
Quote from N1256 5.2.4.2.1 Sizes of integer types <limits.h>
Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.
— minimum value for an object of type int
INT_MIN -32767 // −(2 15 − 1)
— maximum value for an object of type int
INT_MAX +32767 // 2 15 − 1`
Today, signed ints are usually done in two's complement notation.
The highest bit is the "sign bit", it is set for all negative numbers.
This means you have seven bits to represent different values.
With the highest bit unset, you can (with 16 bits total) represent the values 0..32767.
With the highest bit set, and because you already have a representation for zero, you can represent the values -1..-32768.
This is, however, implementation-defined, other representations do exist as well. The actual range limits for signed integers on your platform / for your compiler are the ones found in your environment's <limits.h>. That is the only definite authority.
On today's desktop systems, an int is usually 32 or 64 bits wide, for a correspondingly much larger range than the 16-bit 32767 / 32768 you are talking of. So either those people are talking about really old platforms, really old knowledge, embedded systems, or the minimum guaranteed range -- the standard states that INT_MIN must be at least -32767, and INT_MAX be at least +32767, the lowest common denominator.
My doubt is what is the actual range of signed int in c ,1) [-32767 to 32767] or 2) [-32768 to 32767]?
The whole point of C and its advantage of high portability to old and new platforms is that code should not care.
C defines the range of int with 2 macros: INT_MIN and INT_MAX. The C spec specifies:
INT_MIN is -32,767 or less.
INT_MAX is +32,767 or more.
If code needs a 16-bit 2's complement type, use int16_t. If code needs a 32-bit or wider type, use long or int32least_t, etc. Do not code assuming int is something that it is not defined to be.
The value 32767 is the maximum positive value you can represent on a signed 16-bit integer. The C corresponding type is short.
The int type is represented on at least the same number of bytes as short and at most the same number of bytes as long. The size of int on 16-bit processors is 2 bytes (the same as short). On 32-bit and higher architecture, the size of int is 4 bytes (the same as long).
No matter the architecture, the minumum value of int is INT_MIN and the maximum value of int is INT_MAX.
Similar, there are constants to get the minimum and maximum values for short (SHRT_MIN and SHRT_MAX), long, char etc. You don't need to use hardcoded constants or to guess what is the minimum value for int on your system.
The representation #1 is named "sign and magnitude representation". It is a theoretical model that uses the most significant byte to store the sign and the rest of the bytes to store the absolute value of the number. It was used by some early computers, probably because it seemed a natural map of the numbers representation in mathematics. However, it is not natural for binary computers.
The representation #2 is named two's complement. The two's-complement system has the advantage that the fundamental arithmetic operations of addition, subtraction, and multiplication are identical to those for unsigned binary numbers (as long as the inputs are represented in the same number of bits and any overflow beyond those bits is discarded from the result). This is why it is the preferred encoding nowadays.
The C standard specifies the lowest limits for integer values. As it is written in the Standard (5.2.4.2.1 Sizes of integer types )
...Their implementation-defined values shall be equal or greater in
magnitude (absolute value) to those shown, with the same sign.
For objects of type int these lowest limits are
— minimum value for an object of type int
INT_MIN -32767 // −(215 − 1)
— maximum value for an object of type int
INT_MAX +32767 // 215 − 1
For the two's complement representation of integers the number of positive values is one less than the number of negative values. So if only tow bytes are used for representations of objects of type int then INT_MIN will be equal to -32768.
Take into account that 32768 in magnitude is greater than the value used in the Standard. So it satisfies the Standard requirement.
On the other habd for the representation "sign and magnitude" the limits (when 2 bytes are used) will be the same as shown in the Standard that is -32767:32767
So the actual limits used in the implementation depend on the width of integers and their representation.

Right shifting in c programming.

Consider the expression x>>y , here x is signed int with left most bit is 1 then is the result depend on machine ?
I have tried for signed int with left most bit is 0 i got same result, but i don't know about given case.
There are no unambiguous "leftmost" or "rightmost" bits (which depends on convention), but most significant and least significant bits. The sign bit on a 2's complement machine is the most significant bit.
>> uses zero extension if the shifted is an unsigned.
Positive signed values behave like positive unsigned values. The >> of a negative quantity, however, is implementation defined, but wherever I have used it, negative numbers have been sign-extended.
Also, left-shifting something to the sign bit of a signed quantity is undefined behaviour, so for most portable programs it is best to use bitshift tricks only to unsigned values.

Fixed Point Multiplication of Unsigned numbers

I am trying to solve a multiplication problem with fixed point numbers. The numbers are 32 bit. My architecture is 8 bit. So here goes:
I am using 8.8 notation i.e., 8 for integer, 8 for fraction.
I have A78 which is 10.468. I take its two's complement, and the answer is FFFFF588, which I truncate to 16 bits as F588 and store it. Reason being, I only want to multiply two, 2 byte numbers.
Now when I multiply this F588 (negative 10.42 or 0x0A78) with 0xFF4B which is the two's compliment of 0x00B5 (0.707), answer should be 0x0766. Or something like it.
What I get on the other hand is 66D8.
Now here is where it gets interesting: If I store negative of B5 in two's compliment in 32 bits, I get 0xFF5266D8 which I shift right by 8 bits, truncate then to 16 bits, and answer is 0x5266.
On the other hand if I instead store my negative 10.42 in 32 bits, I get 0xF58F66D8, which after shifting 8 bits and truncating becomes 8F66.
But, if I store both numbers in 32 bit formats, only then I get the correct result after shifting and truncation, which is 0x0766.
Why is this happening? I understand that loss of information is intrinsic when we go from 32 to 16 bits, but 0x07 is much different from 0x55. I will be absolutely grateful for a response.
Let’s look at just the integer representations. You have two 16-bit integers, x and y, and you form their 16-bit two’s complements. However, you keep these 16-bit complements in 32-bit objects. In 32 bits, what you have is 65536–x and 65536–y. (For example, you started with 0xa78, complemented it to make 0xfffff588, and discarded bits to get 0xf588. That equals 0x10000-0xa78.)
When you multiply these, the result is 65536•65536 – 65536•x – 65536•y + x•y.
The 65536•65536 is 232, so it vanishes because unsigned 32-bit arithmetic is performed modulo 232. You are left with – 65536•x – 65536•y + x•y.
Now you can see the problem: x•y is the product of two 16-bit values, so it flows into the high 16 bits of the 32 bits. Up there, you still have – 65536•x – 65536•y, which you do not want.
An easy way to do this is multiplication to keep all 32 bits of the complement. E.g., when you took the two’s complement of 0xa78, you got 0xfffff588. Then you discarded the high bits, keeping only 0xf588. If you do not do that, you will multiply 0xfffff588 by 0xffffff4b, and the product will be 0x766d8 which, when shifted for the fraction, will be 0x766, which is the result you want.
If the high bits are lost because you stored the two’s complement into a 16-bit object, then simply restore them when you reload the object, by extending the sign bit. That is, take bit 15 and repeat it in bits 16 to 31. An easy way to do this is to load the 16-bit object into a 16-bit signed integer, then convert the 16-bit signed integer to an unsigned 32-bit integer.

Resources