FAQ PascalConsultez toutes les FAQ
Nombre d'auteurs : 10, nombre de questions : 402, dernière mise à jour : 7 janvier 2018 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.
- Comment tirer un nombre au hasard ?
- Comment passer du binaire au décimal et vice-versa ?
- Comment transformer un nombre réel en nombre entier ?
- Comment afficher un nombre sous forme hexadécimale ?
- Comment formater l'affichage d'un nombre réel ?
- Comment calculer une puissance d'un nombre ?
- Comment évaluer un polynôme en un point ?
- Comment convertir un entier en base de numération quelconque ?
- Comment obtenir les nombres premiers inférieurs à un entier donné N ?
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; |
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; |
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; |
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) où 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; |
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 |
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 |
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; |
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; |
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; |
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); |
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(r:Width:Precision); End; |
Code delphi : | Sélectionner tout |
1 2 | Write(r:0:Precision); |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 | Var r : Real; s : String; Width, Precision : Byte; Begin Str(r:Width:Prec,s); End; |
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; |
- 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; |
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; |
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; |
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.
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'; |
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; |
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; |
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; |
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'; |
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; |
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.
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 çaLes 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 © 2024 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.