From a356ff0417c0371ccca5fc8b6be697ccc395adaf Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sun, 4 May 2025 20:39:27 +0200 Subject: [PATCH 01/13] Editorial change: removing todo item --- .../advanced-ada/parts/data_types/numerics.rst | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index 9d1268854..1d66dbe75 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -359,24 +359,6 @@ Along these same lines, we can write: and be guaranteed that :ada:`Nil` is equal to zero. -.. :: - - .. _Adv_Ada_Universal_Real_Integer: - - Universal Real and Integer - -------------------------- - - .. todo:: - - Complete section! - - - Universal real vs. integer - - Accuracy - - Compile time vs. runtime evaluation - - Named Numbers - - Operations in named numbers expressions - - .. :: .. _Adv_Ada_Base_Type: From 2005db221753ece8e78e4df9cf108ae3b41eeb4c Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 19 Apr 2025 04:44:49 +0200 Subject: [PATCH 02/13] Adding section on universal numeric types --- .../parts/data_types/numerics.rst | 609 ++++++++++++++++++ 1 file changed, 609 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index 1d66dbe75..9fa0c12d6 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -359,6 +359,615 @@ Along these same lines, we can write: and be guaranteed that :ada:`Nil` is equal to zero. +.. _Adv_Ada_Universal_Numeric_Types: + +Universal Numeric Types +----------------------- + +Previously, we introduced the concept of +:ref:`universal types `. Three of them are numeric +types: universal real, universal integer and universal fixed types. In this +section, we discuss these universal numeric types in more detail. + + +.. _Adv_Ada_Universal_Real_Integer: + +Universal Real and Integer +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Universal real and integer types are mainly used in the declaration of +:ref:`named numbers `: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Universal_Real_Integer + + package Show_Universal_Real_Integer is + + Pi : constant := 3.1415926535; + -- ^^^^^^^^^^^^ + -- universal real type + + N : constant := 10; + -- ^^ + -- universal integer type + + end Show_Universal_Real_Integer; + +The type of a named number is implied by the type of the +:ref:`numeric literal ` and the type of the named +numbers that we use in the +:ref:`static expression `. (We discuss static +expressions next.) In this specific example, we declare :ada:`Pi` using a real +literal, which implies that it's a named number of universal real type. +Likewise, :ada:`N` is of universal integer type because we use an integer +literal in its declaration. + +.. admonition:: In the Ada Reference Manual + + - :arm22:`3.3.2 Number Declarations <3-3-2>` + + +.. _Adv_Ada_Static_Expressions: + +Static expressions +^^^^^^^^^^^^^^^^^^ + +As we've just seen, we can use an expression in the declaration of a named +number. This expression is static, as it's always evaluated at compile time. +Therefore, we must use the keyword :ada:`constant` in the declaration of named +numbers. + +If all components of the static expression are of universal integer type, then +the named number is of universal integer type. Otherwise, the static expression +is of universal real type. For example, if the first element of a static +expression is of universal integer type, but we have a constant of universal +real type in the same expression, then the type of the whole static expression +is universal real: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Static_Expressions + + package Static_Expressions is + + Two_Pi : constant := 2 * 3.1415926535; + -- ^ + -- universal integer type + -- + -- ^^^^^^^^^^^^ + -- universal real type + -- + -- => result: universal real type + + end Static_Expressions; + +In this example, the static expression is of universal real type because of the +real literal (:ada:`3.1415926535`) |mdash| even though we have the universal +integer :ada:`2` in the expression. + +Likewise, if we use a constant of universal real type in the static expression, +the result is of universal real type: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Static_Expressions + + package Static_Expressions is + + Pi : constant := 3.1415926535; + -- ^^^^^^^^^^^^ + -- universal real type + + Two_Pi : constant := 2 * Pi; + -- ^ + -- universal integer type + -- + -- ^^ + -- universal real type + -- + -- => result: universal real type + + end Static_Expressions; + +In this example, the result of the static expression is of universal real type +because of we're using the named number :ada:`Pi`, which is of universal real +type. + +Complexity of static expressions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The operations that we use in static expressions may be arbitrarily complex. +For example: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Static_Expressions + + package Static_Expressions is + + C1 : constant := 300_453.5; + C2 : constant := 455_233.5 * C1; + C3 : constant := 872_922.5 * C2; + C4 : constant := 155_277.5 * C1 + C2 / C3; + C5 : constant := 2.0 * C1 + + 3.0 * (C2 / (C4 * C3)) + + 4.0 * (C1 / (C2 * C2)) + + 5.0 * (C3 / (C1 * C1)); + + end Static_Expressions; + +As we can see in this example, we may create a chain of dependencies, where the +result of a static expression depends on the result of previously evaluated +static expressions. For instance, :ada:`C5` depends on the evaluation of +:ada:`C1`, :ada:`C2`, :ada:`C3`, :ada:`C4`. + +Accuracy of static expressions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The accuracy and range of numeric literals used in static expressions may be +arbitrarily high as well: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Static_Expressions + + package Static_Expressions is + + Pi : constant := + 3.14159_26535_89793_23846_26433_83279_50288; + + Seed : constant := + 143_574_786_272_784_656_928_283_872_972_764; + + Super_Seed : constant := + Seed * Seed * Seed * Seed * Seed * Seed; + + end Static_Expressions; + +In this example, :ada:`Super_Seed` has a value that is above the typical range +of integer constants. This might become challenging when using such named +numbers in actual computations, as we +:ref:`discuss soon `. + +Another example is when the result of the expression is a +:wikipedia:`repeating decimal `: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Repeating_Decimal + + package Repeating_Decimals is + + One_Over_Three : constant := + 1.0 / 3.0; + + end Repeating_Decimals; + + with Ada.Text_IO; use Ada.Text_IO; + + with Repeating_Decimals; + use Repeating_Decimals; + + procedure Show_Repeating_Decimals is + F_1_3 : constant Float := + One_Over_Three; + LF_1_3 : constant Long_Float := + One_Over_Three; + LLF_1_3 : constant Long_Long_Float := + One_Over_Three; + begin + Put_Line (F_1_3'Image); + Put_Line (LF_1_3'Image); + Put_Line (LLF_1_3'Image); + end Show_Repeating_Decimals; + +In this example, as expected, we see that the accuracy of the value we display +increases if we use a type with higher precision. This wouldn't be possible if +we had used a floating-point type with limited precision for the +:ada:`One_Over_Three` constant: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Repeating_Decimal + + package Repeating_Decimals is + + One_Over_Three : constant Long_Float := + 1.0 / 3.0; + -- ^^^^^^^^^^ + -- using Long_Float instead of + -- universal real type + + end Repeating_Decimals; + + with Ada.Text_IO; use Ada.Text_IO; + + with Repeating_Decimals; + use Repeating_Decimals; + + procedure Show_Repeating_Decimals is + F_1_3 : constant Float := + Float (One_Over_Three); + LF_1_3 : constant Long_Float := + Long_Float (One_Over_Three); + LLF_1_3 : constant Long_Long_Float := + Long_Long_Float (One_Over_Three); + begin + Put_Line (F_1_3'Image); + Put_Line (LF_1_3'Image); + Put_Line (LLF_1_3'Image); + end Show_Repeating_Decimals; + +Because we're using the :ada:`Long_Float` type for the :ada:`One_Over_Three` +constant instead of the universal real type, the accuracy doesn't increase when +we use the :ada:`Long_Long_Float` type |mdash| as we see in the value of the +:ada:`LLF_1_3` constant |mdash| even though this type has a higher precision. + +.. admonition:: For further reading... + + When using :ref:`big numbers `, you could simply + assign the named number :ada:`One_Over_Three` to a big real: + + .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Repeating_Decimal switches=Compiler(-gnat2022); + + package Repeating_Decimals is + + One_Over_Three : constant := + 1.0 / 3.0; + + end Repeating_Decimals; + + with Ada.Text_IO; use Ada.Text_IO; + + with Ada.Numerics.Big_Numbers.Big_Reals; + use Ada.Numerics.Big_Numbers.Big_Reals; + + with Repeating_Decimals; + use Repeating_Decimals; + + procedure Show_Repeating_Decimals is + BR_1_3 : constant Big_Real := One_Over_Three; + begin + Put_Line ("BR: " + & To_String (Arg => BR_1_3, + Fore => 2, + Aft => 31, + Exp => 0)); + end Show_Repeating_Decimals; + + Another approach is to use the division operation directly: + + .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Repeating_Decimal switches=Compiler(-gnat2022); + + with Ada.Text_IO; use Ada.Text_IO; + + with Ada.Numerics.Big_Numbers.Big_Reals; + use Ada.Numerics.Big_Numbers.Big_Reals; + + with Repeating_Decimals; + use Repeating_Decimals; + + procedure Show_Repeating_Decimals is + BR_1_3 : constant Big_Real := 1 / 3; + begin + Put_Line ("BR: " + & To_String (Arg => BR_1_3, + Fore => 2, + Aft => 31, + Exp => 0)); + end Show_Repeating_Decimals; + + We talk more about + :ref:`big real and quotients ` later on. + +.. _Adv_Ada_Conversion_Of_Universal_Real_Integer: + +Conversion of universal real and integer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Although a named number exists as an numeric representation form in Ada, the +value it represents cannot be used directly at runtime |mdash| even if we +*just* display the value of the constant at runtime, for example. In fact, a +conversion to a non-universal type is required in order to use the named number +anywhere else other than a static expression: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Conversion_To_Non_Universal_Types + + package Static_Expressions is + + Pi : constant := + 3.14159_26535_89793_23846_26433_83279_50288; + + Seed : constant := + 143_574_786_272_784_656_928_283_872_972_764; + + Super_Seed : constant := + Seed * Seed * Seed * Seed * Seed * Seed; + + end Static_Expressions; + + with Ada.Text_IO; use Ada.Text_IO; + + with Static_Expressions; + use Static_Expressions; + + procedure Show_Static_Expressions is + begin + Put_Line (Pi'Image); + -- Same as: + -- Put_Line (Float (Pi)'Image); + + Put_Line (Seed'Image); + -- Same as: + -- Put_Line ( + -- Long_Long_Long_Integer (Seed)'Image); + end Show_Static_Expressions; + +As we see in this example, the named number :ada:`Pi` is converted to +:ada:`Float` before being used as an actual parameter in the call to +:ada:`Put_Line`. Similarly, :ada:`Seed` is converted to +:ada:`Long_Long_Long_Integer`. + +When we use the :ada:`Image` attribute, the compiler automatically selects a +numeric type which has a suitable range for the named number. In the example +above, we wouldn't be able to represent the value of :ada:`Seed` with +:ada:`Integer`, so the compiler selected :ada:`Long_Long_Long_Integer`. Of +course, we could have also specified the type by using explicit +:ref:`type conversions ` or a +:ref:`qualified expressions `: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Conversion_To_Non_Universal_Types + + with Ada.Text_IO; use Ada.Text_IO; + + with Static_Expressions; + use Static_Expressions; + + procedure Show_Static_Expressions is + begin + Put_Line (Long_Long_Float (Pi)'Image); + Put_Line (Long_Long_Float'(Pi)'Image); + end Show_Static_Expressions; + +Now, we're explicitly converting to :ada:`Long_Long_Float` in the first call +to :ada:`Put_Line` and using a qualified expression in the second call to +:ada:`Put_Line`. + +A conversion is also performed when we use a named number in an object +declaration: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Conversion_To_Non_Universal_Types + + with Ada.Text_IO; use Ada.Text_IO; + + with Static_Expressions; + use Static_Expressions; + + procedure Show_Static_Expressions is + Two_Pi : constant Float := 2.0 * Pi; + -- Same as: + -- Two_Pi: constant Float := + -- 2.0 * Float (Pi); + + Two_Pi_More_Precise : + constant Long_Long_Float := 2.0 * Pi; + -- Same as: + -- Two_Pi_More_Precise : + -- constant Long_Long_Float := + -- 2.0 * Long_Long_Float (Pi); + begin + Put_Line (Two_Pi'Image); + Put_Line (Two_Pi_More_Precise'Image); + end Show_Static_Expressions; + +In this example, :ada:`Pi` is converted to :ada:`Float` in the declaration of +:ada:`Two_Pi` because we use the :ada:`Float` type in its declaration. +Likewise, :ada:`Pi` is converted to :ada:`Long_Long_Float` in the declaration +of :ada:`Two_Pi_More_Precise` because we use the :ada:`Long_Long_Float` type in +its declaration. (Actually, the same conversion is performed for each instance +of the real literal :ada:`2.0` in this example.) + +Note that the range of the type we select might not be suitable for the named +number we want to use. For example: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Conversion_To_Non_Universal_Types + :class: ada-expect-compile-error + + with Ada.Text_IO; use Ada.Text_IO; + + with Static_Expressions; + use Static_Expressions; + + procedure Show_Static_Expressions is + Initial_Seed : constant + Long_Long_Long_Integer := + Super_Seed; + begin + Put_Line (Initial_Seed'Image); + end Show_Static_Expressions; + +In this example, we get a compilation error because the range of the +:ada:`Long_Long_Long_Integer` type isn't enough to store the value of the +:ada:`Super_Seed`. + +.. admonition:: For further reading... + + To circumvent the compilation error in the code example we've just seen, + the best alternative to use :ref:`big numbers ` + |mdash| we discuss this topic later on in this chapter: + + .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Numerics.Universal_Numeric_Types.Conversion_To_Non_Universal_Types switches=Compiler(-gnat2022); + + with Ada.Text_IO; use Ada.Text_IO; + + with Ada.Numerics.Big_Numbers.Big_Integers; + use Ada.Numerics.Big_Numbers.Big_Integers; + + with Static_Expressions; + use Static_Expressions; + + procedure Show_Static_Expressions is + Initial_Seed : constant + Big_Integer := + Super_Seed; + begin + Put_Line (Initial_Seed'Image); + end Show_Static_Expressions; + + By changing the type from :ada:`Long_Long_Long_Integer` to + :ada:`Big_Integer`, we get rid of the compilation error. (The value of + :ada:`Super_Seed` |mdash| stored in :ada:`Initial_Seed` |mdash| is + displayed at runtime.) + + +.. _Adv_Ada_Universal_Fixed: + +Universal Fixed +~~~~~~~~~~~~~~~ + +For fixed-point types, we also have a corresponding universal type. However, in +contrast to the universal real and integer types, universal fixed types aren't +an abstraction used in static expressions, but rather a concept that permeates +actual fixed-point types. In fact, for +:ref:`fixed-point types `, some operations +are accomplished via universal fixed types |mdash| for example, the conversion +between fixed-point types and the multiplication and division operations. + +Let's start by analyzing how floating-point and integer types associate their +operations to the specific type of an object. For example, if we have an object +:ada:`A` of type :ada:`Float` in a multiplication, we cannot just write +:ada:`A * B` if we want to multiply :ada:`A` by an object :ada:`B` of another +floating-point type |mdash| if :ada:`B` is of type :ada:`Long_Float`, for +example, writing :ada:`A * B` triggers a compilation error. Therefore, we have +to convert one of the objects to have matching types: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Types.Universal_Types.Float_Multiplication + + with Ada.Text_IO; use Ada.Text_IO; + + procedure Show_Float_Multiplication_Mismatch is + F : Float := 0.25; + LF : Long_Float := 0.50; + begin + F := F * LF; + Put_Line ("F = " & F'Image); + end Show_Float_Multiplication_Mismatch; + +This code example fails to compile because of the :ada:`F * LF` operation. +(We could correct the code by writing :ada:`F * Float (LF)`, for example.) + +In contrast, for fixed-point types, we can mix objects of different types in a +multiplication: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Types.Universal_Types.Fixed_Point_Multiplication + + package Normalized_Fixed_Point_Types is + + type TQ31 is + delta 2.0 ** (-31) + range -1.0 .. 1.0 - 2.0 ** (-31); + + type TQ15 is + delta 2.0 ** (-15) + range -1.0 .. 1.0 - 2.0 ** (-15); + + end Normalized_Fixed_Point_Types; + + with Ada.Text_IO; use Ada.Text_IO; + + with Normalized_Fixed_Point_Types; + use Normalized_Fixed_Point_Types; + + procedure Show_Fixed_Multiplication is + A : TQ15 := 0.25; + B : TQ31 := 0.50; + begin + A := A * B; + Put_Line ("A = " & A'Image); + end Show_Fixed_Multiplication; + +In this example, the :ada:`A * B` is accepted by the compiler, even though +:ada:`A` and :ada:`B` have different types. This is only possible because the +multiplication operation of fixed-point types makes use of the universal fixed +type. In other words, the multiplication operation in this code example doesn't +operate directly on the fixed-point type :ada:`TQ31`. Instead, it converts +:ada:`A` and :ada:`B` to the universal fixed type, performs the operation using +this type, and converts back to the original type |mdash| :ada:`TQ31` in this +case. + +In addition to the multiplication operation, other operations such as the +conversion between fixed-point types and the division operations make use of +universal fixed types: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Types.Universal_Types.Universal_Fixed + + package Custom_Decimal_Types is + + type T3_D3 is delta 10.0 ** (-3) digits 3; + type T3_D6 is delta 10.0 ** (-3) digits 6; + type T6_D6 is delta 10.0 ** (-6) digits 6; + + end Custom_Decimal_Types; + + with Ada.Text_IO; use Ada.Text_IO; + + with Custom_Decimal_Types; + use Custom_Decimal_Types; + + procedure Show_Universal_Fixed is + Val_T3_D3 : T3_D3; + Val_T3_D6 : T3_D6; + Val_T6_D6 : T6_D6; + begin + Val_T3_D3 := 0.65; + + Val_T3_D6 := T3_D6 (Val_T3_D3); + -- ^^^^^^^^^^^^^^^^^ + -- type conversion using + -- universal fixed type + + Val_T6_D6 := T6_D6 (Val_T3_D6); + -- ^^^^^^^^^^^^^^^^^ + -- type conversion using + -- universal fixed type + + Put_Line ("Val_T3_D3 = " + & Val_T3_D3'Image); + Put_Line ("Val_T3_D6 = " + & Val_T3_D6'Image); + Put_Line ("Val_T6_D6 = " + & Val_T3_D6'Image); + Put_Line ("-----------------"); + + Val_T3_D6 := Val_T6_D6 * 2.0; + -- ^^^^^^^^^^^^^^^^ + -- using universal fixed type for + -- the multiplication operation + Put_Line ("Val_T3_D6 = " + & Val_T3_D6'Image); + + Val_T3_D6 := Val_T6_D6 / Val_T3_D3; + -- ^^^^^^^^^^^^^^^^^^^^^ + -- different fixed-point types: + -- using universal fixed type for + -- the division operation + Put_Line ("Val_T3_D6 = " + & Val_T3_D6'Image); + + + end Show_Universal_Fixed; + +In this example, the conversion from the fixed-point type :ada:`T3_D3` to the +:ada:`T3_D6` and :ada:`T6_D6` types is performed via universal fixed types. + +Similarly, the multiplication operation :ada:`Val_T6_D6 * 2.0` uses universal +fixed types. Here, we're actually multiplying a variable of type :ada:`T6_D6` +by two and assigning it to a variable of type :ada:`Val_T3_D6`. Although these +variable have different fixed-point types, no explicit conversion (e.g.: +:ada:`Val_T3_D6 := T3_D6 (Val_T6_D6 * 2.0);`) is required in this case because +the result of the operation is of universal fixed type, so that it can be +assigned to a variable of any fixed-point type. + +Finally, in the :ada:`Val_T3_D6 := Val_T6_D6 / Val_T3_D3` statement, we're +using three fixed-point types: we're dividing a variable of type :ada:`T6_D6` +by a variable of type :ada:`T3_D3`, and assigning it to a variable of type +:ada:`T3_D6`. All these operations are only possible without explicit type +conversions because the underlying types for the fixed-point division operation +are universal fixed types. + +.. admonition:: In the Ada Reference Manual + + - :arm22:`3.3.2 Number Declarations <3-3-2>` + - :arm22:`4.5.5 Multiplying Operators <4-5-5>` + + .. :: .. _Adv_Ada_Base_Type: From 18b725cf9d943b80c6ef481850c880fa6e2e3b97 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 19 Apr 2025 04:45:54 +0200 Subject: [PATCH 03/13] Editorial change: using reference to section on universal numeric types --- .../advanced-ada/parts/data_types/types.rst | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/types.rst b/content/courses/advanced-ada/parts/data_types/types.rst index 116844223..9bd000b84 100644 --- a/content/courses/advanced-ada/parts/data_types/types.rst +++ b/content/courses/advanced-ada/parts/data_types/types.rst @@ -560,12 +560,9 @@ type associated with it. In fact, its type is called universal real or universal integer |mdash| depending on the number being a real or integer number. (In this specific case, :ada:`Pi` is a universal real number.) We talk about :ref:`universal types ` later on in this -chapter. - -.. todo:: - - Add link to section on universal real, integer and fixed types - (Adv_Ada_Universal_Real_Integer_Fixed) once it's available. +chapter and about +:ref:`universal real and integer types ` +in another chapter. .. admonition:: In the Ada Reference Manual @@ -1516,14 +1513,9 @@ The Ada standard defines four universal types: #. universal access types The first three are numeric types, and we discuss them in detail later on -in another chapter. The last one +:ref:`in another chapter `. The last one is used for :ref:`anonymous access types `. -.. todo:: - - Add link to section on universal real, integer and fixed types - (Adv_Ada_Universal_Real_Integer_Fixed) once it's available. - .. todo:: Add link to section on universal access types once it's available. From 22b7b698304909de6d5a802ef7765ed6051e4a44 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 19 Apr 2025 04:46:35 +0200 Subject: [PATCH 04/13] Minor editorial change: removing deprecated todo item --- content/courses/advanced-ada/parts/data_types/types.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/types.rst b/content/courses/advanced-ada/parts/data_types/types.rst index 9bd000b84..95ee1b853 100644 --- a/content/courses/advanced-ada/parts/data_types/types.rst +++ b/content/courses/advanced-ada/parts/data_types/types.rst @@ -539,10 +539,6 @@ In addition to objects, we can have named numbers. Those aren't objects, but rather :ref:`names ` that we assign to numeric values. For example: -.. todo:: - - Add link to section on names. - .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Types.Objects.Named_Number procedure Show_Named_Number is From 0424c6d61fa0cef5c0068649f95ad4943ff971e5 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 19 Apr 2025 05:23:37 +0200 Subject: [PATCH 05/13] Editorial change: adding Sphinx class to code block --- content/courses/advanced-ada/parts/data_types/numerics.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index 9fa0c12d6..2e27bf655 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -829,6 +829,7 @@ example, writing :ada:`A * B` triggers a compilation error. Therefore, we have to convert one of the objects to have matching types: .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Types.Universal_Types.Float_Multiplication + :class: ada-expect-compile-error with Ada.Text_IO; use Ada.Text_IO; From 09c5f4e0c6ce98d70ac2831ed6f69523a24ac408 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sun, 20 Apr 2025 00:42:25 +0200 Subject: [PATCH 06/13] Editorial change: removing empty line --- content/courses/advanced-ada/parts/data_types/numerics.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index 2e27bf655..1fc4d7f39 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -942,7 +942,6 @@ universal fixed types: Put_Line ("Val_T3_D6 = " & Val_T3_D6'Image); - end Show_Universal_Fixed; In this example, the conversion from the fixed-point type :ada:`T3_D3` to the From a1214dd8f8fadc67fc0e5ad008f8111266e30dc1 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 9 May 2025 21:53:58 +0200 Subject: [PATCH 07/13] Integrating suggestions --- .../courses/advanced-ada/parts/data_types/numerics.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index 1fc4d7f39..367eb89e7 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -393,7 +393,7 @@ Universal real and integer types are mainly used in the declaration of end Show_Universal_Real_Integer; The type of a named number is implied by the type of the -:ref:`numeric literal ` and the type of the named +:ref:`numeric literal ` and the type of any named numbers that we use in the :ref:`static expression `. (We discuss static expressions next.) In this specific example, we declare :ada:`Pi` using a real @@ -825,7 +825,8 @@ operations to the specific type of an object. For example, if we have an object :ada:`A` of type :ada:`Float` in a multiplication, we cannot just write :ada:`A * B` if we want to multiply :ada:`A` by an object :ada:`B` of another floating-point type |mdash| if :ada:`B` is of type :ada:`Long_Float`, for -example, writing :ada:`A * B` triggers a compilation error. Therefore, we have +example, writing :ada:`A * B` triggers a compilation error. (Otherwise, which +precision should be used for the result?) Therefore, we have to convert one of the objects to have matching types: .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Types.Universal_Types.Float_Multiplication @@ -845,7 +846,8 @@ This code example fails to compile because of the :ada:`F * LF` operation. (We could correct the code by writing :ada:`F * Float (LF)`, for example.) In contrast, for fixed-point types, we can mix objects of different types in a -multiplication: +multiplication or division. (In this case, mixing is allowed for the +convenience of the programmer.) For example: .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Types.Universal_Types.Fixed_Point_Multiplication From 4d2f44fa0d12d3218b3b7c3594bd0ec0374ff506 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 9 May 2025 21:54:14 +0200 Subject: [PATCH 08/13] Correcting type --- content/courses/advanced-ada/parts/data_types/numerics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index 367eb89e7..b1e726163 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -882,7 +882,7 @@ multiplication operation of fixed-point types makes use of the universal fixed type. In other words, the multiplication operation in this code example doesn't operate directly on the fixed-point type :ada:`TQ31`. Instead, it converts :ada:`A` and :ada:`B` to the universal fixed type, performs the operation using -this type, and converts back to the original type |mdash| :ada:`TQ31` in this +this type, and converts back to the original type |mdash| :ada:`TQ15` in this case. In addition to the multiplication operation, other operations such as the From de5ee7f3bccdebae80592ef94d3a55fed9275208 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 9 May 2025 21:54:43 +0200 Subject: [PATCH 09/13] Editorial change: removing non-relevant reference --- content/courses/advanced-ada/parts/data_types/numerics.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index b1e726163..077267bca 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -966,7 +966,6 @@ are universal fixed types. .. admonition:: In the Ada Reference Manual - - :arm22:`3.3.2 Number Declarations <3-3-2>` - :arm22:`4.5.5 Multiplying Operators <4-5-5>` From 81bce770261e3cf3bd859c95cb69991ec0f9b3ef Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 9 May 2025 21:55:44 +0200 Subject: [PATCH 10/13] Adding admonition about custom `*` and `/` operators --- .../parts/data_types/numerics.rst | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index 077267bca..abea6fa7b 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -964,6 +964,105 @@ by a variable of type :ada:`T3_D3`, and assigning it to a variable of type conversions because the underlying types for the fixed-point division operation are universal fixed types. +.. admonition:: For further reading... + + It's possible to implement custom :ada:`*` and :ada:`/` operators for + fixed-point types. However, those operators do **not** override the + corresponding operators for universal fixed-point types. For example: + + .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Types.Universal_Types.Fixed_Point_Custom_Multiplication + + package Normalized_Fixed_Point_Types is + + type TQ63 is + delta 2.0 ** (-63) + range -1.0 .. 1.0 - 2.0 ** (-63); + + type TQ31 is + delta 2.0 ** (-31) + range -1.0 .. 1.0 - 2.0 ** (-31); + + overriding + -- ^^^^^^ + -- "+" operator is overriding! + function "+" (L, R: TQ31) + return TQ31; + + not overriding + -- ^^^^^^^^^^ + -- "*" operator is NOT overriding! + function "*" (L, R: TQ31) + return TQ31; + + type TQ15 is + delta 2.0 ** (-15) + range -1.0 .. 1.0 - 2.0 ** (-15); + + end Normalized_Fixed_Point_Types; + + with Ada.Text_IO; use Ada.Text_IO; + + package body Normalized_Fixed_Point_Types is + + function "+" (L, R: TQ31) + return TQ31 is + begin + Put_Line ("Using the overriding ´+' operator"); + return TQ31 (TQ63 (L) + TQ63 (R)); + end "+"; + + function "*" (L, R: TQ31) + return TQ31 is + begin + Put_Line ("Using the non-overriding ´*' operator"); + return TQ31 (TQ63 (L) * TQ63 (R)); + end "*"; + + end Normalized_Fixed_Point_Types; + + with Ada.Text_IO; use Ada.Text_IO; + + with Normalized_Fixed_Point_Types; + use Normalized_Fixed_Point_Types; + + procedure Show_Fixed_Multiplication is + Q31_A : TQ31 := 0.25; + Q31_B : TQ31 := 0.50; + Q15_A : TQ15 := 0.25; + Q15_B : TQ15 := 0.50; + begin + Q31_A := Q31_A * Q31_B; + Put_Line ("Q31_A = " & Q31_A'Image); + + Q15_A := Q15_A * Q15_B; + Put_Line ("Q15_A = " & Q31_A'Image); + + Q15_A := TQ15 (Q31_A) * Q15_B; + -- ^^^^^^^^^^^^ + -- A conversion is required because of + -- the multiplication operator of + -- TQ15. + Put_Line ("Q31_A = " & Q31_A'Image); + end Show_Fixed_Multiplication; + + In this example, we're declaring a custom multiplication operator for the + :ada:`TQ31` type. As we can see in the declaration, we specify that it's + :ada:`not overriding` the :ada:`*` operator. (Removing the :ada:`not` + keyword triggers a compilation error.) In contrast, for the :ada:`+` + operator, we're indeed overriding the default :ada:`+` operator of the + :ada:`TQ31` type in the :ada:`Normalized_Fixed_Point_Types` because the + addition operator is associate with its corresponding fixed-point type, + not with the universal fixed-point type. In the + :ada:`Q31_A := Q31_A * Q31_B` statement, we see at runtime (through the + "Using the non-overriding ´*' operator" message) that the custom + multiplication is being used. + + However, because of this custom :ada:`*` operator, we cannot mix objects of + this type with objects of other fixed-point types in multiplication or + division operations. Therefore, for a statement such as + :ada:`Q15_A := Q31_A * Q15_B`, we have to convert :ada:`Q31_A` to the + :ada:`TQ15` type before multiplying it by :ada:`Q15_B`. + .. admonition:: In the Ada Reference Manual - :arm22:`4.5.5 Multiplying Operators <4-5-5>` From bf12790ab0638c4fcc4c7f7b317d7e754008649a Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 10 May 2025 00:49:39 +0200 Subject: [PATCH 11/13] Editorial change: correcting code style --- .../advanced-ada/parts/data_types/numerics.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index abea6fa7b..ecc740c50 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -985,13 +985,13 @@ are universal fixed types. overriding -- ^^^^^^ -- "+" operator is overriding! - function "+" (L, R: TQ31) + function "+" (L, R : TQ31) return TQ31; not overriding -- ^^^^^^^^^^ -- "*" operator is NOT overriding! - function "*" (L, R: TQ31) + function "*" (L, R : TQ31) return TQ31; type TQ15 is @@ -1004,17 +1004,19 @@ are universal fixed types. package body Normalized_Fixed_Point_Types is - function "+" (L, R: TQ31) + function "+" (L, R : TQ31) return TQ31 is begin - Put_Line ("Using the overriding ´+' operator"); + Put_Line + ("Using the overriding ´+' operator"); return TQ31 (TQ63 (L) + TQ63 (R)); end "+"; - function "*" (L, R: TQ31) + function "*" (L, R : TQ31) return TQ31 is begin - Put_Line ("Using the non-overriding ´*' operator"); + Put_Line + ("Using the non-overriding ´*' operator"); return TQ31 (TQ63 (L) * TQ63 (R)); end "*"; From f2f89822159202be3517fa59397dd78b54e874bb Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 10 May 2025 00:50:00 +0200 Subject: [PATCH 12/13] Editorial change: correcting typo --- content/courses/advanced-ada/parts/data_types/numerics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index ecc740c50..d13355906 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -1053,7 +1053,7 @@ are universal fixed types. keyword triggers a compilation error.) In contrast, for the :ada:`+` operator, we're indeed overriding the default :ada:`+` operator of the :ada:`TQ31` type in the :ada:`Normalized_Fixed_Point_Types` because the - addition operator is associate with its corresponding fixed-point type, + addition operator is associated with its corresponding fixed-point type, not with the universal fixed-point type. In the :ada:`Q31_A := Q31_A * Q31_B` statement, we see at runtime (through the "Using the non-overriding ´*' operator" message) that the custom From 1b65eedbf79928e7c8107a64df08a0ce575a6d77 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 10 May 2025 01:25:24 +0200 Subject: [PATCH 13/13] Editorial change: simplifying user message --- content/courses/advanced-ada/parts/data_types/numerics.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/numerics.rst b/content/courses/advanced-ada/parts/data_types/numerics.rst index d13355906..b7fe2f749 100644 --- a/content/courses/advanced-ada/parts/data_types/numerics.rst +++ b/content/courses/advanced-ada/parts/data_types/numerics.rst @@ -1008,7 +1008,7 @@ are universal fixed types. return TQ31 is begin Put_Line - ("Using the overriding ´+' operator"); + ("=> Overriding '+'"); return TQ31 (TQ63 (L) + TQ63 (R)); end "+"; @@ -1016,7 +1016,8 @@ are universal fixed types. return TQ31 is begin Put_Line - ("Using the non-overriding ´*' operator"); + ("=> Custom " + & "non-overriding '*'"); return TQ31 (TQ63 (L) * TQ63 (R)); end "*"; @@ -1056,7 +1057,7 @@ are universal fixed types. addition operator is associated with its corresponding fixed-point type, not with the universal fixed-point type. In the :ada:`Q31_A := Q31_A * Q31_B` statement, we see at runtime (through the - "Using the non-overriding ´*' operator" message) that the custom + "=> Custom non-overriding '*'" message) that the custom multiplication is being used. However, because of this custom :ada:`*` operator, we cannot mix objects of