Calculer avec l’Arduino (1)

. Par : Jean-Luc. URL : https://www.locoduino.org/spip.php?article66

L’Arduino est programmable, comme cela a été présenté dans « La programmation, qu’est ce que c’est » et il peut manipuler des constantes et des variables qui ont un type, comme on a pu le voir dans « Types, constantes et variables ». Nous avons déjà vu quelques calculs dans ce dernier article et nous allons maintenant examiner plus en détail comment calculer avec l’Arduino et comment utiliser les opérateurs de calcul.

Nous avons déjà rencontré les opérateurs de comparaison dans « Instructions conditionnelles : le if ... else ». Nous n’allons pas revenir dessus mais ce que nous allons voir s’applique également a ces opérateurs.

On combine les opérateurs avec les variables et les constantes, littérales ou symboliques [1], pour construire des expressions plus ou moins complexes. Voici un exemple d’instruction qui affecte à la variable distance le resultat d’une expression :

distance = vitesse * (tempsFin - tempsDebut);

Cette expression calcule la distance parcourue par un train à partir de sa vitesse, de l’instant de départ (tempsDebut) et de l’instant d’arrivée (tempsFin). Le résultat du calcul est rangé dans, on dit également affecté à, la variable distance [2]. Les opérateurs employés ici sont la multiplication (*), la soustraction (-) et l’affectation (=).

Vous avez sans doute remarqué les parenthèses autour de la soustraction. Ces parenthèses sont nécessaires car les opérateurs ont une priorité : la multiplication est plus prioritaire que la soustraction. Que se passerait-il si on retirait les parenthèses comme ceci :

distance = vitesse * tempsFin - tempsDebut;

En l’absence de parenthèses, la multiplication entre vitesse et tempsFin serait effectuée en premier. Puis, en second, la soustraction entre le résultat de la multiplication et tempsDebut serait effectuée. Le résultat serait donc erroné.

Une règle simple a appliquer est de systématiquement mettre des parenthèses pour ne laisser aucune ambiguïté sur l’ordre des calculs [3] !
 

Le signe = est également un opérateur. Il s’agit de l’opérateur d’affectation. Une affectation, par exemple :

a = b + c;

est donc également une expression et par conséquent on peut tout à fait écrire :

d = (a = b + c) + 1;

Ce qui aura pour effet d’ajouter les valeurs contenues dans les variables (ou constantes) b et c, mettre le résultat dans la variable a, ajouter 1 à ce résultat pour le mettre dans la variable d.

En pratique c’est peu utilisé sauf pour initialiser plusieurs variables en une seule ligne. On écrira par exemple :

a = b = c = 0;

Ce qui a pour effet d’initialiser les variables a, b, c et d à 0.

Les quatre opérations

Les opérateurs usuels pour calculer sont l’addition, la soustraction, la multiplication et la division.

  • + est l’opérateur d’addition
  • - est l’opérateur de soustraction
  • * est l’opérateur de multiplication
  • / est l’opérateur de division

Comme nous l’avons vu dans « Types, constantes et variables », le résultat d’un calcul dépend également du type des variables qui figurent dans l’expression, il faut faire attention à ce que le résultat ne soit pas trop grand ou trop petit pour tenir dans le type choisi.

Avec les types entiers : byte, int, word, long ou encore unsigned long, la division est une division entière, ou euclidienne. Elle donne donc un résultat entier : 4/3 donnera 1 et non pas 1,33333333. On peut également calculer le reste de la division entière. Il s’agit de l’opérateur %. Cette opération s’appelle également le modulo. Ainsi 4%3 donnera 1.

À cela s’ajoutent des opérateurs qui rendent l’écriture plus concise. Il s’agit des opérateurs d’incrémentation et de décrémentation ainsi que des quatre opérations combinées avec l’affectation.

Les opérateurs d’incrémentation et de décrémentation

Ces opérateurs sont respectivement notés par ++ et --.
On peut les mettre avant ou après une variable pour l’incrémenter ou la décrémenter. Positionner ces opérateurs avant ou après ne fait pas de différence en ce qui concerne la valeur qui sera mise dans la variable. Par contre cela fait une différence en ce qui concerne la valeur de l’expression. Par exemple :

int c = 0;
int d = c++;

aura pour effet de mettre la valeur 1 dans c et la valeur 0 dans d. En effet, le fait que ++ soit placé après c signifie que la valeur initialement présente dans c est affectée à d puis ensuite c est incrémenté.

À l’inverse, le fait de mettre l’opérateur devant la variable comme ceci :

int c = 0;
int d = ++c;

aura pour effet de mettre la valeur 1 dans c et la valeur 1 dans d. En effet, le fait que ++ soit placé avant c signifie que c est d’abord incrémenté puis la valeur maintenant présente dans c est affectée à d.

Si dans une expression plus compliquée, ces opérateurs apparaissent plusieurs fois et opèrent sur la même variable, on s’y perd rapidement. Une bonne pratique consiste donc à utiliser cet opérateur seul dans les expressions.

Les opérateurs combinés avec l’affectation

Ces opérateurs permettent une plus grande concision. Par exemple, au lieu d’écrire :

a = a + (c * d);

on écrira :

a += c * d;

Il en existe un pour chaque opérateur : +=, -=, *=, /= et %=.

Les nombres à virgule

Un petit mot sur les nombres à virgule. Nous allons assez rarement les utiliser mais si les entiers ne suffisent pas, ils sont nécessaires. On utilise pour ces nombres le type float qui occupe 4 octets. float signifie flottant en anglais et à un rapport avec la façon dont la position de la virgule est codée dans ce type. On parle de flottant car le nombre de chiffre avant et après la virgule change selon les besoins.

Aucun des Arduino disponibles ne possède d’unité de calcul matérielle sur le type float. Les calculs sont donc très lents [4]. Un constante float se déclare comme suit :

const float pi = 3.14159;

Notez le point qui sépare la partie entière de la partie décimale. On note à l’anglo-saxonne avec un point et non une virgule.

Lorsque l’on mélange des calculs avec des nombres entiers et des nombres flottants, il faut être méfiant. Notamment lorsqu’un entier est divisé par un autre pour affecter le résultat à un flottant, la division reste une division entière ce n’est qu’après que le résultat est converti en nombre flottant pour être affecté à la variable flottante. Par exemple :

int a = 200;
int b = 150;
float c = a / b;
Serial.println(c);

affichera 1.00 car la division est une division entière alors qu’on ce serait attendu à obtenir 1.33. Pour obtenir une division flottante, il faut forcer le type d’une des entiers. Forcer se dit cast en jargon informatique anglais. Il s’agit d’expliquer qu’en fait la variable a ou b doit être convertie en nombre flottant avant de faire la division. Ce forçage engendrera l’utilisation de la division flottante au lieu de la division entière. Il suffit pour cela de préfixer la variable ou la constante à forcer par le type voulu entre parenthèses comme ceci :

int a = 200;
int b = 150;
float c = (float)a / b;
Serial.println(c);

Ici la variable entière a est forcée en type flottant. Cette fois le résultat affiché est bien 1.33.

La seconde partie de cet article sera consacrée aux opérateurs de manipulation des bits.

La suite de la série d’articles avec « Répéter des instructions : les boucles ». Si ce n’est pas déjà fait lisez également « La programmation, qu’est ce que c’est », « Types, constantes et variables » et « Instructions conditionnelles : le if ... else »

[1Pour savoir ce qu’est une constante symbolique ou une constante littérale, lisez « Types, constantes et variables »

[2Encore du vocabulaire militaire ! quand je vous disais que l’ordinateur exécutait des instructions et que les instructions étaient des ordres

[3l’alternative étant d’apprendre l’ordre de priorité des 43 opérateurs qui existent ainsi que l’ordre des calculs quand les operateurs ont des priorités identiques.

[4Tout est relatif. Les calculs sont lents comparés aux calculs sur des nombre entiers mais la vitesse est tout de même respectable.