diff mbox series

[Ada] Fix static computation of 'Succ for floating point without denormals

Message ID 20210429080347.GA133854@adacore.com
State New
Headers show
Series [Ada] Fix static computation of 'Succ for floating point without denormals | expand

Commit Message

Pierre-Marie de Rodat April 29, 2021, 8:03 a.m. UTC
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 mbox series

Patch

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;