Comment voir la matrice ?
L’objet de cet article est de montrer au travers d’un exemple complet quelques évolutions apportées par le langage Ada₂₀₂₂. Nous allons faire ici un bref focus sur :
- La généralisation de l’attribut
'Image
, - Les nouveaux types d’agrégats pour les tableaux,
- Une utilisation des « Bigs Numbers ».
Attribut 'Image
et agrégats [...]
¶
Pour les deux premiers points, nous allons nous pencher sur l’exemple suivant :
with Ada.Numerics.Real_Arrays,
Ada.Text_IO;
use Ada;
procedure Neo is
type Matrix_T is new Numerics.Real_Arrays.Real_Matrix (1 .. 3, 1 .. 3);
Matrix : constant Matrix_T := [for I in Matrix_T'Range (1) =>
[for J in Matrix_T'Range (2) =>
(if I = J then 0.0 else 1.0)]]; --> Ada2022
begin
Text_IO.Put_Line (Matrix'Image); --> Ada2022
Text_IO.Put_Line (Inverse (Matrix)'Image); --> Ada2022
end Neo;
Ici, on peut noter une nouvelle forme d’agrégats pour les tableaux
utilisant les crochets et permettant de faire une initialisation
itérative des éléments de la matrice Matrix
. D’autre part, on constate
que l’attribut 'Image
est disponible pour le type Matrix_T
. En
effet, en Ada₂₀₂₂ l’attribut 'Image
est disponible pour n’importe
quel type.
Ce programme produira le résultat suivant sous GNAT :
[
[ 0.00000E+00, 1.00000E+00, 1.00000E+00],
[ 1.00000E+00, 0.00000E+00, 1.00000E+00],
[ 1.00000E+00, 1.00000E+00, 0.00000E+00]]
[
[-5.00000E-01, 5.00000E-01, 5.00000E-01],
[ 5.00000E-01, -5.00000E-01, 5.00000E-01],
[ 5.00000E-01, 5.00000E-01, -5.00000E-01]]
La chaîne de caractères résultant d’une expression utilisant l’attribut
'Image
est dépendante de l’implémentation et elle ne correspond pas
obligatoirement à nos attentes. Heureusement, par le biais du nouvel aspect Put_Image
, il est possible de redéfinir l’attribut 'Image
d’un type.
L’aspect Put_Image
¶
Le code suivant présente la mise en œuvre de l’aspect Put_Image
. Ce
dernier désigne la procédure venant redéfinir le 'Image
de notre type
Matrix_T
.
with Ada.Strings.Text_Buffers,
Ada.Numerics.Real_Arrays,
Ada.Text_IO;
use Ada,
Ada.Numerics.Real_Arrays;
procedure Neo is
type Matrix_T is new Real_Matrix (1 .. 3, 1 .. 3)
with Put_Image => Matrix_Image; --> Ada2022
procedure Matrix_Image (Output : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
Value : in Matrix_T);
procedure Matrix_Image (Output : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
Value : in Matrix_T) is separate;
Matrix : constant Matrix_T := [for I in Matrix_T'Range (1) =>
[for J in Matrix_T'Range (2) =>
(if I = J then 0.0 else 1.0)]]; --> Ada2022
begin
Text_IO.Put_Line (Matrix'Image); --> Ada2022
Text_IO.Put_Line (Inverse (Matrix)'Image); --> Ada2022
end Neo;
L’implémentation choisie étant :
with Ada.Strings.Text_Buffers,
Ada.Numerics.Real_Arrays,
Ada.Text_IO;
use Ada,
Ada.Numerics.Real_Arrays;
procedure Neo is
type Matrix_T is new Real_Matrix (1 .. 3, 1 .. 3)
with Put_Image => Matrix_Image; --> Ada2022
procedure Matrix_Image (Output : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
Value : in Matrix_T);
procedure Matrix_Image (Output : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
Value : in Matrix_T) is separate;
Matrix : constant Matrix_T := [for I in Matrix_T'Range (1) =>
[for J in Matrix_T'Range (2) =>
(if I = J then 0.0 else 1.0)]]; --> Ada2022
begin
Text_IO.Put_Line (Matrix'Image); --> Ada2022
Text_IO.Put_Line (Inverse (Matrix)'Image); --> Ada2022
end Neo;
Indépendamment du compilateur, ce programme produira le résultat suivant :
[[ 0.00000E+00, 1.00000E+00, 1.00000E+00]
[ 1.00000E+00, 0.00000E+00, 1.00000E+00]
[ 1.00000E+00, 1.00000E+00, 0.00000E+00]]
[[-5.00000E-01, 5.00000E-01, 5.00000E-01]
[ 5.00000E-01,-5.00000E-01, 5.00000E-01]
[ 5.00000E-01, 5.00000E-01,-5.00000E-01]]
C’est mieux, mais cela n’est pas encore ça ! En effet, nous aurions aimé avoir :
[[ 0/ 1, 1/ 1, 1/ 1]
[ 1/ 1, 0/ 1, 1/ 1]
[ 1/ 1, 1/ 1, 0/ 1]]
[[-1/ 2, 1/ 2, 1/ 2]
[ 1/ 2,-1/ 2, 1/ 2]
[ 1/ 2, 1/ 2,-1/ 2]]
Qu’à cela ne tienne ! Nous allons utiliser la hiérarchie
Ada.Numerics.Big_Numbers
.
La hiérarchie Ada.Numerics.Big_Numbers
¶
Cette hiérarchie a été introduite en Ada₂₀₂₂ afin de permettre de
faire de l’arithmétique entière non contrainte par l’architecture de la
machine cible au travers du type
Ada.Numerics.Big_Numbers.Big_Integers.Big_Integer
. Cette hiérarchie
permet aussi de faire de l’arithmétique sur des nombres réels avec une
précision arbitraire par le biais du paquetage
Ada.Numerics.Big_Numbers.Big_Reals.Big_Real
.
C’est ce dernier type qui va nous intéresser ici.
Pour satisfaire cette capacité à avoir une précision arbitraire, le type
Big_Real
va être représenté en interne sous une forme fractionnaire.
Ainsi donc, 0,33333333… serait représenté par 1/3.
Le paquetage concerné est proche de :
package Ada.Numerics.Big_Numbers.Big_Reals is
type Big_Real is private;
function Is_Valid (Arg : Big_Real) return Boolean;
subtype Valid_Big_Real is Big_Real
with Dynamic_Predicate => Is_Valid (Valid_Big_Real),
Predicate_Failure => raise Program_Error;
function Numerator (Arg : Valid_Big_Real) return Big_Integers.Valid_Big_Integer;
function Denominator (Arg : Valid_Big_Real) return Big_Integers.Big_Positive;
function "+" (L, R : Valid_Big_Real) return Valid_Big_Real;
function "-" (L, R : Valid_Big_Real) return Valid_Big_Real;
function "*" (L, R : Valid_Big_Real) return Valid_Big_Real;
function "/" (L, R : Valid_Big_Real) return Valid_Big_Real;
function "**" (L : Valid_Big_Real; R : Integer) return Valid_Big_Real;
generic
type Num is digits <>;
package Float_Conversions is
function To_Big_Real (Arg : Num) return Valid_Big_Real;
end Float_Conversions;
private
end Ada.Numerics.Big_Numbers.Big_Reals;
Nous allons donc modifier notre implémentation pour afficher les éléments de notre matrice sous forme fractionnaire. Nous en profiterons pour mettre aussi en œuvre le symbole @ agissant comme l’équivalent de la partie gauche d’une affectation :
with Ada.Strings.Unbounded,
Ada.Numerics.Big_Numbers.Big_Reals, --> Ada2022
Ada.Numerics.Big_Numbers.Big_Integers, --> Ada2022
Ada.Characters.Latin_1;
use Ada.Strings.Unbounded,
Ada.Numerics.Big_Numbers.Big_Reals,
Ada.Numerics.Big_Numbers.Big_Integers;
separate (Neo)
procedure Matrix_Image (Output : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
Value : in Matrix_T) is
package To_BR is new Float_Conversions (Num => Float);
use To_BR;
Result : Unbounded_String := To_Unbounded_String ("[");
LF renames Ada.Characters.Latin_1.LF; --> Ada2022
begin
for I in Matrix_T'Range (1) loop
Result := @ & (if I = Matrix_T'First (1) then "" else " ") & "[";
for J in Matrix_T'Range (2) loop
declare
Tmp : constant Valid_Big_Real := To_Big_Real (Value (I, J));
N : constant Valid_Big_Integer := Numerator (Tmp);
D : constant Big_Positive := Denominator (Tmp);
Str : constant String := N'Image & "/" & D'Image;
begin
Result := @ & Str & (if J = Matrix_T'Last (2) then "" else ",");
end;
end loop;
Result := @ & "]" & (if I = Matrix_T'Last (1) then "" else [LF]);
end loop;
Output.Put (To_String (Result & "]"));
end Matrix_Image;
Et le résultat sera bien conforme à l’attendu :
[[ 0/ 1, 1/ 1, 1/ 1]
[ 1/ 1, 0/ 1, 1/ 1]
[ 1/ 1, 1/ 1, 0/ 1]]
[[-1/ 2, 1/ 2, 1/ 2]
[ 1/ 2,-1/ 2, 1/ 2]
[ 1/ 2, 1/ 2,-1/ 2]]
Conclusion¶
Sans être une profonde évolution du langage Ada comme l’a été Ada₂₀₁₂,
Ada₂₀₂₂ apporte beaucoup de « petites » améliorations qui facilitent
la vie au quotidien. Par exemple, la généralisation de l’attribut
'Image
, va permettre de mettre simplement en place des
traces permettant de voir la Matrice !
Comments