Author Topic: When does C require 10.0 instead of 10 when dealing with float or double?  (Read 20647 times)

0 Members and 3 Guests are viewing this topic.

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6002
  • Country: gb
  • Doing electronics since the 1960s...
float x,y;
x = 10 * y;
x = 10.0 * y;

I see both versions used but AFAICT the presence of any float/double anywhere in an expression makes the whole thing evaluated as floats.

But if you had

float x,y;
int z;

x = ( 10 * x ) / ( z / 10 );

that's different because the z/10 will be evaluated with integer division (with the potential for data loss due to underflow etc). You have to make sure z is appropriately scaled to avoid loss of precision in the /10.

Is that right?


Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 190
  • Country: us
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #1 on: November 09, 2022, 05:39:28 pm »
float x,y;
x = 10 * y;
x = 10.0 * y;

I see both versions used but AFAICT the presence of any float/double anywhere in an expression makes the whole thing evaluated as floats.

Um... So, float or double? The first expression is evaluated as float. The second - as double. I'm still not sure what the point of the above example is.

And no, "anywhere in an expression" is not correct. This rule is applied locally to binary arithmetic operators. If at least one operand of a binary arithmetic operator is a floating-point value, the operator is evaluated in floating-point domain.

But if you had

float x,y;
int z;

x = ( 10 * x ) / ( z / 10 );

that's different because the z/10 will be evaluated with integer division (with the potential for data loss due to underflow etc). You have to make sure z is appropriately scaled to avoid loss of precision in the /10.

Is that right?

Yes. Again, because the rule is applied locally to binary arithmetic operators, not to entire expressions. So, `z / 10` is integer division, but `10 * x` is float multiplication. And the final division is float as well.
 

Online DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6919
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #2 on: November 09, 2022, 05:54:55 pm »
Unless specified, some compilers (if not most) will interpret the decimal as double.

10 = integer
10.0 = double
10.0f = float

For example, a lot of MCUs have float-only FPU.
So doing var/10.0 will be processed as double (Using software routines) and then converted to float, taking >2000x processing than expected.
« Last Edit: November 09, 2022, 06:05:00 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: boB

Online ataradov

  • Super Contributor
  • ***
  • Posts: 12465
  • Country: us
    • Personal site
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #3 on: November 09, 2022, 05:59:59 pm »
Unless specified, some compilers (if not most) will interpret the decimal as double.
All compliant compilers will do that. This is required by the spec section 6.4.4.2 "Floating constants" (C11 case):
Quote
An unsuffixed floating constant has type double. If suffixed by the letter f or F, it has type float. If suffixed by the letter l or L, it has type long double.
Alex
 
The following users thanked this post: newbrain, sokoloff, Jacon, DavidAlfa

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 4838
  • Country: us
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #4 on: November 09, 2022, 06:03:32 pm »
I see both versions used but AFAICT the presence of any float/double anywhere in an expression makes the whole thing evaluated as floats.

No, the expression is evaluated according to the order of operations and then each binary operation is subject to numerical promotion individually based on the operand types.  While a floating point value anywhere in the expression will generally result in the final evaluated expression being floating point, intermediate values can and will be evaluated using integer arithmetic.

Quote
But if you had

float x,y;
int z;

x = ( 10 * x ) / ( z / 10 );

that's different because the z/10 will be evaluated with integer division (with the potential for data loss due to underflow etc). You have to make sure z is appropriately scaled to avoid loss of precision in the /10.

Is that right?

You are right that z / 10 will be evaluated as integer division, but "make sure z is appropriately scaled" isn't the correct general purpose solution although it may work in some situations. The answer here is to use 10.0f or convert z to a floating point type.
« Last Edit: November 09, 2022, 07:40:11 pm by ejeffrey »
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2860
  • Country: nz
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #5 on: November 09, 2022, 07:27:42 pm »
It isn't only division you have to watch out for:

Code: [Select]
#include <stdio.h>

int main(void) {
   int meters = 8;
   double nanometers = meters * 1000000000;
   printf("%d meters is %f micrometers\n", meters, nanometers);
   return 0;
}

My first approximation/rule of thumb, when nothing larger than 'int' or 'double' are involved:

- If either operand is floating point, it's calculated as a floating point operation of the largest floating point size.
- If both operands are int or smaller, it is an integer operation with the size of 'int'.

That explains why this code prints 16, not 0:

Code: [Select]
#include <stdio.h>

int main(void) {
   char x = 8;
   char y = (x * 126)  / 63;
   printf("%d gives %d\n", x, y);
   return 0;
}
« Last Edit: November 09, 2022, 08:26:33 pm by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6002
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #6 on: November 09, 2022, 07:33:26 pm »
I am amazed that in

float x,y,z;
x = 10 * z;
y = 10.0 * z;

x will be evaluated as a float and y as a double (and then be converted back to float). IOW the .0 signifies the use of double.

What about

double x,y,z;
x = 10 * z;
y = 10.0 * z;

Will x and y both be evaluated as double, or will x be evaluated as a float and then be converted to double? It would mean that all numeric constants used around doubles need to have the .0 on the end.

Have I got that right?

Also is double 2000x slower than float? Is single floating hardware completely useless for doubles? Also on a 32F4 which has a 32 x 32 mult or div and a 32 bit barrel shifter?

« Last Edit: November 09, 2022, 07:35:37 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 12465
  • Country: us
    • Personal site
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #7 on: November 09, 2022, 08:08:36 pm »
All of this would be double. For each binary operation the "strongest" type is selected. In this case at least one of the operands is double, so the whole expression  would be evaluated as double.

How much double is slower depends on the hardware and the software library used for the software implementation . On Cortex-M4F it would be slow. None of the float hardware is useful for doubles.
« Last Edit: November 09, 2022, 08:10:52 pm by ataradov »
Alex
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6002
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #8 on: November 09, 2022, 09:49:11 pm »
Could you estimate the time for a double multiply or divide? 168MHz.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 190
  • Country: us
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #9 on: November 09, 2022, 09:54:16 pm »
I am amazed that in

float x,y,z;
x = 10 * z;
y = 10.0 * z;

x will be evaluated as a float and y as a double (and then be converted back to float). IOW the .0 signifies the use of double.

The actual evaluation model is implementation-dependent. On x86 platform using the "classic" x87 FPU command set, all these will be loaded into extended-precision 80-bit FPU registers, evaluated with that high precision and then converted back to `float`. Language specification allows this kind of excessive precision in intermediate floating-point evaluations.

What about

double x,y,z;
x = 10 * z;
y = 10.0 * z;

Will x and y both be evaluated as double, or will x be evaluated as a float and then be converted to double? It would mean that all numeric constants used around doubles need to have the .0 on the end.

There's no `float` anywhere in this example, so everything here is evaluated as `double`. And, again, see the remark above.
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 5764
  • Country: dk
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #10 on: November 09, 2022, 10:10:29 pm »
Unless specified, some compilers (if not most) will interpret the decimal as double.
All compliant compilers will do that. This is required by the spec section 6.4.4.2 "Floating constants" (C11 case):
Quote
An unsuffixed floating constant has type double. If suffixed by the letter f or F, it has type float. If suffixed by the letter l or L, it has type long double.

AVR-GCC does (did?) everything in floats and even defined double as float

on targets with a single precision FPU, -Wdouble-promotion -fsingle-precision-constant might be useful
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 12465
  • Country: us
    • Personal site
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #11 on: November 09, 2022, 10:18:17 pm »
Could you estimate the time for a double multiply or divide? 168MHz.
Speed of the floating point operations depends on the operands a lot. There is no simple way to estimate that. It is easier to get a draft of your entire algorithm (not just a single operation) and time it on the real hardware.

Keep in mind, the same applies to the hardware floating point. Some of those instructions take a lot of cycles.
Alex
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6002
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #12 on: November 09, 2022, 10:26:41 pm »
I am writing a ton of code for analog sensor measurement: PT100, TC, etc. I am storing calibration coefficients (zero and scale) as 4 byte floats and that's important. But I am doing calculations as doubles; exec time is irrelevant.

I've just timed this at 15 secs

Code: [Select]
printf("start");
volatile float x,y;
x=0; y=1.5;

for (int i=0;i<10000000;i++)
{
x=y*3.2;
}
printf("end");

so 1.5us per loop, but a corresponding double version runs much faster so clearly isn't compiling; optimisation must be removing code. I won't spend a lot of time on it but for sure software floats are a lot slower.

The 32F4 does a mult32 in 1 clock i.e. 7ns so the 1.5us means nothing either. Clearly this kind of code needs to be done so the compiler doesn't remove anything. And with varying data.

Anyway, bottom line is that 10 versus 10.0 has no meaning, or does it?

It is similar to people writing 1000L when using a uint32_t integer. ST do this a lot in their code. Why? How can there be a difference between 10 and 10L and 10UL?

« Last Edit: November 09, 2022, 10:39:02 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 5764
  • Country: dk
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #13 on: November 09, 2022, 10:53:58 pm »
I am writing a ton of code for analog sensor measurement: PT100, TC, etc. I am storing calibration coefficients (zero and scale) as 4 byte floats and that's important. But I am doing calculations as doubles; exec time is irrelevant.

I've just timed this at 15 secs

Code: [Select]
printf("start");
volatile float x,y;
x=0; y=1.5;

for (int i=0;i<10000000;i++)
{
x=y*3.2;
}
printf("end");


the type of your constants are important

https://godbolt.org/z/P76q9xhjb

 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 190
  • Country: us
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #14 on: November 09, 2022, 11:24:24 pm »
AVR-GCC does (did?) everything in floats and even defined double as float

No, it did not.

Could you do

Code: [Select]
float *pf = ...;
double *pd = pf; /* type mismatch? */

?

If the above code triggered a type mismatch diagnostics, it meant that it did not "define double as float". It still kept them as two separate types.

These two types might share the same size and representation - this is not prohibited by the language spec. Which also means that AVR-GCC does everything in `double` - exactly as the language specification expects/requires it to, not in `float`.
« Last Edit: November 09, 2022, 11:26:50 pm by TheCalligrapher »
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 12465
  • Country: us
    • Personal site
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #15 on: November 09, 2022, 11:55:22 pm »
x=y*3.2;
As said above, this would be a double math. 3.2 is double, so on CM4F this whole thing would be calculated in software plus calls to f2d and d2f for type conversion. Double inefficient.

Change the constant to "3.2f" and compare the performance between those two versions with just this one change. This will give you a much better idea the difference.

And, yes, use godbolt. It is an invaluable tool if want to know what compilers would be doing in one case or another.
« Last Edit: November 09, 2022, 11:58:31 pm by ataradov »
Alex
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 5764
  • Country: dk
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #16 on: November 09, 2022, 11:59:27 pm »
AVR-GCC does (did?) everything in floats and even defined double as float

No, it did not.

These two types might share the same size and representation - this is not prohibited by the language spec. Which also means that AVR-GCC does everything in `double` - exactly as the language specification expects/requires it to, not in `float`.

I'll assume you are right, I haven't used AVR in eons, I just remember that they were both 32bit
 

Online DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6919
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #17 on: November 10, 2022, 12:00:48 am »
Simple: When any decimal operand lacks "f", the whole operation is made in double.
There's no such (integer*float), (float*double), (double*int) math, it's one thing or another.
You can multiply tomatoes or apples, but not tomatoes with apples.

(Yes, I know you can graft different vegetables in real life. Please don't argue with that lol)
« Last Edit: November 10, 2022, 12:03:40 am by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1908
  • Country: se
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #18 on: November 10, 2022, 12:14:46 am »
All compliant compilers will do that. This is required by the spec section 6.4.4.2 "Floating constants" (C11 case):
Quote
An unsuffixed floating constant has type double. If suffixed by the letter f or F, it has type float. If suffixed by the letter l or L, it has type long double.
Hey! That was my line!  :-DD
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: Siwastaja

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6427
  • Country: nz
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #19 on: November 10, 2022, 12:29:14 am »
so 1.5us per loop, but a corresponding double version runs much faster so clearly isn't compiling; optimisation must be removing code.

FFS. You really do have a one-track mind.
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3912
  • Country: it
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #20 on: November 10, 2022, 06:20:16 am »
now, now, he's still in the phase where he's suspicious of the compiler. give it anothe six months
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6002
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #21 on: November 10, 2022, 08:06:27 am »
OK you experts while you are taking the piss from somebody less super-clever than you... I hate to disappoint you, so here is some more.

float fred = 0;

This ends up in BSS, presumably, because 0 is zero in float as well.

What about

float fred = 0.0;

It should be the same. No runtime calculation.

What about

float fred = 3.2;

It won't be in BSS because it isn't zero. It will be in DATA or COMMON or... but am I right that there is still no runtime calculation i.e. 3.2 will be converted by the compiler into 3.2f ?

I don't think this is widely known because I have never seen 3.2f used anywhere. And on arm32 this should be much faster than doubles.
« Last Edit: November 10, 2022, 08:08:12 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 12465
  • Country: us
    • Personal site
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #22 on: November 10, 2022, 08:12:42 am »
Assignment, even as part of the initialization acts as an operator. you have a float variable initialized by a double constant. Of course it will be converted to float.

Types used for calculation and the final type don't have to match. "int a = 10 * 0.5;" would result in integer 5 stored in "a", even though the right part is double 5.0.

But I don't see what any of this has to do with anything here.

You have not looked at the embedded code that uses floating point a lot. This is used everywhere where people care about performance. Including on the X86 because floats pack better into vectored operations.  All performance-oriented code (like games) use floats for storage of coordinates and stuff like this.

And just as an example, I googled "stm32 dsp github" and clicked on the first link that was not ARM CMSIS package. Here is the code I've got https://github.com/YetAnotherElectronicsChannel/STM32_DSP_Reverb/blob/master/code/Src/main.c .  It uses floats and 'f' suffix everywhere. Honestly the first click on a random search. So, yes, people know about this.

And just for fun, I looked at the ARM DSP library. Again, all 'f's everywhere https://github.com/ARM-software/CMSIS-DSP/blob/main/Source/FastMathFunctions/arm_atan2_f32.c

And just to clarify, they are using 'f' even in the initialization of variables. This is not strictly necessary, but it indicates intent.  Plus if you work with floating point a lot, typing 'f' at the end of constants becomes automatic thing.
« Last Edit: November 10, 2022, 08:32:26 am by ataradov »
Alex
 
The following users thanked this post: peter-h, newbrain, Jacon

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6427
  • Country: nz
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #23 on: November 10, 2022, 08:59:03 am »
OK you experts while you are taking the piss from somebody less super-clever than you...

It's not a question of being clever. Many millions of people use gcc and it has been continuously developed for 35 years. Almost all of what it does is completely machine-independent, certainly the kinds of things you seem to be worried about. If there are any remaining bugs then they are very obscure ones, not in the super-common kinds of things you are writing.

Quote
What about

float fred = 3.2;

It won't be in BSS because it isn't zero. It will be in DATA or COMMON or... but am I right that there is still no runtime calculation i.e. 3.2 will be converted by the compiler into 3.2f ?

I will say it is probably completely undefined how it is done and all that is required is that 0x404ccccd ends up in fred somehow at the end.

If you insist on using -O0 (at least on a compiler more stupid than gcc) as you seem to like to then the compiler might well store a 64 bit double 0x400999999999999A into RAM somehow, then load it into some register, then use an instruction to convert it to float if there is an FPU or a runtime library function otherwise.

If you use -O1 or more than I personally would be disappointed if 0x404ccccd was not loaded directly into the final place.
 

Online peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6002
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #24 on: November 10, 2022, 09:21:53 am »
Quote
It's not a question of being clever. Many millions of people use gcc and it has been continuously developed for 35 years. Almost all of what it does is completely machine-independent, certainly the kinds of things you seem to be worried about. If there are any remaining bugs then they are very obscure ones, not in the super-common kinds of things you are writing.

did i write anything different?

Quote
If you insist on using -O0 (at least on a compiler more stupid than gcc) as you seem to like to

where did i say that?

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf