C arithmetic conversion multiplying unsigned with signed and result in float - c

int main()
{
printf("Hello World\n");
int x = -10;
unsigned y = 25;
float z = x*y;
printf("x=%d,y=%u,z=%f\n",x,y,z);
return 0;
}
When I run the above code, I get the following output:
Hello World
x=-10,y=25,z=4294967046.000000
My question is:
For the second printf, I would have expected z=(float) ( (unsigned)(-10)*25 ) = (float) (4294967286 x 25) = (float) 107374182150, what am I missing here?

Here's what's happening. As per C11 6.3.1.8 Usual arithmetic conversions (the "otherwise" comes into play here since previous paragraphs discuss what happens when either type is already floating point):
Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
This means your signed value of -10 becomes an unsigned value of 0xffff'fff6, or 4,294,967,286. Multiplying that by 25 gives 107,374,182,150 or 0x18'ffff'ff06 (which is the result you want).
However, at this point, no float calculations have been done, the multiplication is a pure integer calculation and the resultant value will be an integer. And that, combined with the fact your unsigned integers are 32 bits long, means it gets truncated to 0xffff'ff06, or 4,294,967,046.
Then you put that into the float.
To fix this to match your expected results, you should change he expression to force this:
float z = 1.0f * (unsigned)x * y;
This changes the int * unsigned-int calculation into a float * unsigned-int * unsigned-int one. The unsigned cast first ensures x will be converted to the equivalent unsigned value and the multiplication by 1.0f ensures the multiplication are done in the float arena to avoid integer truncation.

Following on from the correct answer from #paxdiablo, the starting point for the result is due to unsigned having a rank equal to the rank of the int, e,g,
The rank of any unsigned integer type shall equal the rank of the
corresponding signed integer type, if any. C11 Standard - 6.3.1
Arithmetic
operands(p1)
This comes into play with the integer conversion cited in #paxdiablo's answer:
6.3.1.8 Usual arithmetic conversions
Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:
Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
The problem is that -10 (negative values) are stored (in almost all computers) in two-complement. In two's complement the value for -10 takes the bitwise NOT of 10 and adds 1 (so in binary 00001010 become 11110110 sign extended to 32-bits). That is:
11111111111111111111111111110110
For which the unsigned values is 4294967286. When multiplied by 25, it exceeds the range of unsigned so the value is reduced modulo until it fits within the range of unsigned resulting in 4294967046. 6.2.5 Types(p9).
What Am I Missing?
The part that is missing is understanding the result of unsigned multiplication is being assigned as a float value. The intermediate result from x * y is unsigned. float f = x * y; is just an assignment of the result to a float.
What you want is for the intermediate calculation to be done as a float, so cast one of the operands (not the result) to float, e.g.
float f = (float)x * y
It does not matter which of the two values is cast to float, the following would be just fine:
float f = x * (float)y;
Now the result will be -250.

Related

Unsigned and Signed in same expression: What rules apply?

I'm confused by the issue stated in the title. I've been told that in expressions involving both types of variables, signed are converted to/interpreted as unsigned. However, as the following code snippet shows, that isn't always the case.
Code:
unsigned int x = 1;
int y = -20;
printf("Right shift = %x, %d\n", y>>x, y>>x);
printf("If = %x, %d\n", y < x, y < x);
Result:
Right shift = fffffff6, -10
If = 0, 0
The if statement returns the expected 0, -20 being cast to a very large unsigned integer, but the shift expression returns -10, making it evident that arithmetic and not logical shift has taken place. The x has been interpreted as signed rather than the y being interpreted as unsigned.
Could anyone clear this up for me?
In this expression
y>>x
(the C Standard, 6.5.7 Bitwise shift operators)
3 The integer promotions are performed on each of the operands.
That means that as y has the type int and x has the type unsigned int neither conversion (promotion) occurs. And
...The type of the result is that of the promoted left operand.
So the result of the expression has the type int - the type of the operand y. As y has a negative value then
...IfE1 has a signed type and a negative value, the resulting value is
implementation-defined
As for this expression
y < x
then there is used the usual arithmetic conversions. The boths operands have the same rank so the operand y of the type int is converted to the type unsigned int and its binary representation as an object of the type unsigned int is greater than the binary representation of the operand x.
From the C Standard *6.3.1.8 Usual arithmetic conversions)
Otherwise, if the operand that has unsigned integer type has rank
greater or equal to the rank of the type of the other operand, then
the operand with signed integer type is converted to the type of the
operand with unsigned integer type.

Data size definition in C programming while using mathematical expressions

When using mathematical operators in c programming, it is very important to use casts or define size of variable properly. I need help in it.
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint32_t a;
uint8_t b;
uint8_t d;
uint64_t c;
float cd;
a = 4294967295;
b = 2;
d = 2;
c = a * b * d;
cd = c;
printf("%f\n", cd);
return 0;
}
The result variable is large enough to store the 2 * 2 * uint32_max. However I noticed that the b or d variable need to be 64 bit wide (or use cast) to get the proper result. For this time I thought the mathematical operations takes place in the result variable, but it looks like is not true. Can somebody explain me which variable need to be widened (b or d) and what is the theoretical background behind it?
What is the situation in division? Should I consider whether I want to divide a 32 bit number with a 8bit long. will the result be in that case 8 bit only? Does any rule about the type of the denominator?
When you perform the multiplication a * b * d, what will happen is that b and d will get promoted to uint32_t (or int if int is wider than uint32_t) to match the type of a. However, this operation might overflow. So what you need to do is to cast at least one of them to uint_64_t to prevent this from happening.
Do note that (uint64_t)(a * b * d) will NOT work. Type casts has lower priority than parenthesis.
In C, the evaluation of an expression is determined by the operator and its operands, not by where the result will eventually be stored.
The expression a * b * d is structured as (a * b) * d. So a * b is evaluated, and then the result is multiplied by d.
One of the rules for * is in C 2018 6.5.5 3:
The usual arithmetic conversions are performed on the operands.
The usual arithmetic conversions are defined in 6.3.1.8 1. They are a bit complicated, and I give most of the details below. Applying them to your example:
In a * b, a is a uint32_t , and b is a uint8_t.
The integer promotions convert b to an int—essentially all arithmetic in C is done in a width of at least int.
If int is 32 bits or narrower, a remains uint32_t. Otherwise, a is converted to int.
If converted types of a and b are both int, the conversions are done, and the multiplication is performed.
If the converted type of a is uint32_t, b is converted to uint32_t, and the multiplication is performed.
Then the multiplication with d is performed the same way.
So, if int is 32 bits or narrower, the multiplications are performed with uint32_t, and the result is uint32_t. If int is wider, the multiplications are performed with int, and the result is int.
Casting either operand to uint64_t would cause the arithmetic to be done with uint64_t. (Except it is theoretically possible that int is wider than uint64_t, in which case the arithmetic would be done with int, but that is still satisfactory—performing a cast guarantees the arithmetic will be done with at least that width.)
For real numbers, the usual arithmetic conversions are largely:
If either operand is long double, the other is converted to long double.
Otherwise, if either is double, the other is converted to double.
Otherwise, if either is float, the other is converted to float.
Otherwise, the integer promotions are performed on both operands.
Then, if both have the same type, no further conversion is performed.
Otherwise, if both are signed or both are unsigned, the narrower (actually “lesser rank”) operand is converted to the type of the other.
Otherwise, if the unsigned operand is the same width or wider (greater or equal rank), the signed operand is converted to the type of the unsigned operand.
Otherwise, if the type of the signed operand can represent all the values of the type of the unsigned operand, the unsigned operand is converted to the type of the signed operand.
Otherwise, both operands are converted to the unsigned type that has the same width as the signed operand.
The integer promotions are defined in 6.3.1.1 2. They apply to all integer types as wide as or narrower than int or unsigned int (technically of rank less than or equal to the rank of int and unsigned int), including bit-fields of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.
a * b * d is an expression of type uint32_t, or int if int is wider than uint32_t (due to the conversion rule for uint8_t).
The fact that this expression is assigned to a wider type is not a factor. That's the crux of the issue.
Writing c = 1ULL * a * b * d is a tractable fix.

Comparison of Unsigned bit field value with signed values

while writing the code I observe one thing in my code its related to the comparison of bit-field value with negative integers.
I have one structure member of unsigned of size one bit and one unsigned int. When I compare the negative value with unsigned int variable I am getting expected result as 1 but when I compare the structure member with the negative value I am getting the opposite result as 0.
#include <stdio.h>
struct S0
{
unsigned int bit : 1;
};
struct S0 s;
int main (void)
{
int negVal = -3;
unsigned int p = 123;
printf ("%d\n", (negVal > p)); /*Result as 1 */
printf ("%d\n", (negVal > s.bit));/*Result as 0 but expected 1 */
return 0;
}
My doubt is if I compare the negative value with unsigned int then balancing will happen (implicit type casting). But if I compare structure member of unsigned int why implicit type casting is not happening. Correct me if I miss any basics of bit fields?
(move my remark as an answer)
gcc promotes s.bit to an int, so (negVal > s.bit) does (-3 > 0) valuing 0
See Should bit-fields less than int in size be the subject of integral promotion? but your question is not a duplicate of it.
(negVal > p) returns 1 because negVal is promoted to unsigned producing a big value, see Signed/unsigned comparisons
For illustration, the following uses a 32-bit int and a 32-bit unsigned int.
In negVal > p:
negVal is an int with value −3.
p is an unsigned int with value 123.
C 2018 6.5.8 3, which is discusses > and the other relational operators, tells us that the usual arithmetic conversions are performed on the operands.
6.3.1.8 1 defines the usual arithmetic conversions. For integer types, the first step of the usual arithmetic conversions is to perform the integer promotions on each operand.
6.3.1.1 2 defines the integer promotions. int, unsigned int, and integer types wider than these are unchanged. For other integer types, it says: ”If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int.”
Since negVal is an int, it is unchanged by the integer promotions.
Since p is an unsigned int, it is unchanged by the integer promotions.
The next step in the usual arithmetic conversions is to convert one operand to the type of the other. For int and unsigned int, the int is converted to unsigned int.
Converting the int −3 to unsigned int results in 4,294,967,293. (The conversion is defined to add or subtracting UINT_MAX + 1, which is 4,294,967,296, to the value as many times as necessary to bring it in range. This is equivalent to “wrapping” modulo 4,294,967,296 or to reinterpreting the two’s complement representation of −3 as an unsigned int.)
After the conversions, the expression negVal > p has become 4294967293u > 123u.
This comparison is true, so the result is 1.
In negVal > s.bit:
negVal is an int with value −3.
s.bit is a one-bit bit-field with value 0.
As above, the usual arithmetic conversions are performed on the operands.
As above, the first step of the usual arithmetic conversions is to perform the integer promotions on each operand.
Since negVal is an int, it is unchanged by the integer promotions.
Since s.bit is a bit-field narrower than an int, it will be converted by the integer promotions. This one-bit bit-field can represent either 0 or 1. Both of these can be represented by an int, and therefore the rule “If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int” applies.
Converting 0 to int results in 0.
The next step in the usual arithmetic conversions would be to convert one operand to the type of the other. Since both operands are now int, no conversion is needed.
After the conversions, the expression negVal > s.bit has become -3 > 0.
This comparison is false, so the result is 0.

kbuild C: ~ Operator Converts Unsigned to Signed? [duplicate]

Let say I have a 32-bit machine.
I know during integer promotion the expressions are converted to:
int if all values of the original type can be represented in int
unsigned otherwise
Could you please explain what will happen for the following expression? and In general, how ranking works here?
First snippet:
int16_t x, pt;
int32_t speed;
uint16_t length;
x = (speed*pt)/length;
Second one:
x = pt + length;
#EDIT:
I found the following link that has described the issue very clearly:
Implicit type conversion.
Concretely, read the answer of Lundin, very helpful!
The integer promotion rule, correctly cited C11 6.3.1.1:
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the
integer promotions. All other types are unchanged by the integer
promotions.
Where "otherwise, it is converted to an unsigned int" is in practice only used in one particular special case, namely where the smaller integer type unsigned short has the same size as unsigned int. In that case it will remain unsigned.
Apart from that special case, all small integer types will always get promoted to (signed) int regardless of their signedness.
Assuming 32 bit int, then:
x = (speed*pt)/length;
speed is signed 32, it will not get promoted. pt will get integer promoted to int (signed 32). The result of speed*pt will have type int.
length will get integer promoted to int. The division will get carried out with operands of type int and the resulting type will be int.
The result will get converted to signed 16 as it is assigned to x (lvalue conversion during assignment).
x = pt + length; is similar, here both operands of + will get promoted to int before addition and the result will afterwards get converted to signed 16.
For details see Implicit type promotion rules.
The integer promotion rules are defined in 6.3.1.8 Usual arithmetic conversions.
1. int16_t x, pt;
int32_t speed;
uint16_t length;
x = (speed*pt)/length;
2. x = pt + length;
Ranking means effectively the number of bits from the type as defined by CAM in limits.h. The standards imposes for the types of lower rank in CAM to correspond types of lower rank in implementation.
For your code,
speed * pt
is multiplication between int32_t and int16_t, which means, it is transformed in
speed * (int16_t => int32_t) pt
and the result tmp1 will be int32_t.
Next, it will continue
tmp1_int32 / length
Length will be converted from uint16_t to int32_t, so it will compute tmp2 so:
tmp1_int32 / (uint16_t => int32_t) length
and the result tmp2 will be of type int32_t.
Next it will evaluate an assignment expression, left side of 16 bits and the right side of 32, so it will cut the result so:
x = (int32_t => int16_t) tmp2_int32
Your second case will be evaluated as
x = (int32_t => int16_t) ( (int16_t => int32_t) pt + (uint16_t => int32_t) length )
In case an operator has both operands with rank smaller than the rank of int, the CAM allows to add both types if the operation does not overflow and then to convert the result to integer.
In other words, it is possible to covert INT16+INT16 either in
INT16+INT16
or in
(int32_t => int16_t) ((int16_t => int32_t) INT16 + (int16_t => int32_t) INT16)
provided the addition can be done without overflow.

int promotion: Is the following well-defined?

Suppose that on a C implementation (e.g. on a x86 C compiler) USHRT_MAX = 65535 and INT_MAX = 2147483647. Is, then, the following statement well-defined?
unsigned short product = USHRT_MAX * USHRT_MAX;
According to the following in the C99 standard both operands are promoted to int (since int can represent all possible values of unsigned short) and, therefore, the result is not well-defined, since an overflow will occur (65535 ^ 2 = 4294836225 > 2147483647), which means that the value of product is not well-defined:
6.3.1.1-1
If an int can represent all values of the original type, the value is
converted to an int; otherwise, it is converted to an unsigned int.
These are called the integer promotions.(48) All other types are
unchanged by the integer promotions.
48) The integer promotions are applied only: as part of the usual
arithmetic conversions, to certain argument expressions, to the
operands of the unary +, -, and ~ operators, and to both operands of
the shift operators, as specified by their respective subclauses.
However, according to the following, the result is well-defined, since computations involving unsigned operands do not overflow:
6.2.5-9
The range of nonnegative values of a signed integer type is a subrange
of the corresponding unsigned integer type, and the representation of
the same value in each type is the same.(31) A computation involving
unsigned operands can never overflow, because a result that cannot be
represented by the resulting unsigned integer type is reduced modulo
the number that is one greater than the largest value that can be
represented by the resulting type.
Does the variable product in the aforementioned statement have a well-defined value?
EDIT: What should happen in the following case?
unsigned short lhs = USHRT_MAX;
unsigned short rhs = USHRT_MAX;
unsigned short product = lhs * rhs;
The promotion wins.
Says section 5.2.4.2.1 about the constants USHRT_MAX etc.:
The values given below shall be replaced by constant expressions suitable for use in #if preprocessing directives. Moreover, except for CHAR_BIT and MB_LEN_MAX, the following shall be replaced by expressions that have the same type as would an expression that is an object of the corresponding type converted according to the integer promotions.
So the multiplication is on ints, and involves no unsigned operands, unambiguously, there is no conforming way to implement USHRT_MAX to get an operation involving unsigned operands if USHRT_MAX < INT_MAX. Thus you have overflow, and undefined behaviour.
Regarding the added question
EDIT: What should happen in the following case?
unsigned short lhs = USHRT_MAX;
unsigned short rhs = USHRT_MAX;
unsigned short product = lhs * rhs;
That is exactly the same situation. The operands of * are subject to the integer promotions, all values of type unsigned short can be represented as ints by the assumption on the values of USHRT_MAX and INT_MAX, so the multiplication is on ints, and with the specified values overflows.
You need to convert at least one operand to an unsigned type that is not promoted to int in oerder to have the multiplication be performed on unsigned operands.
You get UB since by the time the multiplication operator is applied, its operands are already signed integers (because of the promotions to int occurring first).
You can work-around that with this:
unsigned short product = USHRT_MAX * (unsigned)USHRT_MAX;
Proof that (unsigned)some_integer stays unsigned:
#include <stdio.h>
int main(void)
{
printf("1u * (-1) = %f\n", (((unsigned)1) * (-1)) + 0.0);
printf("1 * (-1) = %f\n", (1 * (-1)) + 0.0);
return 0;
}
Output (ideone):
1u * (-1) = 4294967295.000000
1 * (-1) = -1.000000
Good catch, btw.

Resources