1
-----------------------------------------------------------------------
4
-- Copyright (C) 2009, AdaCore --
6
-- GPS is free software; you can redistribute it and/or modify it --
7
-- under the terms of the GNU General Public License as published by --
8
-- the Free Software Foundation; either version 2 of the License, or --
9
-- (at your option) any later version. --
11
-- This program is distributed in the hope that it will be useful, --
12
-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
13
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
14
-- General Public License for more details. You should have received --
15
-- a copy of the GNU General Public License along with this library; --
16
-- if not, write to the Free Software Foundation, Inc., 59 Temple --
17
-- Place - Suite 330, Boston, MA 02111-1307, USA. --
18
-----------------------------------------------------------------------
20
with Interfaces.C.Strings;
22
package body GNATCOLL.GMP.Integers is
30
procedure Initialize (This : in out Big_Integer) is
32
mpz_init (This.Value'Access);
39
procedure Finalize (This : in out Big_Integer) is
41
mpz_clear (This.Value'Access);
49
(This : out Big_Integer;
53
use Interfaces.C.Strings;
56
Input : chars_ptr := New_String (To);
58
Result := mpz_set_str (This.Value'Access, Input, Base);
69
function Make (This : String; Base : Int := 10) return Big_Integer is
71
return Result : Big_Integer do
72
Set (Result, This, Base);
80
procedure Set (This : out Big_Integer; To : Big_Integer) is
82
mpz_set (This.Value'Access, To.Value'Access);
89
procedure Set (This : out Big_Integer; To : Long) is
91
mpz_set_si (This.Value'Access, To);
98
procedure Set_UL (This : out Big_Integer; To : Unsigned_Long) is
100
mpz_set_ui (This.Value'Access, To);
107
function "=" (Left : Big_Integer; Right : Big_Integer)
111
return mpz_cmp (Left.Value'Access, Right.Value'Access) = 0;
118
function "=" (Left : Big_Integer; Right : Long)
122
return mpz_cmp_si (Left.Value'Access, Right) = 0;
129
function "=" (Left : Long; Right : Big_Integer)
133
return mpz_cmp_si (Right.Value'Access, Left) = 0;
140
function ">" (Left : Big_Integer; Right : Big_Integer)
144
return mpz_cmp (Left.Value'Access, Right.Value'Access) > 0;
151
function ">" (Left : Big_Integer; Right : Long)
155
return mpz_cmp_si (Left.Value'Access, Right) > 0;
162
function ">" (Left : Long; Right : Big_Integer)
166
return mpz_cmp_si (Right.Value'Access, Left) > 0;
173
function ">=" (Left : Big_Integer; Right : Big_Integer)
177
return mpz_cmp (Left.Value'Access, Right.Value'Access) >= 0;
184
function ">=" (Left : Big_Integer; Right : Long)
188
return mpz_cmp_si (Left.Value'Access, Right) >= 0;
195
function ">=" (Left : Long; Right : Big_Integer)
199
return mpz_cmp_si (Right.Value'Access, Left) >= 0;
206
function "<" (Left : Big_Integer; Right : Big_Integer)
210
return mpz_cmp (Left.Value'Access, Right.Value'Access) < 0;
217
function "<" (Left : Big_Integer; Right : Long)
221
return mpz_cmp_si (Left.Value'Access, Right) < 0;
228
function "<" (Left : Long; Right : Big_Integer)
232
return mpz_cmp_si (Right.Value'Access, Left) < 0;
239
function "<=" (Left : Big_Integer; Right : Big_Integer)
243
return mpz_cmp (Left.Value'Access, Right.Value'Access) <= 0;
250
function "<=" (Left : Big_Integer; Right : Long)
254
return mpz_cmp_si (Left.Value'Access, Right) <= 0;
261
function "<=" (Left : Long; Right : Big_Integer)
265
return mpz_cmp_si (Right.Value'Access, Left) <= 0;
272
procedure Add (To : in out Big_Integer; This : Unsigned_Long) is
274
mpz_add_ui (To.Value'Access, To.Value'Access, This);
281
procedure Add (To : in out Big_Integer; This : Big_Integer) is
283
mpz_add (To.Value'Access, To.Value'Access, This.Value'Access);
290
procedure Add (Result : out Big_Integer; Op1, Op2 : Big_Integer) is
292
mpz_add (Result.Value'Access, Op1.Value'Access, Op2.Value'Access);
299
function "+" (Left, Right : Big_Integer)
303
return Result : Big_Integer do
304
mpz_add (Result.Value'Access, Left.Value'Access, Right.Value'Access);
312
function "+" (Left : Big_Integer; Right : Unsigned_Long)
316
return Result : Big_Integer do
317
mpz_add_ui (Result.Value'Access,
327
function "+" (Left : Unsigned_Long; Right : Big_Integer)
331
return Result : Big_Integer do
332
mpz_add_ui (Result.Value'Access,
342
procedure Subtract (From : in out Big_Integer; This : Unsigned_Long) is
344
mpz_sub_ui (From.Value'Access, From.Value'Access, This);
351
procedure Subtract (From : in out Big_Integer; This : Big_Integer) is
353
mpz_sub (From.Value'Access, From.Value'Access, This.Value'Access);
360
procedure Subtract (Result : out Big_Integer; Op1, Op2 : Big_Integer) is
362
mpz_sub (Result.Value'Access, Op1.Value'Access, Op2.Value'Access);
369
function "-" (Left, Right : Big_Integer)
373
return Result : Big_Integer do
374
mpz_sub (Result.Value'Access, Left.Value'Access, Right.Value'Access);
382
function "-" (Left : Big_Integer; Right : Unsigned_Long)
386
return Result : Big_Integer do
387
mpz_add_ui (Result.Value'Access,
397
function "-" (Left : Unsigned_Long; Right : Big_Integer)
401
return Result : Big_Integer do
402
mpz_add_ui (Result.Value'Access,
412
procedure Multiply (This : in out Big_Integer; By : Long) is
414
mpz_mul_si (This.Value'Access, This.Value'Access, By);
421
procedure Multiply (This : in out Big_Integer; By : Big_Integer) is
423
mpz_mul (This.Value'Access, This.Value'Access, By.Value'Access);
430
procedure Multiply (Result : out Big_Integer; Op1, Op2 : Big_Integer) is
432
mpz_mul (Result.Value'Access, Op1.Value'Access, Op2.Value'Access);
439
function "*" (Left, Right : Big_Integer)
443
return Result : Big_Integer do
444
mpz_mul (Result.Value'Access, Left.Value'Access, Right.Value'Access);
452
function "*" (Left : Long; Right : Big_Integer)
456
return Result : Big_Integer do
457
mpz_mul_si (Result.Value'Access, Right.Value'Access, Left);
465
function "*" (Left : Big_Integer; Right : Long)
469
return Result : Big_Integer do
470
mpz_mul_si (Result.Value'Access, Left.Value'Access, Right);
478
procedure Divide (Q : in out Big_Integer;
483
pragma Unreferenced (Dummy);
486
raise Constraint_Error;
488
Dummy := mpz_tdiv_q_ui (Q.Value'Access, N.Value'Access, D);
495
procedure Divide (Q : in out Big_Integer;
500
if mpz_cmp_ui (D.Value'Access, 0) = 0 then
501
raise Constraint_Error;
503
mpz_tdiv_q (Q.Value'Access, N.Value'Access, D.Value'Access);
510
function "/" (Left, Right : Big_Integer)
514
if mpz_cmp_ui (Right.Value'Access, 0) = 0 then
515
raise Constraint_Error;
517
return Result : Big_Integer do
518
mpz_tdiv_q (Q => Result.Value'Access,
519
N => Left.Value'Access,
520
D => Right.Value'Access);
528
function "/" (Left : Big_Integer; Right : Unsigned_Long)
532
pragma Unreferenced (Dummy);
535
raise Constraint_Error;
537
return Result : Big_Integer do
538
Dummy := mpz_tdiv_q_ui (Q => Result.Value'Access,
539
N => Left.Value'Access,
548
function "rem" (Left : Big_Integer; Right : Big_Integer)
552
if mpz_cmp_ui (Right.Value'Access, 0) = 0 then
553
raise Constraint_Error;
555
return Result : Big_Integer do
556
mpz_tdiv_r (R => Result.Value'Access,
557
N => Left.Value'Access,
558
D => Right.Value'Access);
559
-- the result takes the sign of N, as required by the RM
567
function "rem" (Left : Big_Integer; Right : Unsigned_Long)
571
pragma Unreferenced (Dummy);
574
raise Constraint_Error;
576
return Result : Big_Integer do
577
Dummy := mpz_tdiv_r_ui (R => Result.Value'Access,
578
N => Left.Value'Access,
580
-- the result is always non-negative so we have to set the sign to
582
if Sign (Left) /= Sign (Result) then
592
procedure Get_Rem (Result : out Big_Integer; N, D : Big_Integer) is
594
if mpz_cmp_ui (D.Value'Access, 0) = 0 then
595
raise Constraint_Error;
597
mpz_tdiv_r (Result.Value'Access, N.Value'Access, D.Value'Access);
598
-- the result takes the sign of N, as required by the RM
605
function "-" (Left : Big_Integer)
609
return Result : Big_Integer do
610
mpz_neg (Result.Value'Access, Left.Value'Access);
618
procedure Negate (This : in out Big_Integer) is
620
mpz_neg (This.Value'Access, This.Value'Access);
627
function "**"(Left : Big_Integer; Right : Unsigned_Long)
631
return Result : Big_Integer do
632
mpz_pow_ui (Result.Value'Access, Left.Value'Access, Right);
640
procedure Raise_To_N (This : in out Big_Integer; N : Unsigned_Long) is
642
mpz_pow_ui (This.Value'Access, This.Value'Access, N);
649
function "abs" (Left : Big_Integer)
653
return Result : Big_Integer do
654
mpz_abs (Result.Value'Access, Left.Value'Access);
662
procedure Get_Abs (Result : out Big_Integer; From : Big_Integer) is
664
mpz_abs (Result.Value'Access, From.Value'Access);
671
function "mod" (Left : Big_Integer; Right : Big_Integer)
675
if mpz_cmp_ui (Right.Value'Access, 0) = 0 then
676
raise Constraint_Error;
678
return Result : Big_Integer do
679
Get_Mod (Result, Left, Right);
687
function "mod" (Left : Big_Integer; Right : Long)
692
raise Constraint_Error;
694
return Result : Big_Integer do
696
Temp_Right : Big_Integer;
698
Set (Temp_Right, To => Right);
699
Get_Mod (Result, Left, Temp_Right);
708
procedure Get_Mod (Result : out Big_Integer; N, D : Big_Integer) is
710
if mpz_cmp_ui (D.Value'Access, 0) = 0 then
711
raise Constraint_Error;
713
if Sign (N) /= -1 and Sign (D) /= -1 then -- neither is negative
714
mpz_mod (Result.Value'Access, N.Value'Access, D.Value'Access);
716
-- The GMP library provides operators defined by C semantics, but the
717
-- semantics of Ada's mod operator are not the same as C's when
718
-- negative values are involved. We do the following to implement the
719
-- required Ada semantics.
721
Temp_Left : Big_Integer;
722
Temp_Right : Big_Integer;
723
Temp_Result : Big_Integer;
725
Set (Temp_Left, To => N);
726
Set (Temp_Right, To => D);
728
if Sign (N) = -1 then -- N is negative
731
if Sign (D) = -1 then -- D is negative
734
-- now both Temp_Left and Temp_Right are nonnegative
736
mpz_mod (Temp_Result.Value'Access,
737
Temp_Left.Value'Access,
738
Temp_Right.Value'Access);
740
if mpz_cmp_ui (Temp_Result.Value'Access, 0) = 0 then
741
-- if Temp_Result is zero we are done
742
Set (Result, To => Temp_Result);
744
if Sign (N) = -1 then -- N is negative
745
if Sign (D) = -1 then -- D is negative too
746
Set (Result, To => Temp_Result);
748
else -- N is negative but D is not
749
Set (Result, Temp_Right - Temp_Result);
751
else -- N is not negative
752
if Sign (D) = -1 then -- D is negative
753
-- Set (Result, Temp_Result - Temp_Right);
754
mpz_sub (Result.Value'Access,
755
Temp_Result.Value'Access,
756
Temp_Right.Value'Access);
757
else -- neither is negative
758
Set (Result, To => Temp_Result);
770
function Image (This : Big_Integer; Base : Positive := 10) return String is
771
use Interfaces.C, Interfaces.C.Strings;
773
Number_Digits : constant size_t := mpz_sizeinbase
774
(This.Value'Access, Int (Base));
776
Buffer : String (1 .. Integer (Number_Digits) + 2);
777
-- The correct number to allocate is 2 more than Number_Digits in order
778
-- to handle a possible minus sign and the null-terminator.
782
Result := mpz_get_str (Buffer'Address, Int (Base), This.Value'Access);
783
return Value (Result);
790
function As_mpz_t (This : Big_Integer)
791
return access constant GNATCOLL.GMP.Lib.mpz_t
794
return This.Value'Unchecked_Access;
801
function Sign (This : Big_Integer)
805
return Integer (mpz_sgn (This.Value'Access));
808
end GNATCOLL.GMP.Integers;