Can a int value added to a float value? - c

/**Program for internal typecasting of the compiler**/
#include<stdio.h>
int main(void)
{
float b = 0;
// The Second operand is a integer value which gets added to first operand
// which is of float type. Will the second operand be typecasted to float?
b = (float)15/2 + 15/2;
printf("b is %f\n",b);
return 0;
}
OUTPUT : b is 14.500000

Yes, an integral value can be added to a float value.
The basic math operations (+, -, *, /), when given an operand of type float and int, the int is converted to float first.
So 15.0f + 2 will convert 2 to float (i.e. to 2.0f) and the result is 17.0f.
In your expression (float)15/2 + 15/2, since / has higher precedence than +, the effect will the same as computing ((float)15/2) + (15/2).
(float)15/2 explicitly converts 15 to float and therefore implicitly converts 2 to float, yielding the final result of division as 7.5f.
However, 15/2 does an integer division, so produces the result 7 (there is no implicit conversion to float here).
Since (float)15/2 has been computed as a float, the value 7 is then converted to float before addition. The result will therefore be 14.5f.
Note: floating point types are also characterised by finite precision and rounding error that affects operations. I've ignored that in the above (and it is unlikely to have a notable effect with the particular example anyway).
Note 2: Old versions of C (before the C89/90 standard) actually converted float operands to double in expressions (and therefore had to convert values of type double back to float, when storing the result in a variable of type float). Thankfully the C89/90 standard fixed that.

Rule of thumb: When doing an arithmetic calculation between two different built-in types, the "smaller" type will be converted into the "larger" type.
double > float > long long(C99) > long > short > char.
b = (float)15/2 + 15/2;
Here the first part, (float)15/2 is equivalent to 15.0f / 2. Because an operation involving a "larger" type and a "smaller" type will yield a result in the "larger" type, (float)15/2 is 7.500000, or 7.5f.
When it comes to 15/2, since both operands are integers, the operation is done only on integer level. Therefore the decimal point is stripped (from int), and only gives 7 as a result.
So the expression is calculated into
b = 7.5f + 7;
No doubt you'll have 14.500000 as the final result, because it's exactly 14.5f.

b = (float)15/2 + 15/2;
The first one((float)15/2) will work fine. The second one will also work but will be converted into an integer first, so you will lose precision. Like:
b = (float)15/2 + 15/2;
b = 7.500000f + 7
b = 14.500000

It's worth asking: if an integer value could not be added to floating-point value, what would the symptom be?
Compiler issues error or warning message.
Something gets truncated; you don't get the result you want.
Undefined behavior: you might or might not get the result you want, and the compiler might or might not warn you about it.
But in fact none of these things happen. When you add an integer to a floating-point value, the compiler automatically converts the integer to a floating-point value so it can do the addition that way, and this is perfectly well defined. For example, if you have the code
double d = 7.5;
int i = 7;
double result = d + i;
the compiler interprets this just as if you had written
double result = d + (double)i;
And it works this way for just about all operations: the same logic is applied when you subtract, multiply, or divide a floating-point value and an integer.
And it works this way for just about all types. If you add a long int and an int, the plain int automatically gets converted to a long.
As a general rule (and I really can't think of too many exceptions), the compiler always wants to do arithmetic on two values of the same type. So whenever you have two values of different type, the compiler will just about always convert one of them for you. The full set of rules for how it does this are rather elaborate, but they're all supposed to make sense, and do what you want. The full set of rules is called the usual arithmetic conversions, and if you do a Google search on that phrase you'll find lots of explanations.
One case that does not necessarily do what you want is when the two variables are not different types. In particular, if the two variables are both integers, and the operation you're doing is division, the compiler doesn't have to convert anything: it divides the integer by the integer, discarding any remainder, and gives you an integer result. So if you have
int i = 1;
int j = 2;
int k = i / j;
then k ends up containing 0. And if you have
double d = i / j;
then d ends up containing 0 also, because the compiler follows exactly the same rules when performing the division; it doesn't "peek outside" to see that it's going to need a floating-point result.
P.S. I said, "As a general rule, the compiler always wants to do arithmetic on two values of the same type", and I said I couldn't think of too many exceptions. But if you're curious, two exceptions are the << and >> operators. If you have x << y, where x is a long int and y is a plain int, the compiler does not have to convert y to a long int first.

Related

What is the order in which C expressions are evaluated

int main(){
char a = 5;
float b = 6.0;
int c = a + b;
return c;
}
Looking at the generate instructions with gcc, the above code is evaluated like this:
Load 5 and convert it to float as a
Load 6 as b
Add a and b
Convert the result to an integer and return
Does gcc not care about the return type while it's dealing with the expression?
It could have converted b to an int right off the bat as everything else is an integer type.
Is there a rule which explains how one side of an expression is evaluated first regardless of what the other side is?
You ask "Is there a rule?" Of course there is a rule. Any widely used programming language will have a huge set of rules.
You have an expression "a + b". a has type char, b has type float. There's a rule in the C language that the compiler has to find a common type and convert both to the common type. Since one of the values is a floating-point type, the common type must be a floating-point type, which is float, double, or long double. If you look closer at the rules, it turns out the common type must be float or double, and the compiler must document this. It seems the compiler chose "float" as the common type.
So a is converted from char to float, b is already float, both are added, the result has type float. And then there's a rule that to assign float to int, a conversion takes place according to very specific rules.
Any C compiler must follow these rules exactly. There is one exception: If the compiler can produce the results that it is supposed to produce then it doesn't matter how. As long as you can't distinguish it from the outside. So the compiler can change the whole code to "return 11;".
In the C language, partial expressions are evaluated without regard how they are used later. Whether a+b is assigned to an int, a char, a double, it is always evaluated in the same way. There are other languages with different rules, where the fact that a+b is assigned to an int could change how it is evaluated. C is not one of those languages.
If you change it to:
int main(){
char a = 5;
float b = 6.6;
int c = a + 2*b;
return c;
}
then it becomes clear that you have to keep the float 18.2 until the end.
With no optimizations, gcc acts as if this could happen and does a lot of conversions.
With just -O it already does the math itself and directly returns the final integer, even in above example.
There is no in-between reasoning and short-cut here. Why simplify from 5+6.0 to 5+6 but not to 11? Either act stupid and do cvtsi2ss xmm1,eax (and back etc.), or then tell them directly 11.

C adding int and float, and the type changed

I'm not sure my understanding is right here
int i = 5;
float f = 3.9;
int result = i + f;
then when int and float are being added, 8.9 becomes 8?
does this mean when adding smaller data type to bigger datatype gives the answer in smaller data type?
or is this pringting int because it's type casted because result is declared in int? if so how's this different from putting (int)in front of i + f?
In C, when two real1 arithmetic operands are added, they are converted to a common type:
If either operand is long double, the other is converted to long double, and the result is long double.
Otherwise, if either operand is double, the other is converted to double, and the result is double.
Otherwise, if either operand is float, the other is converted to float, and the result is float.
Otherwise, both operands are integers, and additional rules for integer operands apply.
So, in your i + f, i is converted to a float, the values are added, and the result is a float.
You then assign it to an int. In assignment, the value is converted to the type of the destination. So the float sum is converted to int.
The rules for converting arithmetic operands are called “the usual arithmetic conversions” and are specified in C 2018 6.3.1.8. The rules for assignment are specified in C 6.5.16.1.
Note
1 Complex numbers are handled similarly.
In your specific case the result is 8 because the result of the addition is put into an int.
You can imagine the data types as boxes, each data type has a box size associated with it, while adding a float and an int their corresponding box sizes do not match, an int can be placed inside the box of a float. This is why logically the result of the addition is 8.9 . Unfortunately you want to put this result into a smaller box and this leads to the casting that you mention. Basically bigger boxes have a problem when put into smaller ones, you have to get rid of something.
Answering your questions in order:
Q1:when int and float are being added, 8.9 becomes 8?
A:depends in what you will store it, if you define your result as float you will get the 8.9 result otherwise in your case the part after the deciaml point is thrown away because it can't be stored inside an int "box".
Q2: does this mean when adding smaller data type to bigger datatype gives the answer in smaller data type?
A: not really, again depends in what you will store your result.
Q3:is this pringting int because it's type casted because result is declared in int?
A: yes this assumption is right.
Q4: if so how's this different from putting (int)in front of i + f?
A: while their result are the same for this specific scenario, the difference makes more sense in other scenarios. Imagine having instead of int result a float result, then the value in result would be 8.9 as expected, but if you are to use this casting (int)(i+f)
you would put the result of the addition into a smaller box thus losing data, later on you would put it back into a bigger box but you had already lost some bits and the value in result would be 8.0.
Generally you are safe to cast numeric data types from smaller to bigger ones, this way you won't lose any bits along the way. The other way around if you cast float to int or int to char and so on, you may obtain bad results.

How to print a double data type in C [duplicate]

This question already has answers here:
How to divide 2 int in c?
(5 answers)
C - double result returning the value of 0 [duplicate]
(2 answers)
Closed 4 years ago.
Why in C, when I print a double type variable with %f it shows 8.000000… but that is not the desire result . i want a result like 8.5000 how can i achieve this?
int main(){
int i, j;
double k;
i=8; j=9;
k = (i+j)/2;
printf("%f", k);
}
The problem is not with the format specifier, rather with the arithmatic operation.
By saying
k = (i+j)/2;
where, i and j and 2 - all are ints, you're doing integer division, and then, storing the result in a double. For integer division,
[..] When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded [...]
which is commonly known as "truncation towards zero". To avoid that from happenning, you need to enforce floating point arithmetic, by forcing or casting one of the operands to double (or float). Something like
k = ((double)i+j)/2;
or,
k = (i+j)/2.0; //2.0 is of type double
The point here is, if, in the operation, one of the operands is of the higher rank (double or float is higher ranked that int), all the operands will first be converted to the higher rank, and then the operation will be performed and the result will be of the type of the higher ranked type.
Since i and j are int the result is cast first to int. This looses precision. Explicitly cast to double k = (double)(i+j)/2
Comments are right. To better understand that: A C expression is evaluated in 'one chunk'. The right side of your assignment (i+j)/2 is a complete expression. Since it does only includes integer values, the arithmetic chosen will also be of integer type, (which leads to truncation of the result), creating temporary integer value (invisible to you), which is then assigned to a double.
You need to make at least one of the values in your expression a double (or float), then the compiler will promote all the arithmetic to floating point and the temporary value will also be of float type.
If you don't have a constant in your expression, you can also use casts:
((float)i+J)/2
It does not matter which of the 3 items get the cast, just one is enough.

Why does (int) float == float.truncate instead of garbage (How does casting actually work?)

Going on understanding of these datatypes as primitives
(int) char, and (char) int are intepretations of data. (int) c gives the integer value of that character, and (char) 14 gives you back the character encoded by 14.
I've always understood this as being a "memory parse", such that it just takes the value at that position and then applies a type filter to it.
Given that floating points are stored as some version of scientific notation, what is stored in memory should be garbage as an integer. Looking into this utility http://www.h-schmidt.net/FloatConverter/IEEE754.html it appears that the whole number portion is separated.
However, since this is in the higher portion of memory, how does the int cast know to "reformat"? Does the compiler identify that it was a float and apply special handling, or what's going on?
Your understanding of casts is completely wrong. Casts are nothing but explicit requests for a value conversion from one type to another. They do not reinterpret the representation of one type as if it had a different type. The source code:
float f = 42.5;
int x;
x = (int)f;
simply instructs the compiler to produce code that truncates the floating point value of the expression f to an integer and store the result in the object x.
I've always understood this as being a "memory parse", such that it just takes the value at that position and then applies a type filter to it.
That is an incorrect understanding.
The language specifies conversions between the fundamental arithmetic types. Lookup "Usual Arithmetic Conversions" on the web. You will find a lot of links that describe that. For converting a floating point type to an integral type, this is what the C99 Standard has to say:
6.3.1.4 Real floating and integer
1 When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.
float f = 4.5;
int i = (int); // i is 4
f = -6.3;
i = (int)f; // i is -6

Type of literal operands

I don't think most compilers care if, for instance, you don't append the f to a variable of float type. But just because I want to be as explicit and accurate as I can, I want to express the correct type.
What is the type of the result of two literal operands of different types, or does it depend on the circumstances? e.g.:
int i=1.0f/1;
float f=1.0f/1;
The compiler wouldn't complain in both these instances, is it because of its tolerant view of literal types or because the type of the result of the operation is always converted according to the context?
First, compilers do care about the f suffix. 1.0 is a double. 1.0f is a float. For instance:
printf("%.15f %.15f\n", 0.1f, 0.1);
produces 0.100000001490116 0.100000000000000 (note that the second number is not the real 0.1 any more than the first, it is just closer to it).
This matters not only to determine what numbers can and cannot be represented but also to determine the type of the operations this constant is involved in. For instance:
printf("%.15f %.15f\n", 1.0f/10.0f, 1.0/10.0);
produces the same output as before. What is important to notice here is that 1 and 10 are both representable exactly as float as well as as double. What we are seeing is not rounding taking place at the literal level, but the type of the operation being decided from the type of the operands.
Compilers are not being lenient about your examples. They are strictly applying rules that you can find in the relevant standard, especially sections 6.3.1.4 and 6.3.1.5.
The first one divides a float by an int, which always results in a float (as does dividing an int by a float). This float result is then converted into an int to be stored in i.
The second one takes the float that resulted from the operation, and assigns it to a float variable, preserving the floatness.
There are two separate issues here: How literals with or without suffixes are interpreted by the compiler, and the result of operations performed on mixed numeric types.
The type of literals is important in other contexts, for example (assuming f is a float):
f = f + 1.0; // Cast `f` to double, do a double-precision add, and case the result back.
f = f + 1.0f; // Single-precision addition.
Note that some compilers provide a relaxed mode, where both of them will generate the same code.

Resources