Why does integer division truncation not occur here? - c

I was going through the examples in K&R, and stumbled upon this bit of code:
celcius=5 * (fahr-32) / 9;
The author says that we can't use 5/9 since integer division truncation will lead to a value of 0.
The program however, outputs 17 as answer when fahr=0. By my calculations, (0-32)/9 should lead to -3 (due to truncation) and then -3*5 = -15, and NOT -17. Why does this happen?

(0 - 32) is first multiplied by 5, giving -160. -160 / 9 = -17.

What the author say is that one should not use
celsius = (fahr-32)*(5/9);
As for your question,
celsius = 5 * (fahr-32) / 9;
is different from
celsius = 5 * ((fahr-32) / 9);
In the later case, you would indeed get -15 when fahr=0.

Related

Noob Question! Why does this always return 0? [duplicate]

This question already has answers here:
Integer division returns 0 in C
(2 answers)
Closed last year.
I wanted to get the convert from Fahrenheit to Celsius with this program, but it always returns 0. Why?
#include <stdio.h>
int main() {
int fahr = 15, celsius;
celsius = (5 / 9) * (fahr - 32);
printf("%d\n", celsius);
return 0;
}
It seems that the problem is in celsius = (5 / 9) * (fahr - 32);. I already know that celsius = 5 * (fahr - 32) / 9; fixes the problem. But why did the first one return zero?
In short, when performing arithmetic operations, C compiler has to choose which number format to use. To do this, it won't pick the one of the first operand, nor try to guess what the result would be, but will opt for the most precise type of both operand.
In your particular example, (5 / 9) use two integers, so the result will remain an integer too, thus zero.
A quick way to fix this is to directly specify a decimal in your constant :
(5 / 9.0)
The other answers and comments are steering you in the correct direction with regards to integer division vs floating point. But if you want to avoid floating point altogether and still produce a correct answer (as an integer), then structure your equation such that division comes last.
Since (x/y) * z is the same as (x * z)/y, then this holds:
celsius = (5 * (fahr - 32)) / 9;
In C, if you do a division between two integer type variables, you get an integer back.
So this:
(5 / 9)
gets a result of 0.555, which is then rounded down. (In C, integer division rounds towards zero.)
If you changed it like this, it would be floating point division instead:
celsius = (5.0 / 9) * (fahr - 32);

unary operator in avr: undefined behavior?

I had the issue that
voltage = voltage*2/3;
and
voltage *= 2/3;
gave different results. The variable is uint16_t and is running on an 8bit AVR microcontroller
First statement gave the correct result, second statement always returned 0.
Some friends of mine told me that unary operators should not be used in general which made me think since I also use things like PORTC &= ~(1 << csBit);. For compiling, I use avr-gcc if that might give you an idea.
Thanks in advance for your help
edit#1:
OK, I understood that = is not an unary operator. Also the underlying difference is that '''=''' is starting from the right and ''''*, /''' is starting from left.
I guess for uints, both statements are not correct and I would have to write voltage = (uint16_t)((float)voltage*(float)2/3)
and thanks #Lundin for pointing out how to correctly react to replies
voltage = voltage*2/3 multiplies voltage by 2, divides by 3, and stores the result in voltage.
voltage *= 2/3 divides 2 by 3, multiplies the result by voltage and stores the result of that in voltage. Integer division truncates, so 2/3 produces zero.
None of those are unary operators.
You’re being bitten by a combination of differing order of operations and integer arithmetic.
Arithmetic operators are left-associative, so
voltage = voltage * 2 / 3;
is parsed as
voltage = (voltage * 2) / 3;
you’re dividing the result of voltage * 2 by 3, whereas
voltage *= 2 / 3;
is equivalent to
voltage = voltage * (2 / 3);
you’re multiplying voltage by the result of 2/3, which is 0.
The problem isn’t so much the *=, the problem is that
(a * b) / c != a * (b / c)
the difference is that in voltage = voltage * 2 / 3, voltage is multiplied by 2 and the result divided by 3:
voltage = 5
5 * 2 = 10
10 / 3 = 3
while in voltage * = 2 / 3, since you are using uint16_t, and therefore the decimals are truncated it is first performed 2/3 and the result multiplied by voltage:
votage = 5
2 / 3 = 0
voltage = 5 * 0 = 0
to avoid this you should, for example make the calculation run in floating point before it is assigned to voltage, for example by adding ".0" somewhere:
voltage = voltage * 2.0 / 3 = 3
voltage *= 2.0 / 3 = 3

SEH Exceptions faulting my programs logic?

INFORMATION
My c++ program has no whole program optimization, has a Multi-Byte Character Set, and has enabled C++ Exceptions with SEH Exceptions (/EHa).
The following code reads information and then uses the read information in a simple math equation to determine the outcome.
PROBLEM
Here is an example to the situation that occurs!
For argument sake, underneath will show predetermined integer values, then the logic when the code is executed with these values.
healthalert = 19;
healthpercentage = 0; // THE PROBLEM IS HERE
health = 840;
fixedhealth = 840; // THIS SHOULD BE 885 AND NOT 840; IT IS 840 DUE TO HEALTHPERCENTAGE BEING 0 WHEN IT SHOULDN'T BE!
So in the first line of code determining the value of healthalert, the value is set to 19.
HOWEVER, when the equation for healthpercentage is calculated, even though healthalert is set to 19, the outcome for healthpercentage is zero?!?!?!?!!? WHY is this?
The next line is then executed and the value of health is 840.
Lastly, the value of fixedhealth is also 840; however, this should not be the case as it should be around 885. The reason fixedhealth is 840 is due to the math equation for healthpercentage outcoming to 0 when it shouldn't be!
Please help!
You mention SEH exceptions, but it looks like a simple case of integer division to me. You say healthalert is 19. Therefore 20 - healthalert is 1. Therefore, (20 - healthAlert)/20 is zero, because all the numbers involved are integers. Change that 20 to a 20.0, then cast back to an int at the end, and you should be fine.
Edit: Or do what Dark Falcon suggested seconds before I hit submit. :)
You don't give the variable types, but I'll bet they are integers. In that case, you're doing integer division, which truncates any fractional portion.
healthpercentage = (20 - healthalert) / healthalert * 100;
healthpercentage = (20 - 19) / 19 * 100;
healthpercentage = (int)(1 / 19) * 100;
healthpercentage = 0 * 100;
healthpercentage = 0;
If you want to continue to use integers, reorder operations so the multiplication is first:
healthpercentage = (20 - healthalert) * 100 / healthalert;
healthpercentage = (20 - 19) * 100 / 19;
healthpercentage = 1 * 100 / 19;
healthpercentage = (int)(100 / 19);
healthpercentage = 5;
Of course, even with this, the numbers don't match what you specified, so I don't understand your math. Perhaps this will still set you on the right track, however.

Issue with fahrenheit conversion formula in C [duplicate]

This question already has answers here:
Why does dividing two int not yield the right value when assigned to double?
(10 answers)
Why does division result in zero instead of a decimal?
(5 answers)
Closed 9 years ago.
When writing a program in C to convert celsius to fahrenheit, the following formula gives the incorrect output:
int fahr = 9 / 5 * celsius + 32;
Now, I understand that this is probably an issue with 9/5 being interpreted as an integer, but what I don't understand is that using double or floatit still gives the same incorrect output.
Oddly enough the following formula gives the correct output despite also setting the type to int:
int fahr = celsius / 5 * 9 + 32;
Furthermore, i've noticed even something as simple as the below, when the type is set to double, still gives the output as 1.0 instead of 1.8:
double x = 9 / 5;
printf("%lf\n", x);
I've read this thread:
C program to convert Fahrenheit to Celsius
but I still don't understand why int fahr = celsius / 5 * 9 + 32; works but not int fahr = 9/5 * celsius+32; ?
You're doing math with integers. This expression:
9 / 5
Yields 1 in C. When you say you used double or float, you probably just changed the type of fahr, which doesn't do anything to the operations taking place on the right side of the assignemtn operator. To get the right behaviour, you need to make at least one of those constants a double, too:
9.0 / 5
Likewise, in this statement:
double x = 9 / 5;
You're still doing integer math, and then assigning the result to a double variable. There isn't anything else going on. You'll get the right answer by doing one of these:
double x = 9.0 / 5;
double x = 9 / 5.0;
double x = 9.0 / 5.0;
The reason this expression:
int fahr = celsius / 5 * 9 + 32;
appears to work is just an order of operations thing - here you divide the input by 5 and then multiply by nine, rather than doing the constant operation first. You'd still get more accurate answers by doing:
int fahr = celsius * 9 / 5 + 32;
Besides that, you could also do floating point math in this expression:
int fahr = celsius * 9.0 / 5 + 32;
If you want to do the original calculation using integers, you certainly can - you just need to multiply before dividing:
int fahr = 9 * celsius / 5 + 32;
This expression is equivalent to one of the ones used above.
I still don't understand why int fahr = celsius / 5 * 9 + 32; works but not int fahr = 9/5 * celsius+32;
For the former, you probably declared celsius as a float or as a double, making the entire right side evaluate as such. Assuming you used float, it works out like this:
celsius / 5 * 9 + 32
(celsius / 5.0) * 9 + 32
(celsius / 5.0 * 9.0) + 32
(celsius / 5.0 * 9.0 + 32.0)
For the latter, 9/5 is integer arithmetic that evaluates to 1 before the rest of the math happens as floating point. In this case:
9 / 5 * celsius + 32
1 * celsius + 32 // Because of this, you get an incorrect answer
celsius + 32
celsius + 32.0
Note the the type of the left hand side is irrelevant; the right-hand side is evaluated without regard to that.
Update: You said celsius is an int, which means you just happened to get lucky and test with a value that is a multiple of 5, giving you a correct integer result to celsius / 5 before doing valid integer arithmetic for the rest of the statement. In your second example, being a multiple of 5 doesn't help you.
In any case, now you know why you got lucky, but the linked question gives you the answer to what you actually need to to do have a formula that works when celsius isn't a multiple of 5: use floating point math, as demonstrated in all of the answers there.
The type of each expression or subexpression is (in most cases) evaluated without regard to the context in which it appears.
In this declaration:
double x = 9 / 5;
the initialization expression is 9 / 5; it consists of two int expressions and a division operator. Since the operands of / are of type int it's an int division, resulting in an int value. Since integer division truncates, the result is 1, of type int.
The result of that expression is then used to initialize x. Since x is of type double, the value is implicitly converted from int to double, resulting in x holding the value 1.0.
If you want the value of x to be 1.8, you need to do floating-point division, which means you need floating-point operands. The simplest and clearest way to do this is:
double x = 9.0 / 5.0;
There are several other (IMHO less clear) approaches. If a / operator has two operands, one of type int and one of type double, the int operand is promoted to double, so either of these will also set x to 1.8:
double x = 9.0 / 5;
/* or */
double x = 9 / 5.0;
But be careful with this approach:
double y = 9 / 5 / 3.0;
This is equivalent to:
double y = (9 / 5) / 3.0;
which computes 9 / 5 as an int, yielding 1, then promotes that result to double and divides it by 3.0, yielding 0.333333333.
The point is that the context of an expression does not impose a type on the expression or its operands; the expression is evaluated as if it were isolated, and then the result may be converted depending on its context.

C math calculation not working as expected

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);

Resources