FAQ PascalConsultez toutes les FAQ

Nombre d'auteurs : 10, nombre de questions : 400, dernière mise à jour : 12 septembre 2016  Ajouter une question

 

Bienvenue dans la F.A.Q. Pascal !

Celle-ci rassemble les réponses aux questions les plus fréquemment posées sur le langage Pascal et tous ses outils de programmation. Si elle n'a pas pour vocation de répondre à toutes les interrogations possibles, elle reste une bonne base de connaissances sur le Pascal, et ne demande qu'à être enrichie par vos expériences personnelles.

Nous vous invitons à proposer vos propres questions/réponses directement dans la FAQ ou, si vous souhaitez apporter une modification à une question/réponse existante, à la poster dans le fil de discussion renseigné ci-dessous.

Nous vous souhaitons une bonne lecture !

L'équipe Pascal.

Commentez


SommaireLe langage PascalLes nombres (9)
précédent sommaire suivant
 

Pour obtenir un nombre aléatoire, autrement dit un nombre tiré au hasard, il faut se servir de la fonction Random. Deux syntaxes existent pour celle-ci :

  • Si vous désirez tirer un nombre réel entre 0 et 1 :

Dans ce cas, appelez simplement Random comme ceci :
Code delphi : Sélectionner tout
1
2
3
4
5
6
  
Var 
  r : Real; 
Begin 
  r := Random; 
End;
  • Si vous désirez tirer un nombre entier au hasard :

Il vous faut déterminer un intervalle pour le tirage aléatoire. La fonction Random renverra alors un nombre compris entre 0 inclus et la borne supérieure passée en paramètre non incluse. Par exemple, pour tirer un nombre compris entre 0 et 9 inclus, on écrira :

Code delphi : Sélectionner tout
1
2
3
4
5
6
  
Var 
  i : Integer; 
Begin 
  i := Random(10);      { 0 <= i < 10, donc i appartient à [0..9] } 
End;
L'obtention de nombres aléatoires se base sur un générateur de nombres aléatoires. Il ne s'agit donc que de pseudohasard. De fait, si vous relancez votre programme plusieurs fois de suite, vous vous rendrez compte que ce sont les mêmes suites de nombres qui sont obtenues avec la fonction Random.
Mais ce n'est pas une fatalité ! Le générateur utilise l'heure comme base. Ainsi, si vous relancez votre programme un autre jour, vous n'obtiendrez pas la même suite de nombres pseudoaléatoires. Cela ne reste pas très pratique. La solution consiste donc à réinitialiser le générateur. Pour cela, il suffit d'appeler au début de votre programme la procédure Randomize :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
  
Var 
  i : Integer; 
Begin 
  Randomize;   { On réinitialise le générateur } 
  ... 
  i := Random(10); 
  ... 
End;
Souvent, on a besoin de nombres aléatoires qui ne sont pas compris entre 0 et n, mais entre un minimum et un maximum. Si on choisit de noter Min ce minimum et Max ce maximum, alors on peut utiliser la méthode suivante :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
  
Const  
  Min = 1; 
  Max = 10; 
Var 
  i : Integer; 
Begin 
  Randomize; 
  ... 
  i := Random(Max - Min + 1) + Min;  { Ici,  i appartient à [Min..Max] } 
  ... 
End;

Mis à jour le 22 mars 2004 Eric Sigoillot

Il s'agit de changement de base.

Binaire => Décimal

Considérons un nombre binaire, 10010110b. Chaque bit possède un poids : le plus à droite est dit « bit de poids faible » et celui le plus à gauche est dit « bit de poids fort ». Le poids est égal à 2^(Position)Positionest la position du bit, en commençant à zéro et en comptant à partir de la droite.
Le « bit de poids faible » aura donc toujours2^0 = 1 comme poids. Pour le « bit de poids fort », tout dépend de la taille du nombre. Dans notre cas, il est égal à 2^7 = 128.

Il suffit donc, pour transformer un nombre binaire en décimal, de connaître l'état de chaque bit (0 ou 1), et d'ajouter son poids s'il vaut 1.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
  
Function BinToDec (Bin : String) : Word; 
Var 
  i, L : Integer; 
  Result : Word; 
Begin 
  Result := 0; 
  L := Length(Bin); 
  for i := 1 to L do 
    if Bin[i] = '1' then Result := Result + (1 shl (L - i)); 
  BinToDec := Result; 
End;
Décimal => Binaire

Pour convertir en binaire, en pratique, on divise par 2 jusqu'à ce que le quotient soit nul, et on prend la suite des restes dans l'ordre inverse. On peut bien sûr créer un programme utilisant cette méthode. Néanmoins, Turbo Pascal n'offre pas de fonction offrant à la fois le quotient et le reste d'une division : il faudrait donc soit avoir recours à l'assembleur, soit effectuer deux opérations là où une seule suffirait. Nous allons par conséquent procéder différemment.

Pour connaître l'état d'un bit dans un nombre, il faut utiliser un masque binaire, c'est-à-dire un nombre où seul un bit est à 1, par exemple 00010000b = 16d = 10h. On effectue alors un ET logique avec notre nombre.

Code : Sélectionner tout
1
2
3
4
5
6
7
 
Soit : 
 
    10010110 
and 00010000 
    -------- 
    00010000
On peut donc voir que le résultat sera différent de zéro si le bit considéré est à 1 et qu'il sera nul si le bit est à 0.
Donc, on a le résultat :

Code delphi : Sélectionner tout
1
2
3
  
Nombre and (Masque pour bit n°i)  = 0   si bit n°i = 0 
Nombre and (Masque pour bit n°i) <> 0   si bit n°i = 1
Il suffit ainsi de parcourir tous les bits du nombre, en adaptant le masque pour chaque bit. Pour cela, on utilisera l'instruction shl, qui effectue un décalage de bits vers la gauche.

Le code suivant considère que le nombre est non signé. S'il est signé, alors c'est le bit de poids fort qui indique le signe : positif s'il est à 0, négatif s'il est à 1.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
  
Function DecToBin (n : Word) : String; 
Var 
  Result : String; 
  i : Integer; 
Begin 
  Result := ''; 
  for i := 0 to 15 do 
    if n and (1 shl i) <> 0 then Result := '1' + Result 
                                  else Result := '0' + Result; 
  DecToBin := Result; 
End;

Mis à jour le 7 mars 2004 Eric Sigoillot

Deux solutions sont possibles : soit vous souhaitez arrondir le nombre réel à l'entier le plus proche, soit vous désirez ne prendre que la partie avant la virgule.

  • Arrondir à l'entier le plus proche : Round

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
  
Var 
  r : Real; 
  i : Integer; 
Begin 
  r := 12.7; 
  i := Round(r);  { i = 13 car 0.7 >= 0.5 } 
end;
  • Tronquer le nombre réel : Trunc

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
  
Var 
  r : Real; 
  i : Integer; 
Begin 
  r := 12.7; 
  i := Trunc(r);  { i = 12 } 
end;

Mis à jour le 7 mars 2004 Eric Sigoillot

Pour afficher un nombre entier sous forme hexadécimale, il suffit de le parcourir par paquets de 4 bits à l'aide des opérateurs and, or, shl et shr. Le code suivant permet de choisir le nombre de chiffres hexadécimaux dans la chaîne résultante :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  
Function IntToHex (I : Longint; Digits : Byte) : String; 
Const 
  HexChars : Array [0..15] of Char = '0123456789ABCDEF'; 
Var 
  j : Byte; 
  Result : String; 
Begin 
  Result := ''; 
  if Digits = 0 then Digits := 8; 
  for j := 0 to Digits - 1 do 
    Result := HexChars[(I shr (j shl 2)) and 15] + Result; 
  IntToHex := Result; 
End;

Mis à jour le 5 juin 2004 Eric Sigoillot

Par défaut, lorsque l'on affiche un nombre réel avec Write ou bien lorsqu'on le transforme en chaîne avec Str, il est affiché sous forme scientifique, correspondant à une mantisse réelle m à 20 chiffres (1 <= m < 10) et un exposant e signé à 4 chiffres. Ainsi, le nombre 15 serait écrit : 1.50000000000000E+0001. Mais il arrive souvent que l'on veuille écrire ce nombre 15 sous la forme 15.0.
Pour ce faire, il faut utiliser les spécificateurs de précision. Pour définir une précision, on ajoute derrière le nombre ou le nom de la variable à afficher un caractère deux points « : », la taille minimale du champ, puis encore deux points et le nombre de chiffres souhaités après la virgule, comme ceci :

Code delphi : Sélectionner tout
1
2
  
Write(15:6:2);
Cet exemple affiche le nombre 15, sur 6 caractères (en ajoutant des espaces devant ou en ajoutant des chiffres supplémentaires si nécessaire), et avec 2 chiffres après la virgule.

Si besoin est, on peut aussi utiliser des variables comme spécificateurs :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
  
Var 
  r : Real; 
  Width, Precision : Byte; 
Begin 
  Write(f:Width:Precision); 
End;
Les spécificateurs sont tous les deux facultatifs. On peut donc ne spécifier que Width, pour afficher aligné à droite par exemple. Cependant, si on désire spécifier Precision, alors Width doit obligatoirement être mis ; si jamais on n'en a pas utilité, on peut le mettre à zéro, comme ceci :
Code delphi : Sélectionner tout
1
2
  
Write(f:0:Precision);
Il est à noter que la syntaxe est la même pour Str :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
  
Var 
  f : Real; 
  s : String; 
  Width, Precision : Byte; 
Begin 
  Str(f:Width:Prec,s); 
End;

Mis à jour le 16 mai 2004 droggo Eric Sigoillot Giovanny Temgoua

Le Pascal n'inclut pas de manière native de fonction ou d'opérateur pour calculer une puissance. L'opérateur ^ est réservé pour les pointeurs. Il existe néanmoins différentes méthodes pour calculer la puissance d'un nombre.

  • La formule mathématique a^n = exp(n*ln(a))

Il suffit de prendre garde à ne pas passer d'argument négatif ou nul au logarithme. On pourra rajouter un test le cas échéant, en sachant que si la puissance est impaire, alors le signe ressort, sinon il disparaît.
L'exemple suivant choisit pour convention 0^0 = 1 :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  
Function Power (a : Real; n : Integer) : Real; 
Begin 
  if a = 0.0 then  
    begin 
      if n = 0 then Power := 1.0 
      else Power := 0.0 
    end 
  else  
    if a > 0 then Power := Exp(n * Ln(a)) 
  	  else 
        begin 
          if Odd(n) then Power := -Exp(n * Ln(-a)) 
            else Power := Exp(n * Ln(-a)); 
        end; 
End;
Dans ce cas-ci, il n'est pas nécessaire que la puissance soit entière. n pourrait donc être un Real.
  • La méthode itérative

On peut calculer itérativement une puissance, car a^n = a*a*......*a, avec n fois a. Bien sûr, cela exclut toute puissance non entière.
L'exemple suivant n'inclut pas le test de la puissance ou de l'argument négatif ou nul : c'est à vous de le faire !
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
  
Function Power (a : Real; n : Integer) : Real; 
Var 
  Result : Real; 
  i : Integer; 
Begin 
  Result := a;  
  for i := 1 to n - 1 do 
    Result := Result * a; 
  Power := Result; 
End;
Il faut tout de suite exclure toute méthode récursive ici, car la pile déborderait pour des puissances trop élevées. Vous pouvez néanmoins faire l'essai pour vous rendre compte des limites de cette méthode :
Code delphi : Sélectionner tout
1
2
3
4
5
6
  
Function Power (a : Real; n : Integer) : Real; 
Begin 
  if n > 0 then Power := Power(a, n - 1) 
    else Power := 1.0; 
End;
Il est possible d'optimiser le calcul en se servant du caractère pair d'une puissance. En effet, on peut remarquer que a^(n*p) = (a^n)^p. De fait, a^(2*p) = (a^2)^p et a^(2*p + 1) = a*(a^2)^p. On peut voir le principe de l'algorithme sur un exemple : a^7 = a*a^6 = a*(a^2)^3 = a*(a^2*(a^2)^2). Il reste à généraliser...
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  
Function Power (a : Real; n : Integer) : Real; 
Var 
  Result : Real; 
Begin 
  Result := 1; 
  while n > 0 do 
  begin 
    if Odd(n) then Result := Result * a; 
    n := n div 2; 
    if n > 0 then a := a * a; 
  end; 
  Power := Result; 
End;
Là encore, il n'y a pas de gestion de puissance négative ou nulle dans l'exemple.

Mis à jour le 7 mars 2004 Eric Sigoillot

Soit à évaluer un polynôme à coefficients de type réel en un point donné.

La solution triviale consiste à évaluer la puissance de chaque monôme, multiplier le résultat par le coefficient et faire la somme des monômes obtenus. Mais le calcul des puissances reste coûteux, il existe une méthode qui permet de se passer de ces calculs. En effet, prenons le polynôme 3.x^2+2.x+1, avec une factorisation astucieuse, on peut écrire ((3.x +2).x + 1) qui ne comporte que des additions et des produits, l'élévation à la puissance devient la conséquence du calcul.

Pour un polynôme plus fourni : 5.x^5 + 7.x^3 + 8.x^2 on obtient ((((5.x).x + 7).x + 8).x).x, il suffit de calculer au départ avec les coefficients nuls puis de simplifier.

Modélisons un polynôme comme un tableau démarrant à l'indice 0, le coefficient de degré i étant inscrit dans la cellule i du tableau (les indices sont alignés sur les degrés), on se limite à des polynômes « raisonnables » dont le degré est borné. Par ailleurs, il faut conserver quelque part le degré du polynôme, je crée donc un type (sans ajouter de code de gestion, des méthodes, sur ce type) :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
  
type 
  TDegres = 0..10; 
  TPolynome = record 
    Deg: TDegres; 
    Coefs: array[TDegres] of Double; 
  end;

L'évaluation se fait grâce à la petite fonction :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function PolyEval(const aPoly: TPolynome; X: Double): Double; 
var 
  i: TDegres; 
 (* Pour Turbo Pascal7, il faut déclarer Result : Double; *) 
begin 
  with aPoly do 
  begin 
    Result := 0; 
    for i := Deg downto Low(Coefs) do 
      Result := Result * X + Coefs[i]; 
  end; 
End; 
  
(* Exemples *) 
var 
  P: TPolynome; 
begin 
  P.Deg := 2; 
  P.Coefs[2] := 3; 
  P.Coefs[1] := 2; 
  P.Coefs[0] := 1;   
  (* l'idéal est d initialiser  les autres coeffs avec des 0 *) 
  WriteLn('P(',7,') = ', PolyEval(7):10:2);  
  
  P.Deg := 0; 
  P.Coefs[2] := 0; 
  P.Coefs[1] := 0; 
  P.Coefs[0] := 1;   
  (* l'idéal est d initialiser  les autres coeffs avec des 0 *) 
  WriteLn('P(',7,') = ', PolyEval(7):10:2);  
End

Encore merci à William George Horner.

Mis à jour le 17 avril 2014 e-ric

Pour généraliser une précédente FAQ, il suffit de changer l'algorithme de calcul en se basant uniquement sur des calculs arithmétiques à savoir la division entière et son reste. Pour obtenir les chiffres, on commence par diviser la valeur entière par la base, le reste obtenu est le chiffre des unités, on recommence la division avec le diviseur obtenu par la base, on obtient alors le chiffre des dizaines et on recommence l'opération sur les valeurs successives du diviseur jusqu'à ce que ce dernier vaille 0. Les restes successifs obtenus forment les chiffres recherchés en rang croissant.
Nous limiterons la base maximale à 36, 10 chiffres décimaux et 26 lettres, nous déclarons donc la liste des chiffres valides (l'ordre est important) :

Code : Sélectionner tout
1
2
const 
  Digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
La routine de conversion s'écrit immédiatement :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Exprime la valeur dans la base voulue. 
function IntToBaseStr(Value, BaseOut: integer): String; 
var 
  rmndr: integer;  // reste 
begin 
  // validité de la base? 
  if not InRange(BaseOut, 2, length(Digits)) then 
    raise ERangeError.CreateFmt(rsBadBase, [BaseOut, 2, length(Digits)]); 
  // Décomposition de la valeur, la variable prend à chaque fois la valeur du diviseur 
  // L'instruction repeat permet de tenir compte de la valeur 0 
  Result := ''; 
  repeat 
    divmod(Value, BaseOut, Value, rmndr); 
    Result := Digits[rmndr+1] + Result; 
  until Value = 0; 
End;
il faut ajouter l'unité math pour employer les fonctions divmod et InRange.

La fonction réciproque va nous permettre, connaissant une valeur exprimée dans une base connue d'obtenir l'entier correspondant :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Transforme la chaîne d'un nombre exprimé dans la base paramètre en l'entier 
// équivalent. 
// Si la chaîne est vide, le résultat est 0. 
// Attention : Pas de vérification de dépassement d'entier. il faut utiliser des 
// valeurs raisonnables 
function BaseStrToInt(Value: String; BaseIn: Integer): Integer; 
var 
  d: Char; 
  digit: Integer; 
begin 
  Result := 0; 
  for d in Value do 
  begin 
    digit := Pos(d, Digits) - 1; 
    if not InRange(digit, 0, BaseIn-1) then 
      raise ERangeError.CreateFmt(rsBadDigitInValue, [d, BaseIn]); 
    Result := Result * BaseIn + digit; 
  end; 
End;
N.B. On traite le cas des chiffres inconnus ou trop grands pour la base.
L'instruction for utilisée suppose une version récente de Free Pascal, la conversion de cette boucle en code Pascal « classique » ne pose aucun problème.

Enfin, en combinant ces deux fonctions, on en obtient une troisième permettant la conversion directe d'une base vers une autre :
Code : Sélectionner tout
1
2
3
4
5
6
7
// Conversion directe de nombre exprimé dans une base vers une autre 
function BaseToBase(ValueIn: String; baseIn, BaseOut: Integer): String; 
begin 
  // le cas BaseIn=BaseOut n'est volontairement pas traité de manière spécifique 
  // en vue des tests unitaires. 
  Result := IntToBaseStr(BaseStrToInt(ValueIn, BaseIn), BaseOut); 
End;
Les chaînes de ressource pour les messages d'erreur sont les suivantes :
Code : Sélectionner tout
1
2
3
4
resourceString 
  rsBadBase = 'Base %d invalide, elle doit être comprise entre' 
    +' %d et %d'; 
  rsBadDigitInValue = 'Mauvais chiffre %s dans la valeur, base = %d';
Aucun programme de test n'est donné afin de ne pas encombrer cette FAQ.

Mis à jour le 17 janvier 2015 e-ric

Explications dans Base (arithmétique) (wiki).

On cherche ici à obtenir la liste des nombres premiers inférieurs à un entier donné N.
La méthode employée s'appuie sur le crible d'Eratosthène (cf. wiki p.ex.). Cela consiste à prendre la liste ordonnée des entiers inférieurs N.
et à biffer successivement les multiples des nombres premiers, ces derniers ne l'étant pas. Ainsi on commence par 2 et on biffe tous les nombres pairs, on cherche ensuite le premier nombre non biffé, on trouve 3, on biffe alors tous ses multiples, on recommence avec le prochain nombre non biffé i.e. 5 et ainsi de suite.

Quelques petites optimisations augmentent l'efficacité de l'algorithme :
- au lieu de prendre comme pas de parcours le nombre premier courant p, on peut prendre son double, cela évitera de biffer une deuxième fois les nombres pairs ;
- tous les multiples de p inférieurs à p*p ont déjà été biffés, car ayant traité les nombres premiers inférieurs à p, les multiples communs à p et ses prédécesseurs ont été aussi biffés, on peut donc commencer la recherche des multiples de p à p*p.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
procedure CribleEratosthene(var nombres: array of Byte); 
var 
  i,j, step : integer; 
begin 
  // La cellule prend la valeur 1 si son indice est premier, 0 sinon   
  Nombres[0] := 0; Nombres[1] := 0; 
  Nombres[2] := 1; 
  // Initialise le tableau en éliminant d'office les nombres pairs 
  for i := 3 to High(Nombres) do 
    Nombres[i] := (i and 1); 
  for i := 2 to High(Nombres) do 
    if Nombres[i]=1 then 
    begin 
	  // on recherche   
      j := i*i;  
      step := i * 2; 
      while j <= High(Nombres)do 
      begin 
        Nombres[j] := 0; 
        inc(j, step); 
      end; 
    end; 
End;
L'entier N est la borne maximale du tableau.

Cet algorithme est simple (profitons-en pour féliciter Eratosthène qui a été aussi le premier à mesurer le diamètre de la Terre, sacré bonhomme !), mais son implémentation à l'aide d'un tableau est une grave limite. Il est donc employable pour des petites valeurs de N. Il ne permet pas non plus d'obtenir les N premiers nombres premiers.

Mis à jour le 17 janvier 2015 e-ric

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2017 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
Responsables bénévoles de la rubrique Pascal : Gilles Vasseur - Alcatîz -