The implementation computes an incorrect increment for normalized numbers
with the smallest exponent when the floating-point type does not support
denormalized numbers.
Tested on x86_64-pc-linux-gnu, committed on trunk
gcc/ada/
* eval_fat.adb (Succ): Add a special case for zero if the type does
not support denormalized numbers. Always use the canonical formula
in other cases and add commentary throughout the function.
diff --git a/gcc/ada/eval_fat.adb b/gcc/ada/eval_fat.adb
--- a/gcc/ada/eval_fat.adb
+++ b/gcc/ada/eval_fat.adb
@@ -729,22 +729,30 @@ package body Eval_Fat is
New_Frac : T;
begin
+ -- Treat zero as a regular denormalized number if they are supported,
+ -- otherwise return the smallest normalized number.
+
if UR_Is_Zero (X) then
- Exp := Emin;
+ if Has_Denormals (RT) then
+ Exp := Emin;
+ else
+ return Scaling (RT, Ureal_1, Emin - 1);
+ end if;
end if;
- -- Set exponent such that the radix point will be directly following the
- -- mantissa after scaling.
-
- if Has_Denormals (RT) or Exp /= Emin then
- Exp := Exp - Mantissa;
- else
- Exp := Exp - 1;
- end if;
+ -- Multiply the number by 2.0**(Mantissa-Exp) so that the radix point
+ -- will be directly following the mantissa after scaling.
+ Exp := Exp - Mantissa;
Frac := Scaling (RT, X, -Exp);
+
+ -- Round to the neareast integer towards +Inf
+
New_Frac := Ceiling (RT, Frac);
+ -- If the rounding was a NOP, add one, except for -2.0**(Mantissa-1)
+ -- because the exponent is going to be reduced.
+
if New_Frac = Frac then
if New_Frac = Scaling (RT, -Ureal_1, Mantissa - 1) then
New_Frac := New_Frac + Scaling (RT, Ureal_1, Uint_Minus_1);
@@ -753,6 +761,8 @@ package body Eval_Fat is
end if;
end if;
+ -- Divide back by 2.0**(Mantissa-Exp) to get the final result
+
return Scaling (RT, New_Frac, Exp);
end Succ;