/src/libreoffice/tools/source/generic/bigint.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <sal/config.h> |
21 | | |
22 | | #include <osl/diagnose.h> |
23 | | #include <tools/bigint.hxx> |
24 | | |
25 | | #include <algorithm> |
26 | | #include <cmath> |
27 | | #include <cstring> |
28 | | #include <limits> |
29 | | #include <span> |
30 | | |
31 | | /** |
32 | | * The range in which we can perform add/sub without fear of overflow |
33 | | */ |
34 | | const sal_Int32 MY_MAXLONG = 0x3fffffff; |
35 | | const sal_Int32 MY_MINLONG = -MY_MAXLONG; |
36 | | |
37 | | /* |
38 | | * The algorithms for Addition, Subtraction, Multiplication and Division |
39 | | * of large numbers originate from SEMINUMERICAL ALGORITHMS by |
40 | | * DONALD E. KNUTH in the series The Art of Computer Programming: |
41 | | * chapter 4.3.1. The Classical Algorithms. |
42 | | */ |
43 | | |
44 | | BigInt BigInt::MakeBig() const |
45 | 988k | { |
46 | 988k | if (IsBig()) |
47 | 111k | { |
48 | 111k | BigInt ret(*this); |
49 | 111k | while ( ret.nLen > 1 && ret.nNum[ret.nLen-1] == 0 ) |
50 | 0 | ret.nLen--; |
51 | 111k | return ret; |
52 | 111k | } |
53 | | |
54 | 876k | BigInt ret; |
55 | 876k | if (nVal < 0) |
56 | 40.3k | { |
57 | 40.3k | ret.bIsNeg = true; |
58 | 40.3k | ret.nNum[0] = -static_cast<sal_Int64>(nVal); |
59 | 40.3k | } |
60 | 836k | else |
61 | 836k | { |
62 | 836k | ret.bIsNeg = false; |
63 | 836k | ret.nNum[0] = nVal; |
64 | 836k | } |
65 | 876k | ret.nLen = 1; |
66 | 876k | return ret; |
67 | 988k | } |
68 | | |
69 | | void BigInt::Normalize() |
70 | 612k | { |
71 | 612k | if (IsBig()) |
72 | 532k | { |
73 | 931k | while ( nLen > 1 && nNum[nLen-1] == 0 ) |
74 | 398k | nLen--; |
75 | | |
76 | 532k | if (nLen < 2) |
77 | 426k | { |
78 | 426k | static constexpr sal_uInt32 maxForPosInt32 = std::numeric_limits<sal_Int32>::max(); |
79 | 426k | static constexpr sal_uInt32 maxForNegInt32 = -sal_Int64(std::numeric_limits<sal_Int32>::min()); |
80 | 426k | sal_uInt32 nNum0 = nNum[0]; |
81 | 426k | if (bIsNeg && nNum0 <= maxForNegInt32) |
82 | 33.8k | { |
83 | 33.8k | nVal = -sal_Int64(nNum0); |
84 | 33.8k | nLen = 0; |
85 | 33.8k | } |
86 | 392k | else if (!bIsNeg && nNum0 <= maxForPosInt32) |
87 | 378k | { |
88 | 378k | nVal = nNum0; |
89 | 378k | nLen = 0; |
90 | 378k | } |
91 | 426k | } |
92 | 532k | } |
93 | 612k | } |
94 | | |
95 | | // Normalization in DivLong requires that dividend is multiplied by a number, and the resulting |
96 | | // value has 1 more 32-bit "digits". 'ret' provides enough room for that. Use of std::span gives |
97 | | // run-time index checking in debug builds. |
98 | | static std::span<sal_uInt32> Mult(std::span<const sal_uInt32> aNum, sal_uInt32 nMul, std::span<sal_uInt32> retBuf) |
99 | 24.1k | { |
100 | 24.1k | assert(retBuf.size() >= aNum.size()); |
101 | 24.1k | sal_uInt64 nK = 0; |
102 | 68.5k | for (size_t i = 0; i < aNum.size(); i++) |
103 | 44.3k | { |
104 | 44.3k | sal_uInt64 nTmp = static_cast<sal_uInt64>(aNum[i]) * nMul + nK; |
105 | 44.3k | nK = nTmp >> 32; |
106 | 44.3k | retBuf[i] = static_cast<sal_uInt32>(nTmp); |
107 | 44.3k | } |
108 | | |
109 | 24.1k | if ( nK ) |
110 | 5.89k | { |
111 | 5.89k | assert(retBuf.size() > aNum.size()); |
112 | 5.89k | retBuf[aNum.size()] = nK; |
113 | 5.89k | return retBuf.subspan(0, aNum.size() + 1); |
114 | 5.89k | } |
115 | | |
116 | 18.2k | return retBuf.subspan(0, aNum.size()); |
117 | 24.1k | } |
118 | | |
119 | | static size_t DivInPlace(std::span<sal_uInt32> aNum, sal_uInt32 nDiv, sal_uInt32& rRem) |
120 | 37.0k | { |
121 | 37.0k | assert(aNum.size() > 0); |
122 | 37.0k | sal_uInt64 nK = 0; |
123 | 112k | for (int i = aNum.size() - 1; i >= 0; i--) |
124 | 75.8k | { |
125 | 75.8k | sal_uInt64 nTmp = aNum[i] + (nK << 32); |
126 | 75.8k | aNum[i] = nTmp / nDiv; |
127 | 75.8k | nK = nTmp % nDiv; |
128 | 75.8k | } |
129 | 37.0k | rRem = nK; |
130 | | |
131 | 37.0k | if (aNum[aNum.size() - 1] == 0) |
132 | 32.4k | return aNum.size() - 1; |
133 | | |
134 | 4.65k | return aNum.size(); |
135 | 37.0k | } |
136 | | |
137 | | bool BigInt::ABS_IsLessBig(const BigInt& rVal) const |
138 | 13.3k | { |
139 | 13.3k | assert(IsBig() && rVal.IsBig()); |
140 | 13.3k | if ( rVal.nLen < nLen) |
141 | 7.65k | return false; |
142 | 5.68k | if ( rVal.nLen > nLen ) |
143 | 212 | return true; |
144 | | |
145 | 5.47k | int i = nLen - 1; |
146 | 5.47k | while (i > 0 && nNum[i] == rVal.nNum[i]) |
147 | 0 | --i; |
148 | 5.47k | return nNum[i] < rVal.nNum[i]; |
149 | 5.68k | } |
150 | | |
151 | | void BigInt::AddBig(BigInt& rB, BigInt& rRes) |
152 | 51.6k | { |
153 | 51.6k | assert(IsBig() && rB.IsBig()); |
154 | 51.6k | if ( bIsNeg == rB.bIsNeg ) |
155 | 51.4k | { |
156 | 51.4k | int i; |
157 | 51.4k | char len; |
158 | | |
159 | | // if length of the two values differ, fill remaining positions |
160 | | // of the smaller value with zeros. |
161 | 51.4k | if (nLen >= rB.nLen) |
162 | 51.4k | { |
163 | 51.4k | len = nLen; |
164 | 99.8k | for (i = rB.nLen; i < len; i++) |
165 | 48.4k | rB.nNum[i] = 0; |
166 | 51.4k | } |
167 | 0 | else |
168 | 0 | { |
169 | 0 | len = rB.nLen; |
170 | 0 | for (i = nLen; i < len; i++) |
171 | 0 | nNum[i] = 0; |
172 | 0 | } |
173 | | |
174 | | // Add numerals, starting from the back |
175 | 51.4k | sal_Int64 k = 0; |
176 | 154k | for (i = 0; i < len; i++) { |
177 | 102k | sal_Int64 nZ = static_cast<sal_Int64>(nNum[i]) + static_cast<sal_Int64>(rB.nNum[i]) + k; |
178 | 102k | if (nZ > sal_Int64(std::numeric_limits<sal_uInt32>::max())) |
179 | 8.75k | k = 1; |
180 | 94.0k | else |
181 | 94.0k | k = 0; |
182 | 102k | rRes.nNum[i] = static_cast<sal_uInt32>(nZ); |
183 | 102k | } |
184 | | // If an overflow occurred, add to solution |
185 | 51.4k | if (k) |
186 | 42 | { |
187 | 42 | assert(i < MAX_DIGITS); |
188 | 42 | rRes.nNum[i] = 1; |
189 | 42 | len++; |
190 | 42 | } |
191 | | // Set length and sign |
192 | 51.4k | rRes.nLen = len; |
193 | 51.4k | rRes.bIsNeg = bIsNeg; |
194 | 51.4k | } |
195 | | // If one of the values is negative, perform subtraction instead |
196 | 212 | else |
197 | 212 | { |
198 | 212 | bIsNeg = !bIsNeg; |
199 | 212 | rB.SubBig(*this, rRes); |
200 | 212 | bIsNeg = !bIsNeg; |
201 | 212 | } |
202 | 51.6k | } |
203 | | |
204 | | void BigInt::SubBig(BigInt& rB, BigInt& rRes) |
205 | 11.8k | { |
206 | 11.8k | assert(IsBig() && rB.IsBig()); |
207 | 11.8k | if ( bIsNeg == rB.bIsNeg ) |
208 | 1.26k | { |
209 | 1.26k | char len; |
210 | | |
211 | | // if length of the two values differ, fill remaining positions |
212 | | // of the smaller value with zeros. |
213 | 1.26k | if (nLen >= rB.nLen) |
214 | 1.04k | { |
215 | 1.04k | len = nLen; |
216 | 2.35k | for (int i = rB.nLen; i < len; i++) |
217 | 1.30k | rB.nNum[i] = 0; |
218 | 1.04k | } |
219 | 212 | else |
220 | 212 | { |
221 | 212 | len = rB.nLen; |
222 | 469 | for (int i = nLen; i < len; i++) |
223 | 257 | nNum[i] = 0; |
224 | 212 | } |
225 | | |
226 | 1.26k | const bool bThisIsLess = ABS_IsLessBig(rB); |
227 | 1.26k | BigInt& rGreater = bThisIsLess ? rB : *this; |
228 | 1.26k | BigInt& rSmaller = bThisIsLess ? *this : rB; |
229 | | |
230 | 1.26k | sal_Int64 k = 0; |
231 | 4.08k | for (int i = 0; i < len; i++) |
232 | 2.82k | { |
233 | 2.82k | sal_Int64 nZ = static_cast<sal_Int64>(rGreater.nNum[i]) - static_cast<sal_Int64>(rSmaller.nNum[i]) + k; |
234 | 2.82k | if (nZ < 0) |
235 | 105 | k = -1; |
236 | 2.71k | else |
237 | 2.71k | k = 0; |
238 | 2.82k | rRes.nNum[i] = static_cast<sal_uInt32>(nZ); |
239 | 2.82k | } |
240 | | |
241 | | // if a < b, revert sign |
242 | 1.26k | rRes.bIsNeg = bThisIsLess ? !bIsNeg : bIsNeg; |
243 | 1.26k | rRes.nLen = len; |
244 | 1.26k | } |
245 | | // If one of the values is negative, perform addition instead |
246 | 10.5k | else |
247 | 10.5k | { |
248 | 10.5k | bIsNeg = !bIsNeg; |
249 | 10.5k | AddBig(rB, rRes); |
250 | 10.5k | bIsNeg = !bIsNeg; |
251 | 10.5k | rRes.bIsNeg = bIsNeg; |
252 | 10.5k | } |
253 | 11.8k | } |
254 | | |
255 | | void BigInt::MultBig(const BigInt& rB, BigInt& rRes) const |
256 | 429k | { |
257 | 429k | assert(IsBig() && rB.IsBig()); |
258 | | |
259 | 429k | rRes.bIsNeg = bIsNeg != rB.bIsNeg; |
260 | 429k | rRes.nLen = nLen + rB.nLen; |
261 | 429k | assert(rRes.nLen <= MAX_DIGITS); |
262 | | |
263 | 1.30M | for (int i = 0; i < rRes.nLen; i++) |
264 | 875k | rRes.nNum[i] = 0; |
265 | | |
266 | 868k | for (int j = 0; j < rB.nLen; j++) |
267 | 438k | { |
268 | 438k | sal_uInt64 k = 0; |
269 | 438k | int i; |
270 | 885k | for (i = 0; i < nLen; i++) |
271 | 446k | { |
272 | 446k | sal_uInt64 nZ = static_cast<sal_uInt64>(nNum[i]) * static_cast<sal_uInt64>(rB.nNum[j]) + |
273 | 446k | static_cast<sal_uInt64>(rRes.nNum[i + j]) + k; |
274 | 446k | rRes.nNum[i + j] = static_cast<sal_uInt32>(nZ); |
275 | 446k | k = nZ >> 32; |
276 | 446k | } |
277 | 438k | rRes.nNum[i + j] = k; |
278 | 438k | } |
279 | 429k | } |
280 | | |
281 | | void BigInt::DivModBig(const BigInt& rB, BigInt* pDiv, BigInt* pMod) const |
282 | 12.0k | { |
283 | 12.0k | assert(IsBig() && rB.IsBig()); |
284 | 12.0k | assert(nLen >= rB.nLen); |
285 | | |
286 | 12.0k | assert(rB.nNum[rB.nLen - 1] != 0); |
287 | 12.0k | sal_uInt32 nMult = static_cast<sal_uInt32>(0x100000000 / (static_cast<sal_Int64>(rB.nNum[rB.nLen - 1]) + 1)); |
288 | | |
289 | 12.0k | sal_uInt32 numBuf[MAX_DIGITS + 1]; // normalized dividend |
290 | 12.0k | auto num = Mult({ nNum, nLen }, nMult, numBuf); |
291 | 12.0k | if (num.size() == nLen) |
292 | 6.18k | { |
293 | 6.18k | num = std::span(numBuf, nLen + 1); |
294 | 6.18k | num[nLen] = 0; |
295 | 6.18k | } |
296 | | |
297 | 12.0k | sal_uInt32 denBuf[MAX_DIGITS + 1]; // normalized divisor |
298 | 12.0k | const auto den = Mult({ rB.nNum, rB.nLen }, nMult, denBuf); |
299 | 12.0k | assert(den.size() == rB.nLen); |
300 | 12.0k | const sal_uInt64 nDenMostSig = den[rB.nLen - 1]; |
301 | 12.0k | assert(nDenMostSig >= 0x100000000 / 2); |
302 | 12.0k | const sal_uInt64 nDen2ndSig = rB.nLen > 1 ? den[rB.nLen - 2] : 0; |
303 | | |
304 | 12.0k | BigInt aTmp; |
305 | 12.0k | BigInt& rRes = pDiv ? *pDiv : aTmp; |
306 | | |
307 | 30.7k | for (size_t j = num.size() - 1; j >= den.size(); j--) |
308 | 18.7k | { // guess divisor |
309 | 18.7k | assert(num[j] < nDenMostSig || (num[j] == nDenMostSig && num[j - 1] == 0)); |
310 | 18.7k | sal_uInt64 nTmp = ( static_cast<sal_uInt64>(num[j]) << 32 ) + num[j - 1]; |
311 | 18.7k | sal_uInt32 nQ; |
312 | 18.7k | if (num[j] == nDenMostSig) |
313 | 0 | nQ = 0xFFFFFFFF; |
314 | 18.7k | else |
315 | 18.7k | nQ = static_cast<sal_uInt32>(nTmp / nDenMostSig); |
316 | | |
317 | 18.7k | if (nDen2ndSig && (nDen2ndSig * nQ) > ((nTmp - nDenMostSig * nQ) << 32) + num[j - 2]) |
318 | 2.74k | nQ--; |
319 | | // Start division |
320 | 18.7k | sal_uInt32 nK = 0; |
321 | 18.7k | size_t i; |
322 | 45.5k | for (i = 0; i < den.size(); i++) |
323 | 26.7k | { |
324 | 26.7k | nTmp = static_cast<sal_uInt64>(num[j - den.size() + i]) |
325 | 26.7k | - (static_cast<sal_uInt64>(den[i]) * nQ) |
326 | 26.7k | - nK; |
327 | 26.7k | num[j - den.size() + i] = static_cast<sal_uInt32>(nTmp); |
328 | 26.7k | nK = static_cast<sal_uInt32>(nTmp >> 32); |
329 | 26.7k | if ( nK ) |
330 | 18.6k | nK = static_cast<sal_uInt32>(0x100000000 - nK); |
331 | 26.7k | } |
332 | 18.7k | sal_uInt32& rNum(num[j - den.size() + i]); |
333 | 18.7k | rNum -= nK; |
334 | 18.7k | if (num[j - den.size() + i] == 0) |
335 | 18.7k | rRes.nNum[j - den.size()] = nQ; |
336 | 0 | else |
337 | 0 | { |
338 | 0 | rRes.nNum[j - den.size()] = nQ - 1; |
339 | 0 | nK = 0; |
340 | 0 | for (i = 0; i < den.size(); i++) |
341 | 0 | { |
342 | 0 | nTmp = num[j - den.size() + i] + den[i] + nK; |
343 | 0 | num[j - den.size() + i] = static_cast<sal_uInt32>(nTmp & 0xFFFFFFFF); |
344 | 0 | if (nTmp > std::numeric_limits<sal_uInt32>::max()) |
345 | 0 | nK = 1; |
346 | 0 | else |
347 | 0 | nK = 0; |
348 | 0 | } |
349 | 0 | } |
350 | 18.7k | } |
351 | | |
352 | 12.0k | if (pMod) |
353 | 0 | { |
354 | 0 | pMod->nLen = DivInPlace(num, nMult, nMult); |
355 | 0 | assert(pMod->nLen <= MAX_DIGITS); |
356 | 0 | pMod->bIsNeg = bIsNeg; |
357 | 0 | std::copy_n(num.begin(), pMod->nLen, pMod->nNum); |
358 | 0 | pMod->Normalize(); |
359 | 0 | } |
360 | 12.0k | if (pDiv) // rRes references pDiv |
361 | 12.0k | { |
362 | 12.0k | pDiv->bIsNeg = bIsNeg != rB.bIsNeg; |
363 | 12.0k | pDiv->nLen = nLen - rB.nLen + 1; |
364 | 12.0k | pDiv->Normalize(); |
365 | 12.0k | } |
366 | 12.0k | } |
367 | | |
368 | | BigInt::BigInt( std::u16string_view rString ) |
369 | 0 | : nLen(0) |
370 | 0 | { |
371 | 0 | bIsNeg = false; |
372 | 0 | nVal = 0; |
373 | |
|
374 | 0 | bool bNeg = false; |
375 | 0 | auto p = rString.begin(); |
376 | 0 | auto pEnd = rString.end(); |
377 | 0 | if (p == pEnd) |
378 | 0 | return; |
379 | 0 | if ( *p == '-' ) |
380 | 0 | { |
381 | 0 | bNeg = true; |
382 | 0 | p++; |
383 | 0 | } |
384 | 0 | if (p == pEnd) |
385 | 0 | return; |
386 | 0 | while( p != pEnd && *p >= '0' && *p <= '9' ) |
387 | 0 | { |
388 | 0 | *this *= 10; |
389 | 0 | *this += *p - '0'; |
390 | 0 | p++; |
391 | 0 | } |
392 | 0 | if (IsBig()) |
393 | 0 | bIsNeg = bNeg; |
394 | 0 | else if( bNeg ) |
395 | 0 | nVal = -nVal; |
396 | 0 | } |
397 | | |
398 | | BigInt::BigInt( double nValue ) |
399 | 0 | : nVal(0) |
400 | 0 | { |
401 | 0 | if ( nValue < 0 ) |
402 | 0 | { |
403 | 0 | nValue *= -1; |
404 | 0 | bIsNeg = true; |
405 | 0 | } |
406 | 0 | else |
407 | 0 | { |
408 | 0 | bIsNeg = false; |
409 | 0 | } |
410 | |
|
411 | 0 | if ( nValue < 1 ) |
412 | 0 | { |
413 | 0 | nVal = 0; |
414 | 0 | nLen = 0; |
415 | 0 | } |
416 | 0 | else |
417 | 0 | { |
418 | 0 | int i=0; |
419 | |
|
420 | 0 | while ( ( nValue > 0x100000000 ) && ( i < MAX_DIGITS ) ) |
421 | 0 | { |
422 | 0 | nNum[i] = static_cast<sal_uInt32>(fmod( nValue, 0x100000000 )); |
423 | 0 | nValue -= nNum[i]; |
424 | 0 | nValue /= 0x100000000; |
425 | 0 | i++; |
426 | 0 | } |
427 | 0 | if ( i < MAX_DIGITS ) |
428 | 0 | nNum[i++] = static_cast<sal_uInt32>(nValue); |
429 | |
|
430 | 0 | nLen = i; |
431 | |
|
432 | 0 | if ( i < 2 ) |
433 | 0 | Normalize(); |
434 | 0 | } |
435 | 0 | } |
436 | | |
437 | | BigInt::BigInt( sal_uInt32 nValue ) |
438 | 0 | : nVal(0) |
439 | 0 | , bIsNeg(false) |
440 | 0 | { |
441 | 0 | if ( nValue & 0x80000000U ) |
442 | 0 | { |
443 | 0 | nNum[0] = nValue; |
444 | 0 | nLen = 1; |
445 | 0 | } |
446 | 0 | else |
447 | 0 | { |
448 | 0 | nVal = nValue; |
449 | 0 | nLen = 0; |
450 | 0 | } |
451 | 0 | } |
452 | | |
453 | | BigInt::BigInt( sal_Int64 nValue ) |
454 | 8.71M | : nVal(0) |
455 | 8.71M | { |
456 | 8.71M | bIsNeg = nValue < 0; |
457 | 8.71M | nLen = 0; |
458 | | |
459 | 8.71M | if ((nValue >= SAL_MIN_INT32) && (nValue <= SAL_MAX_INT32)) |
460 | 8.66M | { |
461 | 8.66M | nVal = static_cast<sal_Int32>(nValue); |
462 | 8.66M | } |
463 | 49.5k | else |
464 | 49.5k | { |
465 | 49.5k | for (sal_uInt64 n = static_cast<sal_uInt64>( |
466 | 49.5k | (bIsNeg && nValue != std::numeric_limits<sal_Int64>::min()) ? -nValue : nValue); |
467 | 125k | n != 0; n >>= 32) |
468 | 75.7k | nNum[nLen++] = static_cast<sal_uInt32>(n); |
469 | 49.5k | } |
470 | 8.71M | } |
471 | | |
472 | | BigInt::operator double() const |
473 | 0 | { |
474 | 0 | if (!IsBig()) |
475 | 0 | return static_cast<double>(nVal); |
476 | 0 | else |
477 | 0 | { |
478 | 0 | int i = nLen-1; |
479 | 0 | double nRet = static_cast<double>(nNum[i]); |
480 | |
|
481 | 0 | while ( i ) |
482 | 0 | { |
483 | 0 | nRet *= 0x100000000; |
484 | 0 | i--; |
485 | 0 | nRet += static_cast<double>(nNum[i]); |
486 | 0 | } |
487 | |
|
488 | 0 | if ( bIsNeg ) |
489 | 0 | nRet *= -1; |
490 | |
|
491 | 0 | return nRet; |
492 | 0 | } |
493 | 0 | } |
494 | | |
495 | | BigInt& BigInt::operator=( const BigInt& rBigInt ) |
496 | 118k | { |
497 | 118k | if (this == &rBigInt) |
498 | 118k | return *this; |
499 | | |
500 | 0 | if (rBigInt.IsBig()) |
501 | 0 | memcpy( static_cast<void*>(this), static_cast<const void*>(&rBigInt), sizeof( BigInt ) ); |
502 | 0 | else |
503 | 0 | { |
504 | 0 | nLen = 0; |
505 | 0 | nVal = rBigInt.nVal; |
506 | 0 | } |
507 | 0 | return *this; |
508 | 118k | } |
509 | | |
510 | | BigInt& BigInt::operator+=( const BigInt& rVal ) |
511 | 2.16M | { |
512 | 2.16M | if (!IsBig() && !rVal.IsBig()) |
513 | 2.12M | { |
514 | 2.12M | if( nVal <= MY_MAXLONG && rVal.nVal <= MY_MAXLONG |
515 | 2.12M | && nVal >= MY_MINLONG && rVal.nVal >= MY_MINLONG ) |
516 | 2.12M | { // No overflows may occur here |
517 | 2.12M | nVal += rVal.nVal; |
518 | 2.12M | return *this; |
519 | 2.12M | } |
520 | | |
521 | 1.33k | if( (nVal < 0) != (rVal.nVal < 0) ) |
522 | 2 | { // No overflows may occur here |
523 | 2 | nVal += rVal.nVal; |
524 | 2 | return *this; |
525 | 2 | } |
526 | 1.33k | } |
527 | | |
528 | 41.0k | BigInt aTmp2 = rVal.MakeBig(); |
529 | 41.0k | MakeBig().AddBig(aTmp2, *this); |
530 | 41.0k | Normalize(); |
531 | 41.0k | return *this; |
532 | 2.16M | } |
533 | | |
534 | | BigInt& BigInt::operator-=( const BigInt& rVal ) |
535 | 27.9k | { |
536 | 27.9k | if (!IsBig() && !rVal.IsBig()) |
537 | 17.3k | { |
538 | 17.3k | if ( nVal <= MY_MAXLONG && rVal.nVal <= MY_MAXLONG && |
539 | 17.3k | nVal >= MY_MINLONG && rVal.nVal >= MY_MINLONG ) |
540 | 16.3k | { // No overflows may occur here |
541 | 16.3k | nVal -= rVal.nVal; |
542 | 16.3k | return *this; |
543 | 16.3k | } |
544 | | |
545 | 991 | if ( (nVal < 0) == (rVal.nVal < 0) ) |
546 | 1 | { // No overflows may occur here |
547 | 1 | nVal -= rVal.nVal; |
548 | 1 | return *this; |
549 | 1 | } |
550 | 991 | } |
551 | | |
552 | 11.6k | BigInt aTmp2 = rVal.MakeBig(); |
553 | 11.6k | MakeBig().SubBig(aTmp2, *this); |
554 | 11.6k | Normalize(); |
555 | 11.6k | return *this; |
556 | 27.9k | } |
557 | | |
558 | | BigInt& BigInt::operator*=( const BigInt& rVal ) |
559 | 2.22M | { |
560 | 2.22M | static const sal_Int32 MY_MAXSHORT = 0x00007fff; |
561 | 2.22M | static const sal_Int32 MY_MINSHORT = -MY_MAXSHORT; |
562 | | |
563 | 2.22M | if (!IsBig() && !rVal.IsBig() |
564 | 2.20M | && nVal <= MY_MAXSHORT && rVal.nVal <= MY_MAXSHORT |
565 | 1.82M | && nVal >= MY_MINSHORT && rVal.nVal >= MY_MINSHORT ) |
566 | | // TODO: not optimal !!! W.P. |
567 | 1.79M | { // No overflows may occur here |
568 | 1.79M | nVal *= rVal.nVal; |
569 | 1.79M | } |
570 | 429k | else |
571 | 429k | { |
572 | 429k | rVal.MakeBig().MultBig(MakeBig(), *this); |
573 | 429k | Normalize(); |
574 | 429k | } |
575 | 2.22M | return *this; |
576 | 2.22M | } |
577 | | |
578 | | void BigInt::DivMod(const BigInt& rVal, BigInt* pDiv, BigInt* pMod) const |
579 | 2.22M | { |
580 | 2.22M | assert(pDiv || pMod); // Avoid useless calls |
581 | 2.22M | if (!rVal.IsBig()) |
582 | 2.21M | { |
583 | 2.21M | if ( rVal.nVal == 0 ) |
584 | 10 | { |
585 | 10 | OSL_FAIL( "BigInt::operator/ --> divide by zero" ); |
586 | 10 | return; |
587 | 10 | } |
588 | | |
589 | 2.21M | if (rVal.nVal == 1) |
590 | 80.9k | { |
591 | 80.9k | if (pDiv) |
592 | 80.9k | { |
593 | 80.9k | *pDiv = *this; |
594 | 80.9k | pDiv->Normalize(); |
595 | 80.9k | } |
596 | 80.9k | if (pMod) |
597 | 0 | *pMod = 0; |
598 | 80.9k | return; |
599 | 80.9k | } |
600 | | |
601 | 2.13M | if (!IsBig()) |
602 | 2.09M | { |
603 | | // No overflows may occur here |
604 | 2.09M | const sal_Int32 nDiv = nVal / rVal.nVal; // Compilers usually optimize adjacent |
605 | 2.09M | const sal_Int32 nMod = nVal % rVal.nVal; // / and % into a single instruction |
606 | 2.09M | if (pDiv) |
607 | 2.09M | *pDiv = nDiv; |
608 | 2.09M | if (pMod) |
609 | 0 | *pMod = nMod; |
610 | 2.09M | return; |
611 | 2.09M | } |
612 | | |
613 | 37.0k | if ( rVal.nVal == -1 ) |
614 | 4 | { |
615 | 4 | if (pDiv) |
616 | 4 | { |
617 | 4 | *pDiv = *this; |
618 | 4 | pDiv->bIsNeg = !bIsNeg; |
619 | 4 | pDiv->Normalize(); |
620 | 4 | } |
621 | 4 | if (pMod) |
622 | 0 | *pMod = 0; |
623 | 4 | return; |
624 | 4 | } |
625 | | |
626 | | // Divide BigInt with an sal_uInt32 |
627 | 37.0k | sal_uInt32 nTmp; |
628 | 37.0k | bool bNegate; |
629 | 37.0k | if ( rVal.nVal < 0 ) |
630 | 1.59k | { |
631 | 1.59k | nTmp = static_cast<sal_uInt32>(-rVal.nVal); |
632 | 1.59k | bNegate = true; |
633 | 1.59k | } |
634 | 35.4k | else |
635 | 35.4k | { |
636 | 35.4k | nTmp = static_cast<sal_uInt32>(rVal.nVal); |
637 | 35.4k | bNegate = false; |
638 | 35.4k | } |
639 | | |
640 | 37.0k | BigInt aTmp; |
641 | 37.0k | BigInt& rDiv = pDiv ? *pDiv : aTmp; |
642 | 37.0k | rDiv = *this; |
643 | 37.0k | rDiv.nLen = DivInPlace({ rDiv.nNum, rDiv.nLen }, nTmp, nTmp); |
644 | 37.0k | if (pDiv) |
645 | 37.0k | { |
646 | 37.0k | if (bNegate) |
647 | 1.59k | pDiv->bIsNeg = !pDiv->bIsNeg; |
648 | 37.0k | pDiv->Normalize(); |
649 | 37.0k | } |
650 | 37.0k | if (pMod) |
651 | 0 | { |
652 | 0 | *pMod = BigInt(nTmp); |
653 | 0 | } |
654 | 37.0k | return; |
655 | 37.0k | } |
656 | | |
657 | 12.0k | BigInt tmpA = MakeBig(), tmpB = rVal.MakeBig(); |
658 | 12.0k | if (tmpA.ABS_IsLessBig(tmpB)) |
659 | 0 | { |
660 | | // First store *this to *pMod, then nullify *pDiv, to handle 'pDiv == this' case |
661 | 0 | if (pMod) |
662 | 0 | { |
663 | 0 | *pMod = *this; |
664 | 0 | pMod->Normalize(); |
665 | 0 | } |
666 | 0 | if (pDiv) |
667 | 0 | *pDiv = 0; |
668 | 0 | return; |
669 | 0 | } |
670 | | |
671 | | // Divide BigInt with BigInt |
672 | 12.0k | tmpA.DivModBig(tmpB, pDiv, pMod); |
673 | 12.0k | } |
674 | | |
675 | | BigInt& BigInt::operator/=( const BigInt& rVal ) |
676 | 2.22M | { |
677 | 2.22M | DivMod(rVal, this, nullptr); |
678 | 2.22M | return *this; |
679 | 2.22M | } |
680 | | |
681 | | BigInt& BigInt::operator%=( const BigInt& rVal ) |
682 | 0 | { |
683 | 0 | DivMod(rVal, nullptr, this); |
684 | 0 | return *this; |
685 | 0 | } |
686 | | |
687 | | bool operator==( const BigInt& rVal1, const BigInt& rVal2 ) |
688 | 0 | { |
689 | 0 | if (!rVal1.IsBig() && !rVal2.IsBig()) |
690 | 0 | return rVal1.nVal == rVal2.nVal; |
691 | | |
692 | 0 | BigInt nA = rVal1.MakeBig(), nB = rVal2.MakeBig(); |
693 | 0 | return nA.bIsNeg == nB.bIsNeg && nA.nLen == nB.nLen |
694 | 0 | && std::equal(nA.nNum, nA.nNum + nA.nLen, nB.nNum); |
695 | 0 | } |
696 | | |
697 | | std::strong_ordering operator<=>(const BigInt& rVal1, const BigInt& rVal2) |
698 | 0 | { |
699 | 0 | if (!rVal1.IsBig() && !rVal2.IsBig()) |
700 | 0 | return rVal1.nVal <=> rVal2.nVal; |
701 | | |
702 | 0 | BigInt nA = rVal1.MakeBig(), nB = rVal2.MakeBig(); |
703 | 0 | if (nA.bIsNeg != nB.bIsNeg) |
704 | 0 | return nB.bIsNeg ? std::strong_ordering::less : std::strong_ordering::greater; |
705 | 0 | if (nA.nLen < nB.nLen) |
706 | 0 | return nB.bIsNeg ? std::strong_ordering::greater : std::strong_ordering::less; |
707 | 0 | if (nA.nLen > nB.nLen) |
708 | 0 | return nB.bIsNeg ? std::strong_ordering::less : std::strong_ordering::greater; |
709 | 0 | int i = nA.nLen - 1; |
710 | 0 | while (i > 0 && nA.nNum[i] == nB.nNum[i]) |
711 | 0 | --i; |
712 | 0 | return nB.bIsNeg ? (nB.nNum[i] <=> nA.nNum[i]) : (nA.nNum[i] <=> nB.nNum[i]); |
713 | 0 | } |
714 | | |
715 | | tools::Long BigInt::Scale( tools::Long nVal, tools::Long nMul, tools::Long nDiv ) |
716 | 2.13M | { |
717 | 2.13M | BigInt aVal( nVal ); |
718 | | |
719 | 2.13M | aVal *= nMul; |
720 | | |
721 | 2.13M | if ( aVal.IsNeg() != ( nDiv < 0 ) ) |
722 | 17.5k | aVal -= nDiv / 2; // for correct rounding |
723 | 2.12M | else |
724 | 2.12M | aVal += nDiv / 2; // for correct rounding |
725 | | |
726 | 2.13M | aVal /= nDiv; |
727 | | |
728 | 2.13M | return tools::Long( aVal ); |
729 | 2.13M | } |
730 | | |
731 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |