casting and arithmetic

B

Brice Rebsamen

What happens exactly when you are mixing types (short, floats, double,
etc.) in a mathematical formula? Is it part of the standard or
compiler dependent? Is it better to explicitly cast everything (looks
ugly)?

When working with numbers, I figured out (with gcc) that 2 is an int
and 2.0 is a float (or maybe a double?). same questions: Is it part of
the standard or compiler dependent? Is it better to explicitly cast
everything (looks ugly)?

I tried to come with examples, but unfortunately I could not... Hope
you see what I mean.

Brice
 
P

Peter Nilsson

Brice Rebsamen said:
What happens exactly when you are mixing types (short,
floats, double, etc.) in a mathematical formula?

Look up integral promotion and usual arithmetic conversion.
Is it part of the standard or compiler dependent?
Both.

Is it better to explicitly cast everything (looks
ugly)?
No.

When working with numbers, I figured out (with gcc) that 2
is an int and 2.0 is a float (or maybe a double?).

It's a double. >> 2.f << is a float.
same questions: Is it part of the standard or compiler
dependent?

The type of floating point literal constants is defined by
the standard.
Is it better to explicitly cast everything (looks ugly)?

No.
 
B

Brice Rebsamen

Look up integral promotion and usual arithmetic conversion.


It's a double. >> 2.f << is a float.


The type of floating point literal constants is defined by
the standard.


No.

Thanks Peter.
I found info on IBM site:
http://publib.boulder.ibm.com/infoc...bm.vacpp7l.doc/language/ref/clrc06cplr066.htm
I understand that all operands of an expression are converted to the
type of the largest one.

I guess I should have asked directly:
Is there any situation when we need to worry about this?


Brice
 
C

CBFalconer

Brice said:
.... snip ...

I understand that all operands of an expression are converted to
the type of the largest one. I guess I should have asked directly:
Is there any situation when we need to worry about this?

Some useful references about C:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://c-faq.com/> (C-faq)
<http://benpfaff.org/writings/clc/off-topic.html>
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf> (C99)
<http://cbfalconer.home.att.net/download/n869_txt.bz2> (pre-C99)
<http://www.dinkumware.com/c99.aspx> (C-library}
<http://gcc.gnu.org/onlinedocs/> (GNU docs)
<http://clc-wiki.net/wiki/C_community:comp.lang.c:Introduction>
<http://clc-wiki.net/wiki/Introduction_to_comp.lang.c>

The things marked C99 are the C standard. n869_txt.bz2 is a
bzipped text version.
 
J

James Kuyper

Brice said:
What happens exactly when you are mixing types (short, floats, double,
etc.) in a mathematical formula? Is it part of the standard or
compiler dependent? Is it better to explicitly cast everything (looks
ugly)?

The standard specifies precisely what occurs, but the standard's
specification depends upon things that are implementation-defined, such
as the values of INT_MAX.

"Explicit cast" is redundant; a cast is always explicit. A cast performs
an explicit conversion. Conversions can be implicit. Any conversion
which is not implicit is generally dangerous. A cast expression is often
an error, and it's always a good idea to check whether or not it might
be an error. Casts should be avoided unless needed.

The key things you need to be worried about are performing operations in
a type with insufficient range or precision. If you need to handle
negative numbers, you don't want the operation carried out in an
unsigned data type. If you need to keep track of the fractional part of
a number, you don't want the operation carried out in an integer type.
Unless you're very careful about what you're doing, you don't want to
carry out floating point operations in 'float'; use at least 'double',
or 'long double' if really necessary. It's sometimes necessary (but
usually avoidable) to use casts to ensure these things.

Similarly, don't use real floating point if you need to keep track of
the imaginary component of a complex number; and don't use _Imaginary if
you need to keep track of the real component of a complex number.
However, most people don't need to worry about those issues.
When working with numbers, I figured out (with gcc) that 2 is an int
and 2.0 is a float (or maybe a double?). same questions: Is it part of
the standard or compiler dependent? Is it better to explicitly cast
everything (looks ugly)?

Just as with your previous question, the answer is specified by the
standard, but depends upon implementation-defined features of the
various types. For instance, whether or not the integer constant 65536
has a type of 'int' or 'long' depends upon whether or not 65536 > INT_MAX.

The full answer to these questions gets very complicated; hopefully
you'll be able to find a C textbook that explains these issues well. I
would personally recommend Kernighan and Ritchie's "The C Programming
Language".
 
B

Ben Bacarisse

Brice Rebsamen said:

It is better style not to quote sigs.
I found info on IBM site:
http://publib.boulder.ibm.com/infoc...bm.vacpp7l.doc/language/ref/clrc06cplr066.htm
I understand that all operands of an expression are converted to the
type of the largest one.

That does not summarise what the linked page says! Mind you, it is
hard to work out what it is saying. It seems to be trying to explain
both C and C++'s rules and it ends up no saying much at all. I'd
avoid it for explaining what C does.
I guess I should have asked directly:
Is there any situation when we need to worry about this?

In general the rules "just work". The two most common pitfalls are
probably: forgetting that division gives an integer result unless one
of the operands is of a floating point type and the surprises that
can result from unsigned arithmetic.

To illustrate the latter, strlen returns a size_t -- an unsigned
type. Writing this:

strlen(s) - 1

never results in a negative value. If s points to a null char
(i.e. if the string has length 0) the result is a larger positive
number (specifically SIZE_MAX).

Turning up the warning level on your compiler is a very good idea
while you are learning (I like it even now).
 
E

Eric Sosman

Brice said:
[...]
I found info on IBM site:
http://publib.boulder.ibm.com/infoc...bm.vacpp7l.doc/language/ref/clrc06cplr066.htm
I understand that all operands of an expression are converted to the
type of the largest one.

Sort of, and not "globally." That is, in the second line of

double f = 98.6;
double c = 5 / 9 * (f - 32);

"the largest one" is double, yet the sub-expression `5 / 9'
is evaluated with int arithmetic (and has the value zero).
The promotion rules apply "one operator at a time."
 
B

Brice Rebsamen

Brice said:
[...]
I found info on IBM site:
http://publib.boulder.ibm.com/infocenter/lnxpcomp/v7v91/index.jsp?top...
I understand that all operands of an expression are converted to the
type of the largest one.

     Sort of, and not "globally."  That is, in the second line of

        double f = 98.6;
        double c = 5 / 9 * (f - 32);

"the largest one" is double, yet the sub-expression `5 / 9'
is evaluated with int arithmetic (and has the value zero).
The promotion rules apply "one operator at a time."


Thanks Eric, this is exactly the kind of situation I was looking for.
May I say that it works like this?

1) the compiler starts with the left-most operator after the equal
sign,
checks the type of both operands and operator specific rules, to
decide
the type and value of the result. In that case:
int divided by int gives int, here 0.
2) carries on with next operation following the same rules:
f-32 is double minus int, so the result is double 66.6
(int) 0 times (double) 66.6 which yields (double) 0
3) And finally converts to lvalue type, in this case no conversion
because double on both sides.

Which is tricky because one could expect all operands to be converted
to
double before hand... I am not sure why it is not the case, but I am
sure
there must be a reason. I just want to know exactly what's going on.
When
in doubt I always cast. So far so good, at least as far as I can
tell...

Brice
 
K

Keith Thompson

Brice Rebsamen said:
Brice said:
[...]
I found info on IBM site:
http://publib.boulder.ibm.com/infocenter/lnxpcomp/v7v91/index.jsp?top...
I understand that all operands of an expression are converted to the
type of the largest one.

     Sort of, and not "globally."  That is, in the second line of

        double f = 98.6;
        double c = 5 / 9 * (f - 32);

"the largest one" is double, yet the sub-expression `5 / 9'
is evaluated with int arithmetic (and has the value zero).
The promotion rules apply "one operator at a time."

Thanks Eric, this is exactly the kind of situation I was looking for.
May I say that it works like this?

1) the compiler starts with the left-most operator after the equal
sign,
checks the type of both operands and operator specific rules, to
decide
the type and value of the result. In that case:
int divided by int gives int, here 0.
2) carries on with next operation following the same rules:
f-32 is double minus int, so the result is double 66.6
(int) 0 times (double) 66.6 which yields (double) 0
3) And finally converts to lvalue type, in this case no conversion
because double on both sides.

Not quite. It doesn't necessarily proceed left to right; there's no
particular signficance to the left-most operator.

The precedence and associativity rules (which are implicit in the
language grammar) determine which operands are associated with which
operator. Given these rules, it can be determined that
5 / 9 * (f - 32)
is equivalent to
(5 / 9) * (f - 32)

The order in which the parts of this expression are evaluated is not
important in this case; the only important thing is which operands
are associated with which operator.

The key thing to remember is that the evaluation of each expression or
subexpression is not affected by the context in which it appears. So
the subexpression (5 / 9) yields the int value 0, since both operands
are of type int; the fact that the result is going to be multiplied by
a double value doesn't change that. On the other hand, the
subexpression f - 32 yields the value 66.6 of type double, because f
is of type double and 32 is promoted by the subtraction operator.

If you think about it, this is actually a simpler rule than one that
promotes expressions depending on their context.
Which is tricky because one could expect all operands to be
converted to double before hand... I am not sure why it is not the
case, but I am sure there must be a reason. I just want to know
exactly what's going on. When in doubt I always cast. So far so
good, at least as far as I can tell...

Casting is seldom a good idea, though casting for numeric types isn't
as bad as, say for pointer types.

In this case, you can avoid the problem just by using floating-point
constants:

double c = 5.0 / 9.0 * (f - 32.0);

In a real program, it's likely that either the operands either are
already of the type you need, or you can change the code to make them
so. In most cases, the implicit conversions just do the right thing.
Yes, there are exceptions to this, but if you post some code that uses
casts, we can probably help you improve it by getting rid of them.
 
E

Eric Sosman

Brice said:
Brice said:
[...]
I found info on IBM site:
http://publib.boulder.ibm.com/infocenter/lnxpcomp/v7v91/index.jsp?top...
I understand that all operands of an expression are converted to the
type of the largest one.
Sort of, and not "globally." That is, in the second line of

double f = 98.6;
double c = 5 / 9 * (f - 32);

"the largest one" is double, yet the sub-expression `5 / 9'
is evaluated with int arithmetic (and has the value zero).
The promotion rules apply "one operator at a time."

Thanks Eric, this is exactly the kind of situation I was looking for.
May I say that it works like this?

1) the compiler starts with the left-most operator after the equal
sign,

No. Operators group according to their precedence and
associativity (really, according to the formal grammar of the
language), so the leftmost operator is not necessarily the
first one considered. In `x = a + b / c' the leftmost-after-
equals operator is `+', but `b / c' is evaluated independently,
uninfluenced by `a' and `+'.

Also, there may not even *be* an equal sign involved, as in
`if (x < 2 * y)' or `return a + b / c;'.
checks the type of both operands and operator specific rules, to
decide
the type and value of the result. In that case:
int divided by int gives int, here 0.
2) carries on with next operation following the same rules:
f-32 is double minus int, so the result is double 66.6
(int) 0 times (double) 66.6 which yields (double) 0
3) And finally converts to lvalue type, in this case no conversion
because double on both sides.

Which is tricky because one could expect all operands to be converted
to
double before hand... I am not sure why it is not the case, but I am
sure
there must be a reason.

Think of it this way: Expressions are evaluated "bottom-up."
The rules of precedence and associativity (really, the formal
grammar of the language) decompose a long expression into sub-
expressions and sub-sub-expressions and so on until you get down
to "atoms" like variables and constants. Then the expression is
re-composed in the same pattern, combining operands by operating
on them with their operators. As each operator in turn is handled,
its own operands are promoted as necessary.

So, let's look at my example again and try to pick apart
the second line:

double f = 98.6;
double c = 5 / 9 * (f - 32);

The right-hand side `5 / 9 * (f - 32)' is an expression that
contains three operators. Thanks to the grammar, we know
it is composed as

[*]
|
---- [/]
| |
| ---- [5]
| |
| ---- [9]
|
---- [-]
|
---- [f]
|
---- [32]

or (* (/ 5 9) (- f 32)) for LISPers. We don't know whether
`5 / 9' or `f - 32' is evaluated first (order of evaluation
is another topic altogether), but we know that it goes like

5 / 9 is int / int. The operand types match so no
promotions are needed, and the calculation is done
according to int rules, yielding an int with the
value zero.

f - 32 is double - int. There's a mismatch in the
operand types, so the int is promoted to a double and
we have f - 32.0, double - double. The calculation
is then done according to double rules, yielding a
double with the value 66.6

Finally, 0 * 66.6 is int * double. Again there's a
mismatch, and again the int is promoted to double and
we have 0.0 * 66.6. The calculation is done according
to double rules, yielding 0.0 as its double result.
I just want to know exactly what's going on.

A worthwhile objective.
When
in doubt I always cast. So far so good, at least as far as I can
tell...

Instead of "always cast," I'd encourage you to become more
familiar with the way the language operates. It's a tool, and
muttering half-understood incantations is not the best way to
get it to cut the workpiece instead of your finger.
 
C

CBFalconer

Eric said:
Brice Rebsamen wrote:
.... snip ...


Sort of, and not "globally." That is, in the second line of

double f = 98.6;
double c = 5 / 9 * (f - 32);

"the largest one" is double, yet the sub-expression `5 / 9'
is evaluated with int arithmetic (and has the value zero).
The promotion rules apply "one operator at a time."

However, that expression can be cleaned up by simply writing:

double c = 5 * (f - 32) / 9;

(at least to a single degree). Changing 9 to 9.0 would clean up
the whole thing. The only thing you really have to worry about is
that 5*(f-32) won't cause an integer overflow. That allows for f
to be in the range -6521 to 6585, at least. :)
 
J

James Kuyper

Brice Rebsamen wrote:
....
When
in doubt I always cast. ...

That is almost exactly the reverse of the correct rule. Putting in a
cast hides mistakes, by turning off compiler warnings about type
mis-matches. That may be why:
... So far so good, at least as far as I can
tell...

It's almost always the case that what you need when the compiler warns
about a type mismatch is something other than an explicit cast.

When in doubt, DON'T cast.
 
C

CBFalconer

pete said:
CBFalconer wrote:
.... snip ...


Changing 9 to 9.0, changes nothing but the spelling.

No. Assuming f is an integer, everything is performed with integer
arithmetic up to the division. Using the value '9' (an integer)
results in truncation to an integer quotient. Using the value
'9.0' (a double) causes the numerator to be converted to a double
before dividing, and doing a double division.

The constant 9 is an integer. The constant 9.0 is a double.
 
C

CBFalconer

pete said:
CBFalconer wrote:
.... snip ...


There is no assuming f is an integer.

Your "However, ...",
was in response to:

double f = 98.6;
double c = 5 / 9 * (f - 32);

which you quoted in your reply at the time.

Conceded.
 
D

Dik T. Winter

>
> No. Assuming f is an integer, everything is performed with integer
> arithmetic up to the division.

Well, you may assume as you wish, but in the original there was the line:
 

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,141
Messages
2,570,818
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top