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

0 Members and 1 Guest are viewing this topic.

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 19497
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #25 on: November 10, 2022, 09:58:26 am »
now, now, he's still in the phase where he's suspicious of the compiler. give it anothe six months

Why only 6 months? You should always be suspicious of what a C compiler is doing.

The output can vary between compilers.
The output can vary between optimisation levels.
The output can vary between language standards.
The output can vary over time as the compiler becomes capable of more optimisations. That's up to and including starting to remove blocks of your code because you didn't understand where the nasal dæmons lie.

And, of course, because you[1] don't understand all the interacting "features" of the C language as well as you thought you do.

[1] I am, of course, using "you" in the modern English parlance, to "mean a generic person" rather than one specific person. Shame that it is now regarded as archaic to avoid using "And, of course, because one doesn't understand all the... of one's code..." :)
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 19497
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #26 on: November 10, 2022, 10:10:35 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.

Back in the early 80s (when I first used C), it was common knowledge that multithreading and multiprocessor uses of C were explicitly outside the language definition.

Over the decades the complexity of C and its compilers increased dramatically, and apparently it became so complicated that people forgot that. No doubt that was aided and abetted by some compilers "doing the right thing" when the wind was in the right direction. In any case, in 2004 it became necessary for Hans Boehm (of the conservative C garbage collector fame) to remind people that you couldn't write threading libraries in C.

I am told that has changed with more recent C language standards, but fortunately I've been able to avoid finding out the extent to which recent compilers get it right.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Online brucehoult

  • Super Contributor
  • ***
  • Posts: 4035
  • Country: nz
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #27 on: November 10, 2022, 11:03:06 am »
In any case, in 2004 it became necessary for Hans Boehm (of the conservative C garbage collector fame) to remind people that you couldn't write threading libraries in C.

That was not his claim.

His claim was that C programs can't USE threads implemented in libraries (no matter how they are implemented), under the assumption that they try to synchronise themselves using access to shared global variables instead of using the lock/semaphore primitives provided by the library -- so called "lock free" programming.

If you use the locks to manage any shared globals then all is ok semantically, it's just that on a many core multiprocessor doing this frequently you quickly grind to a halt and get less than single-threaded performance.

Quote
I am told that has changed with more recent C language standards,

It has changed. C now has a memory model, with the ability to specify acquire and/or release semantics on memory accesses.

Quote
but fortunately I've been able to avoid finding out the extent to which recent compilers get it right.

It's more for the users to get right than the compilers.
 
The following users thanked this post: Siwastaja, newbrain

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #28 on: November 10, 2022, 11:21:58 am »
OK you experts while you are taking the piss from somebody less super-clever than you...
Not related, those are not operations, but initialized data, will be handled by the preprocessor and create constants loaded from flash.
The problem comes when a variable enters the game.
Code: [Select]
float a = 1.05;  // This is float from the beginning
void foo(){
  float b = a * 1.3;  //  'a' will be converted and processed as double, later converted into float again
}
« Last Edit: November 10, 2022, 11:25:41 am 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: peter-h

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #29 on: November 10, 2022, 12:07:46 pm »
Interesting. I went through all my code and didn't find any cases where the 'f' would have helped. I use doubles in places where it doesn't matter e.g. calcs related to a 22 bit ADC with a 90ms conversion time :)

I use floats for storing stuff in flash, and I am storing a lot of values, so don't want to use 8 bytes for each one.

Re thread safety of C code, various threads on that. You can look up the ones about the Newlib libc.a in GCC and its bogus mutex stubs, which were not 'weak' so fixing them was nontrivial. This related to printf (if outputting longs or floats) and the heap (itself, and its use by printf). But that is another topic. AFAIK C is thread safe in general, but some libs use statics and such.

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

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #30 on: November 10, 2022, 02:04:53 pm »
Try this in the f446, it has single-precision FPU so the first loop should take a lot longer. (Obviously, remember to enable DWT)
Code: [Select]
void test(void){
    volatile float f=1.0f;  // Volatile to bypass optimizations

    DWT->CYCCNT = 0
    for(uint16_t  i=0; i<10000; i++)
         f  *= 1.05;
    asm("nop");         //Breakpoint

    f=1.0f;
    DWT->CYCCNT = 0;
    for(uint16_t  i=0; i<10000; i++)
        f  *= 1.05f;
    asm("nop");         //Breakpoint
}

Edit: Ran this on my phone (Coding C app, great for these little tests), the results were:
67135ns
43959ns
« Last Edit: November 10, 2022, 02:22:21 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: peter-h

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #31 on: November 10, 2022, 02:21:41 pm »
Let me check two more things:

float x,y;

x=2*y; - is there any double promotion?
x=2.0*y; - double promotion
x=2f*y; - no promotion
x=2.0f*y; - no promotion

Is that right and what happens in the 1st one?

Disregard the possibility of 2x being done by incrementing the exponent (I used to do that in asm) :)

What is the meaning of

uint32_t x;
x = 1000UL;
x = 1000L;
x = 1000;

Surely all are identical, for positive numbers where bit 31 = 0.



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

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 19497
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #32 on: November 10, 2022, 02:39:39 pm »
In any case, in 2004 it became necessary for Hans Boehm (of the conservative C garbage collector fame) to remind people that you couldn't write threading libraries in C.

That was not his claim.

His claim was that C programs can't USE threads implemented in libraries (no matter how they are implemented), under the assumption that they try to synchronise themselves using access to shared global variables instead of using the lock/semaphore primitives provided by the library -- so called "lock free" programming.

If you use the locks to manage any shared globals then all is ok semantically, it's just that on a many core multiprocessor doing this frequently you quickly grind to a halt and get less than single-threaded performance.

If a language precludes using a multithreading library, then it also precludes implementing a multithreading library.

Quote
Quote
I am told that has changed with more recent C language standards,

It has changed. C now has a memory model, with the ability to specify acquire and/or release semantics on memory accesses.

Boehm wrote his paper because it was necessary to force people to realise that a memory model was required. That is remarkable (and IMHO damning) since it had been obvious in other languages for a very long time.

Quote
Quote
but fortunately I've been able to avoid finding out the extent to which recent compilers get it right.

It's more for the users to get right than the compilers.

What was the interval between the C++(99?) standard appearing and the first complete compiler appearing? 6 years, IIRC - but that should be taken with a pinch of salt since I chose not to use C++ in the late 80s, and I've seen nothing to make me doubt that decision.

C/C++ compiler writers traditionally blame the user before examining the alternatives. Whether that is justified is a separate issue. The main point is it indicates that the ecosystem has become too complicated for its own good (and that of its users).
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #33 on: November 10, 2022, 02:43:42 pm »
"2f” is not valid, floats/doubles must be decimal.

UL = Unsigned Long
L = Signed Long
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: newbrain

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #34 on: November 10, 2022, 03:24:02 pm »
Yes I know UL and L but does the compiler do anything different? ISTM that this notation is just a reminder for the programmer.

So anything with an f must have a DP in it. OK.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #35 on: November 10, 2022, 03:44:15 pm »
Ensures it's not threated as a shorter type.
Sometimes you can make something like:
Code: [Select]
#define THIS 64
unsigned long var_A = THIS*2048;
// var_ A is 0, not 131072 ?!
The compiler could threat THIS as 8-bit 16bit, as 64 fitted perfectly in it, causing an unintended overflow if used as math operand:
Code: [Select]
  64                1000000
 *2048         100000000000
 =131072  10000000000000000
 out:      0000000000000000
By specifying the type, you proof yourself from those problems, causing bugs sometimes can be very tricky to catch.
Code: [Select]
#define THIS 64UL
//#define THIS (uint32_t)64

unsigned long var_A = THIS*2048;
// var_ A is 131072!

But this is more common in 8/16 bit architectures, where the working registers can be smaller than the integer used.
« Last Edit: November 10, 2022, 06:56:23 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #36 on: November 10, 2022, 04:37:57 pm »
Quote
#define THIS 64
unsigned long var_A = THIS*128;
// var_ A is 0, not 8192 ?!
The compiler could threat THIS as 8-bit, as 64 fitted perfectly in it.

I find that staggering. Isn't there a rule that each part of the RH expression is cast to the type of the destination, prior to it being evaluated? That is really horrible.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #37 on: November 10, 2022, 04:56:41 pm »
I only had these issues in 8-bit compilers.
On the end you simply learn these tricks.
Nowadays it's rarely required with so many of 32-bitters.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #38 on: November 10, 2022, 05:08:53 pm »
I find that staggering. Isn't there a rule that each part of the RH expression is cast to the type of the destination, prior to it being evaluated? That is really horrible.

In C or in C++ the left-hand side hever has any influence on the right-hand side (with perhaps some narrow exceptions).
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 11257
  • Country: us
    • Personal site
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #39 on: November 10, 2022, 05:09:03 pm »
Isn't there a rule that each part of the RH expression is cast to the type of the destination, prior to it being evaluated?
No, there is not. There may not even be a destination. Expressions don't have to have assignments in them.

C has fixed promotion rules. It helps to know them https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules
Alex
 
The following users thanked this post: newbrain

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #40 on: November 10, 2022, 05:12:17 pm »
Ensures it's not threated as a shorter type.
Sometimes you can make something like:
Code: [Select]
#define THIS 64
unsigned long var_A = THIS*128;
// var_ A is 0, not 8192 ?!
The compiler could threat THIS as 8-bit, as 64 fitted perfectly in it.

Not, it couldn't.

Firstly, `64` is an `int` by the rules of the language. And `int` is required to be at least 16-bit wide, everywhere.
Secondly, C and C++ never preform evaluations in types smaller than `int`, thanks to integral promotions. E.g. even when you multiply two 8-bit `char`s, they will still be multiplied as `int`s.

In other words, no conforming C or C++ implementation can have 8-bit arithmetics.

I only had these issues in 8-bit compilers.

There's no such thing as "8-bit compiler". More precisely, a compiler can refer to itself as "8-bit" as much as it wants, but it will always be required to perform integer arithmetics in 16 bits at least. No way around it.
« Last Edit: November 10, 2022, 06:55:05 pm by TheCalligrapher »
 
The following users thanked this post: newbrain, SiliconWizard

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #41 on: November 10, 2022, 05:34:35 pm »
I might be wrong about the 16-bit min. integer size , I can't remember whether the issue happened with ints or longs.
But that's the idea.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #42 on: November 10, 2022, 05:44:40 pm »
I might be wrong about the 16-bit min. integer size , I can't remember whether the issue happened with ints or longs.

I'm not sure what you are trying to say here. In your previous example you claimed that you saw implementations with 8-bit `int` (i.e. `8192` becomes `0`). Eight, not sixteen.

How does your "I might be wrong about the 16-bit min. integer size" fit into that picture?
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #43 on: November 10, 2022, 06:45:44 pm »
I think its pretty clear, isn't?

"I can't remember whether the issue happened with ints or longs".

Isn't that self-explanatory? It feels really weird to have to explain this to someone apparently smart who just wrote half chapter of the C spec.
That code was a simple example of unexpected overflow, not real code.
I thought It happened with 8-bit, so I made a example for it, but if the rules use at least 16-bit, then just replace 128 by 2000 in your mind.

As I say, I don't remember, happened several years back, a 32bit var was getting a weird result, the problem was caused by the naked define.
« Last Edit: November 10, 2022, 06:57:37 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #44 on: November 10, 2022, 08:18:41 pm »
Not related, those are not operations, but initialized data, will be handled by the preprocessor and create constants loaded from flash.
The preprocessor does not enter the picture at all here.

To be more precise, it has entered the scene and left by the end of translation phase 4, while semantic and syntactic analysis of the resulting tokens happens in translation phase7.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online brucehoult

  • Super Contributor
  • ***
  • Posts: 4035
  • Country: nz
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #45 on: November 10, 2022, 08:59:30 pm »
Quote
#define THIS 64
unsigned long var_A = THIS*128;
// var_ A is 0, not 8192 ?!
The compiler could threat THIS as 8-bit, as 64 fitted perfectly in it.

I find that staggering. Isn't there a rule that each part of the RH expression is cast to the type of the destination, prior to it being evaluated? That is really horrible.

Certainly not! Whatever gave you that idea?

Semantically, the evaluation of the expression is totally unrelated to the place the result will eventually be put. Each constant or variable in an expression has its own type, the result of each operator depends only on the type of its operands.

If you're going to program in a language then you really should learn the rules of that language, not make up something about how you think a language should work.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5907
  • Country: es
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #46 on: November 10, 2022, 09:24:35 pm »
I can only relate to experience! Can't tell if It was a compiler bug or my fault!
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #47 on: November 10, 2022, 09:40:37 pm »
Come on... there has to be something like that, otherwise

int32_t x = -5

would just load -5 into the LS byte :)
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online brucehoult

  • Super Contributor
  • ***
  • Posts: 4035
  • Country: nz
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #48 on: November 10, 2022, 09:50:15 pm »
Come on... there has to be something like that, otherwise

int32_t x = -5

would just load -5 into the LS byte :)

-5 is an int, as it is not large enough to need to be a long.  There is no such thing as a char-sized literal in C. Not even 'A', which is (on ASCII systems) an int with value 65.

The = operator converts the value on the right hand side to whatever type is required by the left hand side.

In this case there is no conversion to be done unless you are compiling for an 8 or 16 bit machine where int is only 16 bits, or a 64 bit machine with ILP64 model where int is 64 bits (this is unusual, almost all 64 bit machines use LP64 with int being 32 bits)

Try reading a book on C, seriously. Don't just make stuff up.
 
The following users thanked this post: newbrain, JPortici, Jacon, SiliconWizard

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14471
  • Country: fr
Re: When does C require 10.0 instead of 10 when dealing with float or double?
« Reply #49 on: November 10, 2022, 09:57:15 pm »
Or, uh... use Rust? :-DD
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf