calcul simple

Bonsoir a tous,

Apres une petite prise de tete sur un sketch qui ne fonctionnait pas comme prévu je me suis rendu compte que

int H=4;
int M=53;

float a;

void setup() {
Serial.begin(9600);

a=((H*60)+M)/60;

Serial.print(a);
}

void loop() {}

retournait = 4.00 au lieu de 4.88
car M aurait du être un float.

je pige pas :
a=((H*60)+M)/60;
la division par 60 ne s'opere qu'a la fin ? non ?

merci pour vos lumieres ...

Bonjour,

Si tous les opėrandes sont entiers, le calcul est fait en entier.
Il faut diviser par un flottant
a=((H*60)+M)/60.0;

Merci kamill pour la réponse.

ça mange du stockage :confused:

et faut penser global global :confused:

pas d'échappatoire ?

ça mange quel stockage ?

Bon,
utiliser un int16_t au lieu d'un float mange .... deux octets supplémentaires. Ca reste frugal.

Les temps d'execution sont peut être un peu plus longs avec des floats.....

A priori , multiplier deux int16_t mange 4 multiplications sur 8 bits, 3 additions.
multiplier deux floats (estimation naîve) mange 9 multiplications sur 8 bits, 9 additions (+ un recadrage).

ok merci pour vos réponses.

ça mange du stockage :confused:

Je m'étonne. D'après votre déclaration :

float a;

Vous utilisez déjà une variable de type float. Donc l'espace de stockage est déjà réservé.
Que l'opération soit plus longue est une autre histoire. Mais si l'on parle de stockage et uniquement de stockage, il est identique dans les deux cas.

ClarkGaybeul:
Mais si l'on parle de stockage et uniquement de stockage, il est identique dans les deux cas.

pas tout à fait, le compilo doit allouer de l'espace mémoire pour 60.0 et générer du code pour un calcul en float versus int

donc impact SRAM et Flash

Il aurait supprimé le float .... ou l'optimiseur l'aurait fait....

pour le

float a;

normal vu que j'attend une valeur avec décimale.
c'est pour le

int M=53;

ClarkGaybeul:
Vous utilisez déjà une variable de type float. Donc l'espace de stockage est déjà réservé.
Que l'opération soit plus longue est une autre histoire. Mais si l'on parle de stockage et uniquement de stockage, il est identique dans les deux cas.

https://eskimon.fr/tuto-arduino-105-le-langage-arduino-12#d%C3%A9finir-une-variable

le float prend 2 fois plus de memoire ? non ?

@+

dbrion06:
Il aurait supprimé le float .... ou l'optimiseur l'aurait fait....

pas sûr de bien comprendre, si vous forcez un int dans un float, le compilateur honore le type demandé et alloue un float.

dbrion06:
Il aurait supprimé le float .... ou l'optimiseur l'aurait fait....

Comment ça ?

a=((H*60)+M)/60;

Le croquis utilise 2522 octets (8%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.
Les variables globales utilisent 184 octets (8%) de mémoire dynamique, ce qui laisse 1864 octets pour les variables locales. Le maximum est de 2048 octets.

a=((H*60)+M)/60.0;

Le croquis utilise 2522 octets (8%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.
Les variables globales utilisent 184 octets (8%) de mémoire dynamique, ce qui laisse 1864 octets pour les variables locales. Le maximum est de 2048 octets.

Il faut savoir que l'espace de stockage ne se réduit pas à la FLASH et la RAM.
Il y a aussi des registres, et le compilateur les utilise en priorité.

Le compilateur reporte ce qu'il est capable de calculer. Le 60.0 est dynamique pas alloué dans une variable.

Ensuite attention aux phase d'optimisation si le compilateur peut calculer pour vous à la compilation. Il faut introduire de la confusion :slight_smile:

Sur un MEGA avec

int H, M;
float a;
void setup()
{
  Serial.begin(115200);
  H = random(0, 24);
  M = random(0, 60);
  a = ((H * 60) + M) / 60;
  Serial.println(a);
}

void loop() {}

On obtient:

[size=8pt]Le croquis utilise [b][color=green]3738[/color][/b] octets (1%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent [b]206[/b] octets (2%) de mémoire dynamique, ce qui laisse 7986 octets pour les variables locales. Le maximum est de 8192 octets.[/size]

alors qu'avec:

int H, M;
float a;
void setup()
{
  Serial.begin(115200);
  H = random(0, 24);
  M = random(0, 60);
  a = ((H * 60) + M) / 60.0; // 60.0 force la seconde partie du calcul en flottant 
  Serial.println(a);
}

void loop() {}
[size=8pt]Le croquis utilise [b][color=red]3870[/color][/b] octets (1%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent [b]206[/b] octets (2%) de mémoire dynamique, ce qui laisse 7986 octets pour les variables locales. Le maximum est de 8192 octets.[/size]

--> On voit que plus de place a été alloué en SRAM dans le cas où on force le calcul en flottant mais la taille allouée pour les variables globales est restée identique puisque le 60 ou 60.0 sont dynamiquement insérés dans le code.

le float prend 2 fois plus de memoire ? non ?

Oui, mais si vous en êtes réduit à rabioter pour deux octets (soit 1 pour mille), vous êtes très proche de la saturation de votre RAM(et frôlez un dysfonctionnement)

Ce qui est bien plus gênant, c'est que, dès que vous utiliser -et surtout imprimez- des floats, comme JML l'a signalé, vous utilisez pas mal de flash : de mémoire, c'est un ou 2 K pour une librairie bien écrite, et, pour l'impression, 2 ou 4 k. Sur 32 K de flash, c'est au mieux 5% ....(cinquante fois plus qu'un float par ci par là)...

Même avec ça, le confort induit par l'usage de floats est plus agréable que de pifomètrer les bornes des variables, et en déduire leur type exact.... (vous pourriez multiplier M par 100 oi 1000 -unsigned int uint16_t- et faire vos calculs en 100 -ièmes- millièmes d'entiers : ça serait dur à écrire et à lire; avec une marge de 5-10%, ça ne vaut pas le coup pour un avr328 -ou supérieur-)

@JML:
dans un post plein de bon sens, vous avez introduit

Il faut introduire de la confusion

s:faut:peut:
(la confusion vient tout naturellement, pas besoin de l'aider)

ok merci dbiron06 et J-M-L pour tous ces éclaircissement. :slight_smile:

dbrion06:
@JML:
dans un post plein de bon sens, vous avez introduit s:faut:peut:
(la confusion vient tout naturellement, pas besoin de l'aider)

LOL :slight_smile:

Ce que je veux dire c'est qu'il faut que le calcul ne soit pas évident pour le pré-processeur

Si j'avais alloué H et M statiquement avec une valeur, alors le pré-processeur aurait fait le calcul pour moi et n'aurait pas généré de code.
Si vous regardez cela (sans la fonction random):

int H, M;
float a;
void setup()
{
  Serial.begin(115200);
  H = 20;
  M = 30;
  a = ((H * 60) + M) / 60.0; // 60.0 force la seconde partie du calcul en flottant
  Serial.println(a);
}

void loop() {}
[size=8pt]Le croquis utilise [b][color=purple]2812[/color][/b] octets (1%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent [b][color=purple]188[/color][/b] octets (2%) de mémoire dynamique, ce qui laisse 8004 octets pour les variables locales. Le maximum est de 8192 octets.[/size]

On voit que la SRAM et la FLASH ne sont plus du tout encombrées. En pratique le pré-processeur a tout viré et probablement affecté juste le résultat du calcul directement dans le print().

Je vais vous sembler un affreux pinailleur, mais c'est l'optimiseur qui vire avec une ardeur parfois déroutante tout ce qui prend de la place.
A ma connaissance, arduino a 2 préprocesseurs, l'un, spécifique a Arduino, pour remettre les fonctions dans l'ordre (ou faire croire qu'elles sont déclarées dans l'ordre) et exploiter les #include et le preprocesseur C: mais il n'a qu'un optimiseur.

Les variables globales utilisent 188 octets (2%) de mémoire dynamique.

Oui et j'obtiens personnellement 184 (IDE 1.8.5).

En pratique le pré-processeur a tout viré et probablement affecté juste le résultat du calcul directement dans le print().

Pas le préproc, plutôt le compilateur (optimisation)
Pour trancher et savoir ce qui se passe effectivement (utilisation des registres ou de la pile), il faudrait demander au compilateur de générer l'assembleur.
Un canon pour tuer une mouche dans le cas qui nous occupe.

Dans l'IDE ARDUINO, les outils mis à disposition ne permettent pas une investigation très poussée.
Sauf erreur de ma part (veuillez m'excuser, je connais mieux les compilateurs utilisés en ligne de commande avec Makefile ou CMake) L'IDE ne permet pas non plus de paramétrer l'optimisation, ce qui est souvent indispensable lorsque l'on utilise un débogueur. Mais comme il n'y a pas de débogueur dans l'IDE, cela ne pose pas de problème.

avr-gcc possède ces options :

  -O<number>                  Set optimization level to <number>
  -Ofast                      Optimize for speed disregarding exact standards
                              compliance
  -Og                         Optimize for debugging experience rather than
                              speed or size
  -Os                         Optimize for space rather than speed

Il faut savoir que l'espace de stockage ne se réduit pas à la FLASH et la RAM.
Il y a aussi des registres, et le compilateur les utilise en priorité.

J'ajouterai - oubli impardonnable de ma part - la pile.

Désolé de vous quitter mais je suis enseignant et très occupé.

Cordialement
Jo