xref: /dragonfly/contrib/gmp/mpz/xor.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1 /* mpz_xor -- Logical xor.
2 
3 Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005 Free Software
4 Foundation, Inc.
5 
6 This file is part of the GNU MP Library.
7 
8 The GNU MP Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The GNU MP Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
20 
21 #include "gmp.h"
22 #include "gmp-impl.h"
23 
24 void
mpz_xor(mpz_ptr res,mpz_srcptr op1,mpz_srcptr op2)25 mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
26 {
27   mp_srcptr op1_ptr, op2_ptr;
28   mp_size_t op1_size, op2_size;
29   mp_ptr res_ptr;
30   mp_size_t res_size, res_alloc;
31   mp_size_t i;
32   TMP_DECL;
33 
34   TMP_MARK;
35   op1_size = SIZ(op1);
36   op2_size = SIZ(op2);
37 
38   op1_ptr = PTR(op1);
39   op2_ptr = PTR(op2);
40   res_ptr = PTR(res);
41 
42   if (op1_size >= 0)
43     {
44       if (op2_size >= 0)
45           {
46             if (op1_size >= op2_size)
47               {
48                 if (ALLOC(res) < op1_size)
49                     {
50                       _mpz_realloc (res, op1_size);
51                       /* No overlapping possible: op1_ptr = PTR(op1); */
52                       op2_ptr = PTR(op2);
53                       res_ptr = PTR(res);
54                     }
55 
56                 if (res_ptr != op1_ptr)
57                     MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
58                                 op1_size - op2_size);
59                 for (i = op2_size - 1; i >= 0; i--)
60                     res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
61                 res_size = op1_size;
62               }
63             else
64               {
65                 if (ALLOC(res) < op2_size)
66                     {
67                       _mpz_realloc (res, op2_size);
68                       op1_ptr = PTR(op1);
69                       /* No overlapping possible: op2_ptr = PTR(op2); */
70                       res_ptr = PTR(res);
71                     }
72 
73                 if (res_ptr != op2_ptr)
74                     MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
75                                 op2_size - op1_size);
76                 for (i = op1_size - 1; i >= 0; i--)
77                     res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
78                 res_size = op2_size;
79               }
80 
81             MPN_NORMALIZE (res_ptr, res_size);
82             SIZ(res) = res_size;
83             return;
84           }
85       else /* op2_size < 0 */
86           {
87             /* Fall through to the code at the end of the function.  */
88           }
89     }
90   else
91     {
92       if (op2_size < 0)
93           {
94             mp_ptr opx;
95 
96             /* Both operands are negative, the result will be positive.
97                 (-OP1) ^ (-OP2) =
98                = ~(OP1 - 1) ^ ~(OP2 - 1) =
99                = (OP1 - 1) ^ (OP2 - 1)  */
100 
101             op1_size = -op1_size;
102             op2_size = -op2_size;
103 
104             /* Possible optimization: Decrease mpn_sub precision,
105                as we won't use the entire res of both.  */
106             opx = TMP_ALLOC_LIMBS (op1_size);
107             mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
108             op1_ptr = opx;
109 
110             opx = TMP_ALLOC_LIMBS (op2_size);
111             mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
112             op2_ptr = opx;
113 
114             res_alloc = MAX (op1_size, op2_size);
115             if (ALLOC(res) < res_alloc)
116               {
117                 _mpz_realloc (res, res_alloc);
118                 res_ptr = PTR(res);
119                 /* op1_ptr and op2_ptr point to temporary space.  */
120               }
121 
122             if (op1_size > op2_size)
123               {
124                 MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
125                               op1_size - op2_size);
126                 for (i = op2_size - 1; i >= 0; i--)
127                     res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
128                 res_size = op1_size;
129               }
130             else
131               {
132                 MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
133                               op2_size - op1_size);
134                 for (i = op1_size - 1; i >= 0; i--)
135                     res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
136                 res_size = op2_size;
137               }
138 
139             MPN_NORMALIZE (res_ptr, res_size);
140             SIZ(res) = res_size;
141             TMP_FREE;
142             return;
143           }
144       else
145           {
146             /* We should compute -OP1 ^ OP2.  Swap OP1 and OP2 and fall
147                through to the code that handles OP1 ^ -OP2.  */
148           MPZ_SRCPTR_SWAP (op1, op2);
149           MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
150           }
151     }
152 
153   {
154     mp_ptr opx;
155     mp_limb_t cy;
156 
157     /* Operand 2 negative, so will be the result.
158        -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) =
159        = ~(OP1 ^ ~(OP2 - 1)) + 1 =
160        = (OP1 ^ (OP2 - 1)) + 1      */
161 
162     op2_size = -op2_size;
163 
164     opx = TMP_ALLOC_LIMBS (op2_size);
165     mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
166     op2_ptr = opx;
167 
168     res_alloc = MAX (op1_size, op2_size) + 1;
169     if (ALLOC(res) < res_alloc)
170       {
171           _mpz_realloc (res, res_alloc);
172           op1_ptr = PTR(op1);
173           /* op2_ptr points to temporary space.  */
174           res_ptr = PTR(res);
175       }
176 
177     if (op1_size > op2_size)
178       {
179           MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
180           for (i = op2_size - 1; i >= 0; i--)
181             res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
182           res_size = op1_size;
183       }
184     else
185       {
186           MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
187           for (i = op1_size - 1; i >= 0; i--)
188             res_ptr[i] = op1_ptr[i] ^ op2_ptr[i];
189           res_size = op2_size;
190       }
191 
192     cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
193     if (cy)
194       {
195           res_ptr[res_size] = cy;
196           res_size++;
197       }
198 
199     MPN_NORMALIZE (res_ptr, res_size);
200     SIZ(res) = -res_size;
201     TMP_FREE;
202   }
203 }
204