@@ -29,17 +29,41 @@
-- --
------------------------------------------------------------------------------
+-- This package provides tables of powers used for real conversions
package System.Powten_Flt is
pragma Pure;
Maxpow_Exact : constant := 10;
- -- Largest power of ten exactly representable with Float. It is equal to
+ -- Largest power of five exactly representable with Float. It is equal to
-- floor (M * log 2 / log 5), when M is the size of the mantissa (24).
+ -- It also works for any number of the form 5*(2**N) and in particular 10.
Maxpow : constant := Maxpow_Exact * 2;
- -- Largest power of ten exactly representable with a double Float
+ -- Largest power of five exactly representable with double Float
+
+ Powfive : constant array (0 .. Maxpow, 1 .. 2) of Float :=
+ [00 => [5.0**00, 0.0],
+ 01 => [5.0**01, 0.0],
+ 02 => [5.0**02, 0.0],
+ 03 => [5.0**03, 0.0],
+ 04 => [5.0**04, 0.0],
+ 05 => [5.0**05, 0.0],
+ 06 => [5.0**06, 0.0],
+ 07 => [5.0**07, 0.0],
+ 08 => [5.0**08, 0.0],
+ 09 => [5.0**09, 0.0],
+ 10 => [5.0**10, 0.0],
+ 11 => [5.0**11, 5.0**11 - Float'Machine (5.0**11)],
+ 12 => [5.0**12, 5.0**12 - Float'Machine (5.0**12)],
+ 13 => [5.0**13, 5.0**13 - Float'Machine (5.0**13)],
+ 14 => [5.0**14, 5.0**14 - Float'Machine (5.0**14)],
+ 15 => [5.0**15, 5.0**15 - Float'Machine (5.0**15)],
+ 16 => [5.0**16, 5.0**16 - Float'Machine (5.0**16)],
+ 17 => [5.0**17, 5.0**17 - Float'Machine (5.0**17)],
+ 18 => [5.0**18, 5.0**18 - Float'Machine (5.0**18)],
+ 19 => [5.0**19, 5.0**19 - Float'Machine (5.0**19)],
+ 20 => [5.0**20, 5.0**20 - Float'Machine (5.0**20)]];
Powten : constant array (0 .. Maxpow, 1 .. 2) of Float :=
[00 => [1.0E+00, 0.0],
@@ -29,17 +29,74 @@
-- --
------------------------------------------------------------------------------
+-- This package provides tables of powers used for real conversions
package System.Powten_LFlt is
pragma Pure;
Maxpow_Exact : constant := 22;
- -- Largest power of ten exactly representable with Long_Float. It is equal
+ -- Largest power of five exactly representable with Long_Float. It is equal
-- to floor (M * log 2 / log 5), when M is the size of the mantissa (53).
+ -- It also works for any number of the form 5*(2**N) and in particular 10.
Maxpow : constant := Maxpow_Exact * 2;
- -- Largest power of ten exactly representable with a double Long_Float
+ -- Largest power of five exactly representable with double Long_Float
+
+ Powfive : constant array (0 .. Maxpow, 1 .. 2) of Long_Float :=
+ [00 => [5.0**00, 0.0],
+ 01 => [5.0**01, 0.0],
+ 02 => [5.0**02, 0.0],
+ 03 => [5.0**03, 0.0],
+ 04 => [5.0**04, 0.0],
+ 05 => [5.0**05, 0.0],
+ 06 => [5.0**06, 0.0],
+ 07 => [5.0**07, 0.0],
+ 08 => [5.0**08, 0.0],
+ 09 => [5.0**09, 0.0],
+ 10 => [5.0**10, 0.0],
+ 11 => [5.0**11, 0.0],
+ 12 => [5.0**12, 0.0],
+ 13 => [5.0**13, 0.0],
+ 14 => [5.0**14, 0.0],
+ 15 => [5.0**15, 0.0],
+ 16 => [5.0**16, 0.0],
+ 17 => [5.0**17, 0.0],
+ 18 => [5.0**18, 0.0],
+ 19 => [5.0**19, 0.0],
+ 20 => [5.0**20, 0.0],
+ 21 => [5.0**21, 0.0],
+ 22 => [5.0**22, 0.0],
+ 23 => [5.0**23, 5.0**23 - Long_Float'Machine (5.0**23)],
+ 24 => [5.0**24, 5.0**24 - Long_Float'Machine (5.0**24)],
+ 25 => [5.0**25, 5.0**25 - Long_Float'Machine (5.0**25)],
+ 26 => [5.0**26, 5.0**26 - Long_Float'Machine (5.0**26)],
+ 27 => [5.0**27, 5.0**27 - Long_Float'Machine (5.0**27)],
+ 28 => [5.0**28, 5.0**28 - Long_Float'Machine (5.0**28)],
+ 29 => [5.0**29, 5.0**29 - Long_Float'Machine (5.0**29)],
+ 30 => [5.0**30, 5.0**30 - Long_Float'Machine (5.0**30)],
+ 31 => [5.0**31, 5.0**31 - Long_Float'Machine (5.0**31)],
+ 32 => [5.0**32, 5.0**32 - Long_Float'Machine (5.0**32)],
+ 33 => [5.0**33, 5.0**33 - Long_Float'Machine (5.0**33)],
+ 34 => [5.0**34, 5.0**34 - Long_Float'Machine (5.0**34)],
+ 35 => [5.0**35, 5.0**35 - Long_Float'Machine (5.0**35)],
+ 36 => [5.0**36, 5.0**36 - Long_Float'Machine (5.0**36)],
+ 37 => [5.0**37, 5.0**37 - Long_Float'Machine (5.0**37)],
+ 38 => [5.0**38, 5.0**38 - Long_Float'Machine (5.0**38)],
+ 39 => [5.0**39, 5.0**39 - Long_Float'Machine (5.0**39)],
+ 40 => [5.0**40, 5.0**40 - Long_Float'Machine (5.0**40)],
+ 41 => [5.0**41, 5.0**41 - Long_Float'Machine (5.0**41)],
+ 42 => [5.0**42, 5.0**42 - Long_Float'Machine (5.0**42)],
+ 43 => [5.0**43, 5.0**43 - Long_Float'Machine (5.0**43)],
+ 44 => [5.0**44, 5.0**44 - Long_Float'Machine (5.0**44)]];
+
+ Powfive_100 : constant array (1 .. 2) of Long_Float :=
+ [5.0**100, 5.0**100 - Long_Float'Machine (5.0**100)];
+
+ Powfive_200 : constant array (1 .. 2) of Long_Float :=
+ [5.0**200, 5.0**200 - Long_Float'Machine (5.0**200)];
+
+ Powfive_300 : constant array (1 .. 2) of Long_Float :=
+ [5.0**300, 5.0**300 - Long_Float'Machine (5.0**300)];
Powten : constant array (0 .. Maxpow, 1 .. 2) of Long_Float :=
[00 => [1.0E+00, 0.0],
@@ -29,19 +29,86 @@
-- --
------------------------------------------------------------------------------
+-- This package provides tables of powers used for real conversions
package System.Powten_LLF is
pragma Pure;
Maxpow_Exact : constant :=
(if Long_Long_Float'Machine_Mantissa = 64 then 27 else 22);
- -- Largest power of ten exactly representable with Long_Long_Float. It is
+ -- Largest power of five exactly representable with Long_Long_Float. It is
-- equal to floor (M * log 2 / log 5), when M is the size of the mantissa
-- assumed to be either 64 for IEEE Extended or 53 for IEEE Double.
+ -- It also works for any number of the form 5*(2**N) and in particular 10.
Maxpow : constant := Maxpow_Exact * 2;
- -- Largest power of ten exactly representable with a double Long_Long_Float
+ -- Largest power of five exactly representable with double Long_Long_Float
+
+ Powfive : constant array (0 .. 54, 1 .. 2) of Long_Long_Float :=
+ [00 => [5.0**00, 0.0],
+ 01 => [5.0**01, 0.0],
+ 02 => [5.0**02, 0.0],
+ 03 => [5.0**03, 0.0],
+ 04 => [5.0**04, 0.0],
+ 05 => [5.0**05, 0.0],
+ 06 => [5.0**06, 0.0],
+ 07 => [5.0**07, 0.0],
+ 08 => [5.0**08, 0.0],
+ 09 => [5.0**09, 0.0],
+ 10 => [5.0**10, 0.0],
+ 11 => [5.0**11, 0.0],
+ 12 => [5.0**12, 0.0],
+ 13 => [5.0**13, 0.0],
+ 14 => [5.0**14, 0.0],
+ 15 => [5.0**15, 0.0],
+ 16 => [5.0**16, 0.0],
+ 17 => [5.0**17, 0.0],
+ 18 => [5.0**18, 0.0],
+ 19 => [5.0**19, 0.0],
+ 20 => [5.0**20, 0.0],
+ 21 => [5.0**21, 0.0],
+ 22 => [5.0**22, 0.0],
+ 23 => [5.0**23, 5.0**23 - Long_Long_Float'Machine (5.0**23)],
+ 24 => [5.0**24, 5.0**24 - Long_Long_Float'Machine (5.0**24)],
+ 25 => [5.0**25, 5.0**25 - Long_Long_Float'Machine (5.0**25)],
+ 26 => [5.0**26, 5.0**26 - Long_Long_Float'Machine (5.0**26)],
+ 27 => [5.0**27, 5.0**27 - Long_Long_Float'Machine (5.0**27)],
+ 28 => [5.0**28, 5.0**28 - Long_Long_Float'Machine (5.0**28)],
+ 29 => [5.0**29, 5.0**29 - Long_Long_Float'Machine (5.0**29)],
+ 30 => [5.0**30, 5.0**30 - Long_Long_Float'Machine (5.0**30)],
+ 31 => [5.0**31, 5.0**31 - Long_Long_Float'Machine (5.0**31)],
+ 32 => [5.0**32, 5.0**32 - Long_Long_Float'Machine (5.0**32)],
+ 33 => [5.0**33, 5.0**33 - Long_Long_Float'Machine (5.0**33)],
+ 34 => [5.0**34, 5.0**34 - Long_Long_Float'Machine (5.0**34)],
+ 35 => [5.0**35, 5.0**35 - Long_Long_Float'Machine (5.0**35)],
+ 36 => [5.0**36, 5.0**36 - Long_Long_Float'Machine (5.0**36)],
+ 37 => [5.0**37, 5.0**37 - Long_Long_Float'Machine (5.0**37)],
+ 38 => [5.0**38, 5.0**38 - Long_Long_Float'Machine (5.0**38)],
+ 39 => [5.0**39, 5.0**39 - Long_Long_Float'Machine (5.0**39)],
+ 40 => [5.0**40, 5.0**40 - Long_Long_Float'Machine (5.0**40)],
+ 41 => [5.0**41, 5.0**41 - Long_Long_Float'Machine (5.0**41)],
+ 42 => [5.0**42, 5.0**42 - Long_Long_Float'Machine (5.0**42)],
+ 43 => [5.0**43, 5.0**43 - Long_Long_Float'Machine (5.0**43)],
+ 44 => [5.0**44, 5.0**44 - Long_Long_Float'Machine (5.0**44)],
+ 45 => [5.0**45, 5.0**45 - Long_Long_Float'Machine (5.0**45)],
+ 46 => [5.0**46, 5.0**46 - Long_Long_Float'Machine (5.0**46)],
+ 47 => [5.0**47, 5.0**47 - Long_Long_Float'Machine (5.0**47)],
+ 48 => [5.0**48, 5.0**48 - Long_Long_Float'Machine (5.0**48)],
+ 49 => [5.0**49, 5.0**49 - Long_Long_Float'Machine (5.0**49)],
+ 50 => [5.0**50, 5.0**50 - Long_Long_Float'Machine (5.0**50)],
+ 51 => [5.0**51, 5.0**51 - Long_Long_Float'Machine (5.0**51)],
+ 52 => [5.0**52, 5.0**52 - Long_Long_Float'Machine (5.0**52)],
+ 53 => [5.0**53, 5.0**53 - Long_Long_Float'Machine (5.0**53)],
+ 54 => [5.0**54, 5.0**54 - Long_Long_Float'Machine (5.0**54)]];
+
+ Powfive_100 : constant array (1 .. 2) of Long_Long_Float :=
+ [5.0**100, 5.0**100 - Long_Long_Float'Machine (5.0**100)];
+
+ Powfive_200 : constant array (1 .. 2) of Long_Long_Float :=
+ [5.0**200, 5.0**200 - Long_Long_Float'Machine (5.0**200)];
+
+ Powfive_300 : constant array (1 .. 2) of Long_Long_Float :=
+ [5.0**300, 5.0**300 - Long_Long_Float'Machine (5.0**300)];
Powten : constant array (0 .. 54, 1 .. 2) of Long_Long_Float :=
[00 => [1.0E+00, 0.0],
@@ -42,7 +42,10 @@ package System.Val_Flt is
package Impl is new Val_Real
(Float,
System.Powten_Flt.Maxpow,
- System.Powten_Flt.Powten'Address,
+ System.Powten_Flt.Powfive'Address,
+ System.Null_Address,
+ System.Null_Address,
+ System.Null_Address,
Unsigned_Types.Unsigned);
function Scan_Float
@@ -42,7 +42,10 @@ package System.Val_LFlt is
package Impl is new Val_Real
(Long_Float,
System.Powten_LFlt.Maxpow,
- System.Powten_LFlt.Powten'Address,
+ System.Powten_LFlt.Powfive'Address,
+ System.Powten_LFlt.Powfive_100'Address,
+ System.Powten_LFlt.Powfive_200'Address,
+ System.Powten_LFlt.Powfive_300'Address,
Unsigned_Types.Long_Long_Unsigned);
function Scan_Long_Float
@@ -42,7 +42,10 @@ package System.Val_LLF is
package Impl is new Val_Real
(Long_Long_Float,
System.Powten_LLF.Maxpow,
- System.Powten_LLF.Powten'Address,
+ System.Powten_LLF.Powfive'Address,
+ System.Powten_LLF.Powfive_100'Address,
+ System.Powten_LLF.Powfive_200'Address,
+ System.Powten_LLF.Powfive_300'Address,
System.Unsigned_Types.Long_Long_Unsigned);
function Scan_Long_Long_Float
@@ -43,7 +43,11 @@ package body System.Val_Real is
pragma Assert (Num'Machine_Mantissa <= Uns'Size);
-- We need an unsigned type large enough to represent the mantissa
+ Is_Large_Type : constant Boolean := Num'Machine_Mantissa >= 53;
+ -- True if the floating-point type is at least IEEE Double
+
Precision_Limit : constant Uns := 2**Num'Machine_Mantissa - 1;
+ -- See below for the rationale
package Impl is new Value_R (Uns, 2, Precision_Limit, Round => False);
@@ -55,18 +59,21 @@ package body System.Val_Real is
Maxexp32 : constant array (Base_T) of Positive :=
[2 => 127, 3 => 80, 4 => 63, 5 => 55, 6 => 49,
- 7 => 45, 8 => 42, 9 => 40, 10 => 38, 11 => 37,
+ 7 => 45, 8 => 42, 9 => 40, 10 => 55, 11 => 37,
12 => 35, 13 => 34, 14 => 33, 15 => 32, 16 => 31];
+ -- The actual value for 10 is 38 but we also use scaling for 10
Maxexp64 : constant array (Base_T) of Positive :=
[2 => 1023, 3 => 646, 4 => 511, 5 => 441, 6 => 396,
- 7 => 364, 8 => 341, 9 => 323, 10 => 308, 11 => 296,
+ 7 => 364, 8 => 341, 9 => 323, 10 => 441, 11 => 296,
12 => 285, 13 => 276, 14 => 268, 15 => 262, 16 => 255];
+ -- The actual value for 10 is 308 but we also use scaling for 10
Maxexp80 : constant array (Base_T) of Positive :=
[2 => 16383, 3 => 10337, 4 => 8191, 5 => 7056, 6 => 6338,
- 7 => 5836, 8 => 5461, 9 => 5168, 10 => 4932, 11 => 4736,
+ 7 => 5836, 8 => 5461, 9 => 5168, 10 => 7056, 11 => 4736,
12 => 4570, 13 => 4427, 14 => 4303, 15 => 4193, 16 => 4095];
+ -- The actual value for 10 is 4932 but we also use scaling for 10
package Double_Real is new System.Double_Real (Num);
use type Double_Real.Double_T;
@@ -91,8 +98,11 @@ package body System.Val_Real is
Minus : Boolean) return Num;
-- Convert the real value from integer to real representation
- function Large_Powten (Exp : Natural) return Double_T;
- -- Return 10.0**Exp as a double number, where Exp > Maxpow
+ function Large_Powfive (Exp : Natural) return Double_T;
+ -- Return 5.0**Exp as a double number, where Exp > Maxpow
+
+ function Large_Powfive (Exp : Natural; S : out Natural) return Double_T;
+ -- Return Num'Scaling (5.0**Exp, -S) as a double number where Exp > Maxexp
---------------------
-- Integer_to_Real --
@@ -177,13 +187,13 @@ package body System.Val_Real is
when 10 =>
declare
- Powten : constant array (0 .. Maxpow) of Double_T;
- pragma Import (Ada, Powten);
- for Powten'Address use Powten_Address;
+ Powfive : constant array (0 .. Maxpow) of Double_T;
+ pragma Import (Ada, Powfive);
+ for Powfive'Address use Powfive_Address;
begin
if DS <= Maxpow then
- D_Val := Powten (DS) * V1 + V2;
+ D_Val := Powfive (DS) * Num'Scaling (V1, DS) + V2;
S := Scale (2);
else
@@ -224,43 +234,46 @@ package body System.Val_Real is
R_Val := Num'Scaling (Double_Real.To_Single (D_Val), S);
end;
- -- If the base is 10, use a double implementation for the sake
- -- of accuracy, to be removed when exponentiation is improved.
-
- -- When the exponent is positive, we can do the computation
- -- directly because, if the exponentiation overflows, then
- -- the final value overflows as well. But when the exponent
- -- is negative, we may need to do it in two steps to avoid
- -- an artificial underflow.
+ -- If the base is 10, we use a double implementation for the sake
+ -- of accuracy combining powers of 5 and scaling attribute. Using
+ -- this combination is better than using powers of 10 only because
+ -- the Large_Powfive function may overflow only if the final value
+ -- will also either overflow or underflow, thus making it possible
+ -- to use a single division for the case of negative powers of 10.
when 10 =>
declare
- Powten : constant array (0 .. Maxpow) of Double_T;
- pragma Import (Ada, Powten);
- for Powten'Address use Powten_Address;
+ Powfive : constant array (0 .. Maxpow) of Double_T;
+ pragma Import (Ada, Powfive);
+ for Powfive'Address use Powfive_Address;
+
+ RS : Natural;
begin
if S > 0 then
if S <= Maxpow then
- D_Val := D_Val * Powten (S);
+ D_Val := D_Val * Powfive (S);
else
- D_Val := D_Val * Large_Powten (S);
+ D_Val := D_Val * Large_Powfive (S);
end if;
else
- if S < -Maxexp then
- D_Val := D_Val / Large_Powten (Maxexp);
- S := S + Maxexp;
- end if;
-
if S >= -Maxpow then
- D_Val := D_Val / Powten (-S);
+ D_Val := D_Val / Powfive (-S);
+
+ -- For small types, typically IEEE Single, the trick
+ -- described above does not fully work.
+
+ elsif not Is_Large_Type and then S < -Maxexp then
+ D_Val := D_Val / Large_Powfive (-S, RS);
+ S := S - RS;
+
else
- D_Val := D_Val / Large_Powten (-S);
+ D_Val := D_Val / Large_Powfive (-S);
end if;
end if;
- R_Val := Double_Real.To_Single (D_Val);
+ R_Val := Num'Scaling (Double_Real.To_Single (D_Val), S);
end;
-- Implementation for other bases with exponentiation
@@ -302,14 +315,26 @@ package body System.Val_Real is
when Constraint_Error => Bad_Value (Str);
end Integer_to_Real;
- ------------------
- -- Large_Powten --
- ------------------
+ -------------------
+ -- Large_Powfive --
+ -------------------
- function Large_Powten (Exp : Natural) return Double_T is
- Powten : constant array (0 .. Maxpow) of Double_T;
- pragma Import (Ada, Powten);
- for Powten'Address use Powten_Address;
+ function Large_Powfive (Exp : Natural) return Double_T is
+ Powfive : constant array (0 .. Maxpow) of Double_T;
+ pragma Import (Ada, Powfive);
+ for Powfive'Address use Powfive_Address;
+
+ Powfive_100 : constant Double_T;
+ pragma Import (Ada, Powfive_100);
+ for Powfive_100'Address use Powfive_100_Address;
+
+ Powfive_200 : constant Double_T;
+ pragma Import (Ada, Powfive_200);
+ for Powfive_200'Address use Powfive_200_Address;
+
+ Powfive_300 : constant Double_T;
+ pragma Import (Ada, Powfive_300);
+ for Powfive_300'Address use Powfive_300_Address;
R : Double_T;
E : Natural;
@@ -317,18 +342,80 @@ package body System.Val_Real is
begin
pragma Assert (Exp > Maxpow);
- R := Powten (Maxpow);
+ if Is_Large_Type and then Exp >= 300 then
+ R := Powfive_300;
+ E := Exp - 300;
+
+ elsif Is_Large_Type and then Exp >= 200 then
+ R := Powfive_200;
+ E := Exp - 200;
+
+ elsif Is_Large_Type and then Exp >= 100 then
+ R := Powfive_100;
+ E := Exp - 100;
+
+ else
+ R := Powfive (Maxpow);
+ E := Exp - Maxpow;
+ end if;
+
+ while E > Maxpow loop
+ R := R * Powfive (Maxpow);
+ E := E - Maxpow;
+ end loop;
+
+ R := R * Powfive (E);
+
+ return R;
+ end Large_Powfive;
+
+ function Large_Powfive (Exp : Natural; S : out Natural) return Double_T is
+ Maxexp : constant Positive :=
+ (if Num'Size = 32 then Maxexp32 (5)
+ elsif Num'Size = 64 then Maxexp64 (5)
+ elsif Num'Machine_Mantissa = 64 then Maxexp80 (5)
+ else raise Program_Error);
+ -- Maximum exponent of 5 that can fit in Num
+
+ Powfive : constant array (0 .. Maxpow) of Double_T;
+ pragma Import (Ada, Powfive);
+ for Powfive'Address use Powfive_Address;
+
+ R : Double_T;
+ E : Natural;
+
+ begin
+ pragma Assert (Exp > Maxexp);
+
+ pragma Warnings (Off, "-gnatw.a");
+ pragma Assert (not Is_Large_Type);
+ pragma Warnings (On, "-gnatw.a");
+
+ R := Powfive (Maxpow);
E := Exp - Maxpow;
+ -- If the exponent is not too large, then scale down the result so that
+ -- its final value does not overflow but, if it's too large, then do not
+ -- bother doing it since overflow is just fine. The scaling factor is -3
+ -- for every power of 5 above the maximum, in other words division by 8.
+
+ if Exp - Maxexp <= Maxpow then
+ S := 3 * (Exp - Maxexp);
+ R.Hi := Num'Scaling (R.Hi, -S);
+ R.Lo := Num'Scaling (R.Lo, -S);
+ else
+ S := 0;
+ end if;
+
while E > Maxpow loop
- R := R * Powten (Maxpow);
+ R := R * Powfive (Maxpow);
E := E - Maxpow;
end loop;
- R := R * Powten (E);
+ R := R * Powfive (E);
return R;
- end Large_Powten;
+ end Large_Powfive;
---------------
-- Scan_Real --
@@ -38,7 +38,13 @@ generic
Maxpow : Positive;
- Powten_Address : System.Address;
+ Powfive_Address : System.Address;
+
+ Powfive_100_Address : System.Address;
+
+ Powfive_200_Address : System.Address;
+
+ Powfive_300_Address : System.Address;
type Uns is mod <>;