# Algorithmique et programmation en seconde ### Renée De Graeve Bernard Parisse

# Table des matières

# Index

(), 2.1.2 :;, 2.3.3 :=, 2.3.1 ;, 2.3.3 =, 2.2.3 ==, 2.1.3 [], 2.1.2, 2.1.2 !=, 2.1.3 ", 2.1.2 <, 2.1.3 <=, 2.1.3 >, 2.1.3 >=, 2.1.3 carre, 4.5 cercle, 4.6 coeff, 2.1.4, 5.2.2 coordonnees, 4.2 debug, 2.5 degree, 2.1.4 dim, 2.1.2 droit, 2.1.2, 5.2.2 droite, 4.3 equation, 4.3, 4.6 erreur d’exécution, 2.5 erreur de syntaxe, 2.5 evalf, 2.1.1 exécution, erreur de, 2.5 expression, 2.2.5 fpour, 2.3.6 fsi, 2.3.8 ftantque, 2.3.10 func, 2.2.5 gauche, 2.1.2, 5.2.2 | gcd, 2.3.5 identifier, 2.2.5 integer, 2.2.5 iquo, 2.2.3 iquorem, 2.2.3 irem, 2.2.3 local, 2.3.5 normal, 2.1.4 op, 2.1.2 pas, 2.3.7 plotfunc, 2.2.3 point, 2.4, 4.1 poly2symb, 2.1.4 polygone, 4.5 polygone_ouvert, 4.4 pour, 2.3.6 purge, 2.3.2 quand, 2.2.4 rational, 2.2.5 real, 2.2.5 retourne, 2.3.4 segment, 2.4, 4.1 si, 2.3.8 simplify, 2.1.4 string, 2.2.5 subtype, 2.2.5 symb2poly, 2.1.4 syntaxe, erreur de, 2.5 tantque, 2.3.10 triangle, 4.5 type, 2.2.5 vector, 2.2.5

# Chapitre 1 Avant-propos

Ce document est principalement destiné aux enseignants qui souhaitent utiliser le langage de programmation de Xcas pour enseigner l’algorithmique au lycée, nous espérons qu’il sera aussi consulté par des élèves. Dans sa version HTML consultable depuis un navigateur, certains champs de saisies peuvent être modifiés et testés directement, y compris sur une tablette ou un smartphone, ce qui devrait être un plus par rapport à un cours de programmation papier ou PDF (les fonctions “utilitaires” qui sont appelées plusieurs fois par d’autres fonctions n’ont pas besoin d’être validées par l’utilisateur, elles sont interprétées au chargement).

L’utilisation de Xcas peut se faire depuis un terminal mobile (smartphone ou tablette) sans installation, il suffit d’ouvrir un navigateur (Firefox recommandé) et de suivre ce lien
http://www-fourier.ujf-grenoble.fr/~parisse/xcasfr.html
(L’accès réseau est nécessaire uniquement lors de la première consultation). Il n’est donc pas indispensable d’aller en salle informatique pour faire un exercice d’algorithmique pendant un cours de mathématiques, on peut utiliser les smartphones (en mode avion) ou les tablettes des élèves comme des super-calculatrices (formelles, graphiques, 3d, ... il ne manque que le mode examen...). C’est une raison supplémentaire pour écrire ce document, car faire programmer les algorithmes par les élèves nous parait indispensable pour les motiver par la satisfaction de faire tourner son programme puis de le modifier et l’améliorer. On peut d’ailleurs regretter le nombre important d’exercices de bac qui demandent de comprendre ce que fait un algorithme non commenté, dans ce type d’exercices l’élève n’a aucun rôle créateur (il ne conçoit pas l’algorithme), il a un rôle analogue à celui d’un professeur corrigeant des copies ce qui n’est pas du tout motivant1, et a devant les yeux un modèle désastreux d’algorithme puisque non commenté! De plus, comprendre ce que fait un algorithme non commenté est souvent plus difficile que d’en concevoir un, car les notations de variable par exemple ne prennent souvent sens qu’une fois l’algorithme compris. Heureusement, d’autres exercices proposent des maquettes d’algorithmes à compléter ce qui est bien plus formateur.

Actuellement aucun langage n’est imposé en 2nde, 1ère et Terminale, nous espérons que cette situation va perdurer et que beaucoup d’enseignants résisteront aux pressions de certains de vouloir imposer un langage unique (comme pour les enseignements obligatoires d’informatique en classe préparatoires). La plupart des langages interprétés permettent d’apprendre à programmer les concepts algorithmiques au programme du lycée (test, boucle, variable, affectation, fonction). En effet, pour les élèves, la difficulté principale ce sont les concepts algorithmiques, rarement la syntaxe du langage lui-même, car ils peuvent se faire aider par l’enseignant s’ils sont bloqués. C’est donc aux enseignants qu’il revient de choisir un langage avec lequel ils sont à l’aise, non seulement pour écrire eux-mêmes un programme, mais aussi pour trouver rapidement une erreur de syntaxe ou d’exécution dans un programme d’un de leurs élèves. Pour la grande majorité des élèves, il est probablement souhaitable qu’ils soient confrontés lors des changements de professeur à plusieurs langages au cours de leur scolarité (par exemple Xcas, calculatrices ou Javascript, Julia, Python, ...), ce qui leur permettra de mieux comprendre les concepts universels partagés (l’algorithmique) et les biais et particularités propres à un langage donné (voir en appendice), et facilitera aussi leur adaptation à d’autres langages. Pour ceux qui se destinent à des études scientifiques, il nous parait important qu’ils soient aussi confrontés à d’autres types de langages (compilés, fonctionnels ...) au cours de leurs études dont au moins un langage de plus bas niveau : les langages interprétés permettent d’utiliser facilement des types ou instructions puissantes, se confronter avec un langage de plus bas niveau permet de mieux comprendre ce qui est basique ou ne l’est pas et ce qui est intrinsèquement rapide ou/et couteux en ressource mémoire ou ne l’est pas (on peut voir ça comme l’analogue entre faire une démonstration ou admettre un théorème).

Le langage de Xcas est fortement orienté mathématique et de ce fait peut facilement interagir avec les thèmes du programme de maths, tous les types mathématiques au programme du lycée sont directement accessibles (par exemple : entiers et rationnels, nombres approchés réels et complexes, vecteurs, polynômes et matrices). De plus nous avons adapté le langage pour en faciliter l’apprentissage d’après notre expérience d’enseignement avec des publics divers :

- Les structures sont délimitées par des mots-clefs explicites en français
  (`si . alors . sinon . fsi`),
  (`pour . de . jusque . faire ... fpour`),
  (`tantque . faire ... ftantque`)...
  L’indentation sert à controler qu’on n’a pas fait de faute de syntaxe (non-fermeture d’une parenthèse par exemple). Les diverses interfaces de Xcas proposent des assistants pour créer facilement les structures de controle usuelles (fonction, test, boucle).
- Il faut déclarer explicitement les variables locales, ainsi une faute de frappe dans un nom de variable est détectée et un avertissement est affiché.
- Lorsqu’on programme une fonction, on peut lui passer en argument des variables qui sont de type fonction ou expression, ceci facilite l’écriture de certains algorithmes (dichotomie, méthode des rectangles par exemple)
- Les thèmes d’algorithmique abordés au lycée sont presque toujours déjà implémentés dans une commande de Xcas, ceci permet de vérifier en comparant le résultat de la fonction qu’on vient de concevoir avec la commande interne.

1
  Imagine-t-on donner les étapes de calcul d’une démonstration, sans explications, et demander quel est le théorème qui a été démontré ?

# Chapitre 2 Types, fonctions, programmation.

## 2.1 Types

### 2.1.1 Les entiers, les rationnels et les nombres approchés.

Dans Xcas :
les entiers sont des nombres de ℤ\mathbb{Z}, par exemple -2,
les rationnels sont des nombres de ℚ\mathbb{Q}, par exemple 1/3 1/3,
les nombres approchés sont des nombres décimaux1, par exemple 3.14 3.14,
les nombres réels sont représentés par des des nombres décimaux ou par des valeurs symboliques, par exemple 2\sqrt 2.
Pour avoir une valeur approchée d’un nombre réel on utilise la commande : evalf, par exemple evalf(sqrt(2)) ou evalf(sqrt(2),20) pour avoir une valeur approchée de 2\sqrt 2 avec 20 chiffres significatifs.
evalf(sqrt(2))
evalf(sqrt(2),20)

### 2.1.2 Les listes, les séquences et les chaînes de caractères

#### Définition d’une liste

Qu’est-ce qu’une liste ?
C’est une énumération d’objets, dont l’ordre est important. Cela peut servir à représenter les coordonnées d’un point ou d’un vecteur, à contenir une liste de valeurs (observations) en statistiques, ...
Une liste est délimitée par des crochets [] et les éléments de la liste sont séparés par une virgule ,
L:=[2,24,1,15,5,10]

#### Définition d’une séquence

Qu’est-ce qu’une séquence ?
C’est presque la même chose qu’une liste, mais sans crochets, on ne peut donc pas créer une séquence de séquences alors qu’on peut créer une liste de listes. Par exemple les arguments d’une fonction sont regroupés en une séquence.
Une séquence n’est pas délimitée (ou est délimitée par des parenthèses ()) et les éléments de la séquence sont séparés par une virgule ,
S:=(2,24,1,15,5,10)

#### Transformation d’une séquence en liste et vice-versa

Si S est une séquence alors [S] est une liste.
Si L est une liste alors op(L)] est une séquence.
L:=[2,24,1,15,5,10]
S:=(2,24,1,15,5,10)
op(L)
[S]

#### Définition d’une chaine de caractères

Qu’est-ce qu’une chaine de caractères ?
C’est la concaténation de 0, 1 ou plusieurs caractères.
Une chaine de caractères est délimitée par ""
s:="Bonjour"

#### Les instructions sur les listes les séquences et les chaînes de caractères

dim(L) renvoie le nombre d’éléments de la liste L.
dim(S) renvoie le nombre d’éléments de la séquence S.
dim(s) renvoie le nombre de caractères de la chaîne s.
[] représente la liste vide et dim([]) vaut 0.
NULL représente la séquence vide et dim(NULL) vaut 0.
"" représente la chaîne vide et dim("") vaut 0.
Les éléments de la liste sont numérotés de 0 jusque dim(L)-1.
L|0] désigne le premier élément de la liste et L[dim(L)-1] désigne le dernier élément de la liste.
Les éléments de la séquence sont numérotés de 0 jusque dim(S)-1.
S|0] désigne le premier élément de la séquence et S[dim(S)-1] désigne le dernier élément de la séquence.
s|0] désigne le premier caractère de la chaîne et s[dim(s)-1] désigne le dernier caractère de la chaîne.
gauche(L,n) renvoie les n premiers éléments de la liste L (c’est le côté gauche de la liste).
droit(L,n) renvoie les n derniers éléments de la liste L (c’est le côté droit de la liste).
gauche(s,n) renvoie les n premiers caractères de la chaîne s (c’est le côté gauche de la chaîne).
droit(s,n) renvoie les n derniers caractères de la chaîne s (c’est le côté droit de la chaîne).
Par exemple : soient la liste L:=[2,24,1,15,5,10] et la chaîne s:="Bonjour".
L1:=seq(2*k,k,0,4) crée la liste [0,2,4,6,8]
count(x->x>2,L1) compte le nombre d’éléments de L1 supérieurs à 2.
S1:=seq(2*k,k=0..4) crée la séquence (0,2,4,6,8)
count(x->x>2,S1) compte le nombre d’éléments de S1 supérieurs à 2.
sum(L) renvoie la somme des éléments de la liste L.
sum(S) renvoie la somme des éléments de la séquence S.
On tape :
L:=[2,24,1,15,5,10]
n1:=dim(L)
L[0]
L[1];L[2]
L[n1-1]
gauche(L,2)
droit(L,2)
sum(L)
S:=(2,24,1,15,5,10)
n1:=dim(S)
S[0]
S[1];S[2]
S[n1-1]
sum(S)
s:="Bonjour"
n2:=dim(s)
s[0]
s[1];s[2]
s[n2-1]
gauche(s,3)
droit(s,4)

### 2.1.3 Les booléens

#### Définition

L’ensemble des booléens est un ensemble à 2 éléments :
vrai ou 1 et faux ou 0.
Pour faire des tests, on utilise des opérateurs booléens.

#### Opérateur booléen infixé qui teste l’égalité avec ==

Exemple :
a:=3
b:=5
b-a==0
b-a-2==0
(1+sqrt(2))^2==3+2*sqrt(2);simplify((1+sqrt(2))^2-3-2*sqrt(2))==0;
Attention
le signe := sert à stocker une valeur dans une variable.2
le signe == sert à tester l’égalité, il est conseillé d’écrire simplify(a-b)==0 plutôt que a==b pour tester légalité entre a et b.
le signe = sert à définir une équation ou à donner la valeur par défaut d’un argument (cf 2.2.3) et non à tester l’égalité.

#### Opérateur booléen infixé qui teste la non égalité avec !=

Exemple :
a:=3
b:=5
b!=a
a+2!=b

#### Opérateur booléen infixé qui teste l’inégalité avec <, >, <=, >=

Exemple :
a:=3
b:=5
b >= a
a+2 > b
a+2 >= b

### 2.1.4 Expressions, polynômes

#### Simplification d’une expression avec normal

Xcas renvoie le résultat d’un calcul sans le simplifier.
Il faut utiliser la fonction normal ou simplify pour avoir le résulat simplifié.
(x^2+1)^2+(x^2-1)^2
normal((x^2+1)^2+(x^2-1)^2)

#### Les polynômes

Un polynôme à une indéterminée à coefficients dans ℝ\mathbb{R} est déterminé par une séquence a n,...,a 1,a 0 a_n,...,a_1,a_0 d’éléments de ℝ\mathbb{R}, c’est l’expression :
a n x n+...+a 1 x+a 0 a_nx^n+...+a_1x+a_0 (resp a 0+a 1 x+a 2 x 2+..+a n x n a_0+a_1x+a_2x^2+..+a_nx^n).
n n est le degré du polynôme.
On dit que l’on a écrit le polynôme selon les puissances décroissantes (resp. croissantes).
a n,..a 1,a 0 a_n,..a_1,a_0 sont les coefficients du polynôme et x x est la variable ou l’indéterminée du polynôme.
On notera l’ensemble des polynômes à une indéterminée x x : ℝ[x]\mathbb{R}[x].
Un polynôme à 2 indéterminées x x et y y à coefficients dans ℝ\mathbb{R} est déterminé par une séquence A n(y),...,A 1(y),A 0(y)A_n(y),...,A_1(y),A_0(y) d’éléments de ℝ[y]\mathbb{R}[y] et a pour expression :
A 0(y)+A 1(y)x+A 2(y)x 2+..+A n(y)x n A_0(y)+A_1(y)x+A_2(y)x^2+..+A_n(y)x^n (resp A n(y)x n+...+A 1(y)x+A 0(y)A_n(y)x^n+...+A_1(y)x+A_0(y)).
par exemple :
si A 0(y)=y 3−2,A 1(y)=−2 y,A 2(y)=y 3+2*y+3 A_0(y)=y^3-2,A_1(y)=-2y,A_2(y)=y^3+2*y+3
Le polynôme s’écrit :
y 3−2−2 y*x+(y 3+2*y+3)*x 2=x 2*y 3+2*x 2*y+3*x 2−2*x*y+y 3−2 y^3-2-2y*x+(y^3+2*y+3)*x^2=x^2*y^3+2*x^2*y+3*x^2-2*x*y+y^3-2
Le degré par rapport à x x du polynôme de cet exemple et égal à 2.
Le degré par rapport à y y du polynôme de cet exemple et égal à 3.

#### Coefficients et degré d’un polynôme

Xcas représente les polynômes :
soit comme la séquence des coefficients selon les puissances décroissantes (poly1[1,2,3] i.e. [a2,a1,a0]:=[1,2,3]) soit sous la forme d’une expression symbolique (x`^`2+2x+3 si x est l’indéterminée).
Les commandes poly2symb et symb2poly permettent de passer d’une représentation à l’autre :
poly2symb([1,2,3],y) renvoie (y+2)*y+3
et symb2poly(y`^`2+2y+3) renvoie poly1[1,2,3].
Pour avoir le degré d’une expression polynômiale par rapport à une variable, on utilise l’instruction degree qui renvoie le degré d’un polynôme par rapport au 2ième argument (x est la variable par défaut).
Pour avoir les coefficients d’un polynôme par rapport à une variable on utilise l’instruction symb2poly qui renvoie la liste des coefficients d’un polynôme par rapport au 2ième argument (x est la variable par défaut).
On a si L:=symb2poly(P(x)), degree(P(x)) est égal à dim(L)-1.
Pour avoir le coefficient d’un polynôme par rapport à une variable de degré donné on utilise l’instruction coeff.
degree(x^2-2x*y+y^3-2)
degree(x^2-2x*y+y^3-2,x)
degree(x^2-2x*y+y^3-2,y)
symb2poly(x^2-2x*y+y^3-2)
symb2poly(x^2-2x*y+y^3-2,x)
symb2poly(x^2-2x*y+y^3-2,y)
coeff(x^2-2x*y+y^3-2,x,2)
coeff(x^2-2x*y+y^3-2,y,1)

## 2.2 Les fonctions

On distingue les fonctions ou commandes de Xcas et les fonctions définies par l’utilisateur. Pour éviter le risque d’utiliser un nom de fonction de Xcas, il est conseillé de nommer les fonctions utilisateurs en utilisant une majuscule comme première lettre.
Pour définir des fonctions (utilisateurs), on distinguera

- les fonctions définies par une expression algébrique. Leur définition peut se faire simplement avec :=
- les fonctions qui nécessitent des calculs intermédiaires ou des structures de contrôle (test, boucle). Leur définition se fait au moyen d’un programme, en utilisant les instructions fonction...ffonction, local et retourne et les structures de contrôle.

### 2.2.1 Quelques fonctions algébriques de Xcas

abs est la fonction valeur absolue.
abs(sqrt(2)-3/2)
ceil est le plus grand entier >=&gt;= à l’argument.
cos est la fonction cosinus.
cos(pi/6)
floor est la partie entière i.e.le plus grand entier <=&lt;= à l’argument.
floor(-2.42)
floor(2.42)
frac est la partie fractionnaire d’un réel.
frac(3/2)
frac(2.42)
max est la fonction maximum pour une séquence de nombres réels.
max(sqrt(2),3,5,sqrt(26))
min est la fonction minimum pour une séquence de nombres réels.
min(sqrt(2),3,5,sqrt(26))
`^` est la fonction puissance.
2^10
round est la fonction qui arrondit un réel en l’entier (resp le décimal) le plus proche.
round(-2.42)
round(-2.42,1)
round(sqrt(2),4)
sign est la fonction signe de l’argument et renvoie -1, 0 ou +1.
sign(-4)
sign(4-4)
sign(4)
sin est la fonction sinus.
sin(pi/3)
sqrt est la racine carrée.
sqrt(2)^2
(sqrt(3)+1)*(sqrt(3)-1)
normal((sqrt(3)+1)*(sqrt(3)-1))
tan est la fonction tangente.
tan(pi/4)

### 2.2.2 Définition d’une fonction algébrique d’une variable

Exemple :
On veut définir la fonction f 1 f_1 définie pour x∈ℝ x \in \mathbb{R}, par f 1(x)=x 2+1 f_1(x)=x^2+1.
f f est le nom de la fonction et x x est le nom de l’argument de f 1 f_1 (ici x x est un réel), la valeur de la fonction f 1 f_1 est x 2+1 x^2+1.
Remarque : En mathématique on dit que x x est une variable.
On tape simplement :
f1(x):=x^2+1;
On pourrait aussi définir f1 par un programme avec fonction...ffonction et retourne :
fonction f1(x) retourne x^2+1; ffonction;
f1(5)

### 2.2.3 Définition d’une fonction algébrique de 2 variables

Exemple :
On veut définir la fonction f 2 f_2 définie pour (x,y)∈ℝ 2(x,y) \in \mathbb{R}^2, par f 2(x,y)=x 2+y 2 f_2(x,y)=x^2+y^2.
f 2 f_2 est le nom de la fonction et f 2 f_2 a 2 arguments réels : x,y x,y (en mathématique on dit que x,y x,y sont les variables de f 2 f_2). La valeur de la fonction f 2 f_2 est x 2+y 2 x^2+y^2.
On tape simplement :
f2(x,y):=x^2+y^2
Ou on tape :
fonction f2(x,y) x^2+y^2; ffonction
Valeur par défaut d’une variable
On peut définir la valeur par défaut de la variable y et ainsi donner le même nom f f aux 2 fonctions f 1 f_1 et f 2 f_2 définies précédement.
Ainsi la fonction f f sera définie par :
si elle a une variable x x alors f(x)=x 2+1 f(x)=x^2+1 et
si elle a 2 variables x,y x,y alors f(x,y)=x 2+y 2 f(x,y)=x^2+y^2.
On tape simplement :
f(x,y=1):=x^2+y^2
Ou on tape :
fonction f(x,y=1) x^2+y^2;ffonction
f(3,4)
f(3)
Autre exemple :
On veut définir la fonction g g définie pour (a,b)∈ℕ 2(a,b) \in \mathbb{N}^2 par g(a,b)=q,r g(a,b)=q,r où q,r q,r désigne le quotient et le reste de la division euclidienne de a a par b b.
On tape simplement :
g(a,b):=iquorem(a,b);
ou bien avec fonction...ffonction et retourne :
fonction g(a,b) retourne iquorem(a,b); ffonction;
g g est le nom de la fonction, a,b a,b sont les noms des arguments de g g (a a et b b sont des entiers) et iquorem renvoie le quotient et le reste de la division euclidienne de a a par b b sous la forme d’une liste.
On a aussi les instructions :
iquo(a,b) qui renvoie le quotient de la division euclidienne de a a par b b.
irem(a,b) qui renvoie le reste de la division euclidienne de a a par b b.
et on a donc iquorem(a,b) est identique à [iquo(a,b),irem(a,b)].
g(25,3)

### 2.2.4 Définition d’une fonction algébrique par morceaux avec quand

Exemple :
quand a 3 arguments : une condition et 2 expressions :
quand(Cond,Expr1,Expr2)
Si la condition Cond est vraie alors quand renvoie Expr1 et
si la condition Cond est fausse alors quand renvoie Expr2.
Soit la fonction Abs1 définie par Abs1(x)=|x−1|−1(x)=|x-1|-1 :
si x>1 x&gt;1 on a Abs1(x)=x−1−1=x−2(x)=x-1-1=x-2 et
si x≤1 x \leq 1 on a Abs1(x)=−x+1−1=−x(x)=-x+1-1=-x.
On tape simplement :
Abs1(x):= quand(x > 1, x-2,-x);
ou bien avec fonction...ffonction et retourne :
fonction Abs1(x) retourne quand(x > 1,x-2,-x); ffonction;
Abs1(1/2),Abs1(1),Abs1(3/2),Abs1(-2),Abs1(2)
plotfunc(Abs1(x),x=-5..7)

### 2.2.5 Connaître les types et les sous-types

Les types
Xcas sait reconnaître le type d’un objet.
Pour avoir le type de l’objet a ou le contenu d’une variable a, on utilise type(a).
Les types utilisés ici sont :
real ou 1 ce qui signifie que a contient un nombre flottant.
a:=3.14
type(a)
type(a)+0
integer ou 2 ce qui signifie que a contient un nombre entier,
a:=2017
type(a)
type(a)+0
rational ou 10 ce qui signifie que a contient un nombre rationnel,
a:=2/7
type(a)
type(a)+0
func ou 13 ce qui signifie que a est le nom d’une fonction,
f(x):=2x+3
type(f)
type(sin)
type(sin)+0
vecteur ou 7 ce qui signifie que a contient une liste,
L:=[2,24,1,15,5,10]
type(L)
type(L)+0
string ou 12 ce qui signifie que a contient une chaîne de caractères,
s:="Bonjour"
type(s)
type(s)+0
expression ou 8 ce qui signifie que a contient une expression,
a:=sqrt(2)
type(a)
type(a)+0
type(f(x))
type(f(x))+0
identifier ou 6 ce qui signifie que a contient le nom d’une variable non affectée.
purge(a)
type(a)
type(a)+0

Les sous-types
Certains types de variables peuvent servir à plusieurs usages : par exemple une liste peut représenter les coordonnées d’un point dans l’espace ou les coefficients d’un polynôme ou un ensemble. Xcas possède une commande subtype permettant de préciser le type d’une variable. Pour avoir le sous-type de la variable a, on utilise subtype(a).
Par exemple si a contient une liste, subtype(a) renvoie 1 pour une séquence, 2 pour un ensemble, 10 pour un polynôme et 0 sinon.
subtype(1,2,3)
subtype(set[1,2,3])
subtype(poly1[1,2,3])
subtype([1,2,3])

## 2.3 Les instructions de programmation utilisées sur des exemples

### 2.3.1 Stocker une valeur dans une variable avec :=

L’opérateur infixé := stocke le deuxième argument dans la variable donnée comme premier argument.
Exemple :
a:=3
b:=5
a,b:=a+b,b-a
a,b

### 2.3.2 Enlever une valeur stockée dans une variable avec purge

L’instruction purge(a) permet d’enlever une valeur stockée dans la variable a. La variable a redevient une variable libre i.e. une variable non affectée.
Exemple :
a:=3
b:=5
purge(a)
a,b

### 2.3.3 Suite d’instructions avec ; ou :;

Pour effectuer une suite d’instructions, il suffit de les écrire les unes à la suite des autres, en terminant chaque instruction par `;`
Exemple :
a:=2; b:=3; a*b;
Remarque :
Lorsque la réponse est trop longue, on peut aussi utiliser :; et on obtient Done comme réponse.
a:=2:; b:=[1,2,3,4,5]:; a*b;

### 2.3.4 L’instruction retourne

L’instruction retourne arrête immédiatement l’exécution du programme et renvoie la valeur de l’instruction située après retourne.
Exemple 1:
fonction Delta(a,b,c) retourne b^2-4*a*c; ffonction;
fonction Abs(x) si x > 0 alors retourne x;fsi;retourne -x;ffonction;
Delta(3,5,2)
Abs(-3),Abs(3)

### 2.3.5 L’instruction local

Exemple 2: notion de variables locales:
On veut, dans cet exemple, définir une fonction h h de deux variables a,b a,b (a a et b b sont des entiers) qui renvoie le numérateur et le dénominateur de la fraction a b\frac{a}{b} simplifiée.
Pour cela il faut diviser a a et b b par leur pgcd qui est gcd(a,b).
si on tape :
fonction h0(a,b) retourne (a/gcd(a,b),b/gcd(a,b)); ffonction:;
cela nécessite de faire 2 fois le calcul de gcd(a,b).
Pour éviter cela, on va utiliser une variable locale c c qui servira à stocker le calcul intermédiaire gcd(a,b) avec l’instruction : c:=gcd(a,b) (:= est le symbole de l’affectation et gcd(a,b) renvoie le pgcd de a a et b b).
Cette variable n’est pas visible à l’extérieur du programme, les modifications faites sur c dans le programme n’ont aucun effet sur la variable c de la session.
On écrit alors local c; (ne pas oublier le ;)
fonction h(a,b) local c; c:=gcd(a,b); retourne (a/c,b/c); ffonction:;
a:=12;b:=22;c:=32;
h0(25,15);
h(25,15);
a,b,c
On voit ainsi que les valeurs de a,b,c n’ont pas été changées par l’exécution des fonctions h0 ou h.

### 2.3.6 L’instruction pour

Exemple 3 : notion de boucle pour
On veut, dans cet exemple, définir une fonction s s d’une variable n n (n n est un entier) qui calcule la somme : 1+3+...+2 n−1 1+3+...+2n-1.
Pour cela, on utilise une variable locale S S que l’on initialise à 0 :
S:=0;
puis on va faire n n étapes en utilisant cette variable locale S S.
S S va contenir successivement :
étape 1 S:=S+(2*1−1);S:=S+(2*1-1); donc S S contient 1 (0+1)
étape 2 S:=S+(2*2−1);S:=S+(2*2-1); donc S S contient 4 (1+3)
...
étape k k S:=S+(2*k−1);S:=S+(2*k-1); donc S S contient 1+3+..2 k−1 1+3+..2k-1
...
étape n n S:=S+2*n−1;S:=S+2*n-1; donc S S contient 1+3+..2 n−1 1+3+..2n-1
Pour décrire cela on utilise une boucle pour :
pour k de 1 jusque n faire S:=S+2*k-1; fpour;
Dans cette boucle k sera successivement égal à 1, 2, 3,...n.
On dit que l’instruction S:=S+2*k-1 figurant dans le corps la boucle sera exécuté n fois.
Comment fonctionne cette boucle pour ?

- la variable k est initialisée à 1,
- les instructions du corps de la boucle sont effectuées (ici il y en a une seule S:=S+2*k-1),
- k est est incrémenté automatiquement de 1 (k:=k+1),
- le test k<=n est effectué : si k<=n est vrai, les instructions du corps de la boucle sont à nouveau effectuées etc ...
  sinon on effectue les instructions qui suivent fpour.

On tape :

    fonction Simpair(n)
     local S,k;
     S:=0;
     pour k de 1 jusque n faire
       S:=S+2*k-1;
     fpour;
     retourne S;
    ffonction:;

Simpair(5),Simpair(6),Simpair(7)

Intermède mathématique
Au vue des résultats obtenus pouvez-vous deviner la valeur de s(100) ?
Pouvez-vous deviner et montrer la formule qui donne s(n) ?
On devine : s(n)=1+3+...2 n−1=(n) 2 s(n)=1+3+...2n-1=(n)^2
On sait que pour tout k∈ℕ k \in \mathbb{N} on a :
k 2−(k−1) 2=((k−1)+1) 2−(k−1) 2=2 k−1 k^2-(k-1)^2=((k-1)+1)^2-(k-1)^2=2k-1 et
(k+1) 2−k 2=2 k+1(k+1)^2-k^2=2k+1
Donc :
1=1 2−0 2 1=1^2-0^2 (k=1 k=1),
3=2 2−1 2 3=2^2-1^2 (k=2 k=2),
5=3 2−2 2 5=3^2-2^2 (k=3 k=3),
...
2 k−1=k 2−(k−1) 2 2k-1=k^2-(k-1)^2
2 k+1=(k+1) 2−(k) 2 2k+1=(k+1)^2-(k)^2
...
2 n−1=n 2−(n−1) 2 2n-1=n^2-(n-1)^2
Donc :
s(n)=1+3+...2 n−1=1+(n) 2=1+(4−1)+(9−4)...+(n 2−(n−1) 2)=n 2 s(n)=1+3+...2n-1=1+(n)^2=1+(4-1)+(9-4)...+(n^2-(n-1)^2)=n^2
En classe de terminales, on peut montrer cette formule par récurrence :
s(1)=1 s(1)=1 si s(n)=(n) 2 s(n)=(n)^2 alors on a :
s(n+1)=s(n)+2(n+1)−1=(n) 2+2 n+1=(n+1) 2 s(n+1)=s(n)+2(n+1)-1=(n)^2+2n+1=(n+1)^2
La formule est donc montrée par récurrence.

### 2.3.7 L’instruction pour avec un pas

Exemple 4 : notion de liste et boucle pour avec un pas
On va tout d’abord faire le programme du ticket de caisse lors d’achats dans un magasin qui ne pratique pas de réduction pour les achats en gros.
Le programme du ticketcaisse a comme paramètre une liste L donnant le nombre d’un même article suivi du prix de cet article, par exemple :
si L:=[2,24,1,15,5,10] cela signifie qu’il y 2 articles à 24 euros, 1 article à 15 euros et 5 articles à 10 euros.
Soit n:=dim(L), dans cet esxemple n:=6.
On va parcourir la liste avec une variable k : L[k] sera le nombre d’articles ayant comme prix L[ k+1] : il faut donc, dans cet exemple, que k prenne successivement pour valeur 0, 2, 4=n-2.
Pour cela on initialise la somme à payer avec 0 : S:=0 puis
on utilise une boucle pour avec un pas de 2 :
pour k de 0 jusque n-2 pas 2 faire S:=S+L[k]*L[k+1]; fpour;
Dans cette boucle pour, la variable k est initialisée à 0, puis les instructions du corps de la boucle sont effectuées, puis k est incrémenté automatiquement de 2 (k:=k+2),
puis on fait le test k<=n-2 si oui les instructions du corps de la boucle sont à nouveau effectuées etc ... sinon on effectue les instructions qui suivent fpour.

    fonction Ticketcaisse(L)
     local S,n,k;
     n:=dim(L);
     S:=0;
     pour k de 0 jusque n-2 pas 2 faire S:=S+L[k]*L[k+1]; fpour;
     retourne S;
    ffonction:;

Ticketcaisse([1,12,3,5,2,8])
1*12+3*5+2*8

### 2.3.8 L’instruction si

Exemple 5 : notion de test
Dans un magasin on favorise les achats en gros :
si un article a a comme prix affiché P euros, pour l’achat d’au moins 3 articles a, vous avez une réduction de 10%.
On veut, dans cet exemple, définir une fonction Prix de 2 variables n (n est un entier) et P un réel qui calcule le prix de n article(s).
Pour cela, on utilise :
une variable locale S qui sera la somme à débourser et
le test :
si <condition> alors <instruction1;> sinon <instruction2;> fsi;
Comment fonctionne le test si ?

- On évalue la condition : une condition a 2 valeurs possibles vrai ou faux c’est ce que l’on nomme un booléen,
- Si la condition est vraie : on effectue les <instruction1;>, et si la condition est fausse : on effectue les <instruction2;>,
- On effectue ensuite les instructions qui suivent fsi;.

On tape pour avoir le prix de n fois le même article de prix P :

    fonction Prix(n,P)
     local S;
     si n>=3 alors S:=n*P*0.9;
     sinon S:=n*P; fsi;
     retourne S
    ffonction:;

onload
Prix(3,8)
3*8-3*8*0.1
Prix(2,8)

### 2.3.9 Utiliser une fonction utilisateur dans un programme

Exemple 6 :
On veut faire le programme du ticket de caisse lorsque le magasin pratique l’achat en gros (la liste L doit spécifier le nombre n n d’un même article de prix P P).
En utilisant la fonction Prix(n,P) écrite précédemment (cf 2.3.8), modifier le programme précédent lorsque le magasin pratique l’achat en gros.

Solution :

    fonction Ticketengros(L)
     local S,n,k;
     n:=dim(L);
     S:=0;
     pour k de 0 jusque n-2 pas 2 faire
       S:=S+Prix(L[k],L[k+1]);
     fpour;
     retourne S;
    ffonction:;

Ticketengros([1,12,3,5,2,8])
12+3*5*0.9+2*8

### 2.3.10 L’instruction tantque

Exemple 7 : Notion de boucle tantque
On utilise une boucle tantque lorsque l’on ne connaît pas à l’avance le nombre d’itérations à effectuer et que l’on arrête les itérations quand une condition devient fausse :
tantque <condition> faire <instructions> ftantque;
Comment fonctionne une boucle tantque ?

- On évalue la condition : une condition a 2 valeurs possibles vrai ou faux c’est ce que l’on nomme un booléen,
- Si la condition est vraie : on effectue <instructions;>, et si la condition est fausse : on effectue les instructions qui suivent ftantque;.

ou bien on peut dire en langage courant que :
<condition> est une condition de continuation de la boucle. tant que la condition est vérifiée, on fait les instructions de la boucle.
Traduction d’une boucle pour en une boucle tantque
Soit une liste L de nombres réels.
On veut faire la somme des réels de L.
On tape en utilisant une boucle pour :

    fonction Somme(L)
     local n,j,S;
     n:=dim(L);
     S:=0;
     pour j de 0 jusque n-1 faire
       S:=S+L[j];
     fpour;
     retourne S;
    ffonction:;

onload
On tape en utilisant une boucle tantque :

    fonction Somme1(L)
     local n,j,S;
     n:=dim(L);
     S:=0;
     j:=0;
     tantque j <= n-1 faire
       S:=S+L[j];
       j:=j+1;
     ftantque;
     retourne S;
    ffonction:;

On peut aussi écrire Somme2, mais Attention à l’ordre des instructions de la boucle tantque et au test d’arrêt :

    fonction Somme2(L)
     local n,j,S;
     n:=dim(L);
     j:=0;
     S:=L[0];
     tantque j < n-1 faire
       j:=j+1;
       S:=S+L[j];
     ftantque;
     retourne S;
    ffonction:;

L:=[10,13,22,15,5]
Somme(L)
Somme1(L)
Somme2(L)
Exemple 8 : autre exemple de boucle tantque
En fin de mois, Paul n’a plus qu’une somme a dans son porte-monnaie. Paul fait sa liste de courses Lc en mettant au début ce qu’il veut vraiement acheter et à la fin de sa liste, il met les achats qu’il doit faire à plus long terme. Dans le magasin (qui ne fait pas de réduction), sa liste de courses Lc devient une liste de prix L.
Dans ce cas, on ne peut pas utiliser une boucle avec pour car on ne sait pas au départ combien de fois on doit effectuer la boucle.
On note S la variable qui stockera successivement la somme des prix des premiers éléments de L : pour cela on utilise la fonction Somme(L) écrite précedemment (cf 2.3.10).
Il veut faire un programme qui arrête sa liste dès que S>a en coupant L en 2 listes : La liste des objets de ce qu’il achète réellement pour un montant S<=a et Lfin liste des objets qu’il n’achète pas (Lfin est une liste vide lorsque Somme(L)<=a).
Ticketfindemois(L,a) doit renvoyer La,Lfin,P où P est la somme à payer.
"arrêt" se traduit ici par Lfin ==[] ou S>a donc
"continuation" se traduit ici par Lfin!=[] et S<=a.
On teste tout d’abord si Paul a assez d’argent pour payer toute sa liste : pour cela, on utilise le programme Somme précédent (cf 2.3.10).
Paul a assez d’argent pour payer toute sa liste lorsque Somme(L)<=a et alors on a La :=L, Lfin :=[] et P:=Somme(L).
Si Somme(L)>a, Paul n’a pas assez d’argent donc Lfin!=[] est vrai et la condition d’arrêt est : S<=a. On écrit Ticketfindemois(L,a) pour que k soit le nombre d’articles achetés lorsqu’ on sort du tantque :

    fonction Ticketfindemois(L,a)
     local S,n,k,Lfin,La;
     S:=Somme(L);
     si S <=a alors retourne L,[],S fsi;
     n:=dim(L);
     k:=0;
     S:=L[0];
     tantque S <=a faire
       k:=k+1;
       S:=S+L[k];
      ftantque;
     La:=gauche(L,k);
     Lfin:=droit(L,n-k);
     retourne La,Lfin,S-L[k];
    ffonction:;

L1:=[15,10,2,7,5,1.2,3,5.5,10,4,5.3]
L2:=[1,15,2,7.8,5,2.2,4,5.5,2,2.7,1,2.1]
Ticketfindemois(L1,50)
Ticketfindemois(L2,60)
On peut aussi écrire mais Attention à l’ordre des instructions dans le tantque.

    fonction Ticketfindemois1(L,a)
     local S,n,k,Lfin,La;
     S:=Somme(L);
     si S <=a alors retourne L,[],S fsi;
     n:=dim(L);
     S:=0;
     k:=0;
     tantque S <=a faire
       S:=S+L[k];
       k:=k+1;
     ftantque;
     La:=gauche(L,k-1);
     Lfin:=droit(L,n-k+1);
     retourne La,Lfin,S-L[k-1];
    ffonction:;

L1:=[15,10,2,7,5,1.2,3,5.5,10,4,5.3]
L2:=[1,15,2,7.8,5,2.2,4,5.5,2,2.7,1,2.1]
Ticketfindemois1(L1,50)
Ticketfindemois1(L2,60)
Dans Ticketfindemois1, c’est k-1 et non k, qui est pas la valeur du nombre d’articles achetés lorsqu’on sort du tantque.
En effet, lorsqu’on s’arrête S S devient supérieur à a a : il ne faut donc pas acheter l’article L[k].
Donc La:=gauche(L,k-1); et Lfin:=droit(L,n-k+1).
Remarque
On aurait pu aussi écrire sans utiliser Somme mais c’est plus compliqué car la condition du tantque porte sur k et sur S !!!

    fonction Ticketfindemois2(L,a)
      local S,n,k,La,Lfin,P;
      n:=dim(L);
      k:=0;
      S:=L[0];
      tantque S<=a et k<n-1 faire
        k:=k+1;
        S:=S+L[k];
      ftantque;
      si S<=a alors retourne L,[],S fsi;
      La:=gauche(L,k);
      Lfin:=droit(L,n-k);
      P:=S-L[k];
     retourne La,Lfin,P;
    ffonction:;

À chaque étape on a :
Au début, on a :
k:=0;S:=L[0]; donc S est le prix de 1 article.
lorsqu’on fait k k fois la boucle on a :
S:=L[0]+..L[k]; donc S est la somme de k+1 articles.
Quand on sort du tantque on a :
soit S<=a est vrai, donc k==n-1 est vrai (puisque (S<=a et k<n-1)==faux).
S est donc la somme de toute la liste L i.e. S est la somme à payer pour l’achat de n articles i.e. Paul peut acheter toute sa liste de courses.
soit S>a et k<=n-1 alors S représente la somme des prix des k+1 premiers articles (k+1 car on a commencé à l’article k=0. Mais Paul ne peut pas acheter le dernier article puisque S>a. Le prix P représente la somme des prix des k premiers articles i.e.des articles L[0],..L[k-1] ou encore des artices de la liste gauche(L,k) donc P:=S-L[k].
L1:=[15,10,2,7,5,1.2,3,5.5,10,4,5.3]
L2:=[1,15,2,7.8,5,2.2,4,5.5,2,2.7,1,2.1]
Ticketfindemois2(L1,50)
Ticketfindemois2(L2,60)

### 2.3.11 Interruption d’une boucle

Si on utilise retourne à l’intérieur d’une boucle dans une fonction, celle-ci est interrompue. Ceci permet de transformer des boucles “tantque” en boucle “pour” souvent plus lisibles.

Reprenons l’exemple ci-dessus, on remarque que la boucle tantque utilise un compteur k qu’on incrémente à chaque itération comme dans une boucle pour. Il est donc naturel d’essayer de réécrire cette fonction avec une boucle pour. Il suffira de tester dans le corps de la boucle si la somme (avec le nouvel article) dépasse le contenu du porte-monnaie, dans ce cas il faut s’arrêter sans acheter le nouvel article, on interrompt la boucle et on renvoie les résultats (on calcule la somme au fur et à mesure et donc on n’utilise pas la fonction Somme). Dans Ticketfindemois3, c’est k, qui est pas la valeur du nombre d’articles achetés lorsqu’on sort du pour.
En effet, lorsqu’on s’arrête S S devient supérieur à a a : il ne faut donc pas acheter l’article L[k].
Donc La:=gauche(L,k); et Lfin:=droit(L,n-k).

    fonction Ticketfindemois3(L,a)
      local k,n,S,La,Lfin;
      n:=dim(L);
      S:=0;
      pour k de 0 jusque n-1 faire
        si S+L[k]>a alors
          La:=gauche(L,k);
          Lfin:=droit(L,n-k);
          retourne La,Lfin,S;
        fsi;
        S:=S+L[k];
      fpour;
      retourne L,[],S;
    ffonction:;

L1:=[15,10,2,7,5,1.2,3,5.5,10,4,5.3]
L2:=[1,15,2,7.8,5,2.2,4,5.5,2,2.7,1,2.1]
Ticketfindemois3(L1,50)
Ticketfindemois3(L2,60)

Cette méthode s’applique pour toute boucle “tantque” dont on peut prévoir à priori un majorant du nombre d’itérations. On peut d’ailleurs aussi l’utiliser si on se fixe un nombre maximal d’itérations qui tient compte du temps d’exécutions, typiquement en Xcas de l’ordre du million d’itérations si on veut un résultat en moins de quelques secondes.

Remarque : si on ne veut pas quitter la fonction, il est quand même possible d’interrompre la boucle prématurément en utilisant l’instruction break.

### 2.3.12 Exemple 9 : autre exemple de boucle tantque

Pour avoir des clients le dimanche matin, le magasin de Paul offre selon les dimanches une réduction immédiate r r qui varie selon le montant a a des achats par exemple une réduction de 10 euros dès 60 euros d’achats, ou une réduction de 5 euros dès 50 euros d’achats etc...
Ce magasin ne pratique pas de réduction pour des achats en gros.
Pour être sûr de bénéficier de la réduction, Paul fait sa liste de courses L c Lc en mettant au début ce qu’il veut vraiement acheter et à la fin de sa liste, il met les achats qu’il doit faire à plus long terme (contrairement au programme précédent, on suppose ici que Paul a suffisamment d’argent).
Attention
On suppose ici que la liste de courses est constituée par une suite des nombres n n,P P où n n est le nombre d’achats du même article de prix P P.
Il veut faire un programme qui arrête sa liste dès que S>=a S&gt;=a en coupant L c Lc en 2 listes L a La liste des objets de ce qu’il achète réellement pour un montant S S avant réduction et L f i n Lfin liste des objets qu’il n’achète pas (L f i n Lfin est éventuellement une liste vide).
Paul veut que son programme ait paramètres L c,a,r Lc,a,r et qu’il renvoie :
L a La, L f i n Lfin, S S, S−r S-r.
Dans ce cas, on ne sait pas au départ combien de fois on doit effectuer la boucle.
Mais on sait quand on doit s’arrêter :
on arrête la boucle lorsque le prix S S de la liste complète L c Lc n’atteint pas le montant a a ou dés que le prix S S du début de L c Lc vérifie S>=a.
On utilise pour cela une boucle tantque :
tantque <condition> faire <instructions> ftantque;
Cela veut dire :
tant que "non arrêt", on fait les instructions de la boucle.
"arrêt" se traduit ici par Lfin ==[] ou S>=a donc,
"non arrêt" se traduit ici par Lfin!=[] et S<a.
Attention la variable k k qui va parcourir la liste L devra être initialisée (ici k:=0;) et modifiée dans le corps de la boucle (ici k:=k+2;).
La fonction Ticketdimanche a 3 paramètres L,a,r et renvoie la liste L a La des courses qui ont été prises en compte,
la liste L f i n Lfin des courses qui n’ont pas été prises en compte (cette liste peut être vide si S<=a)
la somme S des achats sans la remise et
la somme S-r à payer.
On tape :

    fonction Ticketdimanche(L,a,r)
     local S,n,k,Lfin,La;
     n:=dim(L);
     S:=0;
     k:=0;
     tantque k<n et S<a faire
       S:=S+L[k]*L[k+1];
       k:=k+2;
     ftantque;
     La:=gauche(L,k);
     Lfin:=droit(L,n-k);
     si S<a alors r:=0; fsi;
     retourne La,Lfin,S,S-r;
    ffonction:;

L1:=[1,15,2,7,5,1.2,3,5.5]
L2:=[1,15,2,7.8,5,2.2,4,5.5,2,2.7,1,2.1]
Ticketdimanche(L1,50,5)
Ticketdimanche(L2,60,10)

Traduction du “tantque” en “pour”
On remarque que la boucle “tantque” a un compteur k, on peut donc la transformer en boucle “pour” avec sortie prématurée de la boucle lorsque S>a S&gt;a.
Attention gauche(L,k) représente les k premiers éléments de L i.e c’est L[0]..L[k-1].
Ici, on sort de la boucle pour lorsque S>=a donc pour avoir la réduction il faut acheter L[k] fois l’article L[k+1], c’est à dire prendre en compte la liste L[0].. L[k+1] qui est une liste de k+2 éléments c’est donc gauche(L,k+2).

    fonction Ticketdimanche1(L,a,r)
     local S,n,k,Lfin,La;
     n:=dim(L);
     S:=0;
     pour k de 0 jusque n-1 pas 2 faire
       S:=S+L[k]*L[k+1];
       si S>=a alors
         La:=gauche(L,k+2);
         Lfin:=droit(L,n-k-2);
         retourne La,Lfin,S,S-r;
       fsi;
     fpour;
     retourne L,[],S,S;
    ffonction:;

L1:=[1,15,2,7,5,1.2,3,5.5]
L2:=[1,15,2,7.8,5,2.2,4,5.5,2,2.7,1,2.1]
Ticketdimanche1(L1,50,5)
Ticketdimanche1(L2,60,10)

### 2.3.13 Exemple 10 : encore un autre exemple de boucle tantque

Maintenant le magasin de Paul favorise aussi les achats en gros : 10% de réduction lorsque on achète 3 fois le même produit. En plus il offre selon les dimanches une réduction immédiate r r qui varie selon le montant a a des achats, par exemple une réduction de 10 euros dès 60 euros d’achats.
Modifier les programmes précédents pour tenir compte des achats en gros. On utilise ici la fonction Prix écrite précédemment (cf 2.3.8).
Attention comme précédemment on suppose ici que la liste de courses est constituée par une suite des nombres n n,P P où n n est le nombre d’achats du même article de prix P P.
On tape :

    fonction Ticketdimgros(L,a,r)
     local S,n,k,Lfin,La;
     n:=dim(L);
     S:=0;
     k:=0;
     tantque k < n et S<a faire
       S:=S+Prix(L[k],L[k+1]);
       k:=k+2;
     ftantque;
     La:=gauche(L,k);
     Lfin:=droit(L,n-k);
     si S < a alors r:=0 ;fsi;
     retourne La,Lfin,S,S-r;
    ffonction:;

L:=[1,15,2,7.8,5,2.2,4,5.5,2,2.7,1,2.1]
Ticketdimgros(L,60,10)
1*15+2*7.8+5*2.2*0.9+4*5.5*0.9
Transformation en boucle “pour”

    fonction Ticketdimgros1(L,a,r)
     local S,n,k,Lfin,La;
     n:=dim(L);
     S:=0;
     pour k de 0 jusque n-1 pas 2 faire
       S:=S+Prix(L[k],L[k+1]);
       si S>=a alors
         La:=gauche(L,k+2);
         Lfin:=droit(L,n-k-2);
         retourne La,Lfin,S,S-r;
       fsi;
     fpour;
     retourne La,[],S,S;
    ffonction:;

L:=[1,15,2,7.8,5,2.2,4,5.5,2,2.7,1,2.1]
Ticketdimgros1(L,60,10)
1*15+2*7.8+5*2.2*0.9+4*5.5*0.9

## 2.4 Exercice : Algorithme de tracé de courbe

Soit la fonction f définie sur [a,b].
On veut tracer le graphe de cette fonction sur l’intervalle [a,b].
En partageant [a,b] en n parties égales on obtient :
a=a0,a1=a+h,a2=a+2h, ...b=a+n*h avec h=(b-a)/n. Le graphe sera obtenu en reliant les points de coordonnées [a f(a)] [a1 f(a1)] etc ... par des segments.
On tape :

    fonction Graphe(f,a,b,n)
     local L,h,k;
     L:=NULL;
     h:=(b-a)/n;
     pour k de 0 jusque n-1 faire
       L:=L,segment(point(a,f(a)),point(a+h,f(a+h)));
       a:=a+h;
     fpour;
     retourne L;
    ffonction:;

f(x):=x^2+1
g(x):=(x+1)/(x-1)
Graphe(f,-2,2,100)
Graphe(g,-12,12,100)
Graphe(Abs1,-10,12,100)

## 2.5 Mettre au point un programme

Lorsqu’on écrit un programme, il y a deux étapes à franchir :

- Écrire un programme syntaxiquement correct. Quand on tape sur le bouton ok, il “compile” (plus préciśement il est interprété). Les erreurs à ce stade sont appelées erreurs de syntaxe. Certaines interfaces de Xcas essaient de placer le curseur à l’endroit de l’erreur, d’autres affichent le numéro de ligne et colonne de l’erreur. Il faut garder en tête que l’erreur peut être située avant l’endroit indiqué par le curseur ou dans le message d’erreur.
- S’assurer que le programme fait bien ce qu’on attend de lui. Si ce n’est pas le cas on parle d’erreur d’exécution (en anglais runtime error). Pour corriger ce type d’erreur, Xcas propose une commande appelée `debug`. Au lieu d’appeler directement le programme (par exemple au lieu de `Graphe(f,-2,2,100)` on tape `debug(Graphe(f,-2,2,100))`. Le debogueur affiche alors la liste des variables locales et leur valeur ainsi que la prochaine ligne du programme qui sera exécutée. On peut alors exécuter ligne par ligne le programme avec des arguments pour lequel on connait la réponse, regarder l’évolution des valeurs des variables et comprendre plus facilement pourquoi le programme ne fait pas ce qui est attendu.

1
  En toute rigueur ce sont des nombres écrits en base 2 et non en base 10 mais on peut l’ignorer au niveau du lycée
2
  Xcas accepte toutefois = dans certaines situations non ambigües.

# Chapitre 3 Résolution d’équations

## 3.1 Encadrer une racine d’une équation par dichotomie

Algorithme de dichotomie
On suppose que :
la fonction f est continue et croissante (resp décroissante) sur l’intervalle [a,b] et que f(a)<0 et f(b)>0 (si f(a)>0 et f(b)<0 on se ramène au cas précédent en échangeant a et b).
On en déduit que f s’annule pour x=x0 avec a<x0<b.
On cherche une valeur approchée de x0.
Pour avoir une meilleur approximation de x0, on cherche le signe de f(a+b)/2) (c:=(a+b)/2 est le milieu de [a,b])
Si f(c)==0 alors x0=c et on est content !
Si f(c)<0 alors c<x0<b sinon f(c)>0 alors a<x0<c.
On peut donc recommencer le processus jusquà ce que f(c)==0 ou abs(b-a)<10`^`-n (avec par exemple n:=3).
On tape :

    fonction Dichotomie0(f,a,b,n)
     local c;
     si f(a)*f(b)>0 alors retourne [] fsi;
     si f(a)==0 alors retourne [a] fsi;
     si f(b)==0 alors retourne [b] fsi;
     si f(a)>0 alors a,b:=b,a; fsi; // echange a et b pour avoir f(a)<0
     tantque abs(b-a)>10^(-n) faire
       c:=evalf(a+b)/2;
       si f(c)=0 alors retourne [c] fsi;
       si f(c)<0 alors a:=c; sinon b:=c; fsi;// on garde f(c)<0
     ftantque
     retourne [c];
    ffonction:;

Puis, on tape :
f(x):=x^2-2
Dichotomie0(f,1,2,12)
g(x):=cos(x)-x
Dichotomie0(g,0.,1.,12)
On peut rajouter en début de programme un test sur n pour que le nombre d’itération ne soit pas trop grand, par exemple
si n>12 alors n:=12; fsi;
On peut aussi utiliser une variable locale pour ne faire qu’une seule fois le calcul de 10 −n 10^{-n} et de f(c)f(c). Ce qui donne le programme suivant :

    fonction Dichotomie1(f,a,b,n)
     local c,fc,eps;
     si f(a)*f(b)>0 alors retourne [] fsi;
     si f(a)==0 alors retourne [a] fsi;
     si f(b)==0 alors retourne [b] fsi;
     si f(a)>0 alors a,b:=b,a; fsi; // echange a et b pour avoir f(a)<0
     si n>12 alors n:=12; fsi;
     eps:=10^(-n);
     tantque abs(b-a)>eps faire
       c:=evalf(a+b)/2;
       fc:=f(c);
       si fc=0 alors retourne [c] fsi;
       si fc<0 alors a:=c; sinon b:=c; fsi;// on garde f(c)<0
     ftantque
     retourne [c];
    ffonction:;

g(x):=cos(x)-x
Dichotomie1(g,0.,1.,12)
Traduction du “tantque” en “pour”
On observe qu’à chaque itération de la boucle on divise la longueur de l’intervalle par 2, le nombre d’itérations ne peut pas être très grand. On peut donc transformer la boucle “tantque” en boucle “pour” en se fixant à priori un nombre maximal d’itérations ce qui évitera d’ailleurs d’avoir une boucle qui ne se termine jamais. On montrera plus bas que 2100 itérations suffisent en calcul approché.

    fonction Dichotomie2(f,a,b,n)
     local c,k,eps;
     eps:=10^-n;
     si f(a)*f(b)>0 alors retourne []; fsi;
     pour k de 1 jusque 2100 faire
       c:=evalf((a+b)/2);
       si b-a<eps alors retourne [c]; fsi;
       si f(a)*f(c)<=0 alors b:=c; sinon a:=c; fsi;
     fpour;
     retourne [c];
    ffonction:;

g(x):=cos(x)-x
Dichotomie2(g,0.,1.,12)
Si on connaît les logarithmes, on peut calculer le nombre d’itérations N N pour que |b−a|/2 N<10 −n|b-a|/2^N&lt;10^{-n} en résolvant cette équation. On peut aussi observer que les calculs se font en approché, dans Xcas le plus grand nombre représentable par défaut est `evalf(2^(1024-1)`, donc la taille du plus grand intervalle est (légèrement inférieure à) 2 1025 2^{1025}. Le plus petit réel strictement positif représentable est `evalf(2^(-1069))`. Comme on divise par 2 la taille de l’intervalle à chaque itération, le nombre maximal d’itérations est au plus 1025+1069=20941. Au-delà, soit a a et b b sont représentés par le même nombre flottant (et le test |b−a|<10 −n|b-a|&lt;10^{-n} sera donc vrai) soit ils ne différeront que par leur dernier bit de mantisse, et dans ce cas c=(a+b)/2 c=(a+b)/2 sera arrondi vers a a ou vers b b et la boucle tanque continuera indéfiniment.
La majoration est le plus souvent très pessimiste, par exemple si a=1 a=1 et b=2 b=2 ils sont déjà représentés avec le même exposant et le nombre d’itérations sera limité par 48.

    fonction Dichotomie3(f,a,b,n)
     local c,k,N;
     si f(a)*f(b)>0 alors retourne []; fsi;
     N:=ceil(log((b-a)/10^(-n))/log(2));
     si N>2100 alors N:=2100 fsi;
     pour k de 1 jusque N faire
       c:=evalf((a+b)/2);
       si f(a)*f(c)<=0 alors b:=c; sinon a:=c; fsi;
     fpour;
     retourne [c];
    ffonction:;

g(x):=cos(x)-x
Dichotomie3(g,0.,1.,12)
Exercice : Modifier la fonction ci-dessus pour calculer f f une seule fois par itération, c’est-à-dire qu’on calcule c c et f(c)f(c) mais qu’on ne recalcule pas f(a)f(a).
Indication :
On pourra introduire 3 variables locales fa, fb, fc contenant les valeurs de f(a)f(a), f(b)f(b), f(c)f(c). Ajouter un test pour renvoyer [c] si f(c)f(c) est nul.
Correction de l’exercice

    fonction Dichotomie(f,a,b,n)
     local c,k,N,fa,fb,fc;
     fa:=f(a);
     fb:=f(b);
     si fa*fb>0 alors retourne []; fsi;
     si fa==0 alors retourne [a] fsi;
     si fb==0 alors retourne [b] fsi;
     N:=ceil(log((b-a)/10^(-n))/log(2));
     si N>2100 alors N:=2100 fsi;
     pour k de 1 jusque N faire
       c:=evalf((a+b)/2);
       fc:=f(c);
       si fc==0 alors retourne [c] fsi;
       si fa*fc<0 alors b:=c; sinon a:=c;fa:=fc; fsi;
     fpour;
     retourne [c];
    ffonction:;

g(x):=cos(x)-x
Dichotomie(g,0.,1.,12)
On peut vérifier ces résultats en utilisant la commande fsolve de Xcas qui effectue la résolution numérique d’une équation :
fsolve(cos(x)=x,x,0..1)

## 3.2 Résoudre dans ℝ\mathbb{R} une équation se ramenant au premier degré ou au degré 2

On considère une équation qui se ramène au premier ou au deuxième degré.
Si cette équation se ramène au premier degré, elle est de la forme :

a*x+b=0 avec a!=0

donc cette équation a une solution qui est:
x0:=-b/a.
Si cette équation se ramène au deuxième degré, elle est de la forme :

a*x`^`2+b*x+c=0 avec a!=0

donc :

- si Δ\Delta=b`^`2-4*a*c>0 il y a 2 solutions qui sont :
  x1:=(-b+Δ)\sqrt\Delta))/(2*a) et x2:=(-b-Δ)\sqrt\Delta))/(2*a).
- si Δ\Delta=b`^`2-4*a*c=0 il y a 1 solution qui est :
  x1 et x1:=-b/(2*a)
- si Δ\Delta=b`^`2-4*a*c<0 il n’y a pas de solution réelle.

On tape :

    fonction Solution12(Eq,Var)
     local a,b,c,d;
     Eq:=normal(gauche(Eq)-droit(Eq));
     si degree(Eq,Var)==0 alors
       si (Eq==0) alors retourne "infinite de solution" ;
       sinon retourne "pas de solution" ;
       fsi;
     fsi;
     si degree(Eq,Var)==1 alors
       //a:=coeff(Eq,Var,1);b:=coeff(Eq,Var,0);
       b:=subst(Eq,Var=0);
       a:=subst(Eq,Var=1)-b;
       retourne normal([-b/a]);
     fsi;
     si degree(Eq,Var)==2 alors
       //a:=coeff(Eq,Var,2);b:=coeff(Eq,Var,1);c:=coeff(Eq,Var,0);
       c:=subst(Eq,Var=0);
       d:=subst(Eq,Var=1);
       b:=(d-subst(Eq,Var=-1))/2;
       a:=d-b-c;
       d:=b^2-4*a*c;
       si d>0 alors retourne simplify([(-b+sqrt(d))/(2*a),(-b-sqrt(d))/(2*a)]);fsi;
       si d==0 alors retourne simplify([-b/(2*a)]); fsi;
       retourne [];
     fsi;
     retourne "degree >2";
    ffonction:;

onload
Solution12(2*x^2+2*x+2=x^2+2*x+4,x)
Solution12(2*x^2+2*x+2=2x^2+x+4,x)
Solution12(2*x^2+2*x+1=-2*x+31,x)
Solution12(2*x^2+2*x+1=-2*x-2,x)

## 3.3 Résoudre un système de deux équations du premier degré à deux inconnues.

On veut résoudre le système de deux équations du premier degré
a 1 x+b 1 y+c 1=0,a 2 x+b 2 y+c 2=0 a_1 x+b_1 y+c_1=0, \quad a_2x+b_2y+c_2=0 à deux inconnues x,y x,y. On notera a1, b1, c1, a2, b2, c2 les coefficients des équations dans les programmes.
Pour éviter d’étudier des cas particuliers inintéressants, on va supposer que (a 1,b 1)≠(0,0)(a_1,b_1)\neq (0,0) et (a 2,b 2)≠(0,0)(a_2,b_2) \neq (0,0). Dans ce cas a 1 x+b 1 y+c 1=0 a_1 x+b_1 y+c_1=0 et a 2 x+b 2 y+c 2=0 a_2x+b_2y+c_2=0 sont les équations de 2 droites D 1 D_1 et D 2 D_2.

Solution géométrique

- Si D 1 D_1 et D 2 D_2 sont concourantes, il y a une seule solution. Pour la déterminer, on peut utiliser la commande solve de Xcas
  solve([a1*x+b1*y+c1=0,a2*x+b2*y+c2=0],[x,y])
  On justifiera ce résultat plus bas.
- Si D 1 D_1 et D 2 D_2 sont parallèles il n’y a pas de solution, sauf si D 1 D_1 et D 2 D_2 sont confondues, il y a une infinité de solutions. On va montrer que cela se produit si et seulement si a 1 b 2−a 2 b 1≠0 a_1 b_2-a_2b_1 \neq 0.
  En effet, D 1 D_1 et D 2 D_2 sont parallèles lorsque les coefficients [a 1,b 1] [a_1,b_1] et [a 2,b 2] [a_2,b_2] sont proportionnels i.e si il existe k≠0 k\neq0 tel que :
  [a 1,b 1]=k[a 2,b 2]=[k a 2,k b 2] [a_1,b_1]=k[a_2,b_2]=[ka_2,kb_2] ce qui entraine : (b 1 a 2−b 2 a 1)=k b 2 a 2−k b 2 a 2=0(b_1a_2-b_2a_1)=kb_2a_2-kb_2a_2=0 Réciproquement, si (b 1 a 2=b 2 a 1) (b_1a_2=b_2a_1) alors D 1 D_1 et D 2 D_2 sont parallèles ou confondues.
  En effet :
  - Si b 1=0 b_1=0 (resp a 1=0 a_1=0) alors b 2=0 b_2=0 (resp a 2=0 a_2=0) puisque [a 1,b 1]≠[0,0] [a_1,b_1]\neq[0,0] et (b 1 a 2=b 2 a 1) (b_1a_2=b_2a_1), donc D 1 D_1 et D 2 D_2 sont parallèles à l’axe des x x (resp y y).
  - Si b 1≠0 b_1\neq0 et a 1≠0 a_1\neq0 alors b 2/b 1==a 2/a 1=k b_2/b_1==a_2/a_1=k ce qui signifie que D 1 D_1 et D 2 D_2 sont parallèles ou confondues (D 1 D_1 et D 2 D_2 sont confondues lorsque les coefficients [a 1,b 1,c 1] [a_1,b_1,c_1] et [a 2,b 2,c 2] [a_2,b_2,c_2] sont proportionnels i.e si il existe k≠0 k\neq0 tel que :
    [a 1,b 1,c 1]=k[a 2,b 2,c 2]=[k a 2,k b 2,k c 2] [a_1,b_1,c_1]=k[a_2,b_2,c_2]=[ka_2,kb_2,kc_2]).

On commence par écrire un programme dans le cas où les droites D 1 D_1 et D 2 D_2 sont concourrantes.

    fonction Intersection1(Eq1,Eq2,Var1,Var2)
     local a1,b1,c1,a2,b2,c2;
     Eq1:=normal(gauche(Eq1)-droit(Eq1));
     Eq2:=normal(gauche(Eq2)-droit(Eq2));
     a1:=coeff(Eq1,Var1,1);
     a2:=coeff(Eq2,Var1,1);
     b1:=coeff(Eq1,Var2,1);
     b2:=coeff(Eq2,Var2,1);
     si normal(a1*b2-a2*b1)==0 alors
       retourne "Cas non traite : Eq1 ou Eq2 n'est pas une  "+
              "equation de droite ou droites paralleles";
     fsi;
     c1:=subst(Eq1,[Var1,Var2],[0,0]);
     c2:=subst(Eq2,[Var1,Var2],[0,0]);
     print("droites concourantes");
     retourne [normal((-b2*c1+b1*c2)/(a1*b2-a2*b1)),
               normal((a2*c1-a1*c2)/(a1*b2-a2*b1))];
    ffonction:;

d1:=droite(x+y=3);d2:=droite(2x-y=9);d3:=droite(-4x+2y=3)
Intersection1(x+y=3,2x-y=9,x,y)
Intersection1(4x-2y+9=0,2x-y=3,x,y)
Exercice : modifiez le programme ci-dessus pour éviter de calculer plusieurs fois a 1 b 2−a 2 b 1 a_1b_2-a_2b_1, en stockant sa valeur dans une variable locale.
Correction de l’exercice :

    fonction Intersection2(Eq1,Eq2,Var1,Var2)
     local a1,b1,c1,a2,b2,c2,d;
     Eq1:=normal(gauche(Eq1)-droit(Eq1));
     Eq2:=normal(gauche(Eq2)-droit(Eq2));
     a1:=coeff(Eq1,Var1,1);
     a2:=coeff(Eq2,Var1,1);
     b1:=coeff(Eq1,Var2,1);
     b2:=coeff(Eq2,Var2,1);
     d:=normal(a1*b2-a2*b1);
     si d==0 alors
       retourne "Cas non traite : Eq1 ou Eq2 n'est pas une"+
        " equation de droite ou droites paralleles ou confondues";
     fsi;
     c1:=subst(Eq1,[Var1,Var2],[0,0]);
     c2:=subst(Eq2,[Var1,Var2],[0,0]);
     print("droites concourantes");
     retourne [normal((-b2*c1+b1*c2)/d),
               normal((a2*c1-a1*c2)/d)];
    ffonction:;

d1:=droite(x+y=3);d2:=droite(2x-y=9);d3:=droite(-4x+2y=3)
Intersection2(x+y=3,2x-y=9,x,y)
Intersection2(4x-2y+9=0,2x-y=3,x,y)
Voici maintenant un programme qui teste que les équations entrées sont bien des équations de droite et traite aussi le cas des droites parallèles ou confondues :

    fonction Intersection(Eq1,Eq2,Var1,Var2)
     local a1,b1,c1,a2,b2,c2,d;
     Eq1:=normal(gauche(Eq1)-droit(Eq1));
     si degree(Eq1,Var1)>1 et degree(Eq1,Var2)>1  alors
       retourne "pas de degre 1";
     fsi;
     Eq2:=normal(gauche(Eq2)-droit(Eq2));
     si degree(Eq2,Var1)>1 et degree(Eq2,Var2)>1 alors
       retourne "pas de degre 1";
     fsi;
     a1:=coeff(Eq1,Var1,1);
     a2:=coeff(Eq2,Var1,1);
     b1:=coeff(Eq1,Var2,1);
     b2:=coeff(Eq2,Var2,1);
     si [a1,b1]==[0,0] ou [a2,b2]==[0,0] alors
       retourne "Eq1 ou Eq2 est nulle";
     fsi;
     c1:=subst(Eq1,[Var1,Var2],[0,0]);
     c2:=subst(Eq2,[Var1,Var2],[0,0]);
     d:=normal(a1*b2-a2*b1);
     si d!=0 alors
       print("droites concourantes");
       retourne [normal((-b2*c1+b1*c2)/d),
                 normal((a2*c1-a1*c2)/d)];
     fsi;
     si a1!=0 et a2!=0 alors
       si c1*a2-c2*a1==0 alors
         print("droites confondues");
         retourne [normal(-c1/a1),Var2];
       sinon
         print("droites paralleles");
         retourne [] ;
       fsi;
     fsi;
     si b1!=0 et b2!=0 alors
       si c1*b2==c2*b1 alors
         print("droites confondues");
         retourne [Var1,normal(-c1/b1)];
       sinon
         print("droites paralleles");
         retourne [];
       fsi;
     fsi;
    ffonction:;

Intersection(x+y=3,2x-y=9,x,y)
Intersection(4x-2y+3=0,2x-y=9,x,y)
On vérifie avec Xcas :
coordonnees(inter_unique(d1,d2))
est_parallele(d2,d3)
Justification de la solution lorsque D 1 D_1 et D 2 D_2 sont concourantes
On a vu que c’était le cas si et seulement si b 1 a 2−b 2 a 1≠0 b_1a_2-b_2a_1\neq0.

- Si b 1≠0 b_1\neq0 on a y=(−a 1 x−c 1)/b 1 y=(-a_1x-c_1)/b_1 donc l’abscisse du point d’intersection de D 1 D_1 et D 2 D_2 vérifie :
  b 1 a 2 x+b 2(−a 1 x−c 1)+b 1 c 2=0 b_1a_2x+b_2(-a_1x-c_1)+b_1c_2=0
  donc (b 1 a 2−b 2 a 1)x+b 1 c 2−b 2 c 1=0 (b_1a_2-b_2a_1)x+b_1c_2-b_2c_1=0 et finalement x=b 1 c 2−b 2 c 1 b 2 a 1−b 1 a 2 x=\frac{b_1c_2-b_2c_1}{b_2a_1-b_1a_2} On remplace dans l’expression de y y en fonction de x x y = −a 1 b 1 c 2−b 2 c 1 b 2 a 1−b 1 a 2−c 1 b 1 = −a 1 b 1 c 2+a 1 b 2 c 1−c 1(b 2 a 1−b 1 a 2)b 2 a 1−b 1 a 2 b 1 = −a 1 b 1 c 2+c 1 b 1 a 2 b 1(b 2 a 1−b 1 a 2) = −a 1 c 2+c 1 a 2 b 2 a 1−b 1 a 2 \begin{matrix} y&=&\frac{-a_1\frac{b_1c_2-b_2c_1}{b_2a_1-b_1a_2}-c_1}{b_1}\\ &=&\frac{\frac{-a_1b_1c_2+a_1b_2c_1-c_1(b_2a_1-b_1a_2)}{b_2a_1-b_1a_2}}{b_1}\\ &=&\frac{-a_1b_1c_2+c_1b_1a_2}{b_1(b_2a_1-b_1a_2)} \\ &=& \frac{-a_1c_2+c_1a_2}{b_2a_1-b_1a_2} \end{matrix}
- Si b 1=0 b_1=0, on va voir que les mêmes formules s’appliquent. En effet l’abscisse du point d’intersection de D 1 D_1 et D 2 D_2 vérifie a 1 x+c 1=0 a_1x+c_1=0 donc x=−c 1 a 1=b 1 c 2−b 2 c 1 b 2 a 1−b 1 a 2 x=-\frac{c_1}{a_1}=\frac{b_1c_2-b_2c_1}{b_2a_1-b_1a_2} Comme b 2≠0 b_2\neq0, on a y = −a 2 x−c 2 b 2 = a 2 c 1 a 1−c 2 b 2 = a 2 c 1−a 1 c 2 a 1 b 2 = −a 1 c 2+c 1 a 2 b 2 a 1−b 1 a 2 \begin{matrix} y&=&\frac{-a_2x-c_2}{b_2}\\ &=&\frac{a_2\frac{c_1}{a_1}-c_2}{b_2}\\ &=& \frac{a_2 c_1-a_1 c_2}{a_1b_2}\\ &=& \frac{-a_1c_2+c_1a_2}{b_2a_1-b_1a_2} \end{matrix}

1
  Il faut ajouter 5 pour un langage traditionnel où la mantisse a 53 chiffres significatifs. Attention, ceci n’est plus valable dans Xcas si on modifie la valeur de Digits

# Chapitre 4 Les figures en géométrie plane avec Xcas

## 4.1 Le point : point et le segment : segment

point a comme arguments l’abscisse et l’ordonnée du point.
point trace le point à l’aide d’une croix sur l’écran de géométrie 2 d 2d.
Si on a donné un nom au point (par ex A:=point(1,1); ou A:=point([1,1]);) ce nom sera affiché à côté de la croix.
A:=point(1,1);B:=point(2,3);
segment a comme argument 2 points.
segment trace le segment reliant ces 2 points sur l’écran de géométrie 2 d 2d.
A:=A;B:=B;segment(A,B);

## 4.2 Les coordonnées d’un point : coordonnees

coordonnees a comme argument 1 point.
coordonnees renvoie la liste constitué de l’abscisse et de l’ordonnée du point.
coordonnees(A)
coordonnees(B)

## 4.3 La droite et son équation : droite et equation

droite a comme argument 2 points.
droite trace la droite passant par ces 2 points sur l’écran de géométrie 2 d 2d.
A:=A;B:=B;d:=droite(A,B);
equation a comme argument une droite.
equation renvoie l’équation de cette droite
equation(d)

## 4.4 Ligne brisée : polygone_ouvert

polygone_ouvert a comme argument une liste L de points.
polygone_ouvert trace la ligne brisée joignant les points L[k] et L[k+1] pour k=0..dim(L)-2.
A:=point(1,1);B:=point(2,3);C:=point(3,2);D:=point(2,0);polygone_ouvert(A,B,C,D)

## 4.5 Les polygones : triangle, carre, polygone

triangle a comme argument 3 points.
triangle trace le triangle défini par ces 3 points sur l’écran de géométrie 2 d 2d.
A:=A;B:=B;C:=C;triangle(A,B,C)
carre a comme argument 2 points.
carre trace le carré direct défini par ces 2 points sur l’écran de géométrie 2 d 2d.
A:=A;D:=D;carre(A,D)
A:=A;D:=D;carre(D,A)
polygone a comme argument une liste de points.
polygone trace le polygone fermé défini par cette liste de points sur l’écran de géométrie 2 d 2d.
A:=A;B:=B;C:=C;D:=D;polygone(A,B,C,D)

## 4.6 Le cercle et son équation : cercle et equation

Si le cercle est défini par son centre et son rayon alors cercle a pour argument un point et un réel r.
cercle trace le cercle de centre ce point et de rayon abs(r) sur l’écran de géométrie 2 d 2d.
A:=point(1,1);C1:=cercle(A,-2)
equation(C1)

Si le cercle est défini par son diamètre alors cercle a pour argument 2 points.
cercle trace le cercle de diamètre ces 2 points.
A1:=point(1,1);A2:=point(2,3);C2:=cercle(A1,A2)
equation(C2)

## 4.7 Les tangentes à un cercle passant par un point et leurs équations

Si C est un cercle et B un point situé à l’extérieur de (resp sur) C alors tangent(C,B) trace les (resp la) tangente(s) à C passant par B.
B:=point(3,1);C1:=cercle(point(1,1),1);T1:=tangent(C1,B);
equation(T1)
B:=point(3,1);C2:=cercle(A1,A2);T2:=tangent(C2,B);
equation(T2);

# Chapitre 5 La géométrie analytique

Dans ce chapitre, les programmes que l’on va faire ne feront pas de tracés mais renverront des valeurs (coordonnées, coefficients, équations).
On pourra alors faire les figures avec Xcas et vérifier les résultats obtenus par ces programmes.

## 5.1 Les segments

### 5.1.1 Calculer la distance de deux points connaissant leurs coordonnées

Si les points A et B ont pour coordonnées cA:=[xA,yA] et cB:=[xB,yB] le segment AB a pour longueur :
sqrt((xA-xB)`^`2+(yA-yB)`^`2)
On tape :

    fonction Longueur(cA,cB)
     local xA,xB,yA,yB;
     xA:=cA[0];
     yA:=cA[1];
     xB:=cB[0];
     yB:=cB[1];
     retourne simplify(sqrt((xA-xB)^2+(yA-yB)^2));
    ffonction:;

onload
cA:=[1,2]
cB:=[-1,-3]
Longueur(cA,cB)
Vérifions avec Xcas :
longueur(cA,cB)

### 5.1.2 Calculer les coordonnées du milieu d’un segment

Si les points A et B ont pour coordonnées cA:=[xA,yA] et cB:=[xB,yB], le milieu de AB a pour coordonnées [(xA+xB)/2,(yA+yB)/2] :
On tape :

    fonction Milieu(cA,cB)
     local xA,xB,yA,yB;
     xA:=cA[0];
     yA:=cA[1];
     xB:=cB[0];
     yB:=cB[1];
     retourne [(xA+xB)/2,(yA+yB)/2];
    ffonction:;

onload
cA:=[1,2]
cB:=[-1,-3]
Milieu(cA,cB)
Vérifions avec Xcas :
coordonnees(milieu(cA,cB))

## 5.2 Les droites

### 5.2.1 Équation d’une droite définie par 2 points ou par sa pente et un point

Équation d’une droite définie par 2 points
Si les points A et B ont pour coordonnées cA:=[xA,yA] et cB:=[xB,yB], la droite d passant par A et B a pour équation :
(xA-xB)*y-(yA-yB)*x-yB*xA+yA*xB=0 ou encore
si (xA==xB) alors l’équation de d est x=xA
si (xA!=xB) alors l’équation de d est y=(yA-yB)*(x-xB)/(xA-xB)+yB
Équation d’une droite définie par sa pente et un point
La droite passant par le point A de coordonnées cA:=[xA,yA] et de pente m a pour équation :
y=m*(x-xA)+yA.
On tape :

    fonction Droite1(cA,cB)
     local xA,xB,yA,yB;
     xA:=cA[0];
     yA:=cA[1];
     xB:=cB[0];
     yB:=cB[1];
     retourne normal((xA-xB)*y-(yA-yB)*x-yB*xA+yA*xB)=0;
    ffonction:;

    fonction Droite2(cA,m)
     local xA,yA;
     xA:=cA[0];
     yA:=cA[1];
     retourne y-m*(x-xA)-yA=0;
    ffonction:;

On peut réunir les 2 programmes en un seul en testant la dimension du deuxième paramètre de Droite qui est soit une liste de dimension 2, soit un réél.
On peut aussi faire en sorte que Droite accepte 1 seul argument qui soit son équation : pour cela, on donne au deuxième argument une valeur par défaut (ici cette valeur sera arbitraire par exemple 0) (cf 2.2.3).
On tape :

    fonction Droite(cA,L=0)
     local xA,xB,yA,yB,m;
     si type(cA)==expression alors retourne cA;fsi;
     xA:=cA[0];
     yA:=cA[1];
     si type(L)==vecteur alors
       xB:=L[0];
       yB:=L[1];
       retourne normal((xA-xB)*y-(yA-yB)*x-yB*xA+yA*xB)=0;
     sinon
       m:=L;
       retourne y-m*(x-xA)-yA=0;
     fsi;
    ffonction:;

onload
Observez qu’on a donné une valeur par défaut 0 au deuxième paramètre `L`, si `Droite` est appelée avec deux arguments tout se passe comme si on avait écrit `L` et non `L=0`, par contre si `Droite` est appelée avec un seul argument, alors `L` prend la valeur 0 au début de la fonction.
cA:=[1,2]
cB:=[-1,-3]
m:=2
Droite(cA,cB)
Droite(cA,m)
Droite(x+y=1)
Vérifions avec Xcas :
equation(droite(point(cA),point(cB)))
equation(droite(point(cA),pente=m))

### 5.2.2 Coefficients (a,b,c) de la droite d’équation ax+by+c=0

Étant donnée l’équation d’une droite a*x+b*y+c=0, on va écrire une fonction qui renvoie les coefficients a, b et c.
On utilise tout d’abord gauche et droit qui renvoie le côté gauche et le côté droit d’une équation.
Par exemple si Eq:=eq1=eq2 alors gauche(Eq) renvoie eq1 et droit(Eq) renvoie eq2 donc
gauche(Eq)-droit(Eq) renvoie eq qui est égal à eq1-eq2.
On peut alors trouver a, b et c en donnant des valeurs à x et y.
Posons :
c:=subst(eq,[x,y],[0,0])
d1:=subst(eq,[x,y],[1,0])
d2:=subst(eq,[x,y],[0,1])
Alors on a a:=d1-c et b:=d2-c
On tape :

    fonction Coeffsdroite(Eq)
     local a,b,c,d1,d2,eq;
     eq:=gauche(Eq)-droit(Eq);
     c:=subst(eq,[x,y],[0,0]);
     d1:=subst(eq,[x,y],[1,0]);
     d2:=subst(eq,[x,y],[0,1]);
     retourne normal(d1-c,d2-c,c);
    ffonction:;

onload
Coeffsdroite(y-3*(x-1)-1=0)
Coeffsdroite((1+sqrt(2))^2*x-y+3=0)
Remarque
On peut aussi utiliser :
coeff(P(x,y),x) (resp coeff(P(x,y),y)) qui renvoie la liste des coefficients selon les puissances décroissantes du polynôme P par rapport à la variable x (resp y) et
coeff(P(x,y),x,n) (resp coeff(P(x,y),y,n)) qui renvoie le coefficient de x`^`n (resp de y`^`n) du polynôme P.
On tape :

    fonction Coeffdroite(Eq)
     local a,b,c;
     Eq:=gauche(Eq)-droit(Eq);
     a:=coeff(Eq,x,1);
     b:=coeff(Eq,y,1);
     c:=subst(Eq,[x,y]=[0,0]);
     retourne normal(a,b,c);
    ffonction:;

Coeffdroite(y-3*(x-1)-1=0)
Coeffdroite(Droite(y-3*(x-1)-1=0))
Vérifions avec Xcas :
Eq:=y-3*(x-1)-1;[coeff(Eq,x,1),coeff(Eq,y,1),subst(Eq,[x,y]=[0,0])]

### 5.2.3 Point d’intersection de 2 droites sécantes

Cette section reprend la section sur la résolution de système de 2 équations à 2 inconnues. Soient deux droites d1 et d2 d’équation :
a 1 x+b 1 y+c 1=0 a_1x+b_1y+c_1=0 et a 2 x+b 2 y+c 2=0 a_2x+b_2y+c_2=0
Ces 2 droites sont parallèles si a 1 b 2=a 2 b 1 a_1b_2=a_2b_1.
Si a 1 b 2≠a 2 b 1 a_1b_2\neq a_2b_1 d1 et d2 sont sécantes.
Les coordonnées de leur point d’intersection sont
(−c 2*b 1+b 2*c 1)/(−b 2*a 1+a 2*b 1),(c 2*a 1−a 2*c 1)/(−b 2*a 1+a 2*b 1)(-c_2*b_1+b_2*c_1)/(-b_2*a_1+a_2*b_1),(c_2*a_1-a_2*c_1)/(-b_2*a_1+a_2*b_1) Interdroite(d1,d2) renvoie [] si d1 et d2 sont paralléles et sinon renvoie les coordonées de leur point d’intersection.
On utilise les programmes Droite et Coeffsdroite précédents (cf 5.2.2 pour avoir les coefficients des équations Eq1 et Eq2 de d1 et de d2 On tape :

    fonction Interdroite(d1,d2)
     local a1,a2,b1,b2,c1,c2,gd1,gd2,d;
     (a1,b1,c1):=Coeffsdroite(d1);
     (a2,b2,c2):=Coeffsdroite(d2);
     d:=normal(a2*b1-b2*a1);
     si d==0 alors retourne [];fsi;
     retourne [(b2*c1-b1*c2)/d,(c2*a1-a2*c1)/d];
    ffonction:;

d1:=Droite(2x+3y-1=0)
d2:=Droite(-x+y+1=0)
d3:=Droite([1,1],[2,3])
d4:=Droite([1,0],[0,1])
d5:=Droite([1,2],2)
Interdroite(d1,d2)
Interdroite(d3,d4)
Interdroite(d5,d3)
On fait la figure avec Xcas:
droite(d1),droite(d2),droite(d3),droite(d4),droite(d5)
Vérifions avec Xcas :
coordonnees(inter_unique(droite(d1),droite(d2)))
coordonnees(inter_unique(droite(d3),droite(d4)))

## 5.3 Triangles et quadrilatères définis par les coordonnées des sommets

On définit des versions de la commande `polygone` de Xcas donc ces 2 programmes vont faire des figures.

    fonction Triangle(cA,cB,cC)
     retourne polygone(cA,cB,cC);
    ffonction:;
    fonction Quadrilatere(cA,cB,cC,cD)
     retourne polygone(cA,cB,cC,cD);
    ffonction:;

cA:=[1,-1]
cB:=[1/2,2]
cC:=[0,3/2]
cD:=[-1/2,0]
Triangle(cA,cB,cC)
Quadrilatere(cA,cB,cC,cD)

## 5.4 Les vecteurs

### 5.4.1 Les coordonnées d’un vecteur défini par 2 points

Si les coordonnées du point A (resp B) sont cA:=[xA,yA] (resp cB:=[xB,yB]), les coordonnées du vecteur AB sont [xB-xA,yB-yA].
On tape :

    fonction Vecteur(cA,cB)
     local xA,xB,yA,yB;
     xA:=cA[0];
     yA:=cA[1];
     xB:=cB[0];
     yB:=cB[1];
     retourne normal([xB-xA,yB-yA]);
    ffonction:;

ou plus simplement :
Vecteur(cA,cB):=normal(cB-cA);
cA:=[1,2]
cB:=[-1,-3]
Vecteur(cA,cB)
On fait la figure avec Xcas :
A:=point(cA);B:=point(cB);vecteur(A,B);
Vérifions avec Xcas :
coordonnees(vecteur(A,B))

### 5.4.2 Calculer les coordonnées de la somme de deux vecteurs dans un repère

Si les vecteurs V1 et V2 ont pour coordonnées cV1:=[x1,y1] et cV2:=[x2,y2], les coordonnées du vecteur V1+V2 sont [x1+x2,y1+y2].
On tape :

    fonction SumVect(cV1,cV2)
     local x1,x2,y1,y2;
     x1:=cV1[0];
     y1:=cV1[1];
     x2:=cV2[0];
     y2:=cV2[1];
     retourne normal([x1+x2,y1+y2]);
    ffonction:;

ou plus simplement :
SumVect(cV1,cV2):=normal(cV1+cV2);
cV1:=[1,2]
cV2:=[-2,3]
cV3:=SumVect(cV1,cV2)
On fait la figure avec Xcas :
V1:=vecteur(0,cV1);V2:=vecteur(0,cV2);V3:=vecteur(0,cV3)
Vérifions avec Xcas :
cV1+cV2

### 5.4.3 Coordonnées de D D extrémité du vecteur d’origine C C équipollent au vecteur A B AB

On a D:=C+(B−A)D:=C+(B-A).
On tape :
Translation(cA,cB,cC):=cC+(cB-cA);
cA:=[1,2]
cB:=[2,3]
cC:=[-1,1]
cD:=Translation(cA,cB,cC)
On fait la figure avec Xcas :
A:=point(cA);B:=point(cB);C:=point(cC);D:=point(cD);polygone(cA,cB,cD,cC)
Vérifions avec Xcas :
coordonnees(translation(cB-cA,point(cC)))

### 5.4.4 Norme d’un vecteur

Soit le vecteur V:=[xV,yV], on pose cV:=[xV,yV] la liste des coordonnées de V.
La norme de V est égale à sqrt(xV`^`2+yV`^`2).
On tape :

    fonction Norme(cV)
     local xV,yV;
     xV:=cV[0];
     yV:=cV[1];
     retourne sqrt(xV^2+yV^2);
    ffonction:;

cA:=[1,2]
cB:=[2,3]
Norme(cB-cA)
Vérifions avec Xcas :
norm(vecteur(point(cA),point(cB)))

## 5.5 Changement de repères

### 5.5.1 Le problème

Soient 2 repères orthonormés O,O x,O y O,Ox,Oy et I,I X,I Y I,IX,IY.
Notations :

- Soit M M un point ou un vecteur.
  On note c M c_M les coordonnées [x M,y M] [x_M,y_M] de M M dans le repère O x y Oxy.
  On note C M C_M les coordonnées [X M,Y M] [X_M,Y_M] de M M dans le repère I X Y IXY.
- On note u u (resp v v) le vecteur unitaire porté par O x Ox (resp O y Oy)
- On note U U (resp V V) le vecteur unitaire porté par O X OX (resp O Y OY)

Avec ces notations, on a :

- le point I I a pour coordonnées c I:=[x I,y I] c_I:=[x_I,y_I] dans le repère O,O x,O y O,Ox,Oy donc O I=x I u+y I v OI=x_Iu+y_Iv
- le vecteur U U a pour coordonnées c U:=[x U,y U] c_U:=[x_U,yU] dans le repère O,O x,O y O,Ox,Oy (x U 2+y U 2=1 x_U^2+y_U^2=1) donc U=x U u+y U v U=x_Uu+y_Uv
- le vecteur V V a pour coordonnées c V:=[x V,y V] c_V:=[x_V,y_V] dans le repère O,O x,O y O,Ox,Oy (x V 2+y V 2=1 x_V^2+y_V^2=1) donc V=x V u+y V v V=x_Vu+y_Vv. L’angle (U,V)=π/2 (U,V)=\pi/2 donc x V:=−y U x_V:=-y_U et y V:=x U y_V:=x_U

### 5.5.2 Le programme Changexy2XY(cM,cI,cU)

On connaît les coordonnées c M:=[x M,y M] cM:=[x_M,y_M] d’un point M M dans le repère (O,O x,O y) (O,Ox,Oy) ainsi que les coordonnées c I:=[x I,y I] c_I:=[x_I,y_I] et c U:=[x U,y U] c_U:=[x_U,y_U] de I I et de U U dans le repère (O,O x,O y) (O,Ox,Oy).
On cherche les coordonnées C M:=[X M,Y M] C_M:=[X_M,Y_M] de M M dans le repère (I,I X,I Y) (I,IX,IY).
On a donc : O M=x M u+y M v = O I+I M = (x I u+y I v)+(X M U+Y M V) = x I u+y I v+X M(x U u+y U v)+Y M(x V u+y V v) = (x I+X M x U+Y M x V)u+(y I+X M y U+Y M y V)v \begin{matrix} OM=x_Mu+y_Mv&=&OI+IM\\ &=&(x_Iu+y_Iv)+(X_MU+Y_MV) \\ &=&x_Iu+y_Iv+X_M(x_Uu+y_Uv)+Y_M(x_Vu+y_Vv)\\ &=&(x_I+X_Mx_U+Y_Mx_V)u+(y_I+X_My_U+Y_My_V)v \end{matrix} Donc : x M=x I+X M x U+Y M x V,y M=y I+X M y U+Y M y V x_M=x_I+X_Mx_U+Y_Mx_V, \quad y_M=y_I+X_My_U+Y_My_V on en déduit X M,Y M X_M, Y_M X M=(x M−x I)y V−(y M−y I)x V x U y V−y U x V,Y M=(x M−x I)y U−(y M−y I)x U x V y U−y V x U X_M= \frac{(x_M-x_I)y_V-(y_M-y_I)x_V}{x_Uy_V-y_Ux_V}, \quad Y_M= \frac{(x_M-x_I)y_U-(y_M-y_I)x_U}{x_Vy_U-y_Vx_U} Or x V=−y U x_V=-y_U et y V=x U y_V=x_U donc x U y V−y U x V=x U 2+y U 2=1 x_Uy_V-y_Ux_V=x_U^2+y_U^2=1 Finalement : X M=(x M−x I)x U+(y M−y I)y U,Y M=(x M−x I)y U−(y M−y I)x U X_M= (x_M-x_I)x_U+(y_M-y_I)y_U, \quad Y_M= (x_M-x_I)y_U-(y_M-y_I)x_U On tape :

    fonction Changexy2XY(cM,cI,cU)
    local xM,xI,xU,xV,yM,yI,yU,yV,l;
    xM:=cM[0];
    yM:=cM[1];
    xI:=cI[0];
    yI:=cI[1];
    xU:=cU[0];
    yU:=cU[1];
    l:=xU^2+yU^2;
    si l!=1 alors l:=sqrt(l);xU:=xU/l;yU:=yU/l;fsi;
    xV:=-yU;
    yV:=xU;
    retourne normal([((xM-xI)*xU+(yM-yI)*yU),(-(xM-xI)*yU+(yM-yI)*xU)]);
    ffonction:;

Remarque
Dans le programme ci-dessus, on teste si le vecteur U est unitaire, si ce n’est pas le cas, on le rend unitaire avec :
l:=xU`^`2+yU`^`2;si l!=1 alors l:=sqrt(l);xU:=xU/l;yU:=yU/l;fsi;
On tape :
cM:=[5/2,9/2]
cI:=[2,3]
cU:=[sqrt(2)/2,sqrt(2)/2]
cV:=[-sqrt(2)/2,sqrt(2)/2]
Changexy2XY(cM,cI,cU)
La figure avec Xcas :
O:=point(0);M:=point(cM);I:=point(cI);U:=point(cI+cU);V:=point(cI+cV);vecteur(I,U);vecteur(I,V);vecteur(I,M)

### 5.5.3 Le programme ChangeXY2xy(CM,cI,cU)

Il s’agit du programme inverse du précédent : on connaît les coordonnées C M:=[X M,Y M]C_M:=[X_M,Y_M] d’un point M M dans le repère (I,I X,I Y)(I,IX,IY) ainsi que les coordonnées c I:=[x I,y I]c_I:=[x_I,y_I] et c U:=[x U,y U]c_U:=[x_U,y_U] de I I et de U U dans le repère (O,O x,O y)(O,Ox,Oy). On cherche les coordonnées c M:=[x M,y M]c_M:=[x_M,y_M] de M M dans le repère (O,O x,O y)(O,Ox,Oy).

On a vu précédemment que : x M=x I+X M x U+Y M x V,y M=y I+X M y U+Y M y V x_M=x_I+X_Mx_U+Y_Mx_V, \quad y_M=y_I+X_My_U+Y_My_V On tape :

    fonction ChangeXY2xy(CM,cI,cU)
     local XM,xI,xU,xV,YM,yI,yU,yV,l;
     XM:=CM[0];
     YM:=CM[1];
     xI:=cI[0];
     yI:=cI[1];
     xU:=cU[0];
     yU:=cU[1];
     l:=xU^2+yU^2;
     si l!=1 alors l:=sqrt(l);xU:=xU/l;yU:=yU/l;fsi;
     xV:=-yU;
     yV:=xU;
     retourne normal([xI+XM*xU+YM*xV,yI+XM*yU+YM*yV]);
    ffonction:;

onload
Remarque
Dans le programme ci-dessus, si le vecteur U n’est pas unitaire, on le rend unitaire :
l:=xU`^`2+yU`^`2;si l!=1 alors l:=sqrt(l);xU:=xU/l;yU:=yU/l;fsi;
On tape :
CM:=[sqrt(2),sqrt(2)/2]
cI:=[2,3]
cU:=[sqrt(2)/2,sqrt(2)/2]
cV:=[-sqrt(2)/52,sqrt(2)/2]
ChangeXY2xy(CM,cI,cU)
La figure avec Xcas :
O:=point(0);M:=point(cI+CM[0]*cU+CM[1]*cV);I:=point(cI);U:=point(cI+cU);V:=point(cI+cV);vecteur(I,U);vecteur(I,V);vecteur(I,M)

### 5.5.4 Exercices

En se servant des programmes précédents, faire les programmes :

1. calculant les coordonnées c C c_C du sommet C C d’un triangle équilatéral direct A B C ABC connaissant les coordonnées c A c_A de A A et c B c_B de B B,
2. calculant les coordonnées c C c_C et c D c_D des sommets C C et D D d’un carré direct A B C D ABCD connaissant les coordonnées c A c_A de A A et c B c_B de B B.

Solution
1/ Soit un triangle équilatéral direct A B C ABC. Dans le repère orthonormé O x y Oxy, A A a pour coordonnées c A:=[x A,y A] c_A:=[x_A,y_A] et B B a pour coordonnées c B:=[x B,y B] c_B:=[x_B,y_B].
Cherchons les coordonnées C C=[X C,Y C] C_C=[X_C,Y_C] du point C C dans le repère d’origine A A et d’axe des X X dirigé selon le vecteur A B AB. On pose : l:=(x B−x A) 2+(y B−y A) 2 l:=\sqrt{(x_B-x_A)^2+(y_B-y_A)^2} On a : c U:=[x B−x A l,y B−y A l],C C:=[l 2,l 3 2]c_U:=[\frac{x_B-x_A}{l},\frac{y_B-y_A}{l}], \quad C_C:=[\frac{l}{2},\frac{l\sqrt{3}}{2}] Et les coordonnées de C C dans le repère orthonormé O x y Oxy sont :
ChangeXY2xy(CC,cA,cU) (fonction écrite précédemment cf 5.5.3).
On tape :

    fonction Coordequi(cA,cB)
     local xA,yA,xB,yB,cU,l,CC;
     xA:=cA[0];
     yA:=cA[1];
     xB:=cB[0];
     yB:=cB[1];
     l:=sqrt((xB-xA)^2+(yB-yA)^2);
     cU:=[(xB-xA)/l,(yB-yA)/l];
     CC:=[l/2,l*sqrt(3)/2];
     retourne ChangeXY2xy(CC,cA,cU);
    ffonction:;

cA:=[1,2]
cB:=[-1,-3]
cC:=Coordequi(cA,cB)
On fait la figure avec Xcas :
A:=point(cA);B:=point(cB);T:=triangle_equilateral(A,B);
Vérifions avec Xcas :
normal(coordonnees(sommets(T)[2]))
2/ Soit un carré direct A B C D ABCD, avec A A de coordonnées c A:=[x A,y A]c_A:=[x_A,y_A] et B B de coordonnées c B:=[x B,y B]c_B:=[x_B,y_B] dans le repère orthonormé O x y Oxy.
Cherchons les coordonnées C C:=[X C,Y C]C_C:=[X_C,Y_C] du point C C et C D:=[X D,Y D]C_D:=[X_D,Y_D] des points C C et D D dans le repère d’origine A A et d’axe des X X dirigé selon le vecteur A B AB. On pose : l:=(x B−x A) 2+(y B−y A) 2 l:=\sqrt{(x_B-x_A)^2+(y_B-y_A)^2} On a : c U:=[x B−x A l,y B−y A l],c C=[l,l],c D=[0,l]c_U:=[\frac{x_B-x_A}{l},\frac{y_B-y_A}{l}], \quad c_C=[l,l], \quad c_D=[0,l] Donc les coordonnées de C C dans le repère orthonormé O x y Oxy sont :
ChangeXY2xy(CC,cA,cU)
les coordonnées de D D dans le repère orthonormé O x y Oxy sont :
ChangeXY2xy(CD,cA,cU) (fonction écrite précédemment cf 5.5.3).

    fonction Coordcarre(cA,cB)
     local xA,yA,xB,yB,CC,CD,cU,l;
     xA:=cA[0];
     yA:=cA[1];
     xB:=cB[0];
     yB:=cB[1];
     l:=sqrt((xB-xA)^2+(yB-yA)^2);
     cU:=[(xB-xA)/l,(yB-yA)/l];
     CC:=[l,l];
     CD:=[0,l];
     retourne ChangeXY2xy(CC,cA,cU),ChangeXY2xy(CD,cA,cU);
    ffonction:;

cA:=[1,2]
cB:=[-1,-3]
cC:=Coordcarre(cA,cB)[0]
cD:=Coordcarre(cA,cB)[1]
On fait la figure avec Xcas :
A:=point(cA);B:=point(cB);K:=carre(A,B)
On vérifie avec Xcas :
normal(coordonnees(sommets(K)[2],sommets(K)[3]))

## 5.6 Cercles, Tangentes à un cercle

### 5.6.1 Équation d’un cercle défini par son centre et son rayon

Le cercle C C défini par son centre A A de coordonnées [x A,y A][x_A,y_A] et de rayon r r a pour équation : (x−x A) 2+(y−y A) 2=r 2(x-x_A)^2+(y-y_A)^2=r^2 ou encore x 2+y 2−2 x A x−2 y A y+x A 2+y A 2−r 2=0 x^2+y^2-2x_Ax-2y_Ay+x_A^2+y_A^2-r^2=0 On va écrire une procédure Cercle qui renvoie une liste constituée des coordonnées de son centre, de son rayon et de son équation.
On tape :

    fonction Cercle1(cA,r)
     //cercle defini par son centre et son rayon
     local xA,yA;
     xA:=cA[0];
     yA:=cA[1];
     retourne [cA,r,x^2+y^2-2*xA*x-2*yA*y+xA^2+yA^2-r^2=0];
    ffonction:;

### 5.6.2 Équation d’un cercle défini par son diamètre

Si les points A A et B B ont pour coordonnées [x A,y A][x_A,y_A] et [x B,y B][xB,yB], le cercle C C de diamètre A B AB a pour équation :
si M:= Milieu(A,B), si xM:=M[0], si yM:=M[1] et si r:=Longueur(A,B)/2 :
(x-xM)`^`2+(y-yM)`^`2=r`^`2 ou encore
x`^`2+y`^`2-2*xM*x-2*yM*y+xM`^`2+yM`^`2-r`^`2=0
On va écrire une procédure Cercle qui renvoie une liste constituée des coordonnées de son centre, de son rayon et de son équation.
On tape :

    fonction Cercle2(cA,cB)
     //cercle d\'efini par son diam\`etre
     local xA,xB,xM,yA,yB,yM,M,r;
     xA:=cA[0];
     yA:=cA[1];
     xB:=cB[0];
     yB:=cB[1];
     cM:=Milieu(cA,cB):
     xM:=cM[0];
     yM:=cM[1];
     r:=Longueur(cA,cB):
     retourne [cM,r,x^2+y^2-2*xM*x-2*yM*y+xM^2+yM^2-r^2=0];
    ffonction:;

### 5.6.3 Équation d’un cercle défini par son centre et son rayon ou par son diamètre

On peut reunir les 2 programmes en un seul en testant la dimension du deuxième paramètre de Cercle qui est soit une liste de dimension 2 (cercle défini par son diamètre), soit un réel (cercle défini par centre et rayon).
On tape :

    fonction Cercle(cA,L)
     local cB,xA,xB,xM,yA,yB,yM,cM,r;
     xA:=cA[0];
     yA:=cA[1];
     si type(L)==vecteur alors
       xB:=L[0];
       yB:=L[1];
       cB:=[xB,yB]
       cM:=Milieu(cA,cB);
       xM:=cM[0];
       yM:=cM[1];
       r:=Longueur(cA,cB)/2;
       retourne  [cM,r,x^2+y^2-2*xM*x-2*yM*y+xM^2+yM^2-r^2=0];
     sinon
       r:=L;
       retourne [cA,r,x^2+y^2-2*xA*x-2*yA*y+xA^2+yA^2-r^2=0];
     fsi;
    ffonction:;

onload
cA:=[1,2]
cB:=[-1,-3]
r:=2
Cercle(cA,cB)
Cercle(cA,r)
On fait la figure avec Xcas :
A:=point(cA);B:=point(cB);C1:=cercle(A,B);C2:=cercle(A,r)
On vérifie avec Xcas :
normal(equation(C1));normal(equation(C2))

### 5.6.4 Centre et rayon d’un cercle donné par son équation

On utilise ici les commandes Xcas gauche, droit ,coeff, subst
On tape :

    fonction Centrerayon(Eq)
     local k,a,b,c;
     Eq:=gauche(Eq)-droit(Eq);
     k:=coeff(Eq,x,2);
     si k!=coeff(Eq,y,2) alors retourne "ce n'est pas un cercle";fsi;
     Eq:=Eq/k;
     a:=-coeff(Eq,x,1)/2;
     b:=-coeff(Eq,y,1)/2;
     c:=subst(Eq,[x,y],[0,0]);
     retourne [a,b], normal(sqrt(a^2+b^2-c));
    ffonction:;

Centrerayon(2x^2+2y^2-4x+2y=0)
On vérifie avec Xcas :
coordonnees(centre(2x^2+2y^2-4x+2y=0)),rayon(2x^2+2y^2-4x+2y=0)

### 5.6.5 Construire la tangente à un cercle en l’un de ses points

Soit C C un cercle de centre I I de coordonnées c I=[x I,y I] c_I=[x_I,y_I] et de rayon r r.
Soit A A un point de C C de coordonnées c A=[x A,y A]c_A=[x_A,y_A]. la tangente au cercle C C en A A est perpendiculaire à I A IA, donc a pour pente m=−(x A−x I)/(y A−y I) m=-(x_A-x_I)/(y_A-y_I)
L’équation de cette tangente est donc : Droite(cA,m) (fonction Droite a été écrite précédemment cf 5.2.1).
On utilise aussi, ici, les fonctions Longueur (cf 5.1.1) et Cercle (cf 5.6.3).
On tape :

    fonction Tangent1(C,cA)
     local I,r,m,xI,yI,xA,yA,cI;
     cI:=C[0];
     r:=C[1];
     si Longueur(cA,cI)!=r alors retourne "A n'est pas sur C"; fsi;
     xI:=cI[0];
     yI:=cI[1];
     xA:=cA[0];
     yA:=cA[1];
     si yA!=yI alors
       m:=-(xA-xI)/(yA-yI);
       retourne Droite(cA,m);
     fsi
     retourne x=xA;
    ffonction:;

cI:=[0,1]
cA:=[1,0]
r:=sqrt(2)
C:=Cercle(cI,r)
T1:=Tangent1(C,cA);
On fait la figure avec Xcas :
I:=point(cI);c:=cercle(I,r);A:=point(cA);droite(T1);
On vérifie avec Xcas :
t:=tangent(c,A):;equation(t)

### 5.6.6 Construire les tangentes à un cercle passant par un point

Soit C C un cercle de centre I I de coordonnées c I:=[x I,y I] c_I:=[x_I,y_I] et de rayon r r.
Soit A A un point du plan de coordonnées c A:=[x A,y A] c_A:=[x_A,y_A].
Si A A est à l’intérieur de C C il n’y a pas de tangente à C C passant par A A.

#### Le cas simple

On suppose qu’on a choisi comme repère, le repère I X Y IXY d’origine le centre I I du cercle C C et tel que A A est sur l’axe des X X (i.e. de coordonnées [X A,0][X_A,0]) et à l’extérieur de C C.
On peut mener par A A, 2 tangentes T 1 T_1 et T 2 T_2 à C C.
Soient M 1 M_1 et M 2 M_2 les 2 points de tangeance de T 1 T_1 et T 2 T_2.
Les triangles I A M 1 IAM_1 (resp I A M 2 IAM_2) sont rectangles en M 1 M_1 (resp M 2 M_2) et M 1 M 2 M_1M_2 est perpendiculaire à A I AI.
Soit H H l’intersection de M 1 M 2 M_1M_2 avec A I AI.
On fait la figure avec Xcas :
I:=point(0);C:=cercle(I,1);A:=point(2,0);T:=tangent(C,A);M1:=inter_unique(C,T[0]);M2:=inter_unique(C,T[1]);droite(M1,M2);M12:=droite(M1,M2):;H:=inter_unique(M12,droite(A,I))
On a : r 2=I M 1 2=I M 2 2=I A×I H r^2=IM_1^2=IM_2^2=IA \times IH Donc dans le repère I X Y IXY, A A a pour abscisse X A=Longueur(cI,cA)X_A=\mbox{Longueur(cI,cA)} et pour ordonnée 0.
H H a pour abscisse r 2 X A\frac{r^2}{X_A} et pour ordonnée 0.
M 1 M_1 et M 2 M_2 ont la même abscisse : X M 1=X M 2=r 2 X A X_{M_1}=X_{M_2}=\frac{r^2}{X_A} M 1 M_1 et M 2 M_2 ont des ordonnées opposées :
Y M 1>0,Y M 1 2=r 2−r 4 X A 2=r 2(1−r 2 X A 2),Y M 2=−Y M 1 Y_{M_1}&gt;0,\quad Y_{M_1}^2=r^2-\frac{r^4}{X_A^2}=r^2(1-\frac{r^2}{X_A^2}), \quad Y_{M_2}=-Y_{M_1} Y M 1=r X A 2−r 2 X A,Y M 2=−Y M 1 Y_{M_1}=r\frac{\sqrt{X_A^2-r^2}}{X_A}, \quad Y_{M_2}=-Y_{M_1} Les tangentes sont donc :

Droite([X A,0],[X M 1,Y M 1]) \mbox{Droite}([X_A,0], [X_{M_1},Y_{M_1}]) et Droite([X A,0],[X M 2,Y M 2]) \mbox{Droite}([X_A,0], [X_{M_2},Y_{M_2}])

Si A A est sur C C (i.e. X A==r X_A==r) alors on peut mener par A A , une tangente T 1 T_1 à C C qui est Droite(x=X A) \mbox{Droite}(x=X_A).

#### Le cas général

On se ramène au cas précédent par changement de repère.
Soit O x y Oxy le repère. Dans le repère O x y Oxy, I I (resp A A) a pour coordonnées c I c_I (resp c A c_A).
On fait un changement de repère en prenant le centre I I du cercle comme origine et I A IA comme axe des X X.
On note X M X_M et Y M Y_M les coordonnées d’un point M M ou d’un vecteur M M dans le nouveau repère I X Y IXY et x M x_M et y M y_M les coordonnées de M M dans le repère O x y Oxy.
Dans le repère I X Y IXY, A A a pour abscisse X A=Longueur(c A,c I)X_A=\mbox{Longueur}(c_A,c_I) et pour ordonnée 0.
H H a pour abscisse r 2 X A\frac{r^2}{X_A} et pour ordonnée 0.
Si U U est le vecteur unitaire de I X IX on a :
x U:=(x A−x I)/X A x_U:=(x_A-x_I)/X_A et y U:=(y A−y I)/X A y_U:=(y_A-y_I)/X_A avec X A:=Longueur(c A,c I) X_A:=\mbox{Longueur}(c_A,c_I).
On a vu que (cf 5.5.2) : x M=x I+X M x U+Y M x V,y M=y I+X M y U+Y M y V x_M=x_I+X_Mx_U+Y_Mx_V, \quad y_M=y_I+X_My_U+Y_My_V x V:=−y U,y V:=x U x_V:=-y_U, \quad y_V:= x_U Donc :
x M=x I+X M x U−Y M y U,y M=y I+X M y U+Y M x U x_M=x_I+X_Mx_U-Y_My_U, \quad y_M=y_I+X_My_U+Y_Mx_U En remplaçant x U x_U et y U y_U par leur valeur, on a :
x M=x I+X M(x A−x I)−Y M(y A−y I)Longueur(c A,c I)y M=y I+X M(y A−y I)+Y M(x A−x I)Longueur(c A,c I)x_M=x_I+\frac{X_M(x_A-x_I)-Y_M(y_A-y_I)}{\mbox{Longueur}(c_A,c_I)} \quad y_M=y_I+\frac{X_M(y_A-y_I)+Y_M(x_A-x_I)}{\mbox{Longueur}(c_A,c_I)} Dans le repère I X Y IXY les coordonnées de M 1 M_1 et M 2 M_2 sont :
X M 1=X M 2=r 2/x A X_{M_1}=X_{M_2}=r^2/x_A Y M 1=r X A 2−r 2 X A,Y M 2=−Y M 1 Y_{M_1}=r\frac{\sqrt{X_A^2-r^2}}{X_A}, \quad Y_{M_2}=-Y_{M_1} Donc : x M 1 = x I+r 2/x A(x A−x I)−r 1−r 2/x A(y A−y I)Longueur(c A,c I) y M 1 = y I+r 2/x A(y A−y I)+r 1−r 2/x A(x A−x I)Longueur(c A,c I), x M 2 = x I+r 2/x A(x A−x I)+r 1−r 2/x A(y A−y I)Longueur(c A,c I), y M 2 = y I+r 2/x A(y A−y I)−r 1−r 2/x A(x A−x I)Longueur(c A,c I) \begin{matrix} x_{M_1}&=&x_I+\frac{r^2/x_A(x_A-x_I)-r\sqrt{1-r^2/x_A}(y_A-y_I)}{\mbox{Longueur}(c_A,c_I)} \\ y_{M_1}&=&y_I+\frac{r^2/x_A(y_A-y_I)+r\sqrt{1-r^2/x_A}(x_A-x_I)}{\mbox{Longueur}(c_A,c_I)}, \\ x_{M_2}&=&x_I+\frac{r^2/x_A(x_A-x_I)+r\sqrt{1-r^2/x_A}(y_A-y_I)}{\mbox{Longueur}(c_A,c_I)},\\ y_{M_2}&=&y_I+\frac{r^2/x_A(y_A-y_I)-r\sqrt{1-r^2/x_A}(x_A-x_I)}{\mbox{Longueur}(c_A,c_I)} \end{matrix} On écrit la fonction Tangent(C,cA) qui renvoie une liste (éventuellement vide) contenant la ou les équations des tangentes au cercle C passant par le point A A de coordonnées cA, en utilisant Milieu (cf 5.1.2), Longueur (cf 5.1.1), Droite(cf 5.2.1) et Cercle (cf 5.6.3).
On tape :

    fonction Tangent(C,cA)
     local cI,r,xI,yI,xA,yA,XM1,YM1,xM1,yM1,XM2,YM2,xM2,yM2,l;
     cI:=C[0];
     xI:=cI[0];
     yI:=cI[1];
     r:=C[1];
     l:=Longueur(cA,cI);
     xA:=cA[0];
     yA:=cA[1];
     si l < r alors
       print("A n'est pas a l'exterieur de C");
       retourne [];
     fsi;
     si l==r et yA==yI alors
       retourne [x-xA=0];
     fsi;
     si l==r et (yA-yI)!=0 alors
       retourne [normal(Droite([xA,yA],-(xA-xI)/(yA-yI)))];
     fsi;
     XM1:=r^2/l;
     YM1:=r*sqrt(1-r^2/l^2);
     xM1:=normal(xI+(XM1*(xA-xI)-YM1*(yA-yI))/l);
     yM1:=normal(yI+(XM1*(yA-yI)+YM1*(xA-xI))/l);
     XM2:=r^2/l;
     YM2:=-r*sqrt(1-r^2/l^2);
     xM2:=normal(xI+(XM2*(xA-xI)-YM2*(yA-yI))/l);
     yM2:=normal(yI+(XM2*(yA-yI)+YM2*(xA-xI))/l);
     retourne [Droite([xM1,yM1],[xA,yA]),Droite([xM2,yM2],[xA,yA])];
    ffonction:;

cI:=[0,1]
cA:=[2,1]
r:=sqrt(2);
C1:=Cercle(cI,r)
T1:=Tangent(C1,cA)
On fait la figure avec Xcas :
I:=point(cI);A:=point(cA);c1:=cercle(I,r);droite(T1[0]);droite(T1[1])
C2:=Cercle([1,2],2);T2:=Tangent(C2,[1+sqrt(2),2+sqrt(2)])
On fait la figure avec Xcas :
J:=point(1,2);B:=point(1+sqrt(2),2+sqrt(2));c2:=cercle(J,2);droite(T2[0]);
On vérifie avec Xcas :
equation(tangent(c1,A))
equation(tangent(c2,B))
On peut utiliser non seulement Milieu (cf 5.1.2), Longueur (cf 5.1.1), Droite(cf 5.2.1) et Cercle (cf 5.6.3), mais aussi le programme de changement de repère écrit précedemment ChangeXY2xy (cf 5.5.3 :

    fonction Tangentes(C,cA)
     local cI,r,xI,yI,xA,yA,XA,CM1,CM2,cM1,cM2,cU;
     cI,r:=C;
     xI,yI:=cI;
     xA,yA:=cA;
     XA:=Longueur(cA,cI);
     cU:=[xA-xI,yA-yI]/XA;
     si XA >r alors
       CM1:=[r^2/XA,r*sqrt(1-r^2/XA^2)];
       CM2:=[r^2/XA,-r*sqrt(1-r^2/XA^2)];
       cM1:=ChangeXY2xy(CM1,cI,cU);
       cM2:=ChangeXY2xy(CM2,cI,cU);
       retourne [Droite(cM1,[xA,yA]),Droite(cM2,[xA,yA])];
     fsi;
     si XA==r alors
       CM1:=[r,1];
       cM1:=ChangeXY2xy(CM1,cI,cU);
       retourne [Droite(cM1,[xA,yA])];
     fsi
     retourne [];
    ffonction:;

cI:=[0,1]
cA:=[2,1]
r:=sqrt(2);
C:=Cercle(cI,r)
Tangentes(C,cA)
Tangentes(Cercle([1,2],1),[1,3])
On vérfie avec Xcas :
equation(tangent(cercle(point(cI),r),point(cA)))
equation(tangent(cercle(point([1,2]),1),point([1,3])))

### 5.6.7 Solution analytique des tangentes à un cercle

On peut aussi faire une résolution analytique pour construire la (ou les) tangente(s) à un cercle C C passant par un point A A.
On pourra se servir des programmes écrits précédement : Longueur (cf 5.1.1), Droite(cf 5.2.1), Cercle (cf 5.6.3) et Solution12 (cf 3.2).

On considère un repère orthonormé dans lequel le centre I I du cercle C C de rayon r r a pour coordonnées [x I,y I][x_I,y_I].
C C a pour équation (x−x I) 2+(y−y I) 2=r 2(x-x_I)^2+(y-y_I)^2=r^2 soit x 2+y 2−2 x I x−2 y I y+x I 2+y I 2−r 2=0 x^2+y^2-2x_Ix-2y_Iy+x_I^2+y_I^2-r^2=0 Soit A A un point de coordonnées [x A,y A] [x_A,y_A].
Si A A se trouve à l’extérieur du cercle C C, on peut mener par A A, deux tangentes. Les points de contact M 1 M_1 et M 2 M_2 de ces tangentes avec C C sont aussi les points d’intersection de C C et du cercle de diamètre I A IA.
Le cercle de diamètre I A IA a pour centre K K et rayon R R où K K est le milieu de I A IA de coordonnées [x K,y K]=c K [x_K,y_K]=c_K=Milieu(c I,c A)(cI,cA) et R= R=Longueur(c I,c A)/2(cI,cA)/2. Ce cercle a donc comme équation (x−x K) +(y−y K) 2=R 2(x-x_K)^+(y-y_K)^2=R^2 i.e.
x 2+y 2−2 x K x−2 y K y+x K 2+y K 2−R 2=0 x^2+y^2-2x_Kx-2y_Ky+x_K^2+y_K^2-R^2=0 Il faut donc résoudre le système d’inconnues x,y x,y x 2+y 2−2 x I x−2 y I y+x I 2+y I 2−r 2 = 0 x 2+y 2−2 x K x−2 y K y+x K 2+y K 2−R 2 = 0 \begin{matrix} x^2+y^2-2xIx-2yIy+xI^2+yI^2-r^2&=&0\\ x^2+y^2-2x_Kx-2y_Ky+x_K^2+y_K^2-R^2&=&0 \end{matrix} qui est équivalent à : x 2+y 2−2 x I x−2 y I y+x I 2+y I 2−r 2 = 0 2(x I−x K)x+2(y I−y K)y+x K 2+y K 2+r 2−x I 2−y I 2−R 2 = 0 \begin{matrix} x^2+y^2-2xIx-2yIy+xI^2+yI^2-r^2&=&0 \\ 2(xI-x_K)x+2(yI-y_K)y+x_K^2+y_K^2+r^2-xI^2-yI^2-R^2&=&0 \end{matrix} On a 2(x I−x K)=(x I−x A)2(xI-x_K)=(xI-x_A) et 2(y I−y K)=(y I−y A)2(yI-y_K)=(yI-y_A)
Or A≠I A\neq I donc x A≠x I≠x K x_A\neq x_I \neq x_K ou y A≠y I≠y K y_A \neq y_I \neq y_K. Si (y I−y K)≠0(yI-y_K) \neq 0 (resp (x I−x A)≠(xI-x_A) \neq ) alors on connaît y y (resp x x) en fonction de x x (resp y y) et il faut résoudre une équation de degré 2 en x x (res y y).
Si A A est sur le cercle C C, on peut mener par A A, une tangente (c’est une droite passant par A A et qui est perpendiculaire à I A IA.
Si A A est à l’intérieur du cercle C C, il n’y a pas de tangente passant par A A.
On utilise encore Longueur (cf 5.1.1), Droite (cf 5.2.1) et Cercle (cf 5.6.3), mais aussi le programme Solution12 écrit précedemment (cf 3.2 : On tape :

    fonction Tangenteq(C,cA)
     local cI,r,l,xI,yI,xA,yA,xK,yK,Eq,xM,yM,xM1,yM1,xM2,yM2,R,m;
     cI:=C[0];
     xI:=cI[0];
     yI:=cI[1];
     r:=C[1];
     l:=Longueur(cA,cI);
     xA:=cA[0];
     yA:=cA[1];
     R:=l/2;
     si l >r alors
      xK:=(xI+xA)/2;
      yK:=(yI+yA)/2;
      si (yI-yA)!=0 alors
        yM:=(xK^2+yK^2+r^2-xI^2-yI^2-R^2+2*(xI-xK)*x)/(yA-yI);
        Eq:=x^2+yM^2-2xI*x-2yI*yM+xI^2+yI^2-r^2=0;
        [xM1,xM2]:=Solution12(Eq,x);
        yM1:=subst(yM,x=xM1);
        yM2:=subst(yM,x=xM2);
      sinon
        xM:=(xK^2+yK^2+r^2-xI^2-yI^2-R^2+2*(yI-yK)*y)/(xA-xI);
        Eq:=xM^2+y^2-2xI*xM-2yI*y+xI^2+yI^2-r^2=0;
        [yM1,yM2]:=Solution12(Eq,y)
        xM1:=subst(xM,y=yM1);
        xM2:=subst(xM,y=yM2);
      fsi;
     retourne [Droite(cA,[xM1,yM1]),Droite(cA,[xM2,yM2])];
     fsi;
     si l==r alors
       si (yI-yA)!=0 alors
         m:=normal(-(xA-xI)/(yA-yI));
         retourne [Droite([xA,yA],m)];
       sinon
         retourne [Droite([xA,yA],[xA,yA+1])];
       fsi;
     fsi;
     retourne [];
    ffonction:;

cI:=[0,1]
cA:=[2,1]
r:=sqrt(2);
C:=Cercle(cI,r)
Tangenteq(C,cA)
Tangenteq(Cercle([1,2],1),[1,3])
On vérifie avec Xcas :
equation(tangent(cercle(point([0,1]),r),point(cA)))
equation(tangent(cercle(point([1,2]),1),point([1,3])))

# Chapitre 6 Quelques tests géométriques

## 6.1 Test d’alignement de 3 points

Établir que trois points sont alignés ou non alignés.
Si les 3 points sont confondus Estaligne(A,B,C) renvoie 2
Si les 3 points sont alignés Estaligne(A,B,C) renvoie 1
Si les 3 points ne sont pas alignés Estaligne(A,B,C) renvoie 0
On tape :

    fonction Estaligne(cA,cB,cC)
     local xA,yA,xB,yB,xC,yC;
     si cA==cB et cA==cC alors retourne 2; fsi;
     si cA==cB ou cA==cC alors retourne 1; fsi;
     xA:=cA[0];
     yA:=cA[1];
     xB:=cB[0];
     yB:=cB[1];
     xC:=cC[0];
     yC:=cC[1];
     si normal((xB-xA)*(yC-yA)-(xC-xA)*(yB-yA))==0 alors
       retourne 1;
     fsi;
     retourne 0;

    ffonction:;

Estaligne([1,2],[1,2],[1,2])
Estaligne([1,2],[3,6],[1,2])
Estaligne([1,2],[3,6],[-1,-2])
Estaligne([1,2],[1,6],[-1,-2])
On fait la figure avec Xcas :
A:=point(1,2);B:=point(3,1);C:=point(3,6);D:=point(-1,-2);
On vérifie avec Xcas :
est_aligne([1,2],[3,6],[-1,-2])
est_aligne([1,2],[3,1],[-1,-2])

## 6.2 Test de parallélisme de 2 droites

Soient deux droites D 1 D_1 et D 2 D_2 d’équation :
a 1 x+b 1 y+c 1=0 a_1x+b_1y+c_1=0 et a 2 x+b 2 y+c 2=0 a_2x+b_2y+c_2=0
Ces 2 droites sont parallèles si a 1 b 2=a 2 b 1 a_1b_2=a_2b_1.
On utilise la fonction Coeffsdroite (cf 5.2.2 qui calcule les coefficients a, b et c de l’équation d’une droite ax+by+c=0 : On tape :

    fonction Estparallele(d1,d2)
     local a1,a2,b1,b2,d,c1,c2;
     a1,b1,c1:=Coeffsdroite(d1);
     a2,b2,c2:=Coeffsdroite(d2);
     d:=normal(a2*b1-b2*a1);
     si d==0 alors retourne 1; fsi;
     retourne 0;
    ffonction:;

D1:=Droite(2*x-3*y=1)
D2:=Droite(-4*x+6*y=23)
Estparallele(D1,D2)
D3:=Droite(-5*x+15*y=16)
Estparallele(D1,D3)
On fait la figure avec Xcas :
d1:=droite(2*x-3*y=1);d2:=droite(-4*x+6*y=23);d3:=droite(-5*x+15*y=16)
On vérifie avec Xcas :
est_parallele(d1,d2)
est_parallele(d1,d3)

## 6.3 Caractériser alignement et parallélisme par la colinéarité

Trois points A A, B B et C C sont alignés si les vecteurs A B AB et A C AC sont colinéaires.
Deux droites A B AB et C D CD sont parallèles si les vecteurs A B AB et C D CD sont colinéaires.

# Chapitre 7 Statistiques

## 7.1 Calcul de moyenne et écart-type

Exercice : Écrire une fonction prenant en argument la liste des données et renvoyant sa moyenne et son écart-type, au moyen d’une boucle `pour` (sans utiliser `mean` ou `stddev` qui sont les commandes Xcas pour moyenne et écart-type).

    fonction Stats(L)
      local j,Lj,n,s,s2;
      n:=dim(L);
      s:=0; s2:=0;
      pour j de 0 jusque n-1 faire
        Lj := L[j];
        s := s+Lj
        s2 := s2+Lj^2;
      fpour
      retourne s/n,sqrt(s2/n-(s/n)^2);
    ffonction:;

L:=[7,9,11,10,7,14,11];
Stats(L);
On vérifie avec Xcas :
mean(L); stddev(L);
Exercice : Écrire une fonction prenant en argument la liste des données et renvoyant sa médiane.
Indication : Pour déterminer une médiane, il faut au préalable trier les données, ce qui est la partie difficile de l’algorithme, le reste de l’algorithme est simple. Au niveau du lycée on peut utiliser la commande Xcas `sort` qui trie une liste par ordre croissant, puis on renvoie l’élément d’indice la taille de la liste/2.

    fonction Median(L)
      local n;
      n:=dim(L);
      L:=sort(L);
      si irem(n,2)==1 alors
        retourne L[(n-1)/2];
      sinon
        retourne (L[n/2-1]+ L[n/2])/2.;
      fsi;
    ffonction:;

L1:=[148,143,142,146,144,146,142,147,140];
Median(L1)
L2:=[143,142,146,144,146,142,147,140];
Median(L2)
On vérifie avec Xcas :
median(L1)
Exercice : Écrire une fonction qui calcule la moyenne et l’écart-type et qui a comme argument soit la liste alternant valeur et effectif soit 2 listes.

    fonction Statexo1(L)
      local j,lj,n,n1,s,s2,vj,ej;
      n:=dim(L);
      si type(n)!=vecteur alors retourne "erreur"; fsi;
      s:=0;
      s2:=0;
      n1:=n[0];
      n:=sum(col(L,1));
      pour j de 0 jusque n1-1 faire
        lj := L[j];
        vj := lj[0];
        ej := lj[1];
        s := s+vj*ej
        s2 := s2+vj^2*ej;
      fpour;
      retourne s/n,sqrt(s2/n-(s/n)^2);
    ffonction:;
    fonction Statexo2(L1,L2)
      local j,vj,ej,n,n1,n2,s,s2;
      n1:=dim(L1);
      n2:=dim(L2);
      si n1!=n2 alors retourne "erreur"; fsi;
      n:=sum(L2);
      s:=0;
      s2:=0;
      pour j de 0 jusque n1-1 faire
        vj := L1[j];
        ej := L2[j];
        s := s+vj*ej
        s2 := s2+vj^2*ej;
      fpour;
      retourne s/n,sqrt(s2/n-(s/n)^2);
    ffonction:;

On a mesuré la taille en cm (arrondie à l’entier le plus proche) de 200 fossiles de la même espèce. On a obtenu pour k=0..12 une taille L1[k] d’effectif de L2[k].
Calculer la moyenne et l’écart-type de cette distribution.
L1:=[0,1,2,3,4,5,6,7,8,9,10,11,12]
L2:=[1,16,31,37,41,30,23,13,6,1,0,1,0]
L12:=seq([L1[k],L2[k]],k,0,12)
Statexo1(L12)
On a mesuré la taille en cm (arrondie à l’entier le plus proche) d’une autre espèce de fossiles. On a obtenu pour k=0..12 une taille L1[k] d’effectif de L3[k].
Calculer la moyenne et l’écart-type de cette distribution.
L1:=[0,1,2,3,4,5,6,7,8,9,10,11,12]
L3:=[2,11,21,52,64,77,62,46,41,11,8,5,0]
Statexo2(L1,L3)
On vérifie avec Xcas :
mean(L1,L2),stddev(L1,L2)
mean(L1,L3),stddev(L1,L3)

## 7.2 Simulation d’un échantillon

Exercice : Générer aléatoirement n n valeurs 0 ou 1, la probabilité d’avoir 1 étant fixée à p p (pour faire cela, on comparera avec p p le résultat de la commande Xcas `alea(0,1)` qui renvoie un réel entre 0 et 1). Calculer la fréquence de 1 observée.

    fonction Simu(n,p)
      local j,a,n1;
      n1:=0;
      pour j de 1 jusque n faire
        a:=alea(0,1);
        si a<=p alors n1:=n1+1; fsi;
      fpour
      retourne n1/n;
    ffonction:;

onload
L:=seq(Simu(20.,.4),k,1,10);
On peut visualiser les fréquences obtenues avec la commande plotlist([y0,...,yn]) de Xcas qui trace la ligne polygonale reliant les points d’abscisse k et d’ordonnée yk pour k=0..n.
plotlist(L);droite(y=0.4-1/sqrt(20)); droite(y=0.4+1/sqrt(20))

Commandes Xcas permettant de faire le calcul directement :
n:=20.; p:=.4; v:=randvector(n,binomial,1,p); sum(v)/n;
(la commande `randvector` génère ici n n valeurs aléatoires selon la loi binomiale de paramètres 1 et p p, on en fait ensuite la moyenne)

## 7.3 Intervalle de fluctuation

Écrire un algorithme effectuant N N simulations d’échantillons, en utilisant la fonction précédente, renvoyer la liste des fréquences ainsi que la proportion de fréquences situées en-dehors de l’intervalle [p−1/n,p+1/n][p-1/\sqrt{n},p+1/\sqrt{n}].
En effet une simulation suit une loi binomiale de moyenne n p np et d’écart-type σ=n*p*(1−p)\sigma=\sqrt{n*p*(1-p)} les fréquences suivent une loi binomiale de moyenne p p et d’écart-type σ/n)=p*(1−p)/n\sigma/n)=\sqrt{p*(1-p)/n} et on a :
4*p*(1−p)−1=−(2*p−1) 2 4*p*(1-p)-1=-(2*p-1)^2 donc 4*p*(1−p)≤1 4*p*(1-p)\leq 1 et
2 σ/n=4*p*(1−p)/n≤1/n 2\sigma/n=\sqrt{4*p*(1-p)/n} \leq 1/\sqrt n.
On uitilise la fonction Simu écrite précédemment (cf 7.2).

    fonction Fluctuat(N,n,p)
      local j,L,out;
      L:=[];
      out:=0;
      pour j de 0 jusque N-1 faire
        L[j]:=Simu(n,p);
        si abs(L[j]-p)>1/sqrt(n) alors out:=out+1; fsi;
      fpour;
      retourne out/N,L;
    ffonction:;

On lance 20 fois une pièce de de monnaie mal équilibrée car la probabilité d’obtenir face ést égale à 0.4.
Simu(20,0.4) renvoie donc la fréquence du nombre de faces observées. On effectue plusieurs fois 100 simulations : L:=Fluctuat(100.,20,.4);L1:=L[1]:;
LL:=Fluctuat(100.,20,.4);LL1:=LL[1]:;
LLL:=Fluctuat(100.,20,.4);LLL1:=LLL[1]:;
On peut visualiser la répartition de ces fréquences avec Xcas :
plotlist(L1);plotlist(LL1,affichage=21);plotlist(LLL1,affichage=4);droite(y=0.4-1/sqrt(20)); droite(y=0.4+1/sqrt(20))

Avec les commandes de Xcas
On génère une séquence de N N moyennes de vecteurs de n n valeurs aléatoires selon la loi binomiale de paramètres 1 et p p :
N:=100.; n:=20; p:=.4;l:=seq(sum(randvector(n,binomial,1,p))/n,j,1,N);
On compte les moyennes dont l’écart à p p est plus grand que 1/n 1/\sqrt{n} :
count(x->abs(x-p)>1/sqrt(n),l)/N;
Avec Xcas, la probabilité d’être dans l’intervalle [p−1/n,p+1/n][p-1/\sqrt{n},p+1/\sqrt{n}] est donnée par :
binomial_cdf(n,p,n*(p-1/sqrt(n)),n*(p+1/sqrt(n)))
Il y a donc une probabilité faible (de l’ordre de 4%) de ne pas être dans l’intervalle de fluctuation.
Avec Xcas, la probabilité d’être dans l’intervalle [n*p−σ/n,n*p+σ/n][n*p-\sigma/\sqrt{n},n*p+\sigma/\sqrt{n}] est donnée par :
sigma:=stddev(binomial(n,p));2*sigma/n,1./sqrt(n)
binomial_cdf(n,p,n*p-2*sigma,n*p+2*sigma)
.

# Chapitre 8 Aide

## 8.1 Les fonctions usuelles avec Xcas

abs : valeur absolue ou le module de l’argument.
ceil : renvoie le plus petit entier >= à l’argument.
cos : renvoie le cosinus de l’argument.
Digits : pseudo-variable pour modifier le nombre n de chiffres significatifs (par ex Digits:=n).
evalf : évaluation numérique du premier argument (le nombre de digits peut être donné comme second argument).
floor : renvoie la partie entière de l’argument (le plus grand entier <= à l’argument.
frac : partie fractionnaire de l’argument.
max : renvoie le maximum des éléments d’une séquence ou d’une liste de réels.
min : renvoie le minimum des éléments d’une séquence ou d’une liste de réels.
+ : renvoie la concaténation de 2 chaînes ou addition terme à terme de 2 expressions ou 2 listes (opérateur infixé).
round : renvoie l’argument réel arrondi à l’entier (ou le décimal) le plus proche.
sin : renvoie le sinus de l’argument.
sign : renvoie le signe (-1,0,+1) de l’argument.
sqrt : renvoie la racine carrée de l’argument.
tan : renvoie la tangente de l’argument.

## 8.2 Les fonctions Xcas de calcul formel utilisées

coeff(P,var,[n] : renvoie la liste des coefficients d’un polynôme P par rapport à la variable Var ou le coefficient de degré n.
count(f,L) : applique la fonction f aux éléments de la liste L et en renvoie la somme.
degree(P,var : renvoie le degré du polynôme P par rapport à la variable var.
dim : renvoie la longueur d’une liste, d’une séquence ou d’une chaîne de caractères.
droit : renvoie le côté droit d’une équation, d’un intervalle, d’une liste ou d’une chaîne .
fsolve: renvoie la solution numérique d’une équation.
gauche : renvoie le côté gauche d’une équation, d’un intervalle, d’une liste ou d’une chaîne.
iquo : renvoie le quotient euclidien de 2 entiers.
iquorem : renvoie la liste du quotient et du reste euclidien de 2 entiers.
irem : renvoie le reste euclidien de 2 entiers.
normal : renvoie une simplification de l’argument.
purge(a) : enlève la valeur stockée dans la variable a.
simplify : renvoie une simplification de l’argument.
solve : renvoie la solution d’une équation.
sommets : renvoie la liste des sommets d’un polygone.
subst : remplace dans une expression, une variable non affectée par une valeur.
sum : somme des éléments d’une liste (ou séquence).
subtype : renvoie 1 pour une séquence, 2 pour un ensemble, 10 pour un polynôme et 0 sinon ce qui définit le sous-type de l’argument.
type : renvoie n n dans [1..12] définissant le type de l’argument.

## 8.3 Les fonctions Xcas de géométrie utilisées

affichage : employé comme option de commandes graphiques permet de faire des dessins en couleur (par ex A:=point([1,1],affichage=rouge)).
carre : renvoie et dessine le carré direct donné par 2 points.
centre : renvoie et dessine le centre du cercle donné en argument.
cercle : renvoie et dessine le cercle donné par 1 point et 1 réel (son centre et son rayon) ou par 2 points (son diamètre) ou par son équation.
droite : renvoie et dessine la droite donnée par 2 points ou par 1 point et son vecteur directeur.
est_aligne : renvoie 1 si les points sont alignés, 2 si les points sont confondus et 0 sinon.
est_parallele : renvoie 1 si 2 droites sont parallèles et 0 sinon.
equation : renvoie l’équation de l’argument.
inter dessine et renvoie la liste des points d’intersection de 2 objets géométriques.
inter_unique renvoie et dessine un des points d’intersection de 2 objets géométriques.
longueur : renvoie la longueur du segment défini par 2 points ou par les coordonnées de ces points. norm : renvoie la norme l2 d’un vecteur :
norm([x 1,..x n])([x_1,..x_n]) : renvoie (x 1 2+...x n 2)\sqrt(x_1^2+...x_n^2)
point : renvoie et dessine le point de coordonnées l’argument.
polygone : renvoie et dessine le polygone donné par une liste de points.
polygone_ouvert : renvoie et dessine la ligne polygonale donnée par une liste de points.
rayon :renvoie le rayon du cercle donné en argument.
segment : renvoie et dessine soit le segment donné par 2 points ou le vecteur donné par un point et son vecteur directeur. Bien voir la différence entre segment(point(cA),point(cB)) (c’est le segment (A,B)) et segment(cA,cB) qui est aussi segment(point(cA),point(cA+cB)).
sommets : renvoie la liste des sommets du polygone donné en argument et les dessine.
translation(B-A,C) : renvoie et dessine le translaté de C dans la translation de vecteur AB.
triangle : renvoie et dessine le triangle donné par 3 points.
vecteur : renvoie et dessine le vecteur donné par 2 points ou par un point et son vecteur directeur. Bien voir la différence entre vecteur(point(cA),point(cB))(c’est le vecteur (A,B)) et vecteur(cA,cB) qui est aussi vecteur(point(cA),point(cA+cB)).

## 8.4 Les fonctions Xcas de programmation utilisées

break : pour interrompre une boucle (tantque <cond> faire inst1; si <cond> alors inst2;break;fsi;ftantque;).
fpour
fsi
ftantque
jusque
local
pas
pour <k> de <k1> jusque <k2> faire <instructions> pas <p> fpour
quand
retourne
si <condition> alors <instructions1> sinon <instructions2> fsi
tantque <condition> faire <instructions> ftantque

## 8.5 Les fonctions Xcas utilisées en statistiques

alea(n1,n2) : renvoie un réel aléatoire de [n1,n2[.
binomial : peut être employé comme option de la commande randvector.
binomial_cdf(n,p,x1,x2) : renvoie Proba(x1<=X<=x2) quand X suit la loi binomiale B(n,p).
mean : renvoie la moyenne d’une liste ou d’une liste pondérée par le deuxième argument.
median : renvoie la médiane d’une liste ou d’une liste pondérée par le deuxième argument.
plotlist : lorsque l’argument est L=[y 0,...,y n]L=[y_0,...,y_n], trace la ligne polygonale reliant les points d’abscisse k k et d’ordonnée y k y_k pour k=0..n k=0..n.
randvector : renvoie une liste de nombres aléatoires de taille n n constituée d’entiers aléatoires distribués selon la loi indiquée.
stddev : renvoie l’écart-type d’une liste ou d’une liste pondérée par le deuxième argument.

# Annexe A Xcas, Javascript et Python.

Cet appendice est destiné aux utilisateurs maitrisant bien le langage de Xcas ou tout langage équivalent et qui veulent aller plus loin.

Javascript est le langage des navigateurs, il est donc extrêmement répandu et peut être utilisé sans installation sur PC/Mac. De ce fait, un programme écrit en javascript pourra facilement être intégré dans une petite interface utilisateur en HTML (voir l’exemple ci-dessous), et exécuté depuis n’importe quel autre navigateur, ce qui peut être assez motivant.
Du point de vue des types de variables utilisables, on dispose entre autres de nombres approchés, de chaines de caractères et de listes, il n’y a pas de type particulier pour les entiers. Les structures de controle ont une syntaxe proche du langage C, point-virgule en fin d’instruction, délimiteurs de blocs explicites `{}`, test en `if () { ... } else { ... }` et boucle en `for(init;condition;incrementation){...}` ou `while(condition){...}`, déclaration de variable par `var` et retour de fonction par `return`.
Si vous connaissez javascript, vous pouvez utiliser une syntaxe très proche dans Xcas. Exemple, syntaxe utilisable dans les deux langages pour le calcul du n n-ième nombre de Fibonacci :

    function fibo(n){
      var u,v,w,j;
      u=1; v=1;
      if (n<2) return 1;
      for (j=2;j<=n;j++){
        w=u+v; u=v; v=w; // ou en Xcas (u,v)=(v,u+v);
      }
      return v;
    }

Pour avoir une interface HTML minimaliste pour cette fonction, on crée un fichier nommé disons `fibo.html` (que l’on consultera depuis un navigateur) contenant :

    <script>
    function fibo(n){
      var u,v,w,j;
      u=1; v=1;
      if (n<2) return 1;
      for (j=2;j<=n;j++){
        w=u+v; u=v; v=w;
      }
      return v;
    }
    </script>
    Le
    <textarea cols="5" rows="1" id="input"
    onkeypress="if (event.keyCode!=13) return true;
    document.getElementById('output').value=fibo(eval(value));
    return false;">5</textarea>
    i&egrave;me nombre de Fibonacci est
    <textarea rows="1" id="output"></textarea>

On peut utiliser les commandes de Xcas depuis Javascript, c’est exactement ce que fait l’interface Xcas pour Firefox.

Python est un langage assez populaire dans les milieux scientifiques et est facile à installer. Il possède un type spécifique pour les entiers. Sa principale différence par rapport aux autres langages est que les structures de controle n’ont pas de délimiteur explicite de fin de bloc, c’est l’indentation qui joue ce role. L’obligation d’indenter correctement a certes des vertus pédagogiques, mais pas l’absence de délimiteur explicite de fin de bloc. Ceci rend aussi l’échange de code source Python dans des applications orientées texte (mail, forums, traitement de texte) plus fragile1, ou même la lecture difficile si le code est affiché sur plus qu’une page. De plus, la déclaration de variables locales dans une fonction est implicite, ce qui n’est pas très pédagogique. D’autre part, la syntaxe de la boucle for en Python utilise des objets plus abstraits (itérateurs) ou qui peuvent être inutles (liste d’entiers en Python 2), elle s’éloigne de celle de la grande majorité des autres langages, y compris la traduction en langage machine. Ainsi l’exemple de Fibonacci donne

    def fibo(n):
      u=1
      v=1
      if n<2:
        return 1
      for j in range(2,n+1):
        w=u+v
        u=v
        v=w
      return v

Il n’y a pas de mode de syntaxe compatible Python dans Xcas. On peut toutefois utiliser les commandes de Xcas depuis Python en installant `giacpy`, puis en tapant `from giacpy import *`.

La principale différence entre les 3 langages, c’est que Xcas est un logiciel de calcul formel et permet de travailler avec des variables symboliques et des expressions. Dans Xcas, une variable globale peut ne pas avoir de valeur (son évaluation la renvoie), ce n’est pas le cas en Javascript ou en Python (l’évaluation d’une variable non initialisée renvoie une erreur). De ce fait, il ne faut pas oublier de déclarer les variables locales d’une fonction pour éviter des erreurs. En contrepartie pour réaliser des fonctions comme la dichotomie ou la recherche d’une valeur approchée d’intégrale par la méthode des rectangles, on peut passer une expression symbolique en paramètre et l’évaluer en un point, ce qui est conceptuellement plus simple que de passer une fonction en argument à une autre fonction. Avec Xcas, on peut aussi faire du calcul symbolique à l’intérieur d’une fonction, par exemple dériver une expression, calculer des valeurs exactes ou approchée, et dans ce dernier cas travailler avec un nombre arbitraire de décimales.

Des trois langages, Javascript est le plus rapide, puis Python puis Xcas.

1
  Ainsi, l’exercice de spécialité du sujet de bac S 2017 centres etrangers demande aux candidats d’interpréter un algorithme écrit à la Python sans délimiteurs de blocs explicites ... et l’un des blocs est mal indenté, très probablement au cours d’un passage par un logiciel de traitement de texte

# Annexe B Les biais des langages interprétés

Les ordinateurs n’exécutent pas directement les instructions données dans un langage comme Xcas, Javascript, Python, C, Pascal, etc., ils exécutent uniquement du code machine spécifique au micro-processeur de l’ordinateur. Il y a deux façons de traduire le langage en code machine : soit une fois pour toutes lors d’une étape appelée compilation, soit au moment de l’exécution de l’instruction du langage par l’interpréteur (qui est lui-même un programme écrit dans un langage compilé), on parle alors de langage interprété (en toute rigueur, il existe une troisième possibilité un peu intermédiaire qui consiste à compiler au moment où on exécute l’instruction du langage).

Les langages interprétés sont par nature plus faciles à mettre en oeuvre (pas de compilation) et de ce fait rendent l’apprentissage plus simple. Mais la traduction au moment de l’exécution a bien entendu un impact sur le temps d’exécution, parce que les boucles sont traduites autant de fois qu’elles sont exécutées (des optimisations peuvent y remédier plus ou moins). De plus, les langages interprétés utilisent des variables dont le type est déterminé au moment de l’exécution du code, ce qui a un impact aussi bien pour la taille occupée par la variable que pour l’exécution d’une opération qui doit commencer par déterminer le type des arguments pour agir en conséquence. Enfin, lorsqu’on utilise un langage compilé, on a accès aux types de données directement manipulables par le microprocesseur, dont la place occupée en mémoire est optimale et le temps d’exécution très rapide, par exemple on peut multiplier deux entiers dont le produit est inférieur à 2 63 2^{63} en moins d’un milliardième de seconde.

Bien entendu, on peut améliorer le temps d’exécution avec un langage interprété si certaines taches répétitives sont codées dans une instruction du langage, par exemple l’instruction effectuant le produit de deux matrices n’est pas programmé dans le langage interprété lui-même mais est compilé une fois pour toutes dans le code exécutable de l’interpréteur. Le programmeur qui souhaite avoir un code suffisamment rapide va donc adopter un style de programmation qui favorisera l’utilisation de commandes du langage effectuant en une seule instruction ce qui nécessiterait une ou plusieurs boucles imbriquées si on le programmait uniquement avec les instructions de base d’un langage compilé. C’est pour cette raison que les programmeurs expérimentés travaillant avec un langage interprété écrivent souvent dans un style “algébrique” avec le moins possible de structures de controle explicites et des types de données souvent assez complexes. Par exemple pour écrire un produit scalaire de deux listes en Xcas, on utilisera la commande `dot`, si elle n’existait pas, on pourrait écrire `sum(x[j]*y[j],j,0,size(x)-1)` pour éviter de faire une boucle `pour`. Pour des commandes plus compliquées, on utilisera sans doute des commandes `seq` imbriquées au lieu de boucles. Mais ce style présente un risque, celui de calculer plusieurs fois la même quantité : une expression algébrique n’a pas de variables locales pour stocker de résultats intermédiaires. Il faut donc prendre garde au biais de ne pas calculer des quantités intermédiaires. Ce n’est pas le seul biais, il faut également faire attention à l’utilisation d’instructions faisant des boucles implicitement et à l’utilisation de types de données puissants qui risquent de masquer la complexité des opérations nécessaires et pourraient être remplacés par des types plus simples, par exemple utiliser un dictionnaire (ou annuaire) alors qu’un tableau ferait l’affaire. D’ailleurs d’un point de vue pédagogique il est toujours bon de savoir ce qu’il y a derrière une boite noire lorsque c’est accessible au niveau de l’élève ou de l’étudiant. De plus le style algébrique est certes compact, mais il est souvent plus difficile à maintenir (aussi bien à relire qu’à corriger), et il peut aussi générer une occupation mémoire inutile : par exemple en simulation, générer une grosse matrice de nombre aléatoires alors qu’une boucle agissant sur des lignes de cette matrice générées une par une et effacées après usage est incomparablement moins gourmand en mémoire.

Enfin, l’optimisation d’un code destiné à être vraiment utilisé nécessite souvent la compilation des parties critiques, et l’optimisation de ces parties critiques se fait souvent de manière différente et parfois opposée aux habitudes acquises en optimisant du code interprété. Illustrons cela plus en détails sur un exemple très utile en mathématique: le produit scalaire de deux vecteurs et le produit d’une matrice par un vecteur. Il s’agit d’une boucle `pour` que l’on code par

    fonction ps(u,v)
     local r,j,n
     r:=0;
     pour j de 0 jusque n-1 faire
      r:=r+u[j]*v[j];
     fpour;
     return r;
    ffonction

On peut optimiser en utilisant l’instruction d’incrémentation `r += u[j]*v[j];` au lieu de `r:=r+u[j]*v[j];`.

Traduit dans un langage compilé, ce code n’est pas loin d’être optimal, par exemple en C++ :

    double ps(const vector<double> & u,const vector<double> & v){
      size_t j,n=u.size();
      double r=0;
      for (j=0;j<n;j++){
        r += u[j]*v[j];
      }
      return r;
    }

Les variables `r,j,n` sont stockées dans des régistres du microprocesseur. Par itération, il y a 2 additions d’entiers 64 bits (adresse de base des vecteurs et valeur de l’indice), 2 lectures en mémoire de 8 octets (`u[j]` et `v[j]`), puis une multiplication de flottants, une addition de flottant, une incrémentation d’entier 64 bits (l’indice), une comparaison entre 2 entiers 64 bits, un branchement. Ce qui prend le plus de temps c’est la lecture en mémoire des double des vecteurs `u` et `v` et le branchement/test de fin de boucle.

En langage interprété, ce code sera beaucoup plus lent, car à chaque itération, pour déterminer la valeur de `u[j]` et `v[j]`, il faut évaluer la variable d’indice `j` (lue dans l’annuaire des variables affectées), de même pour les variables `u` et `v`, s’apercevoir que ce sont bien des tableaux, comparer `j` à la taille de `u` et de `v` (erreur si l’indice est trop grand), extraire la j j-ième case du tableau. Ensuite on fait le produit, ce qui nécessite de tester le type des variables, on ajoute le résultat à `r` ce qui nécessite à nouveau de tester le type des arguments de `+=`. Puis on incrémente `j` de 1 et on compare à `n` (qu’il faut évaluer). Pour diminuer les opérations de gestion de la boucle, certains langages interprétés ont une instruction de boucle spécifique pour itérer sur les éléments d’une liste, par exemple si on veut afficher les éléments d’une liste au lieu de faire

    fonction aff(u)
     local j,n
     pour j de 0 jusque n-1 faire
      afficher(u[j]);
     fpour;
    ffonction;

on écrira

    fonction aff(u)
     local j;
     pour j in u faire
      afficher(j);
     fpour;
    ffonction;

Cette boucle est implémentée en interne par une variable de longueur de la liste `n`, une autre d’indice, disons `k`, et `j` est évalué par calcul de `u[k]`, mais les opérations de gestion de la boucle sont pré-compilées et donc plus rapides. Dans ce type de boucle, le code est plus compact et ne pose aucun problème de maintenance. Par contre, pour le produit scalaire, faire la même chose nécessite d’introduire des objets plus complexes : on peut imaginer générer la liste des paires `u[j],v[j]` puis itérer sur cette liste. Mais si on ne veut pas créer inutilement en mémoire une liste de paires, cette liste doit être générée de manière virtuelle (par exemple au moyen d’une paire de pointeurs sur les tableaux `u` et `v`) et il faut disposer d’une commande capable de prendre en argument une liste virtuelle. Par exemple en Python on pourrait écrire `sum(i*j for i,j in zip(u,v))`. Un mécanisme de création de liste virtuelle peut bien entendu avoir un intérêt intrinsèque, mais il faut avoir conscience que les objets que l’on manipule sont plus complexes que les listes (qui sont déjà des objets non triviaux), et que l’utilisation de cet objet dans l’exemple du produit scalaire pour optimiser une boucle est un artéfact de langage interprété, et qu’il sera difficile d’optimiser plus avec ce style de programmation. Il sera d’ailleurs plus facile d’optimiser en langage compilé sans utiliser ce type d’objets.

Ainsi, il est possible d’optimiser la boucle du produit scalaire, on peut pour n n grand regrouper plusieurs itérations, et gagner du temps sur les parties test/branchement, par exemple 2 par 2

    double ps(const vector<double> & u,const vector<double> & v){
      size_t j,n=u.size();
      double r=0;
      n--;
      for (j=0;j<n;j+=2){
        r += u[j]*v[j]+u[j+1]*v[j+1];
      }
      n++;
      for (;j<n;j++){
        r += u[j]*v[j];
      }
      return r;
    }

Et si on effectue le produit d’une matrice M M par un vecteur v v, on peut optimiser le temps d’exécution en mutualisant la lecture des coefficients de v v, on fait plusieurs produits scalaires avec v v simultanément.

    double ps(const vector<double> & u1,
      const vector<double> & u2,const vector<double> & v){
      size_t j,n=u1.size();
      double r1=0,r2=0;
      n--;
      for (j=0;j<n;j+=2){
        double vj=v[j],vj1=v[j+1];
        r1 += u1[j]*vj+u1[j+1]*vj1;
        r2 += u2[j]*vj+u2[j+1]*vj1;
      }
      n++;
      for (;j<n;j++){
        r1 += u1[j]*v[j];
        r2 += u1[j]*v[j];
      }
      return r;
    }

Ici en faisant 2 produits scalaires simultanément, on fait 6 lectures en mémoire au lieu de 8 pour 2 itérations.

Il nous parait donc essentiel pour un scientifique d’apprendre aussi un langage pas trop éloigné de la machine, ou au moins d’être capable de coder avec des objets de base.

Retour à la page principale de Giac/Xcas.