Question on the FAQ

T

Topi Linkala

Question 3.15:

Why does the code

double degC, degF;
degC = 5 / 9 * (degF - 32);

keep giving me 0?


Would the following rearrangement solve the problem?

degC = 5 * (degF - 32) / 9;


Topi Linkala
 
R

Robert Gamble

Question 3.15:

Why does the code

double degC, degF;
degC = 5 / 9 * (degF - 32);

keep giving me 0?

Would the following rearrangement solve the problem?

degC = 5 * (degF - 32) / 9;

Did you read the answer to the question (<http://c-faq.com/expr/
truncation1.html>)?
 
T

Topi Linkala

Robert said:
Did you read the answer to the question (<http://c-faq.com/expr/
truncation1.html>)?

Yes I read and it says:

"If both operands of a binary operator are integers, C performs an
integer operation,..."

But in my rewriting there are no binary operation with integer values.
That's why I'm asking if it would work.

Topi
 
R

Robert Gamble

Yes I read and it says:

"If both operands of a binary operator are integers, C performs an
integer operation,..."

But in my rewriting there are no binary operation with integer values.
That's why I'm asking if it would work.

Sorry, I missed the fact that degF was a double. Yes, your example
will work properly since the division will be happening on floating
point values.
 
F

Flash Gordon

Topi Linkala wrote, On 13/04/08 20:48:
Yes I read and it says:

"If both operands of a binary operator are integers, C performs an
integer operation,..."

Which is why it does not work.
But in my rewriting there are no binary operation with integer values.

Which is why it would work.
That's why I'm asking if it would work.

You obviously did not make it clear enough to Robert that you had read
it. Don't worry about it.
 
T

Topi Linkala

Joe said:
The statement..

degC = 5 / 9 * (degF - 32);

..can't work because 5 / 9 is (int) zero. Also degF is not initialized.

degC = (degF - 32) * 5 / 9;

should work better for you.

I don't think so because there's no reason to believe that the
multiplication is done before the division, but in my example that
doesn't matter as one of the operands is double in any case.

Topi
 
R

Robert Gamble

I don't think so because there's no reason to believe that the
multiplication is done before the division, but in my example that
doesn't matter as one of the operands is double in any case.

Actually, the multiplication is guaranteed to be performed before the
division because they both have the same precedence and are left-to-
right associative.
 
I

Ian Collins

CBFalconer said:
Think about it. 5 and 9 are ints. What is the value of 5/9?. How
many times can you subtract 9 from 5 and have the result
non-negative? What is the result of that multiplied by (degF -32)?


That depends on the type of degF.

If you read the OP, degF was declared as double.
 
T

Topi Linkala

Dann said:
More important than the order here is the types.
By automatic promotions, all of the mathematical operations you see here
take place as double:

(double - int) performed as (double-double) returns double value
double * int performed as double * double returns double value
double / int performed as double / double returns double value

From ISO/IEC 9899:1999 (E):
"6.3.1.8 Usual arithmetic conversions

1 Many operators that expect operands of arithmetic type cause conversions
and yield result types in a similar way. The purpose is to determine a
common real type for the operands and result. For the specified operands,
each operand is converted, without change of type domain, to a type whose
corresponding real type is the common real type. Unless explicitly stated
otherwise, the common real type is also the corresponding real type of the
result, whose type domain is the type domain of the operands if they are the
same, and complex otherwise. This pattern is called the usual arithmetic
conversions: First, if the corresponding real type of either operand is long
double, the other operand is converted, without change of type domain, to a
type whose corresponding real type is long double. Otherwise, if the
corresponding real type of either operand is double, the other operand is
converted, without change of type domain, to a type whose corresponding real
type is double. Otherwise, if the corresponding real type of either operand
is float, the other operand is converted, without change of type domain, to
a type whose corresponding real type is float.51) Otherwise, the integer
promotions are performed on both operands. Then the following rules are
applied to the promoted operands: If both operands have the same type, then
no further conversion is needed. Otherwise, if both operands have signed
integer types or both have unsigned integer types, the operand with the type
of lesser integer conversion rank is converted to the type of the operand
with greater rank. 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. Otherwise, if the type of the operand with
signed integer type can represent all of the values of the type of the
operand with unsigned integer type, then the operand with unsigned integer
type is converted to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type.
2 The values of floating operands and of the results of floating expressions
may be represented in greater precision and range than that required by the
type; the types are not changed thereby.52)

Footnote 51) For example, addition of a double _Complex and a float entails
just the conversion of the float operand to double (and yields a double
_Complex result).

Footnote 52) The cast and assignment operators are still required to perform
their specified conversions as described in 6.3.1.4 and 6.3.1.5."

You can summarize the general idea of the promotions as "if an operation
takes place between wide and narrow, perform using wide and wide instead"

But what stops the compiler to calculate the 5/9 first as it is a
constant expression and can be done on compile time?

AFAIK only guaranteed sequencing on expressions are:

1. precedence
2. comma operation
3. boolean operations || and &&
4. ?:

So an expression a*b/c can be calculated (a*b)/c or a*(b/c).

Topi
 
T

Topi Linkala

Richard said:
Topi Linkala said:




If I am not mistaken, the statement under consideration is this:

degC = (degF - 32) * 5 / 9;

where degC and degF are doubles.

The answer to your question is that multiplication and division have the
same precedence and left-to-right associativity. Whilst it is true that
5 / 9 is a constant expression with value 0, that constant expression *does
not appear* in the statement under consideration (despite appearances!).

The precedence and associativity "rules" that apply here can be expressed
in a different way, as the following parse tree shows:

assign
/ \
degC div
/ \
mul 9
/ \
sub 5
/ \
degF 32

The rule for order of evaluation is simple: you can do stuff in any order
you like, *provided* that the result is the same as if you'd fully
evaluated both operands of an arithmetic operator to discover what value
should be passed back up the tree.

So you can do the division by 9 first if you like, but *only* if you can
deduce correctly what the left-hand operand of the division should be. And
let's face it, the simplest way to do that is to do the sub and mul first.




You forgot associativity and sequence points.




These are special cases of sequence points.




Wrong. Multiplication and division are associated left-to-right.

From whence? My K&R states in section 2.5 Arithmetic Operators:

"The order of evaluation is not specified for associative and
commutative operators like * and +; the compiler may rearrange a
parenthesized computation involving onr of these. thus a+(b+c) can be
evaluated as (a+b)+c. This rarely makes ant difference, but if
particular order is required, explicite temporary variables must be used."

Topi
 
J

Jean-Marc Bourguet

Topi Linkala said:
From whence? My K&R states in section 2.5 Arithmetic Operators:

"The order of evaluation is not specified for associative and commutative
operators like * and +; the compiler may rearrange a parenthesized
computation involving onr of these. thus a+(b+c) can be evaluated as
(a+b)+c. This rarely makes ant difference, but if particular order is
required, explicite temporary variables must be used."

That's not in mine; is yours the first edition? Mine is the second one
(with the ANSI C red stamp).

And the standard is quite explicit that it isn't the case (see 5.1.2.3/3
and example 6 of the same paragraph).

Yours,
 
L

lawrence.jones

Topi Linkala said:
From whence? My K&R states in section 2.5 Arithmetic Operators:

"The order of evaluation is not specified for associative and
commutative operators like * and +; the compiler may rearrange a
parenthesized computation involving onr of these. thus a+(b+c) can be
evaluated as (a+b)+c. This rarely makes ant difference, but if
particular order is required, explicite temporary variables must be used."

That was changed by the original ANSI standard and no longer appears in
K&R2. It was replaced by what's referred to as "the as-if rule", which
basically says that the compiler can rearrange things however it wants
as long as the answer is the same as if it had not been rearranged.
That allows the above regrouping for integer operations as long as
integer overflow is silent and reversible (which it is on most machines)
but forbids it for machines where that is not true and for floating
point.

-Larry Jones

I can feel my brain beginning to atrophy already. -- Calvin
 
A

Andrey Tarasevich

Topi said:
...
But what stops the compiler to calculate the 5/9 first as it is a
constant expression and can be done on compile time?

Nothing really. In the expresison 'E * 5/9' the compiler is free to
calculate '5/9' in advance. What the compiler _cannot_ do is to destroy
the semantics if the full expression (derived from the grammar) and
evaluate '5/9' as an integral division. If the compiler want to
pre-evaluate '5/9', it can do that, but it has to make sure that the
result is precise enough so that the whole thing works "as if" it
evaluated 'E * 5' first and then divided the result by '9'.
AFAIK only guaranteed sequencing on expressions are:

1. precedence

Precedence does not guarantee any sequencing. If defines the semantics
of the expression, i.e. it disambiguates the result. It tells you that
'2 + 2 * 2' is 6 and not 8. But the compiler is perfectly free to forget
about these 2's and obtain that final 6 as '37 / 5 + 1' if it is so
inclined.
2. comma operation
3. boolean operations || and &&
4. ?:

These three do indeed introduce real sequencing.
So an expression a*b/c can be calculated (a*b)/c or a*(b/c).

Yes, it can be calculated as 'a*(b/c)' as long as the result is the same
as '(a*b)/c'. If on the given platform 'a*(b/c)' give a different
result, then it the compiler will have no choice but calculate it as
'(a*b)/c'.
 
A

Andrey Tarasevich

Topi said:
From whence? My K&R states in section 2.5 Arithmetic Operators:

"The order of evaluation is not specified for associative and
commutative operators like * and +; the compiler may rearrange a
parenthesized computation involving onr of these. thus a+(b+c) can be
evaluated as (a+b)+c. This rarely makes ant difference, but if
particular order is required, explicite temporary variables must be used."

You are continuing to mix to different and virtually unrelated concepts:
associativity and order of evaluation.
 
T

Topi Linkala

Richard said:
And now that you've got K&R2 out, check section 2.12 - Precedence and Order
of Evaluation. Observe the precedence table on p53, and note the
associativity column.

Section 2.12 fourth paragraph:

"As mentioned before, expressions involving one of the associative and
commutative operators (*, +, &, ^, |) can be rearranbged even when
parenthesized."


Topi
 
L

lawrence.jones

Topi Linkala said:
Section 2.12 fourth paragraph:

"As mentioned before, expressions involving one of the associative and
commutative operators (*, +, &, ^, |) can be rearranbged even when
parenthesized."

That's K&R. K&R2 (the Second Edition) does not contain that text.

-Larry Jones

Hey Doc, for 10 bucks I'll make sure you see those kids in the
waiting room again real soon! -- Calvin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top