* [Ada] Correctly round Value attribute for floating point in more cases
@ 2022-09-06 7:15 Marc Poulhiès
0 siblings, 0 replies; 2+ messages in thread
From: Marc Poulhiès @ 2022-09-06 7:15 UTC (permalink / raw)
To: gcc-patches; +Cc: Eric Botcazou
[-- Attachment #1: Type: text/plain, Size: 1675 bytes --]
This provides correct rounding in the IEEE 754 sense for the Value attribute
of floating-point types in more cases, by switching from tables of powers of
10 to tables of powers of 5 for precomputed values, thus making it possible
to use a single divide for denormals and normalized numbers just above them.
Although this significantly increases the size of the tables, object files
for them are still quite small (1, 2 and 4 KB respectively on x86-64).
Tested on x86_64-pc-linux-gnu, committed on trunk
gcc/ada/
* libgnat/s-powflt.ads (Powfive): New constant array.
* libgnat/s-powlfl.ads (Powfive): Likewise.
(Powfive_100): New constant.
(Powfive_200): Likewise.
(Powfive_300): Likewise.
* libgnat/s-powllf.ads (Powfive): New constant array.
(Powfive_100): New constant.
(Powfive_200): Likewise.
(Powfive_300): Likewise.
* libgnat/s-valflt.ads (Impl): Replace Powten with Powfive and pass
Null_Address for the address of large constants.
* libgnat/s-vallfl.ads (Impl): Replace Powten with Powfive and pass
the address of large constants.
* libgnat/s-valllf.ads (Impl): Likewise.
* libgnat/s-valrea.ads (System.Val_Real): Replace Powten_Address
with Powfive_Address and add Powfive_{1,2,3}00_Address parameters.
* libgnat/s-valrea.adb (Is_Large_Type): New boolean constant.
(Is_Very_Large_Type): Likewise.
(Maxexp32): Change value of 10 to that of 5.
(Maxexp64): Likewise.
(Maxexp80): Likewise.
(Integer_to_Real): Use a combination of tables of powers of 5 and
scaling if the base is 10.
(Large_Powten): Rename into...
(Large_Powfive): ...this. Add support for large constants.
(Large_Powfive): New overloaded function for very large exponents.
[-- Attachment #2: patch.diff --]
[-- Type: text/x-diff, Size: 22434 bytes --]
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 <>;
^ permalink raw reply [flat|nested] 2+ messages in thread
* [Ada] Correctly round Value attribute for floating point in more cases
@ 2022-09-06 7:15 Marc Poulhiès
0 siblings, 0 replies; 2+ messages in thread
From: Marc Poulhiès @ 2022-09-06 7:15 UTC (permalink / raw)
To: gcc-patches; +Cc: Eric Botcazou
[-- Attachment #1: Type: text/plain, Size: 1494 bytes --]
This provides correct rounding in the IEEE 754 sense for the Value attribute
of floating-point types in more cases, by bumping the number of significant
bits used in the initial integer mantissa obtained from parsing.
Tested on x86_64-pc-linux-gnu, committed on trunk
gcc/ada/
* libgnat/s-valuer.ads (System.Value_R): Add Parts formal parameter
as well as Data_Index, Scale_Array and Value_Array types.
(Scan_Raw_Real): Change type of Scale and return type.
(Value_Raw_Real): Likewise.
* libgnat/s-valuer.adb (Round_Extra): Reorder parameters and adjust
recursive call.
(Scan_Decimal_Digits): Reorder parameters, add N parameter and deal
with multi-part scale and value.
(Scan_Integral_Digits): Likewise.
(Scan_Raw_Real): Change type of Scale and return type and deal with
multi-part scale and value.
(Value_Raw_Real): Change type of Scale and return type and tidy up.
* libgnat/s-valued.adb (Impl): Pass 1 as Parts actual parameter.
(Scan_Decimal): Adjust to type changes.
(Value_Decimal): Likewise.
* libgnat/s-valuef.adb (Impl): Pass 1 as Parts actual parameter.
(Scan_Fixed): Adjust to type changes.
(Value_Fixed): Likewise.
* libgnat/s-valrea.adb (Need_Extra): Delete.
(Precision_Limit): Always use the precision of the mantissa.
(Impl): Pass 2 as Parts actual parameter.
(Exact_Log2): New expression function.
(Integer_to_Real): Change type of Scale and Val and deal with a
2-part integer mantissa.
(Scan_Real): Adjust to type changes.
(Value_Real): Likewise.
[-- Attachment #2: patch.diff.gz --]
[-- Type: application/gzip, Size: 6647 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2022-09-06 7:15 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-06 7:15 [Ada] Correctly round Value attribute for floating point in more cases Marc Poulhiès
-- strict thread matches above, loose matches on Subject: below --
2022-09-06 7:15 Marc Poulhiès
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).