diff --git a/gcc/ada/libgnat/s-powflt.ads b/gcc/ada/libgnat/s-powflt.ads --- a/gcc/ada/libgnat/s-powflt.ads +++ b/gcc/ada/libgnat/s-powflt.ads @@ -29,17 +29,41 @@ -- -- ------------------------------------------------------------------------------ --- This package provides a powers of ten table used for real conversions +-- 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], diff --git a/gcc/ada/libgnat/s-powlfl.ads b/gcc/ada/libgnat/s-powlfl.ads --- a/gcc/ada/libgnat/s-powlfl.ads +++ b/gcc/ada/libgnat/s-powlfl.ads @@ -29,17 +29,74 @@ -- -- ------------------------------------------------------------------------------ --- This package provides a powers of ten table used for real conversions +-- 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], diff --git a/gcc/ada/libgnat/s-powllf.ads b/gcc/ada/libgnat/s-powllf.ads --- a/gcc/ada/libgnat/s-powllf.ads +++ b/gcc/ada/libgnat/s-powllf.ads @@ -29,19 +29,86 @@ -- -- ------------------------------------------------------------------------------ --- This package provides a powers of ten table used for real conversions +-- 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], diff --git a/gcc/ada/libgnat/s-valflt.ads b/gcc/ada/libgnat/s-valflt.ads --- a/gcc/ada/libgnat/s-valflt.ads +++ b/gcc/ada/libgnat/s-valflt.ads @@ -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 diff --git a/gcc/ada/libgnat/s-vallfl.ads b/gcc/ada/libgnat/s-vallfl.ads --- a/gcc/ada/libgnat/s-vallfl.ads +++ b/gcc/ada/libgnat/s-vallfl.ads @@ -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 diff --git a/gcc/ada/libgnat/s-valllf.ads b/gcc/ada/libgnat/s-valllf.ads --- a/gcc/ada/libgnat/s-valllf.ads +++ b/gcc/ada/libgnat/s-valllf.ads @@ -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 diff --git a/gcc/ada/libgnat/s-valrea.adb b/gcc/ada/libgnat/s-valrea.adb --- a/gcc/ada/libgnat/s-valrea.adb +++ b/gcc/ada/libgnat/s-valrea.adb @@ -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 -- diff --git a/gcc/ada/libgnat/s-valrea.ads b/gcc/ada/libgnat/s-valrea.ads --- a/gcc/ada/libgnat/s-valrea.ads +++ b/gcc/ada/libgnat/s-valrea.ads @@ -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 <>;