aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeert Bosch <bosch@adacore.com>2007-12-13 11:24:08 +0100
committerArnaud Charlet <charlet@gcc.gnu.org>2007-12-13 11:24:08 +0100
commit1937a0c4c8b918c6216a0bd7e8e9b44b210712d0 (patch)
treed31666d1f5ae2a4eb30efba490dfc245e697e3bb
parent987c5cecd034d57ef50e2e93266acd15e693f3e7 (diff)
downloadgcc-1937a0c4c8b918c6216a0bd7e8e9b44b210712d0.zip
gcc-1937a0c4c8b918c6216a0bd7e8e9b44b210712d0.tar.gz
gcc-1937a0c4c8b918c6216a0bd7e8e9b44b210712d0.tar.bz2
eval_fat.adb (Decompose_Int): Handle argument of zero.
2007-12-06 Geert Bosch <bosch@adacore.com> * eval_fat.adb (Decompose_Int): Handle argument of zero. (Compose): Remove special casing of zero. (Exponent): Likewise. (Fraction): Likewise. (Machine): Likewise. (Decompose): Update comment. From-SVN: r130827
-rw-r--r--gcc/ada/eval_fat.adb275
1 files changed, 128 insertions, 147 deletions
diff --git a/gcc/ada/eval_fat.adb b/gcc/ada/eval_fat.adb
index ab5e49f..78dcea6 100644
--- a/gcc/ada/eval_fat.adb
+++ b/gcc/ada/eval_fat.adb
@@ -32,13 +32,13 @@ with Targparm; use Targparm;
package body Eval_Fat is
Radix : constant Int := 2;
- -- This code is currently only correct for the radix 2 case. We use
- -- the symbolic value Radix where possible to help in the unlikely
- -- case of anyone ever having to adjust this code for another value,
- -- and for documentation purposes.
+ -- This code is currently only correct for the radix 2 case. We use the
+ -- symbolic value Radix where possible to help in the unlikely case of
+ -- anyone ever having to adjust this code for another value, and for
+ -- documentation purposes.
- -- Another assumption is that the range of the floating-point type
- -- is symmetric around zero.
+ -- Another assumption is that the range of the floating-point type is
+ -- symmetric around zero.
type Radix_Power_Table is array (Int range 1 .. 4) of Int;
@@ -55,10 +55,9 @@ package body Eval_Fat is
Fraction : out T;
Exponent : out UI;
Mode : Rounding_Mode := Round);
- -- Decomposes a non-zero floating-point number into fraction and
- -- exponent parts. The fraction is in the interval 1.0 / Radix ..
- -- T'Pred (1.0) and uses Rbase = Radix.
- -- The result is rounded to a nearest machine number.
+ -- Decomposes a non-zero floating-point number into fraction and exponent
+ -- parts. The fraction is in the interval 1.0 / Radix .. T'Pred (1.0) and
+ -- uses Rbase = Radix. The result is rounded to a nearest machine number.
procedure Decompose_Int
(RT : R;
@@ -116,12 +115,8 @@ package body Eval_Fat is
Arg_Exp : UI;
pragma Warnings (Off, Arg_Exp);
begin
- if UR_Is_Zero (Fraction) then
- return Fraction;
- else
- Decompose (RT, Fraction, Arg_Frac, Arg_Exp);
- return Scaling (RT, Arg_Frac, Exponent);
- end if;
+ Decompose (RT, Fraction, Arg_Frac, Arg_Exp);
+ return Scaling (RT, Arg_Frac, Exponent);
end Compose;
---------------
@@ -175,10 +170,10 @@ package body Eval_Fat is
-- Decompose_Int --
-------------------
- -- This procedure should be modified with care, as there are many
- -- non-obvious details that may cause problems that are hard to
- -- detect. The cases of positive and negative zeroes are also
- -- special and should be verified separately.
+ -- This procedure should be modified with care, as there are many non-
+ -- obvious details that may cause problems that are hard to detect. For
+ -- zero arguments, Fraction and Exponent are set to zero. Note that sign
+ -- of zero cannot be preserved.
procedure Decompose_Int
(RT : R;
@@ -204,13 +199,19 @@ package body Eval_Fat is
-- intermediate values (this routine generates lots of junk!)
begin
+ if N = Uint_0 then
+ Fraction := Uint_0;
+ Exponent := Uint_0;
+ return;
+ end if;
+
Calculate_D_And_Exponent_1 : begin
Uintp_Mark := Mark;
Exponent := Uint_0;
- -- In cases where Base > 1, the actual denominator is
- -- Base**D. For cases where Base is a power of Radix, use
- -- the value 1 for the Denominator and adjust the exponent.
+ -- In cases where Base > 1, the actual denominator is Base**D. For
+ -- cases where Base is a power of Radix, use the value 1 for the
+ -- Denominator and adjust the exponent.
-- Note: Exponent has different sign from D, because D is a divisor
@@ -230,13 +231,13 @@ package body Eval_Fat is
Calculate_Exponent : begin
Uintp_Mark := Mark;
- -- For bases that are a multiple of the Radix, divide
- -- the base by Radix and adjust the Exponent. This will
- -- help because D will be much smaller and faster to process.
+ -- For bases that are a multiple of the Radix, divide the base by
+ -- Radix and adjust the Exponent. This will help because D will be
+ -- much smaller and faster to process.
- -- This occurs for decimal bases on a machine with binary
- -- floating-point for example. When calculating 1E40,
- -- with Radix = 2, N will be 93 bits instead of 133.
+ -- This occurs for decimal bases on machines with binary floating-
+ -- point for example. When calculating 1E40, with Radix = 2, N
+ -- will be 93 bits instead of 133.
-- N E
-- ------ * Radix
@@ -264,11 +265,10 @@ package body Eval_Fat is
Release_And_Save (Uintp_Mark, Exponent);
end Calculate_Exponent;
- -- For remaining bases we must actually compute
- -- the exponentiation.
+ -- For remaining bases we must actually compute the exponentiation
- -- Because the exponentiation can be negative, and D must
- -- be integer, the numerator is corrected instead.
+ -- Because the exponentiation can be negative, and D must be integer,
+ -- the numerator is corrected instead.
Calculate_N_And_D : begin
Uintp_Mark := Mark;
@@ -286,29 +286,25 @@ package body Eval_Fat is
Base := 0;
end if;
- -- Now scale N and D so that N / D is a value in the
- -- interval [1.0 / Radix, 1.0) and adjust Exponent accordingly,
- -- so the value N / D * Radix ** Exponent remains unchanged.
+ -- Now scale N and D so that N / D is a value in the interval [1.0 /
+ -- Radix, 1.0) and adjust Exponent accordingly, so the value N / D *
+ -- Radix ** Exponent remains unchanged.
-- Step 1 - Adjust N so N / D >= 1 / Radix, or N = 0
-- N and D are positive, so N / D >= 1 / Radix implies N * Radix >= D.
- -- This scaling is not possible for N is Uint_0 as there
- -- is no way to scale Uint_0 so the first digit is non-zero.
+ -- As this scaling is not possible for N is Uint_0, zero is handled
+ -- explicitly at the start of this subprogram.
Calculate_N_And_Exponent : begin
Uintp_Mark := Mark;
N_Times_Radix := N * Radix;
-
- if N /= Uint_0 then
- while not (N_Times_Radix >= D) loop
- N := N_Times_Radix;
- Exponent := Exponent - 1;
-
- N_Times_Radix := N * Radix;
- end loop;
- end if;
+ while not (N_Times_Radix >= D) loop
+ N := N_Times_Radix;
+ Exponent := Exponent - 1;
+ N_Times_Radix := N * Radix;
+ end loop;
Release_And_Save (Uintp_Mark, N, Exponent);
end Calculate_N_And_Exponent;
@@ -322,8 +318,8 @@ package body Eval_Fat is
while not (N < D) loop
- -- As N / D >= 1, N / (D * Radix) will be at least 1 / Radix,
- -- so the result of Step 1 stays valid
+ -- As N / D >= 1, N / (D * Radix) will be at least 1 / Radix, so
+ -- the result of Step 1 stays valid
D := D * Radix;
Exponent := Exponent + 1;
@@ -334,14 +330,14 @@ package body Eval_Fat is
-- Here the value N / D is in the range [1.0 / Radix .. 1.0)
- -- Now find the fraction by doing a very simple-minded
- -- division until enough digits have been computed.
+ -- Now find the fraction by doing a very simple-minded division until
+ -- enough digits have been computed.
- -- This division works for all radices, but is only efficient for
- -- a binary radix. It is just like a manual division algorithm,
- -- but instead of moving the denominator one digit right, we move
- -- the numerator one digit left so the numerator and denominator
- -- remain integral.
+ -- This division works for all radices, but is only efficient for a
+ -- binary radix. It is just like a manual division algorithm, but
+ -- instead of moving the denominator one digit right, we move the
+ -- numerator one digit left so the numerator and denominator remain
+ -- integral.
Fraction := Uint_0;
Even := True;
@@ -380,8 +376,8 @@ package body Eval_Fat is
when Round_Even =>
-- This rounding mode should not be used for static
- -- expressions, but only for compile-time evaluation
- -- of non-static expressions.
+ -- expressions, but only for compile-time evaluation of
+ -- non-static expressions.
if (Even and then N * 2 > D)
or else
@@ -392,9 +388,9 @@ package body Eval_Fat is
when Round =>
- -- Do not round to even as is done with IEEE arithmetic,
- -- but instead round away from zero when the result is
- -- exactly between two machine numbers. See RM 4.9(38).
+ -- Do not round to even as is done with IEEE arithmetic, but
+ -- instead round away from zero when the result is exactly
+ -- between two machine numbers. See RM 4.9(38).
if N * 2 >= D then
Fraction := Fraction + 1;
@@ -411,8 +407,8 @@ package body Eval_Fat is
end if;
end case;
- -- The result must be normalized to [1.0/Radix, 1.0),
- -- so adjust if the result is 1.0 because of rounding.
+ -- The result must be normalized to [1.0/Radix, 1.0), so adjust if
+ -- the result is 1.0 because of rounding.
if Fraction = Most_Significant_Digit * Radix then
Fraction := Most_Significant_Digit;
@@ -438,12 +434,8 @@ package body Eval_Fat is
X_Exp : UI;
pragma Warnings (Off, X_Frac);
begin
- if UR_Is_Zero (X) then
- return Uint_0;
- else
- Decompose_Int (RT, X, X_Frac, X_Exp, Round_Even);
- return X_Exp;
- end if;
+ Decompose_Int (RT, X, X_Frac, X_Exp, Round_Even);
+ return X_Exp;
end Exponent;
-----------
@@ -474,12 +466,8 @@ package body Eval_Fat is
X_Exp : UI;
pragma Warnings (Off, X_Exp);
begin
- if UR_Is_Zero (X) then
- return X;
- else
- Decompose (RT, X, X_Frac, X_Exp);
- return X_Frac;
- end if;
+ Decompose (RT, X, X_Frac, X_Exp);
+ return X_Frac;
end Fraction;
------------------
@@ -511,81 +499,74 @@ package body Eval_Fat is
Emin : constant UI := UI_From_Int (Machine_Emin (RT));
begin
- if UR_Is_Zero (X) then
- return X;
+ Decompose (RT, X, X_Frac, X_Exp, Mode);
+
+ -- Case of denormalized number or (gradual) underflow
+
+ -- A denormalized number is one with the minimum exponent Emin, but that
+ -- breaks the assumption that the first digit of the mantissa is a one.
+ -- This allows the first non-zero digit to be in any of the remaining
+ -- Mant - 1 spots. The gap between subsequent denormalized numbers is
+ -- the same as for the smallest normalized numbers. However, the number
+ -- of significant digits left decreases as a result of the mantissa now
+ -- having leading seros.
+
+ if X_Exp < Emin then
+ declare
+ Emin_Den : constant UI :=
+ UI_From_Int
+ (Machine_Emin (RT) - Machine_Mantissa (RT) + 1);
+ begin
+ if X_Exp < Emin_Den or not Denorm_On_Target then
+ if UR_Is_Negative (X) then
+ Error_Msg_N
+ ("floating-point value underflows to -0.0?", Enode);
+ return Ureal_M_0;
+
+ else
+ Error_Msg_N
+ ("floating-point value underflows to 0.0?", Enode);
+ return Ureal_0;
+ end if;
- else
- Decompose (RT, X, X_Frac, X_Exp, Mode);
-
- -- Case of denormalized number or (gradual) underflow
-
- -- A denormalized number is one with the minimum exponent Emin, but
- -- that breaks the assumption that the first digit of the mantissa
- -- is a one. This allows the first non-zero digit to be in any
- -- of the remaining Mant - 1 spots. The gap between subsequent
- -- denormalized numbers is the same as for the smallest normalized
- -- numbers. However, the number of significant digits left decreases
- -- as a result of the mantissa now having leading seros.
-
- if X_Exp < Emin then
- declare
- Emin_Den : constant UI :=
- UI_From_Int
- (Machine_Emin (RT) - Machine_Mantissa (RT) + 1);
- begin
- if X_Exp < Emin_Den or not Denorm_On_Target then
- if UR_Is_Negative (X) then
- Error_Msg_N
- ("floating-point value underflows to -0.0?", Enode);
- return Ureal_M_0;
+ elsif Denorm_On_Target then
- else
- Error_Msg_N
- ("floating-point value underflows to 0.0?", Enode);
- return Ureal_0;
- end if;
+ -- Emin - Mant <= X_Exp < Emin, so result is denormal. Handle
+ -- gradual underflow by first computing the number of
+ -- significant bits still available for the mantissa and
+ -- then truncating the fraction to this number of bits.
- elsif Denorm_On_Target then
-
- -- Emin - Mant <= X_Exp < Emin, so result is denormal.
- -- Handle gradual underflow by first computing the
- -- number of significant bits still available for the
- -- mantissa and then truncating the fraction to this
- -- number of bits.
-
- -- If this value is different from the original
- -- fraction, precision is lost due to gradual underflow.
-
- -- We probably should round here and prevent double
- -- rounding as a result of first rounding to a model
- -- number and then to a machine number. However, this
- -- is an extremely rare case that is not worth the extra
- -- complexity. In any case, a warning is issued in cases
- -- where gradual underflow occurs.
-
- declare
- Denorm_Sig_Bits : constant UI := X_Exp - Emin_Den + 1;
-
- X_Frac_Denorm : constant T := UR_From_Components
- (UR_Trunc (Scaling (RT, abs X_Frac, Denorm_Sig_Bits)),
- Denorm_Sig_Bits,
- Radix,
- UR_Is_Negative (X));
-
- begin
- if X_Frac_Denorm /= X_Frac then
- Error_Msg_N
- ("gradual underflow causes loss of precision?",
- Enode);
- X_Frac := X_Frac_Denorm;
- end if;
- end;
- end if;
- end;
- end if;
+ -- If this value is different from the original fraction,
+ -- precision is lost due to gradual underflow.
+
+ -- We probably should round here and prevent double rounding as
+ -- a result of first rounding to a model number and then to a
+ -- machine number. However, this is an extremely rare case that
+ -- is not worth the extra complexity. In any case, a warning is
+ -- issued in cases where gradual underflow occurs.
+
+ declare
+ Denorm_Sig_Bits : constant UI := X_Exp - Emin_Den + 1;
+
+ X_Frac_Denorm : constant T := UR_From_Components
+ (UR_Trunc (Scaling (RT, abs X_Frac, Denorm_Sig_Bits)),
+ Denorm_Sig_Bits,
+ Radix,
+ UR_Is_Negative (X));
- return Scaling (RT, X_Frac, X_Exp);
+ begin
+ if X_Frac_Denorm /= X_Frac then
+ Error_Msg_N
+ ("gradual underflow causes loss of precision?",
+ Enode);
+ X_Frac := X_Frac_Denorm;
+ end if;
+ end;
+ end if;
+ end;
end if;
+
+ return Scaling (RT, X_Frac, X_Exp);
end Machine;
------------------
@@ -848,8 +829,8 @@ package body Eval_Fat is
Exp := Emin;
end if;
- -- Set exponent such that the radix point will be directly
- -- following the mantissa after scaling
+ -- Set exponent such that the radix point will be directly following the
+ -- mantissa after scaling.
if Denorm_On_Target or Exp /= Emin then
Exp := Exp - Mantissa;