7

For example, these variables:

result (double)
a (double)
b (float)
c (float)
d (double)

A simple calculation:

result = a * (b + c) * d

How and when are the types converted and how do I figure out what precision each calculation is performed at?

Dan
  • 33,953
  • 24
  • 61
  • 87
  • Possible duplicate of [Order of commutative mathematical operations](https://stackoverflow.com/q/49506802/608639), [C/C++ Math Order of Operation](https://stackoverflow.com/q/11296854/608639), [What are the rules governing C++ single and double precision mixed calculations?](https://stackoverflow.com/q/4239770/608639), [Order of operations to maximize precision](https://stackoverflow.com/q/45524072/608639), etc. – jww Mar 27 '18 at 07:47

7 Answers7

14

All operations are done on objects of the same type (assuming normal arithmetic operations).

If you write a program that uses different types then the compiler will auto upgrade ONE parameter so that they are both the same.

In this situations floats will be upgraded to doubles:

result      = a * (b + c) * d

float  tmp1 = b + c;            // Plus operation done on floats.
                                // So the result is a float

double tmp2 = a * (double)tmp1; // Multiplication done on double (as `a` is double)
                                // so tmp1 will be up converted to a double.

double tmp3 = tmp2 * d;         // Multiplication done on doubles.
                                // So result is a double

result      = tmp3;             // No conversion as tmp3 is same type as result.
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • also note unspecified constants are assumed to be double so float a; a=a+2.5; is going to convert a to double, perform the add then convert back to single. a=a+2.5F; would force it to all single math. – old_timer Nov 22 '10 at 23:23
3

If you have:

float f;
double d;

...then an arithmetic expression like f * d will promote both operands to the larger type, which in this case is double.

So, the expression a * (b + c) * d evaluates to a double, and is then stored in result, which is also a double. This type promotion is done in order to avoid accidental precision loss.

For further information, read this article about the usual arithmetic conversions.

Charles Salvia
  • 52,325
  • 13
  • 128
  • 140
  • 3
    But both the operands to plus are float. So the plus will be done using float the result of which will be upgraded to a double before the multiplication operation is done. – Martin York Nov 21 '10 at 19:32
2

You have to differentiate between type conversion and value conversion. The C++ standard (C as well) allows floating-point calculations to be done at extended precision.

"The values of the floating operands and 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."

As types, b + c is an addition of two float(s). The result is a float. The result is then type promoted to a double and the two multiplications are done as doubles with a result of double.

However, an implementation is allowed to do all the calculations, including b + c, using doubles (or higher precision). Indeed, I tried it out using Visual C++ and it did all the calculations using the 80-bit floating-point stack available on x86.

user515430
  • 3,341
  • 2
  • 17
  • 13
  • The only real correct answer here: As the result, 'a' and 'd' are double we know that those computations are done at least with double-precision. But the part "a + b" could be 32 bit, 64bit, or 80 bit. This can even lead to non-deterministic code: Comparing a float 'a' to a direct copy 'b' can give varyinf results. If a was just computed and is still in register it might be 64/80 bit, while the copy 'b' is only 32bit - and the comparison fails. And doing the same comparison 2 lines later might show the numbers as being equal now when both where loaded from memory instead of registers. – ABaumstumpf Aug 04 '20 at 12:01
1

You have parenthesis delimiting the float adition. So it would do b + c as float + float. Convert this to double for keeping largest precision, then multiply the double values.

However in such case where you want control over conversions, and not guessing: use static_cast<>();

Stephane Rolland
  • 38,876
  • 35
  • 121
  • 169
1

Following order of operations, each sub-expression is converted to the type of it's (not sure of the term here, dominant perhaps?) type. double is dominant over float, so:

(b + c) // this is evaluated as a float, since both b and c are floats
a * (b + c) // this is evaluated as a double, since a is a double
a * (b + c) * d // this is evaluated as a double, since both "a * (b + c)" and d are doubles
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
0

The floats will be upconverted to doubles. Explicitly cast the values.

ie if you want double as your result you would write:

result = a * double( b + c ) * d;

It is ALWAYS worth being explicit. It gets round misunderstandings like this and it is INSTANTLY obvious to anyone trying to use your code exactly what you mean.

Goz
  • 61,365
  • 24
  • 124
  • 204
  • This is not correct. In the original expression neither of `b` or `c` will not be promoted to double, they will be added as two `float` s. The result will be promoted to a `double` only when multiplied with something that is already a `double`, i.e. `a` . – CB Bailey Nov 21 '10 at 19:37
  • @Martin: As above. My mistake :( – Goz Nov 21 '10 at 19:54
0

In your example, all the float types are type-promoted to double when the right-side formula is evaluated.

As for how they're converted: What I've read regarding floating point operations is that most contemporary hardware perform FP operations using extended-precision (80 bit) long doubles in special hardware registers (at least that's what I remember about modern Intel x86/x87 processors). As I understand it, float and double are type-promoted IN HARDWARE via special FP instructions (someone correct me if I'm wrong).

pr1268
  • 1,176
  • 3
  • 9
  • 16
  • 1
    This is not correct. `float` are not automatically promoted to `double`. They are only converted to `double` if they appear in an arithmetic operation with something that is already `double`. In this case neither `b` nor `c` will be converted to `double` before the addition. – CB Bailey Nov 21 '10 at 19:39