I am new to Ada and have tried fixed-point delta types. In particular, I created a 32-bit range of delta 0.0 .. 1.0. However, when I try to determine specific values, I get CONSTRAINT_ERROR. As far as I know, this should not happen with my specified range. The threshold for this error looks like sqrt(1/2) . I am using GNAT from MinGW-w64 version 4.8.0.
Test code (all this compiles as gnatmake <file> without 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 specific .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, val multiplication itself gave a negative number, which explains CONSTRAINT_ERROR ... but it doesn't matter why I get the negative number in the first place?
Then I decided to test the point where squaring the numbers started with an error, 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. Can someone explain to me why my code does this? Is there a way to make this a multiplication right?