10

In Steven Prata's book "C Primer Plus", there's a section on Type Conversions, wherein "The basic rules are" section has stated in rule 1:

Under K&R C, but not under current C, float is automatically converted to double.

http://www.9wy.net/onlinebook/CPrimerPlus5/ch05lev1sec5.html

Could someone explain what but not under current C means? Are there versions of C that auto-convert and versions that don't?

I'm trying understand if I have an expression that mixes floats and doubles, can I rely on C to promote floats to doubles when it's evaluated?

phuclv
  • 37,963
  • 15
  • 156
  • 475
ggkmath
  • 4,188
  • 23
  • 72
  • 129
  • @CodeMonkey, don't be so quick labeling potential duplicates. That question you point to occurred more than 2 years after this one did. I don't believe in StackExchange a question can start off not being a duplicate and then become declared so years later. – alife May 28 '20 at 19:59
  • @alife Not sure what happened here. Maybe I wanted to mark the other one as duplicate. Thank you for pointing it out anyway. – CodeMonkey Jun 02 '20 at 08:37

5 Answers5

13

It must refer to the result of binary arithmetic operations of float * float format. In the pre-standard versions of C operands of such expressions were promoted to double and the result had double type.

For example, here's a quote from "C Reference Manual"

If both operands are int or char, the result is int. If both are float or double, the result is double.

In C89/90 already this behavior was changed and float * float expressions produce float result.

  • If either operand has type long double, the other operand is converted to long double
  • Otherwise, if either operand is double, the other operand is converted to double.
  • Otherwise, if either operand is float, the other operand is converted to float.
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • So, in an expression with floats and doubles, do all versions of C convert the floats to doubles during evaluation? – ggkmath Nov 16 '12 at 22:15
  • 2
    @ggkmath: What and when is converted depends on the structure of expression. Every time `float` and `double` meet each other as operands of the same operator, `float` gets converted to `double`. For example, in `f*f + f*d` expression, the first multiplication is performed without promotion. Promotion occurs in the second multiplication and in the addition. – AnT stands with Russia Nov 16 '12 at 22:16
  • 1
    There are worse things lurking in those same promotion hills. I, and the other old timers here I'm sure, ran afoul of this a couple times with regard to parameter passing in the mid 80's. We always "knew" that any `float` on the stack was auto-promoted to `double`. This was a bit of a massive slowdown especially before FPUs, and further was so in consistently implemented that it drove many porters nuts. Sizes of formal parameters (describing the stack) could be declared `float` and still end up being 8 bytes wide, despite it being 4 bytes wide everywhere else. It was truly a messy era. – alife Jul 01 '20 at 14:58
  • @alife: On the flip side, on many implementations it was cheaper from a code-size perspective to perform all arithmetic operations on a common floating-point type than to have separate routines for float and double, and when calling non-prototyped functions, using a consistent format for floating-point types is essential to make things behave sanely--a point which the C89 Committee failed to recognize when they added `long double`. – supercat Nov 30 '20 at 23:03
  • @supercat, There's two different things here. First is whether or not sending a float to a function requiring double would work. The other is whether or not all floats on the stack were _always_ doubles in disguise, regardless of the formal parameter. Sending a float to function(float f) resulted in a double on the stack. And there were two ugly stages to how this was implemented as well pre-C90: First, C compilers in the wild were not allowing prototyping at all and required methods to be ordered properly. And _then_ came the notion that _prototype or not_, auto-promotion occurred regardless. – alife Jul 15 '21 at 11:28
  • @alife: IMHO, the Standard should have expressly allowed implementations to treat `int foo(float);` and `int foo()` as different functions, and treat calls to `foo` with no prototype in scope as calls to the latter. Many implementations bent over backward to avoid behaving nonsensically if functions with new-style argument lists were called without prototypes in scope, when e.g. appending an underscore to the linker name of the former would have made it possible for compilers to use more efficient calling conventions for functions with new-style argument lists. BTW,... – supercat Jul 15 '21 at 15:40
  • ...if I could change argument promotion rules, I'd make all floating points (including long double!) passed to non-prototyped or variadic functions convert to double, but define a pass-long-double macro such that a %Ld argument to sprintf would indicate an argument should be converted into the form expected by %Ld argument [e.g the macro could call a function that returns a structure containing a `long double`, which would be passed that structure type without conversion]. – supercat Jul 15 '21 at 15:44
5

Look at the entire rule:

When appearing in an expression, char and short, both signed and unsigned, are automatically converted to int or, if necessary, to unsigned int. (If short is the same size as int, unsigned short is larger than int; in that case, unsigned short is converted to unsigned int.) Under K&R C, but not under current C, float is automatically converted to double. Because they are conversions to larger types, they are called promotions.

If we consider the integer types, when they appear in e.g. arithmetic expressions, they are still promoted, so no arithmetic is -theoretically - performed at the types char or short, but all at type int, unsigned int or a type with higher conversion rank (under the as-if rule, if the implementation can guarantee that the result is the same as if the promotion were actually carried out, it can perform arithmetic at smaller types if the platform provides the instructions).

The analogous used to hold for float, under the old pre-standard rules, floats were promoted to double for all arithmetic etc.

That is no longer the case, arithmetic on floats does not involve automatic promotion under standardised C.

In expressions with mixed types, generally everything is still promoted to the largest involved type, so if you compare or add a float to a double, the float is converted to double before the operation.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
2

Yes, there are difference versions of C, just as there are different versions of most software products.

K&R is the original version as described by Brian Kernighan and Dennis Ritchie in their book The C Programming Language.

The first standardized version was ANSI C, or C89 and there have been a couple of new versions since then. "Current C" can either mean C11 (the latest version) or C99 (probably the most usad version today).

DrummerB
  • 39,814
  • 12
  • 105
  • 142
  • If you want to make it work with all C version, yes. But I don't think K&R is in use anywhere today except a few rare occasions maybe. – DrummerB Nov 16 '12 at 22:10
2

The C language definition has been standardized and modified several times over the years. The original (non-standardized) version of C is known as "K&R C"; it's the language Kernighan and Ritchie originally developed.

In 1989, ANSI created an official standards document (adopted in 1990 by ISO) to define the language, and in that standard some things were changed and extended; one of the changes is that the automatic promotion from float to double was removed.

Since then, there have been two revisions to the standard, one in 1999 and one in 2011.

I'm trying understand if I have an expression that mixes floats and doubles, can I rely on C to promote floats to doubles when it's evaluated?

Here's the rule from the current standard:

6.3.1.8 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.62)
62) 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).

So basically, if you have an expression with two different types, the operand with the narrower/less precise type will be promoted to the type of the operand with the wider/more precise type.

John Bode
  • 119,563
  • 19
  • 122
  • 198
1

Yes you can rely on C to promote floats to doubles when evaluated.

708 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. 

I'm using the documentation found here.

Sorry, I cited the wrong thing earlier

NickO
  • 731
  • 1
  • 6
  • 20
  • 1
    “you can rely on C to promote floats to doubles when evaluated” No, in C99 and C11 (and probably in C90) there is no promotion to double in the expression `1.0f + 1.0f`, nor in `x + 1.0f` when variable `x` is declared of type `float`. The clause you cite does not support that claim either, it only describes what happens when a promotion to `double` occurs, **not** when it should occur. – Pascal Cuoq Nov 16 '12 at 22:07
  • yes, good call. I've updated the answer to reflect your comment. – NickO Nov 16 '12 at 22:09
  • +1 and, for the reader, note that my comment applied to a previous version of the answer. – Pascal Cuoq Nov 16 '12 at 22:10