I found a strange (to me) behavior of casting to int in C. Appologies if that's a basic question but I'm unable to find the answer to why the following code produces an unexpected result.
#include <stdio.h>
int main(void)
{
printf("1000 * 0.1 = %d\n", (1000 * 0.1));
printf("1000 * (10/100) = %d\n", (1000 * (10/100)));
printf("(int)1000 * 0.1 = %d\n", (int)(1000 * 0.1));
printf("(int)1000 * (10/100) = %d\n", (int)(1000 * (10/100)));
return 0;
}
Result with both -O0 and -O3 is the same:
1000 * 0.1 = -957043896
1000 * (10/100) = 0
(int)1000 * 0.1 = 100
(int)1000 * (10/100) = 0
I expect a non-sensical result for the first two (I don't know why but I expect passing a double to int argument shouldn't work). However the difference between 3 and 4 is puzzling to me. I expected (10/100) to be calculated on compile time and render the same result as 3.
Can someone explain to me why such result happens, and what is the proper/safe way to do integer-based divisions here?
printf("1000 * 0.1 = %d\n", (1000 * 0.1));
// int double
int * double gives a double. You're trying to print a double with "%d" which is Undefined Behaviour (usually written UB). Try printf("1000 * 0.1 = %f\n", 1000 * 0.1);
printf("1000 * (10/100) = %d\n", (1000 * (10/100)));
// int int int
int / int does integer division, with no decimals. 10/100 yields 0 (and a remainder of 10)
printf("(int)1000 * 0.1 = %d\n", (int)(1000 * 0.1));
// int double
the double 100.0 is converted to int and printed naturally. Note that it's possible that 1000 * 0.1 would generate 99.999999635264318 which would convert to 99
printf("(int)1000 * (10/100) = %d\n", (int)(1000 * (10/100)));
// int int int
10/100 is integer division ... is 0 in this case, same as 2nd statement above.
There is a difference for example between these two calls of printf
printf("1000 * 0.1 = %d\n", (1000 * 0.1));
printf("1000 * (10/100) = %d\n", (1000 * (10/100)));
In the firs call the expression 1000 * 0.1 has the type double but you are using the incorrect conversion specifier %d that is designed for objects of the type int.
In the second call the expression 1000 * (10/100) indeed has the type int. Pay attention to that the casting of the expression to the type int like (int)(1000 * (10/100)) is redundant and does not make a sense. Instead you could write for example ( int )( 1000 * (10.0/100) ). So this call is correct. However the value of the original outputted expression is equal to 0 due to the integer arithmetic.
Related
I have this issue where I need to print float number while I use int parameters in function.
float lift_a_car(const int stick_length, const int human_weight, const int car_weight) {
return (stick_length*human_weight)/(car_weight+human_weight);
}
I'm checking it by using:
printf("%.4f\n", lift_a_car(2, 80, 1400));
It only returns 0.0000.
The reason for this is, that in C every calculation is made with the most complex type in use. In your case this type is int, because int/int is treated as an integer division. The same for the addition and multiplication. To fix this, you have to cast the integers to floats explicitly, otherwise it will only be done at the end.
Your code return (stick_length*human_weight)/(car_weight+human_weight); equals the following operation:
int t1 = stick_length * human_weight; // 2 * 80 = 160
int t2 = car_weight * human_weight; // 1400 * 80 = 112000
int t3 = t1 / t2; (integer division) // 160 / 112000 = 0
return (float) t3;
But what you want is to do this:
return ((float) stick_length*human_weight)/((float) car_weight+human_weight);
// or
return (float) (stick_length*human_weight)/(car_weight+human_weight);
This will be evaluated like:
float t1 = (float) stick_length * human_weight; // 2.0f * 80 = 160.0f
float t2 = (float) car_weight + human_weight; // 160.0f * 140 = 112000.0f
float t3 = t1 / t2; (floating division) // 160.0f / 112000.0f = 0.0014...
// or
int t1 = stick_length * human_weight; // 2 * 80 = 160
int t2 = car_weight + human_weight; // 160 * 140 = 112000
float t3 = (float) t1 / t2; (floating division) // 160.0f / 140 = 0.0014...
The calculation
(stick_length*human_weight)/(car_weight+human_weight)
is an all integer calculation with an integer result. You should cast at least one of the variables or intermediate results to a floating point value.
Like for example
(float) (stick_length*human_weight)/(car_weight+human_weight)
That will convert the result of stick_length*human_weight into a float value, making the division a floating-point operation with a floating-point result.
Although the answer of our programming dude is correct, it looks quite dangerous:
Indeed, this is integer arithmetic:
(stick_length*human_weight)/(car_weight+human_weight)
Indeed, this is floating point arithmetic:
(float) (stick_length*human_weight)/(car_weight+human_weight)
But why? Simply because typecasting precedes multiplication (or division): it's the same as:
((float) (stick_length*human_weight))/(car_weight+human_weight)
But beginners might not be aware of that and might start to do stuff like:
(float) ((stick_length*human_weight)/(car_weight+human_weight))
=> which will again give a bad result.
Therefore I would propose to perform a typecasting, as narrow as possible, something like:
((float) stick_length*human_weight)/(car_weight+human_weight)
Type-casting while returning the calculated value should help you. Otherwise, you are returning 160/1480 which is 0 unless type-casting is not applied.
This code should help:
float lift_a_car(const int stick_length, const int human_weight, const int car_weight)
{
return ((float)(stick_length*human_weight))/((float)(car_weight+human_weight));
}
OP's code is doing integer division and so gets a truncated quotient.
For fun, a non-floating point, cast-less, integer approach. Useful in small processors where FP support is expensive.
void print_lift_a_car(int stick_length, int human_weight, int car_weight) {
// Use wider types like long or long long to avoid overflow.
// Scale integer math by 10000 as "%.4f" was desired.
long num = 10000L * stick_length * human_weight;
long den = 0L + car_weight + human_weight; // A long instead of an int addition.
long ratio = (num + den/2) / den; // Rounded division.
printf("%ld.%04ld\n", ratio/10000, ratio%10000);
}
May also want to handle den == 0 and ratio < 0 with additional code.
I was surprised to find that a floating-point-to-integer conversion rounded up instead of truncating the fractional part. Here is some sample code, compiled using Clang, that reproduces that behavior:
double a = 1.12; // 1.1200000000000001 * 2^0
double b = 1024LL * 1024 * 1024 * 1024 * 1024; // 1 * 2^50
double c = a * b; // 1.1200000000000001 * 2^50
long long d = c; // 1261007895663739
Using exact math, the floating-point value represents
1.1200000000000001 * 2^50 = 1261007895663738.9925899906842624
I was expecting the resulting integer to be 1261007895663738 due to truncation but it is actually 1261007895663739. Why?
Assuming IEEE 754 double precision, 1.12 is exactly
1.12000000000000010658141036401502788066864013671875
Written in binary, its significand is exactly:
1.0001111010111000010100011110101110000101000111101100
Note the last two zeros are intentional, since it's what you get with double precision (1 bit before fraction separator, plus 52 fractional bits).
So, if you shift by 50 places, you'll get an integer value
100011110101110000101000111101011100001010001111011.00
or in decimal
1261007895663739
when converting to long long, no truncation/rounding occurs, the conversion is exact.
Using exact math, the floating-point value represents ...
a is not exactly 1.12 as 0.12 is not dyadic.
// `a` not exactly 1.12
double a = 1.12; // 1.1200000000000001 * 2^0
Nearby double values:
1.11999999999999988... Next closest double
1.12 Code
1.12000000000000011... Closest double
1.12000000000000033...
Instead, let us look closer to truer values.
#include <stdio.h>
#include <float.h>
int main() {
double a = 1.12; // 1.1200000000000001 * 2^0
double b = 1024LL * 1024 * 1024 * 1024 * 1024; // 1 * 2^50
int prec = DBL_DECIMAL_DIG;
printf("a %.*e\n", prec, a);
printf("b %.*e\n", prec, b);
double c = a * b;
double whole;
printf("c %.*e (r:%g)\n", prec, c, modf(c, &whole));
long long d = (long long) c;
printf("d %lld\n", d);
}
Output
a 1.12000000000000011e+00
b 1.12589990684262400e+15
c 1.26100789566373900e+15 (r:0)
d 1261007895663739
This question already has answers here:
What is the behavior of integer division?
(6 answers)
Why do we separately cast to "float" in an integer division?
(4 answers)
Closed 5 years ago.
I'm actually totally stuck I don't understand the behavior of this function:
#include <stdio.h>
typedef struct s_resolution
{
int x;
int y;
float fx;
float fy;
} t_resolution;
typedef struct s_pixel_info
{
int tablen;
t_resolution resolution;
char name;
int line;
int pos_suite[6];
int suite[6];
} t_pixel_info;
void get_proportion_ratio(t_pixel_info DataB, t_pixel_info pix_info,
t_resolution *proportion)
{
proportion->fx = (float)(DataB.resolution.x / pix_info.resolution.x);
//I also tried without the cast
proportion->y = (int)(DataB.resolution.y / pix_info.resolution.y * 100);
//if (proportion->y != 100)
printf("%d | %d | %d\n",proportion->y, DataB.resolution.y, pix_info.resolution.y);
}
int main()
{
t_pixel_info DataB;
t_pixel_info pix_info;
t_resolution proportion;
DataB.resolution.x = 5;
pix_info.resolution.x = 10;
DataB.resolution.y = 5;
pix_info.resolution.y = 10;
get_proportion_ratio(DataB, pix_info, &proportion);
}
DataB.resolution.y, pix_info.resolution.y and proportion->y are all Int type.
My problem is that I have this result:
0 | 5 | 10
The operation only works when the result is 100... I must be missing something obvious but I've no idea what.
All of your divisions are being done on integers. Take this expression:
5 / 10 * 100
This groups as:
(5 / 10) * 100
This evaluates to 0: 5 / 10 is 0, and 0 * 100 is still 0. Casting the result after the fact doesn't change it.
If you multiply by 100 before you divide, you will obtain two more digits of precision:
100 * 5 / 10
This evaluates to 50: 100 * 5 is 500, and 500 / 10 is 50.
You could also perform the arithmetic in floating point, e.g.
(double) 5 / (double) 10 * (double) 100
Or you could just cast the first operand and let the standard arithmetic conversions handle the rest; the result is equivalent:
(double) 5 / 10 * 100
In either case, the result will be 50.0
Since resolution.x and resolution.y are ints, the division between them will done as integer division, which keeps only the "whole" part of the division. If you want to perform a floating point ("regular") division, you should cast to a floating point type before performing the division. E.g.:
proportion->fx = ((float) DataB.resolution.x) / ((float) pix_info.resolution.x);
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
double a;
double b;
double q0 = 0.5 * M_PI + 0.5 * -2.1500000405000002;
double q1 = 0.5 * M_PI + 0.5 * 0.0000000000000000;
double w0 = 0.5 * M_PI + 0.5 * -43000.0008100000050000;
double w1 = 0.5 * M_PI + 0.5 * -0.0000000000000000;
double m = 1;
double g = 43000000.81;
double l1 = 0.1;
double l2 = 0.1;
double h = 0.0001;
a = ((-g / l1) * sin(q0) + (sin(q1 - q0) * (cos(q1 - q0) * (w0 * w0 + (g / l1) * cos(q0)) + l2 * (w1 * w1 / l1))) / (m + pow(sin(q1 - q0), 2)));
a = h * a;
b = h * ((-g / l1) * sin(q0) + (sin(q1 - q0) * (cos(q1 - q0) * (w0 * w0 + (g / l1) * cos(q0)) + l2 * (w1 * w1 / l1))) / (m + pow(sin(q1 - q0), 2)));
printf("%.20lf ", a);
printf("%.20lf", b);
return 0;
}
I do the same calculations with a and b, just with the difference that I get the value of a in two steps, and the b in one.
My code returns:
-629.47620126173774000000 -629.47620126173763000000
What is the reason of the difference between the two last decimals?
The C Standard (99 and 11) says:
The values of operations with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type.
So in an expression such as h*(X+Y) as you have in the assignment to b, the implementation is allowed to use greater precision for the intermediate result of X+Y than can possibly be stored in a double, even though the type of the subexpression is still considered to be double. But in a=X+Y; a=h*a;, the first assignment forces the value to be one that actually can be stored in a double, causing a slightly different result.
Another possibility is that the compiler has done "floating point contraction". To quote the C Standard again,
A floating expression may be contracted, that is, evaluated as though it were an atomic operation, thereby omitting rounding errors implied by the source code and the expression evaluation method.
This would most likely happen if the processor has a single instruction that can do a floating point addition and then a multiplication in one step, and the compiler decided to use it.
Assuming one or both of these is the cause, your value b is likely a more accurate representation of the computation you specified (given that all the inputs were restricted to values which can be represented in a double).
The cppreference page about macro FLT_EVAL_METHOD discusses both of these issues in a little more detail. It may be interesting to find out your value of FLT_EVAL_METHOD and play with #pragma STDC FP_CONTRACT OFF.
The answer is because in the float numbers calculations the equation a=bcde does not have to be equal to x = bc y = de and a.= xy.
It is because floating point arithmetic has a limited precision.
I have the following in a program (part of a much larger function, but this is the relevant testing bit):
int test = 100 + (100 * (9 / 100));
sprintf (buf, "Test: %d\n\r", test);
display_to_pc (buf, player);
Basically it amounts to:
x = a + (a * (b / 100))
Where a is a given figure, b is a percentage modifier, and x is the result (the original plus a percentage of the original)... I hope that makes sense.
It gives me:
Test: 100
I thought the math in my head might be wrong, but I've checked several calculators and even the expression evaluator in my IDE, and they all give me the expected result of 109 for the first expression.
Can anyone enlighten me as to what I'm missing here?
Thanks much. :)
Replace
int test = 100 + (100 * (9 / 100));
with
int test = 100 + (100 * 9 / 100);
// x = a + (a * b / 100)
and it will work as expected. 9 / 100 is performed using integer division; the nearest integer to .09 is 0 (and 0 * 100 is still 0).
Doing the multiplication first results in 900 / 100, which gives you the 9 that you were expecting.
If you need more than integer precision, you may need to go the floating point route.
You're using integer math.
9/100 = 0.
100 + (100 * (0) = 100.
Your calculators use floating point math, and can handle decimals appropriately.
As others have pointed out, the problem is that you are doing integer arithmethic. You need to do the calculation as floating point by casting the variable to double or using a double constant, then allow truncation to give you just the integer portion.
x = a + (a * (b / 100.0));
or
x = a + (a * ((double)b / 100)));
Your mistake is that 9 / 100 is interpreted as integer division, and evaluates to 0 and not 0.09.
You can write 9 / 100.0 instead, or rearrange the expression.
int test = 100 + (100 * (9 / 100));
9/100 = 0
0 * 100 = 0
100 + 0 = 100
you are using integer division so 9 / 100 is zero so test = 100 + 0 = 100
Use Daniel L's answer if you will only be working with expressions that will result in whole integer values. If the values you'll be working with are less clean, use double literals instead of integer literals:
int test = 100.0 + (100.0 * (9.0 / 100.0));
The answer of 9/10 gets truncated to 0, and then you multiply that by 100, and then add 100 to it.
Change:
int test = 100 + (100 * (9 / 100));
to
int test = (int)(100 + (100 * (9 / 100.0)));
and see if it works as expected.
EDIT: wow. Lots of answers while I was typing. Most of them will work, too.
You should be using floating point arithmetic so 9/100 becomes 0.09.
int test = 100.0 + (100.0 * 9.0 / 100.0);
You are using integers for your variable types, so the inner most expression (9 / 100) will result in a 0. Then the next expression would be 100 * 0, which is 0, and finally 100 + 0...
To get your desired result try using float instead:
float test = 100.0 + (100.0 * (9.0 / 100.0));
printf("result: %0.2f\n", test);