beta-0.89.2
[luatex.git] / source / libs / gmp / gmp-src / mpz / xor.c
blobcd701000d56143778dbf746fb886ae021478f647
1 /* mpz_xor -- Logical xor.
3 Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012 Free Software
4 Foundation, Inc.
6 This file is part of the GNU MP Library.
8 The GNU MP Library is free software; you can redistribute it and/or modify
9 it under the terms of either:
11 * the GNU Lesser General Public License as published by the Free
12 Software Foundation; either version 3 of the License, or (at your
13 option) any later version.
17 * the GNU General Public License as published by the Free Software
18 Foundation; either version 2 of the License, or (at your option) any
19 later version.
21 or both in parallel, as here.
23 The GNU MP Library is distributed in the hope that it will be useful, but
24 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 for more details.
28 You should have received copies of the GNU General Public License and the
29 GNU Lesser General Public License along with the GNU MP Library. If not,
30 see https://www.gnu.org/licenses/. */
32 #include "gmp.h"
33 #include "gmp-impl.h"
35 void
36 mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
38 mp_srcptr op1_ptr, op2_ptr;
39 mp_size_t op1_size, op2_size;
40 mp_ptr res_ptr;
41 mp_size_t res_size, res_alloc;
42 TMP_DECL;
44 TMP_MARK;
45 op1_size = SIZ(op1);
46 op2_size = SIZ(op2);
48 op1_ptr = PTR(op1);
49 op2_ptr = PTR(op2);
50 res_ptr = PTR(res);
52 if (op1_size >= 0)
54 if (op2_size >= 0)
56 if (op1_size >= op2_size)
58 if (ALLOC(res) < op1_size)
60 _mpz_realloc (res, op1_size);
61 /* No overlapping possible: op1_ptr = PTR(op1); */
62 op2_ptr = PTR(op2);
63 res_ptr = PTR(res);
66 if (res_ptr != op1_ptr)
67 MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
68 op1_size - op2_size);
69 if (LIKELY (op2_size != 0))
70 mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size);
71 res_size = op1_size;
73 else
75 if (ALLOC(res) < op2_size)
77 _mpz_realloc (res, op2_size);
78 op1_ptr = PTR(op1);
79 /* No overlapping possible: op2_ptr = PTR(op2); */
80 res_ptr = PTR(res);
83 if (res_ptr != op2_ptr)
84 MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
85 op2_size - op1_size);
86 if (LIKELY (op1_size != 0))
87 mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
88 res_size = op2_size;
91 MPN_NORMALIZE (res_ptr, res_size);
92 SIZ(res) = res_size;
93 return;
95 else /* op2_size < 0 */
97 /* Fall through to the code at the end of the function. */
100 else
102 if (op2_size < 0)
104 mp_ptr opx, opy;
106 /* Both operands are negative, the result will be positive.
107 (-OP1) ^ (-OP2) =
108 = ~(OP1 - 1) ^ ~(OP2 - 1) =
109 = (OP1 - 1) ^ (OP2 - 1) */
111 op1_size = -op1_size;
112 op2_size = -op2_size;
114 /* Possible optimization: Decrease mpn_sub precision,
115 as we won't use the entire res of both. */
116 TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
117 mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
118 op1_ptr = opx;
120 mpn_sub_1 (opy, op2_ptr, op2_size, (mp_limb_t) 1);
121 op2_ptr = opy;
123 if (op1_size > op2_size)
124 MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
126 res_alloc = op2_size;
127 res_ptr = MPZ_REALLOC (res, res_alloc);
129 MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
130 op2_size - op1_size);
131 mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
132 res_size = op2_size;
134 MPN_NORMALIZE (res_ptr, res_size);
135 SIZ(res) = res_size;
136 TMP_FREE;
137 return;
139 else
141 /* We should compute -OP1 ^ OP2. Swap OP1 and OP2 and fall
142 through to the code that handles OP1 ^ -OP2. */
143 MPZ_SRCPTR_SWAP (op1, op2);
144 MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
149 mp_ptr opx;
150 mp_limb_t cy;
152 /* Operand 2 negative, so will be the result.
153 -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) =
154 = ~(OP1 ^ ~(OP2 - 1)) + 1 =
155 = (OP1 ^ (OP2 - 1)) + 1 */
157 op2_size = -op2_size;
159 opx = TMP_ALLOC_LIMBS (op2_size);
160 mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
161 op2_ptr = opx;
163 res_alloc = MAX (op1_size, op2_size) + 1;
164 if (ALLOC(res) < res_alloc)
166 _mpz_realloc (res, res_alloc);
167 op1_ptr = PTR(op1);
168 /* op2_ptr points to temporary space. */
169 res_ptr = PTR(res);
172 if (op1_size > op2_size)
174 MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
175 mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size);
176 res_size = op1_size;
178 else
180 MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
181 if (LIKELY (op1_size != 0))
182 mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
183 res_size = op2_size;
186 cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
187 res_ptr[res_size] = cy;
188 res_size += (cy != 0);
190 MPN_NORMALIZE (res_ptr, res_size);
191 SIZ(res) = -res_size;
192 TMP_FREE;