5. Nombres et variables

5.1. Les nombres

Dans tout langage de programmation, la représentation des nombres occupe une place centrale. R n’échappe pas à la règle.

Une des caractéristiques les plus importantes de R est que c’est un langage vectorisé. C’est à dire que les opérateurs classiques prennent en argument des structures de données de type vecteur et non pas de simples scalaires. Ceci permet une écriture très compacte et favorise les performances algorithmiques.

La structure de données de base est donc le vecteur et le traitement de scalaires n’est en fait que le traitement de vecteurs de dimension 1 !

La conséquence directe est que le traitement d’un ensemble de valeurs ne nécessite pas l’emploi de boucles. Un corollaire de ceci est que l’utilisation d’une boucle for est généralement le marqueur d’un code de piètre qualité.

Important

A bas niveau, la vectorisation est traduite en une structure plus classique mettant en oeuvre le concept de boucle. Mais ceci est totalement transparent pour l’utilisateur.

Observons comment ceci fonctionne

> 1:10 # syntactic sugar to define a vector
 [1]  1  2  3  4  5  6  7  8  9 10
> 1:10 * 2    # no explicit loop !!
 [1]  2  4  6  8 10 12 14 16 18 20

D’autres exemples:

> 1:3 + 7:9
[1]  8 10 12

> 1:10 / 3 # division
 [1] 0.3333333 0.6666667 1.0000000 1.3333333 1.6666667 2.0000000 2.3333333
 [8] 2.6666667 3.0000000 3.3333333

 > 1:10 %/% 3 # integer division
 [1] 0 0 1 1 1 2 2 2 3 3

On peut effectuer des opérations mathématiques plus avancées:

> sum(1:1000)
[1] 500500

> mean(1:49)
[1] 25

> cos(pi/4 * 0:8)
[1]  1.000000e+00  7.071068e-01  6.123032e-17 -7.071068e-01 -1.000000e+00
[6] -7.071068e-01 -1.836910e-16  7.071068e-01  1.000000e+00

Comme dans tous les langages de programmation, la représentation des nombres réels est un sujet important. Comme cette représentation est liée à la mémoire de la machine, les opérations d’égalité ou d’inégalité doivent être traitées avec soin:

> cos(pi/2) == cos(3*pi/2)
[1] FALSE
> cos(pi/2)
[1] 6.123032e-17
> cos(3*pi/2)
[1] -1.83691e-16

Classiquement, on peut tester l’égalité à une marge près:

> abs(cos(pi/2) - cos(3*pi/2)) < 1e-15
[1] TRUE

Mais c’est une bonne pratique d’utiliser les fonctionnalités du langage, et pour ce sujet R core propose la fonction all.equal():

> all.equal(cos(pi/2), cos(3*pi/2))
[1] TRUE

Comme en Python, le nombre complexe fait partie du langage de façon native:

> 2 * (1 + 2i)
[1] 2+4i
> exp(pi * 1i)
[1] -1+0i

Les nombres réels sont dans le domaine décrit par l’instruction .Machine

> .Machine
...

$double.xmin
[1] 2.225074e-308

$double.xmax
[1] 1.797693e+308
...

Le domaine est dépendant de la machine.

5.2. Variables

Le résultat de calcul peut être affecté à des variables pour une réutilisation ultérieure:

> x <- cos(pi/6)
> x
[1] 0.8660254

> y = sin(pi/6)
> y
[1] 0.5

Important

L’opérateur d’affectation <- est l’opérateur historique et sera utilisé de préférence bien que l’opérateur = fonctionne également. Cet article recense les opérateurs d’affectation utilisés par différents langages.

La variable est généralement à gauche (LHS : left hand side) et c’est la façon qui sera privilégiée pour rester cohérent avec la plupart des langages, dont Python. Mais il est également possible de la mettre à droite (RHS : right hand side) de l’opérateur d’affectation

> cos(pi/6) -> x
> x
[1] 0.8660254

Comme on l’a vu précédemment, “ls() fournit la liste des variables disponibles dans l’espace de travail:

> ls()
[1] "x" "y"

Stocker le résultat de l’évaluation d’une expression est indispensable pour une réutilisation ultérieure:

> z <- x**2 + y**2
> z
[1] 1
> ls()
[1] "x" "y" "z"

Les variables peuvent être détruites avec la fonction rm() comme on l’a déjà vu dans le chapitre” Utiliser R:

> rm(z)
> ls()
[1] "x" "y"

5.3. Nombres spéciaux

La manipulation de données numériques nécessite les types int, double et complex. Ceci est parfaitement opérationnel pour les données existantes.

Mais comment représenter l’absence de données ? En fonction du contexte, on pourra utiliser 0, une très grande valeur, une valeur négative lorsque l’on traite des données positives, etc… Mais ceci doit se faire au cas par cas, en fonction du contexte et interdit les opérations vectorisées.

Pour résoudre ces problèmes, R utilise une valeur numérique spéciale NA (Not available):

> x <- NA
> x
[1] NA

Les opérations mathématiques mettant en jeu des NA produisent des NA:

> cos(x)
[1] NA

Ceci permet d’éviter l’utilisation de tests avant le traitement des données ce qui simplifie grandement le code.

Une autre valeur singulière est la représentation de l’infini qui peut apparaitre au cours d’un calcul avec l’opération 1/0 par exemple. La plupart des langages ont une réponse insatisfaisante à ce problème, voire pas de réponse du tout. Ce genre de problème se traite avec des tests pre opératoires ou par la gestion d’exceptions.

R apporte une réponse élégante en identifiant explicitement les valeurs infinies:

> 1/0
[1] Inf
> -1/0
[1] -Inf
> exp(-Inf)
[1] 0

Un dernier nombre spécial est utilisé par R pour représenter l’indétermination mathématique. Il s’agit de NaN (Not A Number):

> Inf/Inf
[1] NaN

Généralement, les opérations produisant des NaN déclenchent des warnings:

> sin(Inf)
[1] NaN
Warning message:
In sin(Inf) : NaNs produced