Having too many special cases can be counter-productive as shown here.
Tested on x86-64/Linux, applied on the mainline and 16 branch.
RMs, I'd like to backport the fixlet for the 15.3 release, any objections?
2026-06-09 Eric Botcazou <[email protected]>
PR ada/125695
* libgnat/s-genbig.adb ("**"): Do not drop the sign on the floor.
(Big_Exp): Take into account the parity of the exponent for -2.
2026-06-09 Eric Botcazou <[email protected]>
* gnat.dg/bigint1.adb: New test.
--
Eric Botcazoudiff --git a/gcc/ada/libgnat/s-genbig.adb b/gcc/ada/libgnat/s-genbig.adb
index f5ed11c06a4..50f724b060a 100644
--- a/gcc/ada/libgnat/s-genbig.adb
+++ b/gcc/ada/libgnat/s-genbig.adb
@@ -262,7 +262,7 @@ package body System.Generic_Bignums is
-- X ** 1 is X
when 1 =>
- return Normalize (X.D);
+ return Normalize (X.D, X.Neg);
-- X ** 2 is X * X
@@ -331,14 +331,14 @@ package body System.Generic_Bignums is
elsif Y.Len > 1 then
raise Storage_Error with "exponentiation result is too large";
- -- Special case (+/-)2 ** K, where K is 1 .. 31 using a shift
+ -- Special case (+/-)2 ** K, where K is in 1 .. 31, using a left shift
elsif X.Len = 1 and then X.D (1) = 2 and then Y.D (1) < 32 then
declare
D : constant Digit_Vector (1 .. 1) :=
[Shift_Left (SD'(1), Natural (Y.D (1)))];
begin
- return Normalize (D, X.Neg);
+ return Normalize (D, X.Neg and then (Y.D (1) and 1) = 1);
end;
-- Remaining cases have right operand of one word
-- { dg-do run }
-- { dg-options "-gnat2022 -gnata" }
with Ada.Numerics.Big_Numbers.Big_Integers;
use Ada.Numerics.Big_Numbers.Big_Integers;
procedure Bigint1 is
Minus_One : constant Big_Integer := To_Big_Integer (-1);
Minus_Two : constant Big_Integer := To_Big_Integer (-2);
Minus_Three : constant Big_Integer := To_Big_Integer (-3);
begin
pragma Assert (Minus_One ** 1 = Minus_One);
pragma Assert (Minus_One ** 2 = To_Big_Integer (1));
pragma Assert (Minus_One ** 3 = Minus_One);
pragma Assert (Minus_Two ** 1 = Minus_Two);
pragma Assert (Minus_Two ** 2 = To_Big_Integer (4));
pragma Assert (Minus_Two ** 3 = To_Big_Integer (-8));
pragma Assert (Minus_Three ** 1 = Minus_Three);
pragma Assert (Minus_Three ** 2 = To_Big_Integer (9));
pragma Assert (Minus_Three ** 3 = To_Big_Integer (-27));
end;