Ada.Text_IO.Float_IO.get() not behaving as expected - ada

I'm about 5 hours into learning Ada. I made a simple program and I was putting different values into it and experienced behavior I can't explain.
My program works fine with normal inputs like km = 100, litres = 10, result = 10.0.
And obviously bad inputs work: km = "cat" result in "raised ADA.IO_EXCEPTIONS.DATA_ERROR"
But this combination of inputs has me baffled: km = 100..10. The program skips over the litres input and presents a result that works back to a litres value of 0.10. I was expecting a constraint error like when I entered 'cat'.
Can someone please explain this to me and how Ada programmers work around it so that 100..10 results in an error.
Here's my program:
-- This program takes km driven and litres consumed to calculate
-- fuel economy.
with Ada.Text_IO;
with Ada.Float_Text_IO;
procedure Main is
package TIO renames Ada.Text_IO;
package FIO renames Ada.Float_Text_IO;
type Km is new Float range 0.01 .. 10_000.00;
type Litres is new Float range 0.01 .. 10_000.00;
package Km_IO is new TIO.Float_IO (Km);
package Litres_IO is new TIO.Float_IO (Litres);
Entered_Km : Km;
Entered_Litres : Litres;
function Fuel_Economy (
Entered_Km : in Km;
Entered_Litres : in Litres
) return Float is
-- returns fuel economy normalized to litres per 100 km
begin
return Float(Entered_Litres) / Float(Entered_Km) * 100.0;
end Fuel_Economy;
begin
TIO.Put_Line ("This program calculates fuel economy.");
TIO.Put_Line ("Enter km:");
Km_IO.Get (Entered_Km);
TIO.Put_Line ("Enter litres:");
Litres_IO.Get (Entered_Litres);
TIO.Put ("Your fuel economy is ");
FIO.Put (Item => Fuel_Economy (Entered_Km, Entered_Litres),
Fore => 1,
Aft => 2,
Exp => 0
);
TIO.Put_Line (" litres per 100 km.");
end Main;
Exact output:
This program calculates fuel economy.
Enter km:
100..10
Enter litres:
Your fuel economy is 0.10 litres per 100 km.
[2018-05-06 14:08:16] process terminated successfully, elapsed time: 04.01s
I'm using GPS 2017 on windows 7.
Many thanks.

Typically experienced Ada users read the entire line into a String (using function Get_Line) and then extract the numeric value(s) from the String. Since programs like this typically loop until the user enters a valid value, reading into a String avoids a common problem with direct numeric I/O in which invalid input results in an infinite loop:
Get_Km : loop
Handle_Invalid : begin
Put_Line (Item => "Enter km");
Get (Item => Entered_Km);
exit Get_Km;
exception -- Handle_Invalid
when others =>
Put_Line ("Invalid input");
end Handle_Invalid;
end loop Get_Km;
The invalid input remains in the buffer and is repeatedly processed by Get.
Wright demonstrated a variation of this, but usually anything left on the line after the value(s) is discarded, so that input can be redirected from a file with trailing comments:
13.3 -- km traveled

One solution would be to discard the rest of the line after having read the (leading) number:
TIO.Put_Line ("Enter km:");
Km_IO.Get (Entered_Km);
TIO.Skip_Line;
Another, less straightforward, would be to check that there wasn’t anything left over:
TIO.Put_Line ("Enter km:");
Get_Km:
loop
declare
Input : constant String := TIO.Get_Line;
Last : Natural;
begin
Km_IO.Get (From => Input, Item => Entered_Km, Last => Last);
exit Get_Km when Input (Last + 1 .. Input'Length)
= (Last + 1 .. Input'Length => ' ');
TIO.Put_Line ("... just the number, please; '"
& Input (Last + 1 .. Input'Length)
& "' was left over");
exception
when others =>
TIO.Put_Line ("... a number, please");
end;
end loop Get_Km;

According to the Ada Language Reference Manual A.10.9(15-16) your run-time library is behaving correctly, as these two formats are allowed syntax for Ada.Text_IO.Float_IO.Get:
[+|–]numeral.[exponent]
[+|–].numeral[exponent]

Related

Ada constraint error: Discriminant check failed. What does this mean?

I've tried searching the docs and the code, but I'm unable to find what this is and therefore how to correct it.
Scenario:
I'm using the Ada SPARK vectors library and I have the following code:
package MyPackage
with SPARK_Mode => On
is
package New_Vectors is new Formal_Vectors (Index_Type => test, Element_Type => My_Element.Object);
type Object is private;
private
type Object is
record
Data : New_Vectors.Vector (Block_Vectors.Last_Count);
Identifier : Identifier_Range;
end record;
I get the error when the code calls:
function Make (Identifier : Identifier_Range) return Object is
begin
return (
Data => New_Vectors.Empty_Vector,
Identifier => Identifier);
end Make;
Pointing to Empty_Vector. The difficulty is that Empty_Vector defines the Capacity as 0 which appears to be leading to the problem. Now I'm not sure then how to deal with that as Capacity seems to be in the type definition (having looked in a-cofove.ads).
So basically I'm stuck as to how to resolve this; or quite how to spot this happening in future.
Your analysis is correct. The error occurs because you attempt to assign an empty vector (i.e. a vector with capacity 0) to a vector with capacity Block_Vectors.Last_Count (which appears to be non-zero).
You actually do not need to initialize the vector explicitly in order to use it. A default initialization (using <>, see, for example, here) suffices as shown in de example below.
However, in order to prove the absence of runtime errors, you do need to explicitly clear the vector using Clear. The Empty_Vector function can then be used to in assertions that check if a vector is empty or not as shown in the example below. The example can be shown to be free of runtime errors using gnatprove. For example by opening the prove settings via menu SPARK > Prove in GNAT Studio, selecting "Report checks moved" in the "General" section (top left) and then running the analysis by selecting "Execute" (bottom right).
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Formal_Vectors;
procedure Main with SPARK_Mode is
package My_Vectors is new Ada.Containers.Formal_Vectors
(Index_Type => Natural,
Element_Type => Integer);
use My_Vectors;
type Object is record
Data : Vector (Capacity => 10); -- Max. # of elements: 10
Value : Integer;
end record;
-- Initialize with default value (i.e. <>), no explicit initialization needed.
Obj : Object :=
(Data => <>,
Value => 42);
begin
-- Clear the vector, required for the assertions to be proven.
Clear (Obj.Data);
-- Assert that the vector is not empty.
pragma Assert (Obj.Data = Empty_Vector);
-- Populate the vector with some elements.
Append (Obj.Data, 4);
Append (Obj.Data, 5);
Append (Obj.Data, 6);
-- Assert that the vector is populated.
pragma Assert (Obj.Data /= Empty_Vector);
-- Show the contents of Obj.Data.
Put_Line ("Contents of Obj.Data:");
for I in Natural range 0 .. Natural (Length (Obj.Data)) - 1 loop
Put_Line ("[" & I'Image & "]" & Element (Obj.Data, I)'Image);
end loop;
New_Line;
-- or, alternatively using an iterator ...
declare
I : Extended_Index := Iter_First (Obj.Data);
begin
while Iter_Has_Element (Obj.Data, I) loop
Put_Line ("[" & I'Image & "]" & Element (Obj.Data, I)'Image);
I := Iter_Next (Obj.Data, I);
end loop;
end;
New_Line;
-- Show the contents of Obj.Value.
Put_Line ("Contents of Obj.Value:");
Put_Line (Obj.Value'Image);
New_Line;
end Main;
output
Contents of Obj.Data:
[ 0] 4
[ 1] 5
[ 2] 6
[ 0] 4
[ 1] 5
[ 2] 6
Contents of Obj.Value:
42

Cutting a string at first space

I'm in the process of making my own package for an Ada main program. I read a string followed by an integer and another string and the problem is I need to cut the first string at sign of first space. I don't know how to do it and I've searched stack overflow only to find solutions in other languages.
My code right now in the package body is:
Get_Line(Item.String, Item.X1)
where X1 is an integer and String is the string. This works if you define the length in the type to match the exact length of your input but of course you want to be able to insert whatever you want and thus it doesn't work.
Can somebody point me in the right direction?
Thanks
Why do you need to make a package for an Ada main program? Most compilers need them to be parameterless library-level procedures.
Anyway, this might give you some tips.
with Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Agrell is
begin
declare
Line : constant String := Ada.Text_IO.Get_Line;
This is how to deal with reading a string of unknown length. You have to work out how to preserve it for future use (maybe use an Unbounded_String?)
The_Integer : Integer;
begin
Looking_For_Space :
for J in Line'Range loop
if Line (J) = ' ' then
Everything from Line’First to J - 1 is the string you wanted.
declare
Dummy : Positive;
begin
Ada.Integer_Text_IO.Get (From => Line (J .. Line'Last),
Item => The_Integer,
Last => Dummy);
end;
OK, now we have The Integer...
...
exit Looking_For_Space;
... and we’re done with the first line.
end if;
end loop Looking_For_Space;
end;
end Agrell;

Using a Variant Record by Pointer

I simply don't catch why the following does not work. Could someone help me to fix it? It complains (at runtime):
raised CONSTRAINT_ERROR : variant2.adb:21 discriminant check failed
procedure Variant2 is
type POWER is (NONE,GAS, STEAM);
type VEHICLE (Engine : POWER := NONE) is
record
Model_Year : INTEGER range 1888..1992;
case Engine is
when NONE => null;
when GAS => Cylinders : INTEGER range 1..16;
when STEAM => Boiler_Size : INTEGER range 5..22;
Coal_Burner : BOOLEAN;
end case;
end record;
Works : VEHICLE;
Works_Not : access VEHICLE := new VEHICLE;
begin
Works := (GAS,1980,4); -- (1)
Works_Not.all := (GAS,1981,8); -- (2)
end Variant2;
(1) is working, but (2) does not
Thanks in advance!
The RM explicitly states that "If the designated type is composite, [...] the created object is constrained by its initial value (even if the designated subtype is unconstrained with defaults)." (RM 4.8(6/3))
which means you have to reallocate your access type
Works_Not := new VEHICLE'(GAS,1981,8);
(of course, you should deallocate the old access value first (see RM 13.11.2 Unchecked Storage Deallocation), but I leave that as an exercise)
UPDATE: as discussed in the comments
Here's an example you can play around with:
with Ada.Text_IO;
procedure Array_Of_Aliased is
type POWER is (NONE, GAS, STEAM);
type VEHICLE(Engine : POWER := NONE) is
record
Model_Year : Integer range 1888..1992;
case Engine is
when NONE => null;
when GAS => Cylinders : INTEGER range 1..16;
when STEAM => Boiler_Size : INTEGER range 5..22;
Coal_Burner : BOOLEAN;
end case;
end record;
-- array of aliased elements
type Vehicle_Array is array(1..5) of aliased VEHICLE;
-- the access type need to be "all" or "constant" in order to access aliased values
type Vehicle_Access is access all VEHICLE;
Vehicles : Vehicle_Array;
Works : Vehicle_Access;
begin
-- access to the first element of the array. Can't change discriminant this way...
Works := Vehicles(1)'Access;
Ada.Text_IO.Put_Line(POWER'Image(Works.Engine));
-- However, using the array, we _can_ change the discriminant, since it's _not_ an access value
Vehicles(1) := (STEAM, 1890, 20, True);
Vehicles(2) := (GAS, 1981, 8);
Ada.Text_IO.Put_Line(POWER'Image(Works.Engine));
-- We can still update the record elements using the access value, as long as the discriminant stays the same
Works.all := (STEAM, 1900, 15, False);
end Array_Of_Aliased;
As egilhh said, when you allocate a discriminant record using new, you can't change the discriminant of the record you allocated, even though you could do this for a variable of the type (as opposed to an allocated record). This rule has been around since Ada 83. The rationale was, I believe, that it allows the compiler to optimize space when allocating records. In your example, if we assume all the fields (including the discriminant) are 1 word, then the record will be 2 words if ENGINE=NONE, 3 words if ENGINE=GAS, 4 words if ENGINE=STEAM. When Works_Not is initialized, it's initialized to a NONE, which means it may take only 2 words on the heap (note: it's not a requirement that compilers optimize in this way). If it uses only 2 words, then reassigning the record to one with ENGINE=GAS would be a disaster--you'd be overflowing the area that you previously allocated, and stomping on other data.
Whether this was a good language design decision or not, I can't say; I don't know how many compilers, and how many applications, needed to take advantage of this optimization. Somebody 33 years ago thought it would be useful, and they must have had some good reasons for thinking so.
The restriction is annoying but not insurmountable. I've definitely run into it before, multiple times, but the simple answer is to wrap it in another record.
type VEHICLE_DATA (Engine : POWER := NONE) is
record
Model_Year : INTEGER range 1888..1992;
case Engine is
when NONE => null;
when GAS => Cylinders : INTEGER range 1..16;
when STEAM => Boiler_Size : INTEGER range 5..22;
Coal_Burner : BOOLEAN;
end case;
end record;
type VEHICLE is record
Data : VEHICLE_DATA;
end record;
Now_Works : access VEHICLE := new VEHICLE; -- still sets ENGINE=NONE
Now_Works := (Data => (Gas, 1981, 8)); -- legal
Now_Works.Data := (Gas, 1981, 8); -- legal, does the same thing
These are OK because the allocated record is a VEHICLE, which isn't a discriminant record. It's OK to change the discriminant of a subcomponent like this. That's how I've gotten around the rule.

Calling "Ada.float_text_IO.get" from a package to read user input from the console

I want to use Ada.float_text_IO.Get , in a packagefile created : (.adb)&(.ads) from a mainfile to read user input from the console using the procedure:
procedure Get(Item : out Num; Width : in Field := 0);
There is no example anywhere . Help :)
Here is a complete working example which includes a package specification (floatget.ads) and body (floatget.adb) and a separate program (mainfile.adb) to call the Read_Floats_From_Console function in the FloatGet package.
The Ada 95 RM section A.10.9 Input-Output for Real Types indicates Ada.Float_Text_IO.Get skips leading whitespace and parses a float literal value of various formats from a file, optionally if you use the form without the File : in File_Type; argument then Get will read from the console.
Contents of floatget.ads package specification:
-- floatget.ads
--
-- FloatGet package specification defining procedure to read floats
-- from console
package FloatGet is
procedure Read_Floats_From_Console;
end FloatGet;
Contents of floatget.adb package body:
-- floatget.adb
--
-- FloatGet package body using Ada.Float_Text_IO.Get to read floats
-- from console
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO;
package body FloatGet is
procedure Read_Floats_From_Console is
Val : Float;
Sum : Float := 0.0;
N : Integer := 0;
begin
Put_Line("Enter float values, one per line. Press CTRL-D when done.");
Read_Loop:
loop
exit Read_Loop when End_Of_File;
begin
Ada.Float_Text_IO.Get (Val);
exception
when Data_Error =>
Put_Line ("ERROR: Invalid float format");
exit Read_Loop;
end;
Put ("Read value = ");
Ada.Float_Text_IO.Put (Val);
Put (", ");
Ada.Float_Text_IO.Put (Val, Fore => 3, Exp => 0);
Put (", ");
Ada.Float_Text_IO.Put (Val, Aft => 2, Exp => 0);
New_Line;
Sum := Sum + Val;
N := N + 1;
end loop Read_Loop;
Put_Line ("Number of values = " & Integer'Image(N));
Put ("Sum of values = ");
Ada.Float_Text_IO.Put (Sum, Exp => 0);
New_Line;
end Read_Floats_From_Console;
end FloatGet;
Contents of mainfile.adb:
-- mainfile.adb
--
-- Main program calls FloatGet.Read_Floats_From_Console
--
-- Compilation: gnatmake floatget mainfile
--
-- Usage: ./mainfile
--
with FloatGet;
procedure MainFile is
begin
FloatGet.Read_Floats_From_Console;
end MainFile;
How to compile it... (tested with gnat 4.8.4, 4.9.3, 5.2.0 on Ubuntu 14.04)
$ gnatmake floatget mainfile
Sample run illustrating several valid float values...
$ ./mainfile
Enter float values, one per line. Press CTRL-D when done.
1
Read value = 1.00000E+00, 1.00000, 1.00
-1
Read value = -1.00000E+00, -1.00000, -1.00
42
Read value = 4.20000E+01, 42.00000, 42.00
-42
Read value = -4.20000E+01, -42.00000, -42.00
.3
Read value = 3.00000E-01, 0.30000, 0.30
-.3
Read value = -3.00000E-01, -0.30000, -0.30
2.0e3
Read value = 2.00000E+03, 2000.00000, 2000.00
-2.0e3
Read value = -2.00000E+03, -2000.00000, -2000.00
-16#1C.#e-1
Read value = -1.75000E+00, -1.75000, -1.75
2#.11#e6
Read value = 4.80000E+01, 48.00000, 48.00
... Press CTRL-D here ...
Number of values = 10
Sum of values = 46.25000
This example doesn't rely upon anything gnat-specific so should work with any Ada 95 compiler although I have no way to test with other compilers besides gnat presently.
EDIT Simplified to only read from console instead per OP's request.
There are two alternatives: wrap the procedure or rename it.
with Ada.Text_IO;
with Ada.Float_Text_IO;
procedure Main is
package My_Float_Text_IO is
procedure Get_1 (Item : out Float; Width : Ada.Text_IO.Field := 0);
procedure Get_2 (Item : out Float; Width : Ada.Text_IO.Field := 0) renames Ada.Float_Text_IO.Get;
end;
package body My_Float_Text_IO is
procedure Get_1 (Item : out Float; Width : Ada.Text_IO.Field := 0) is
begin
Ada.Float_Text_IO.Get (Item, Width);
end;
end;
F : Float;
begin
My_Float_Text_IO.Get_1 (F);
My_Float_Text_IO.Get_2 (F);
end;
Put specification code into .ads files and body cody (implementation code) into .adb files.
You can also just put one procedure or function in .ads and .adb file without package. You can also have a specification package without body package.

Fixed point type not multiplying correctly

I'm new to Ada, and have been trying out the fixed-point "delta" types. Specifically, I've created a 32-bit delta type range 0.0 .. 1.0. However, when I try to square certain values, I get a CONSTRAINT_ERROR. As far as I know, that should't happen with my specified range. The threshold for this error appears to be sqrt(1/2). I'm using GNAT from MinGW-w64 version 4.8.0.
Test code (all of it compiles in the form of gnatmake <file> with no warnings/errors):
types.ads:
pragma Ada_2012;
with Ada.Unchecked_Conversion;
with Ada.Text_IO;
package Types is
type Fixed_Type is delta 1.0 / 2**32 range 0.0 .. 1.0
with Size => 32;
type Modular_Type is mod 2**32
with Size => 32;
function Fixed_To_Mod is new Ada.Unchecked_Conversion(Fixed_Type, Modular_Type);
package MIO is new Ada.Text_IO.Modular_IO(Modular_Type);
package FIO is new Ada.Text_IO.Fixed_IO(Fixed_Type);
end Types;
specifics.adb:
pragma Ada_2012;
with Ada.Text_IO;
with Types; use Types;
procedure Specifics is
package TIO renames Ada.Text_IO;
procedure TestValue(val: in Fixed_Type) is
square : Fixed_Type;
begin
square := val * val;
TIO.Put_Line("Value " & Fixed_Type'Image(val) & " squares properly.");
TIO.Put_Line("Square: " & Fixed_Type'Image(square));
TIO.New_Line;
exception
when Constraint_Error =>
TIO.Put_Line("Value " & Fixed_Type'Image(val) & " does not square properly.");
TIO.Put_Line("Square: " & Fixed_Type'Image(val * val));
TIO.Put_Line("Not sure how that worked.");
TIO.New_Line;
end TestValue;
function ParseFixed(s: in String; last: in Natural; val: out Fixed_Type) return Boolean is
l : Natural;
begin
FIO.Get(s(s'First..last), val, l);
return TRUE;
exception
when others =>
TIO.Put_Line("Parsing failed.");
return FALSE;
end ParseFixed;
buffer : String(1..20);
last : Natural;
f : Fixed_Type;
begin
loop
TIO.Put(">>> ");
TIO.Get_Line(buffer, last);
exit when buffer(1..last) = "quit";
if ParseFixed(buffer, last, f) then
TestValue(f);
end if;
end loop;
end Specifics;
Output of specifics.adb:
>>> 0.1
Value 0.1000000001 squares properly.
Square: 0.0100000000
>>> 0.2
Value 0.2000000000 squares properly.
Square: 0.0399999998
>>> 0.4
Value 0.3999999999 squares properly.
Square: 0.1599999999
>>> 0.6
Value 0.6000000001 squares properly.
Square: 0.3600000001
>>> 0.7
Value 0.7000000000 squares properly.
Square: 0.4899999998
>>> 0.75
Value 0.7500000000 does not square properly.
Square: -0.4375000000
Not sure how that worked.
>>> quit
Somehow, multiplying val by itself yielded a negative number, which explains the CONSTRAINT_ERROR... but never mind that, why am I getting a negative number in the first place?
I then decided to test for the point at which squaring the numbers started failing, so I wrote the following snippet:
fixedpointtest.adb:
pragma Ada_2012;
with Ada.Text_IO;
with Types; use Types;
procedure FixedPointTest is
package TIO renames Ada.Text_IO;
test, square : Fixed_Type := 0.0;
begin
while test /= Fixed_Type'Last loop
square := test * test;
test := test + Fixed_Type'Delta;
end loop;
exception
when Constraint_Error =>
TIO.Put_Line("Last valid value: " & Fixed_Type'Image(test-Fixed_Type'Delta));
TIO.Put("Hex value: ");
MIO.Put(Item => Fixed_To_Mod(test-Fixed_Type'Delta), Base => 16);
TIO.New_Line;
TIO.Put("Binary value: ");
MIO.Put(Item => Fixed_To_Mod(test-Fixed_Type'Delta), Base => 2);
TIO.New_Line;
TIO.New_Line;
TIO.Put_Line("First invalid value: " & Fixed_Type'Image(test));
TIO.Put("Hex value: ");
MIO.Put(Item => Fixed_To_Mod(test), Base => 16);
TIO.New_Line;
TIO.Put("Binary value: ");
MIO.Put(Item => Fixed_To_Mod(test), Base => 2);
TIO.New_Line;
TIO.New_Line;
end FixedPointTest;
and got the following output:
Last valid value: 0.7071067810
Hex value: 16#B504F333#
Binary value: 2#10110101000001001111001100110011#
First invalid value: 0.7071067812
Hex value: 16#B504F334#
Binary value: 2#10110101000001001111001100110100#
So, sqrt(1/2), we meet again. Could someone please explain to me why my code is doing this? Is there a way to make it multiply properly?
I think you are asking for 1 more bit of precision than is actually available "under the hood".
Your declaration
type Fixed_Type is delta 1.0 / 2**32 range 0.0 .. 1.0
with Size => 32;
is only accepted because GNAT has used a biased representation; there's no room for a sign bit. You can see this because 0.7071067810 is represented as 16#B504F333#, with the most significant bit set. So, when you multiply 0.71 by 0.71, the result has the most significant bit set; and the low-level code thinks that this must be the sign bit, so we have an overflow.
If you declare Fixed_Type as
type Fixed_Type is delta 1.0 / 2**31 range 0.0 .. 1.0
with Size => 32;
all should be well.
A further point: in your report of the behaviour of specifics with an input of 0.75, you quote the result
>>> 0.75
Value 0.7500000000 does not square properly.
Square: -0.4375000000
Not sure how that worked.
I rebuilt with gnatmake specifics.adb -g -gnato -bargs -E, and the result is now
>>> 0.75
Value 0.7500000000 does not square properly.
Execution terminated by unhandled exception
Exception name: CONSTRAINT_ERROR
Message: 64-bit arithmetic overflow
Call stack traceback locations:
0x100020b79 0x10000ea80 0x100003520 0x100003912 0x10000143e
and the traceback decodes as
system__arith_64__raise_error (in specifics) (s-arit64.adb:364)
__gnat_mulv64 (in specifics) (s-arit64.adb:318)
specifics__testvalue.2581 (in specifics) (specifics.adb:20) <<<<<<<<<<
_ada_specifics (in specifics) (specifics.adb:45)
main (in specifics) (b~specifics.adb:246)
and specifics.adb:20 is
TIO.Put_Line("Square: " & Fixed_Type'Image(val * val));
in the exception handler, which involves the problematic square again (not a good thing to do in an exception handler). You can see that the value 0.75 was printed without any problem in the line above: and in fixedpointtest.adb there was no problem in the additions leading to the last valid value 0.7071067810.
I was rather surprised to find that -gnato detects this error, since I'd thought it only applied to integer arithmetic; but in fact there's a discussion in the GNAT User Guide which states that it applies to fixed-point arithmetic too. It turns out that you can avoid the constraint error and get the correct arithmetic result by using -gnato3:
>>> 0.75
Value 0.7500000000 squares properly.
Square: 0.5625000000
but only at the cost of using arbitrary multiple-precision arithmetic - not a good idea for a time-constrained system!

Resources