Arduino et calcul

Bonjour tout le monde

Débutant sur cette plateforme avec un programme simple , une simple multilication mais le résultat final est aberrant.

le Code:

long a = 0 ;

void setup()
{
Serial.begin(115200);
}

void loop()
{
a = 10*3600 ;
Serial.print ("a :");
Serial.println (a);
delay (2000);
}

résultat affiché dans le terminal série -29536
En definissant la variable a en unsigned long le resultat est : 4294937760
en réalisant l'oppération 5*3600 le résultat est 18000 juste

Une idée?

J'ai omis de préciser Arduino 2000 et Pro mini avec Atmega 328 5V

Bonjour,

t'es sûr que tu as déclaré a en long ? et pas en int ?

essaie de déclarer:
long a = 0L;

et
a = 10L *3600L;

La représentation binaire des deux résultats que tu obtiens est la même: FFFF8CA0 alors que tu devrais avoir 8CA0.
C'est probablement un problème d'initialisation de tous les bits du long.
Normalement j'imagine que les littéraux int sont convertis en long quand ils sont affectés à une variable de type long mais je n'en suis pas sûr et il est plus prudent de déclarer les littéraux comme étant des long.

Copier collé du code

par contre un test que je n'ai pas fait (je suis sous linux arduino 1.0.5) essayé sous windows

Pour moi c'est une problème de précompilateur pas bien malin.

Ton expression 10x3600 n'est pas évaluée lors de l'exécution du programme, mais lors de la phase de précompil, avec un résultat de calcul inséré dans le code.
Et visiblement ce résultat est stocké sur deux octets, et considéré comme un entier signé.
Tu remarqueras que 10*3600 + 29536 = 65536 = 2^16
Sur deux octets, la valeur 36000 stockée en hexadécimal est 8CA0, qui peut aussi correspondre à -29536 si tu raisonnes en entier signé codé sur deux octets.

Par la suite, à l'exécution de ton programme, cette valeur est transférée dans un entier long signé a (ton premier cas de test), stocké sur 4 octets. Lors de ce transfert, il y a ambiguité : ta variable a peut stocker aussi bien -29536 (FFFF8CA0) que 3600 (00008CA0). Visiblement le compilo choisit d'étendre le 8CA0 en FFFF8CA0 pour le stocker sur 4 octets.
C'est-à-dire qu'il considère qu'il a à faire à un entier signé.

Cette valeur FFFF8CA0 stockée en mémoire donne à l'affichage :
-29536 si tu considères qu'il s'agit d'un entier long signé
2^32 - 29536 = 4294937760 si tu considères qu'il s'agit d'un entier long non signé

Ce qui explique bien les deux résultats que tu obtiens.
5x3600 ne pose aucun problème car le résultat 18000 est inférieur = 32768 = 2^16 / 2
J'espère avoir été clair.

Il faut donc que tu expliques à ton idiot de compilo ce que tu attends de lui.
Peut-être en jouant sur certaines de ses options, mais le plus simple est de lui expliciter ton code.

Par exemples qui devraient marcher :

a = 10L * 3600L;
a = (long int)10 * (long int)3600;
a = 3600;
a *= 10;

@ bricoleau

Merci pour cette réponse claire.

Tu doit t'en douter que le code que j'ai posté est un exemple extrait d'un ensemble plus complexe.

En fait le but est de trouver a un instant "t" le Nb de ms ecoulée depuis minuit, l'ensemble étant basée sur la librairie time.h.

  time_t t = now(); // Store the current time in time variable t
  timer = (hour(t)*3600 + minute(t)*60 + second(t))*1000;

Je vais donc voir comment contourner ce probleme

@bricoleau : belle analyse !

Dans tous les cas si c'est vérifié, ça mérite un petit signalement chez la team Arduino ... Quand on voit la simplicité du code pour générer le problème, déjà que moi je me serais sacrément pris la tête, j'imagine un débutant ...

@jacquot : quelle version de l'IDE utilises-tu ?

1.0.5 sous Debian

J'ai fais le testsous la 1.0.6 sous windows le probleme est le meme

B@tto:
Dans tous les cas si c'est vérifié, ça mérite un petit signalement chez la team Arduino ... Quand on voit la simplicité du code pour générer le problème, déjà que moi je me serais sacrément pris la tête, j'imagine un débutant ...

C'est pas un problème d'ide arduino mais bien de compilateur.
Et comme le compilateur AVR-GCC fourni avec l'ide arduino (version window uniquement) date de 2008 ... ça fait un sacré paquet de bug connus qui peuvent poser problème.

Si j'en crois ma boule de cristal c'est un bug connu qui date de 2009 :
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37466
(pas encore totalement sur que ce soit celui-là en particulier mais ça y ressemble bien)

Donc en gros :

  • Soit la team arduino se décide à passer à MHV AVR TOOLS pour la version windows de AVRGCC.
  • Soit tout le monde fait la mise à jour soit même (c'est juste un simple ^c^v à faire).

Le seul problème de la mise à jour, c'est que les nouvelles versions de AVR-GCC sont beaucoup plus stricts concernant les constantes PROGMEM "non-const". Du coup à la compilation il faut penser à modifier pas mal d'anciennes librairies qui utilisent progmem sans "const".

pepe:
Je confirme l'analyse de bricoleau. J'ai fait quelques essais (avec l'IDE version 1.5.7 pour Mac OS X) qui ont donné :

Tu peux aller dans le dossier d'installation de avr-gcc (je sais pas du tout comment il s'appelle sous OSx. Sous windows c'est ledossierd'installationd'arduino/hardware/tool/avr/bin). Et faire un "avrgcc -v" en console pour avoir la version d'avr-gcc ?

pepe:
Chez moi il donne :

gcc version 4.8.1 (GCC)

Et le bug est présent ?
(si oui ça sent la vilaine régression qu'il faut signaler sur le bug-tracker de gnu-gcc).

Edit Je suis aller vérifier et d'un point de vue purement langage C/C++, le suffixe L/U/UL est sensé être mis à chaque déclaration de variable pour dimensionner les constants lors de la phase de précompilation. Le suffixe n'est obligatoire que pour le membre le plus à gauche de l'expression.
Donc en soit c'est pas vraiment un bug, c'est plutôt une (drôle de) fonctionnalité. :grin:

En plus ça marche !!!

Merci beaucoup pour ces infos que je n’avais jamais trouvé. Je parles de ces suffix.

+1 ...

pepe:
C'est un comportement compréhensible du point de vue de la norme, mais plutôt surprenant quand on sait à quel point GCC est habituellement trop permissif.

Tout dépends du dév qui a bossé sur l'implémentation de la norme.
Avec gcc tu as des trucs assez marrant dés fois :sweat_smile:
(comme les "variable length array", que dieu punisse l'inventeur de cette saloperie :zipper_mouth_face:)

pepe:
Pour le coup, c'est une assez mauvaise surprise. Arduino étant plutôt destiné aux débutants, on aurait pu espérer que ce genre de problème (qui ne se pose généralement plus) ne leur soit pas imposé en plus des autres difficultés qu'ils ont déjà à régler.

Si la team arduino se décidait à mettre à jour la version d'avr-gcc fourni avec l'ide se serait déja pas mal. Depuis 2008 pas mal de chose ont changé (en bien comme en mal d’ailleurs).