Line data Source code
1 : // Copyright (c) 2019-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/prinbee
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
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
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // self
20 : //
21 : #include "catch_main.h"
22 :
23 : #include "num.hpp"
24 :
25 :
26 : // prinbee
27 : //
28 : #include <prinbee/bigint/add_sub.h>
29 : #include <prinbee/bigint/uint512.h>
30 : #include <prinbee/exception.h>
31 : #include <prinbee/utils.h>
32 :
33 :
34 : // snapdev
35 : //
36 : #include <snapdev/hexadecimal_string.h>
37 :
38 :
39 : // last include
40 : //
41 : #include <snapdev/poison.h>
42 :
43 :
44 :
45 : namespace
46 : {
47 :
48 :
49 :
50 :
51 :
52 : }
53 : // no name namespace
54 :
55 :
56 12 : CATCH_TEST_CASE("bigint", "[bigint] [valid]")
57 : {
58 14 : CATCH_START_SECTION("bigint: zero()")
59 : {
60 11 : for(int count(0); count < 10; ++count)
61 : {
62 10 : prinbee::uint512_t a;
63 10 : prinbee::int512_t b;
64 110 : for(int n(0); n < 10; ++n)
65 : {
66 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
67 100 : CATCH_REQUIRE(a.zero().is_zero());
68 :
69 100 : SNAP_CATCH2_NAMESPACE::rand512(b);
70 100 : CATCH_REQUIRE(b.zero().is_zero());
71 : }
72 : }
73 : }
74 13 : CATCH_END_SECTION()
75 :
76 14 : CATCH_START_SECTION("bigint: comparison operators")
77 : {
78 1 : prinbee::int512_t a;
79 :
80 1 : CATCH_REQUIRE(a == 0);
81 1 : CATCH_REQUIRE_FALSE(a != 0);
82 : //CATCH_REQUIRE(a <= 0); -- TODO: implement
83 1 : CATCH_REQUIRE_FALSE(a < 0);
84 : //CATCH_REQUIRE(a >= 0);
85 : //CATCH_REQUIRE_FALSE(a > 0);
86 :
87 1 : CATCH_REQUIRE_FALSE(a == 1);
88 1 : CATCH_REQUIRE(a != 1);
89 : //CATCH_REQUIRE(a <= 1);
90 1 : CATCH_REQUIRE(a < 1);
91 : //CATCH_REQUIRE_FALSE(a >= 1);
92 : //CATCH_REQUIRE_FALSE(a > 1);
93 :
94 1 : CATCH_REQUIRE_FALSE(a == -1);
95 1 : CATCH_REQUIRE(a != -1);
96 : //CATCH_REQUIRE_FALSE(a <= -1);
97 1 : CATCH_REQUIRE_FALSE(a < -1);
98 : //CATCH_REQUIRE(a >= -1);
99 : //CATCH_REQUIRE(a > -1);
100 :
101 : // set 'a' to -1
102 : //
103 1 : --a;
104 :
105 1 : CATCH_REQUIRE_FALSE(a == 0);
106 1 : CATCH_REQUIRE(a != 0);
107 : //CATCH_REQUIRE(a <= 0); -- TODO: implement
108 1 : CATCH_REQUIRE(a < 0);
109 : //CATCH_REQUIRE(a >= 0);
110 : //CATCH_REQUIRE_FALSE(a > 0);
111 :
112 1 : CATCH_REQUIRE_FALSE(a == 1);
113 1 : CATCH_REQUIRE(a != 1);
114 : //CATCH_REQUIRE(a <= 1);
115 1 : CATCH_REQUIRE(a < 1);
116 : //CATCH_REQUIRE_FALSE(a >= 1);
117 : //CATCH_REQUIRE_FALSE(a > 1);
118 :
119 1 : CATCH_REQUIRE(a == -1);
120 1 : CATCH_REQUIRE_FALSE(a != -1);
121 : //CATCH_REQUIRE_FALSE(a <= -1);
122 1 : CATCH_REQUIRE_FALSE(a < -1);
123 : //CATCH_REQUIRE(a >= -1);
124 : //CATCH_REQUIRE(a > -1);
125 :
126 : // set 'a' to -2
127 : //
128 1 : --a;
129 :
130 1 : CATCH_REQUIRE_FALSE(a == 0);
131 1 : CATCH_REQUIRE(a != 0);
132 : //CATCH_REQUIRE(a <= 0); -- TODO: implement
133 1 : CATCH_REQUIRE(a < 0);
134 : //CATCH_REQUIRE(a >= 0);
135 : //CATCH_REQUIRE_FALSE(a > 0);
136 :
137 1 : CATCH_REQUIRE_FALSE(a == 1);
138 1 : CATCH_REQUIRE(a != 1);
139 : //CATCH_REQUIRE(a <= 1);
140 1 : CATCH_REQUIRE(a < 1);
141 : //CATCH_REQUIRE_FALSE(a >= 1);
142 : //CATCH_REQUIRE_FALSE(a > 1);
143 :
144 1 : CATCH_REQUIRE_FALSE(a == -1);
145 1 : CATCH_REQUIRE(a != -1);
146 : //CATCH_REQUIRE_FALSE(a <= -1);
147 1 : CATCH_REQUIRE(a < -1);
148 : //CATCH_REQUIRE(a >= -1);
149 : //CATCH_REQUIRE(a > -1);
150 :
151 : // set 'a' to +1
152 : //
153 1 : a += 3;
154 :
155 1 : CATCH_REQUIRE_FALSE(a == 0);
156 1 : CATCH_REQUIRE(a != 0);
157 : //CATCH_REQUIRE(a <= 0); -- TODO: implement
158 1 : CATCH_REQUIRE_FALSE(a < 0);
159 : //CATCH_REQUIRE(a >= 0);
160 : //CATCH_REQUIRE_FALSE(a > 0);
161 :
162 1 : CATCH_REQUIRE(a == 1);
163 1 : CATCH_REQUIRE_FALSE(a != 1);
164 : //CATCH_REQUIRE(a <= 1);
165 1 : CATCH_REQUIRE_FALSE(a < 1);
166 : //CATCH_REQUIRE_FALSE(a >= 1);
167 : //CATCH_REQUIRE_FALSE(a > 1);
168 :
169 1 : CATCH_REQUIRE_FALSE(a == -1);
170 1 : CATCH_REQUIRE(a != -1);
171 : //CATCH_REQUIRE_FALSE(a <= -1);
172 1 : CATCH_REQUIRE_FALSE(a < -1);
173 : //CATCH_REQUIRE(a >= -1);
174 : //CATCH_REQUIRE(a > -1);
175 :
176 : // set 'a' to +2
177 : //
178 1 : ++a;
179 :
180 1 : CATCH_REQUIRE_FALSE(a == 0);
181 1 : CATCH_REQUIRE(a != 0);
182 : //CATCH_REQUIRE(a <= 0); -- TODO: implement
183 1 : CATCH_REQUIRE_FALSE(a < 0);
184 : //CATCH_REQUIRE(a >= 0);
185 : //CATCH_REQUIRE_FALSE(a > 0);
186 :
187 1 : CATCH_REQUIRE_FALSE(a == 1);
188 1 : CATCH_REQUIRE(a != 1);
189 : //CATCH_REQUIRE(a <= 1);
190 1 : CATCH_REQUIRE_FALSE(a < 1);
191 : //CATCH_REQUIRE_FALSE(a >= 1);
192 : //CATCH_REQUIRE_FALSE(a > 1);
193 :
194 1 : CATCH_REQUIRE_FALSE(a == -1);
195 1 : CATCH_REQUIRE(a != -1);
196 : //CATCH_REQUIRE_FALSE(a <= -1);
197 1 : CATCH_REQUIRE_FALSE(a < -1);
198 : //CATCH_REQUIRE(a >= -1);
199 : //CATCH_REQUIRE(a > -1);
200 :
201 : // generate a negative number which is far from -1
202 : //
203 : for(;;)
204 : {
205 1 : SNAP_CATCH2_NAMESPACE::rand512(a);
206 1 : a.f_high_value |= 0x8000000000000000LL;
207 :
208 : // make sure it's not "a small value" (fits in 64 bits)
209 1 : if(a.f_value[1] != 0xFFFFFFFFFFFFFFFFULL
210 0 : || a.f_value[2] != 0xFFFFFFFFFFFFFFFFULL
211 0 : || a.f_value[3] != 0xFFFFFFFFFFFFFFFFULL
212 0 : || a.f_value[4] != 0xFFFFFFFFFFFFFFFFULL
213 0 : || a.f_value[5] != 0xFFFFFFFFFFFFFFFFULL
214 0 : || a.f_value[6] != 0xFFFFFFFFFFFFFFFFULL
215 0 : || a.f_value[7] != 0xFFFFFFFFFFFFFFFFULL
216 0 : || a.f_high_value != -1LL)
217 : {
218 : break;
219 : }
220 : }
221 :
222 1 : CATCH_REQUIRE_FALSE(a == 0);
223 1 : CATCH_REQUIRE(a != 0);
224 : //CATCH_REQUIRE(a <= 0); -- TODO: implement
225 1 : CATCH_REQUIRE(a < 0);
226 : //CATCH_REQUIRE(a >= 0);
227 : //CATCH_REQUIRE_FALSE(a > 0);
228 :
229 1 : CATCH_REQUIRE_FALSE(a == 1);
230 1 : CATCH_REQUIRE(a != 1);
231 : //CATCH_REQUIRE(a <= 1);
232 1 : CATCH_REQUIRE(a < 1);
233 : //CATCH_REQUIRE_FALSE(a >= 1);
234 : //CATCH_REQUIRE_FALSE(a > 1);
235 :
236 1 : CATCH_REQUIRE_FALSE(a == -1);
237 1 : CATCH_REQUIRE(a != -1);
238 : //CATCH_REQUIRE_FALSE(a <= -1);
239 1 : CATCH_REQUIRE(a < -1);
240 : //CATCH_REQUIRE(a >= -1);
241 : //CATCH_REQUIRE(a > -1);
242 :
243 : // generate a positive number which is far from +1
244 : //
245 : for(;;)
246 : {
247 1 : SNAP_CATCH2_NAMESPACE::rand512(a);
248 1 : a.f_high_value &= 0x7FFFFFFFFFFFFFFFLL;
249 :
250 : // make sure it's not "a small value" (fits in 64 bits)
251 1 : if(a.f_value[1] != 0ULL
252 0 : || a.f_value[2] != 0ULL
253 0 : || a.f_value[3] != 0ULL
254 0 : || a.f_value[4] != 0ULL
255 0 : || a.f_value[5] != 0ULL
256 0 : || a.f_value[6] != 0ULL
257 0 : || a.f_value[7] != 0ULL
258 0 : || a.f_high_value != 0LL)
259 : {
260 : break;
261 : }
262 : }
263 :
264 1 : CATCH_REQUIRE_FALSE(a == 0);
265 1 : CATCH_REQUIRE(a != 0);
266 : //CATCH_REQUIRE(a <= 0); -- TODO: implement
267 1 : CATCH_REQUIRE_FALSE(a < 0);
268 : //CATCH_REQUIRE(a >= 0);
269 : //CATCH_REQUIRE_FALSE(a > 0);
270 :
271 1 : CATCH_REQUIRE_FALSE(a == 1);
272 1 : CATCH_REQUIRE(a != 1);
273 : //CATCH_REQUIRE(a <= 1);
274 1 : CATCH_REQUIRE_FALSE(a < 1);
275 : //CATCH_REQUIRE_FALSE(a >= 1);
276 : //CATCH_REQUIRE_FALSE(a > 1);
277 :
278 1 : CATCH_REQUIRE_FALSE(a == -1);
279 1 : CATCH_REQUIRE(a != -1);
280 : //CATCH_REQUIRE_FALSE(a <= -1);
281 1 : CATCH_REQUIRE_FALSE(a < -1);
282 : //CATCH_REQUIRE(a >= -1);
283 : //CATCH_REQUIRE(a > -1);
284 : }
285 13 : CATCH_END_SECTION()
286 :
287 14 : CATCH_START_SECTION("bigint: bit_size & lsr")
288 : {
289 11 : for(int count(0); count < 10; ++count)
290 : {
291 10 : prinbee::uint512_t a;
292 10 : prinbee::uint512_t b;
293 110 : for(int n(0); n < 10; ++n)
294 : {
295 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
296 100 : CATCH_REQUIRE(a.is_positive());
297 100 : CATCH_REQUIRE_FALSE(a.is_negative());
298 900 : for(std::size_t i(0); i < 8; ++i)
299 : {
300 800 : b.f_value[i] = 0;
301 : }
302 100 : CATCH_REQUIRE(b.is_zero());
303 :
304 100 : prinbee::uint512_t copy(a);
305 100 : copy.lsr(0);
306 100 : CATCH_REQUIRE(a == copy);
307 100 : copy.lsl(0);
308 100 : CATCH_REQUIRE(a == copy);
309 :
310 100 : a.f_value[7] |= 1ULL << 63;
311 100 : b.f_value[0] |= 1ULL;
312 :
313 100 : CATCH_REQUIRE(a != b);
314 :
315 : // compute shifts at once and verify in the loop below
316 : //
317 51300 : prinbee::uint512_t r_shifted[512];
318 51300 : prinbee::uint512_t l_shifted[512];
319 51300 : for(int size(512); size > 0; --size)
320 : {
321 51200 : r_shifted[size - 1] = a;
322 51200 : r_shifted[size - 1].lsr(512 - size + 1);
323 :
324 51200 : l_shifted[size - 1] = b;
325 51200 : l_shifted[size - 1].lsl(512 - size + 1);
326 : }
327 :
328 100 : prinbee::uint512_t a_op(a);
329 100 : prinbee::uint512_t b_op(b);
330 51300 : for(int size(512); size > 0; --size)
331 : {
332 51200 : CATCH_REQUIRE(a.bit_size() == static_cast<std::size_t>(size));
333 51200 : CATCH_REQUIRE(b.bit_size() == static_cast<std::size_t>(512 - size + 1));
334 51200 : CATCH_REQUIRE(a_op.bit_size() == static_cast<std::size_t>(size));
335 51200 : CATCH_REQUIRE(b_op.bit_size() == static_cast<std::size_t>(512 - size + 1));
336 :
337 51200 : if(size == 512)
338 : {
339 : // we use -a in this case so the size is ??? from 'a'
340 : // so I check with b which has a known size
341 : //
342 100 : prinbee::int512_t c(b);
343 100 : CATCH_REQUIRE(c.bit_size() == static_cast<std::size_t>(1));
344 100 : CATCH_REQUIRE(c.abs() == c);
345 100 : CATCH_REQUIRE(c == 1LL);
346 100 : CATCH_REQUIRE_FALSE(c == 2LL);
347 100 : CATCH_REQUIRE(c != 2LL);
348 :
349 100 : c = -c;
350 100 : CATCH_REQUIRE(c.bit_size() == static_cast<std::size_t>(1));
351 100 : CATCH_REQUIRE(c.abs() == -c);
352 100 : CATCH_REQUIRE(c == -1LL);
353 100 : CATCH_REQUIRE_FALSE(c != -1LL);
354 :
355 : // at this stage a and b are still not possibly equal
356 : //
357 100 : prinbee::int512_t d(a);
358 100 : CATCH_REQUIRE_FALSE(c == d);
359 100 : CATCH_REQUIRE(c != d);
360 :
361 100 : c = b;
362 100 : c.f_high_value = 1;
363 100 : CATCH_REQUIRE_FALSE(c == 1LL);
364 100 : CATCH_REQUIRE(c != 1LL);
365 :
366 100 : c = -c;
367 100 : CATCH_REQUIRE_FALSE(c == -1LL);
368 100 : CATCH_REQUIRE(c != -1LL);
369 : }
370 : else
371 : {
372 51100 : prinbee::int512_t c(a);
373 51100 : CATCH_REQUIRE(c.bit_size() == static_cast<std::size_t>(size));
374 :
375 51100 : if(size > 256)
376 : {
377 25500 : prinbee::int512_t d(b);
378 25500 : CATCH_REQUIRE(c > d);
379 25500 : CATCH_REQUIRE(c >= d);
380 25500 : CATCH_REQUIRE(c >= c);
381 25500 : CATCH_REQUIRE_FALSE(c < d);
382 25500 : CATCH_REQUIRE_FALSE(c <= d);
383 25500 : CATCH_REQUIRE(c >= c);
384 : }
385 :
386 : {
387 51100 : prinbee::int512_t d(a);
388 51100 : CATCH_REQUIRE(c == d);
389 51100 : CATCH_REQUIRE_FALSE(c != d);
390 51100 : ++d.f_high_value;
391 51100 : CATCH_REQUIRE_FALSE(c == d);
392 51100 : CATCH_REQUIRE(c != d);
393 : }
394 :
395 51100 : if(size == 1)
396 : {
397 : // in this case b is 1 << 511 which represents a
398 : // negative number "which remains negative" and
399 : // that's treated as a special case
400 : //
401 100 : prinbee::int512_t neg(b);
402 100 : CATCH_REQUIRE_FALSE(neg.is_positive());
403 100 : CATCH_REQUIRE(neg.is_negative());
404 100 : CATCH_REQUIRE(neg.bit_size() == 512ULL);
405 100 : CATCH_REQUIRE(neg != 1LL);
406 100 : CATCH_REQUIRE(neg != -1LL);
407 :
408 : // there is no valid representation of the
409 : // absolute value in this case...
410 : //
411 100 : CATCH_REQUIRE(neg.abs().is_negative());
412 : }
413 : else
414 : {
415 51000 : prinbee::int512_t pos(b);
416 51000 : CATCH_REQUIRE(pos.is_positive());
417 51000 : CATCH_REQUIRE_FALSE(pos.is_negative());
418 : }
419 : }
420 :
421 51200 : prinbee::uint512_t a_op2(a >> 1);
422 51200 : prinbee::uint512_t b_op2(b << 1);
423 :
424 51200 : CATCH_REQUIRE(a_op2 == r_shifted[size - 1]);
425 51200 : CATCH_REQUIRE(b_op2 == l_shifted[size - 1]);
426 :
427 51200 : a.lsr(1);
428 51200 : b.lsl(1);
429 :
430 51200 : CATCH_REQUIRE(a == r_shifted[size - 1]);
431 51200 : CATCH_REQUIRE(b == l_shifted[size - 1]);
432 :
433 51200 : a_op >>= 1;
434 51200 : b_op <<= 1;
435 :
436 51200 : CATCH_REQUIRE(a_op == r_shifted[size - 1]);
437 51200 : CATCH_REQUIRE(b_op == l_shifted[size - 1]);
438 : }
439 :
440 100 : CATCH_REQUIRE(a.is_zero());
441 100 : CATCH_REQUIRE(a.bit_size() == 0);
442 :
443 100 : CATCH_REQUIRE(b.is_zero());
444 100 : CATCH_REQUIRE(b.bit_size() == 0);
445 :
446 : {
447 100 : prinbee::int512_t c(a);
448 100 : CATCH_REQUIRE(c.bit_size() == 0);
449 : }
450 : }
451 : }
452 : }
453 13 : CATCH_END_SECTION()
454 :
455 14 : CATCH_START_SECTION("bigint: large shifts")
456 : {
457 1 : prinbee::uint512_t a;
458 1 : prinbee::uint512_t b;
459 9 : for(int n(512); n < 520; ++n)
460 : {
461 8 : SNAP_CATCH2_NAMESPACE::rand512(a);
462 8 : SNAP_CATCH2_NAMESPACE::rand512(b);
463 :
464 8 : a.lsr(n);
465 8 : CATCH_REQUIRE(a.is_zero());
466 :
467 8 : b.lsl(n);
468 8 : CATCH_REQUIRE(b.is_zero());
469 : }
470 : }
471 13 : CATCH_END_SECTION()
472 :
473 14 : CATCH_START_SECTION("bigint: logical operators")
474 : {
475 1 : prinbee::uint512_t a;
476 1 : prinbee::uint512_t b;
477 101 : for(int n(0); n < 100; ++n)
478 : {
479 : // AND
480 : {
481 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
482 100 : SNAP_CATCH2_NAMESPACE::rand512(b);
483 :
484 100 : std::uint64_t expected[8];
485 900 : for(int i(0); i < 8; ++i)
486 : {
487 800 : expected[i] = a.f_value[i] & b.f_value[i];
488 : }
489 :
490 100 : std::uint64_t const e(SNAP_CATCH2_NAMESPACE::rand64());
491 100 : prinbee::uint512_t const d(a & e);
492 100 : std::uint64_t const expected_uint64(a.f_value[0] & e);
493 100 : CATCH_REQUIRE(expected_uint64 == d.f_value[0]);
494 100 : CATCH_REQUIRE(0 == d.f_value[1]);
495 100 : CATCH_REQUIRE(0 == d.f_value[2]);
496 100 : CATCH_REQUIRE(0 == d.f_value[3]);
497 100 : CATCH_REQUIRE(0 == d.f_value[4]);
498 100 : CATCH_REQUIRE(0 == d.f_value[5]);
499 100 : CATCH_REQUIRE(0 == d.f_value[6]);
500 100 : CATCH_REQUIRE(0 == d.f_value[7]);
501 :
502 100 : prinbee::uint512_t l;
503 100 : l = a & b;
504 900 : for(int i(0); i < 8; ++i)
505 : {
506 800 : CATCH_REQUIRE(expected[i] == l.f_value[i]);
507 : }
508 :
509 100 : a &= b;
510 900 : for(int i(0); i < 8; ++i)
511 : {
512 800 : CATCH_REQUIRE(expected[i] == a.f_value[i]);
513 : }
514 : }
515 :
516 : // OR
517 : {
518 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
519 100 : SNAP_CATCH2_NAMESPACE::rand512(b);
520 :
521 100 : std::uint64_t expected[8];
522 900 : for(int i(0); i < 8; ++i)
523 : {
524 800 : expected[i] = a.f_value[i] | b.f_value[i];
525 : }
526 :
527 100 : std::uint64_t const e(SNAP_CATCH2_NAMESPACE::rand64());
528 100 : prinbee::uint512_t const d(a | e);
529 100 : std::uint64_t const expected_uint64(a.f_value[0] | e);
530 100 : CATCH_REQUIRE(expected_uint64 == d.f_value[0]);
531 100 : CATCH_REQUIRE(a.f_value[1] == d.f_value[1]);
532 100 : CATCH_REQUIRE(a.f_value[2] == d.f_value[2]);
533 100 : CATCH_REQUIRE(a.f_value[3] == d.f_value[3]);
534 100 : CATCH_REQUIRE(a.f_value[4] == d.f_value[4]);
535 100 : CATCH_REQUIRE(a.f_value[5] == d.f_value[5]);
536 100 : CATCH_REQUIRE(a.f_value[6] == d.f_value[6]);
537 100 : CATCH_REQUIRE(a.f_value[7] == d.f_value[7]);
538 :
539 100 : prinbee::uint512_t l;
540 100 : l = a | b;
541 900 : for(int i(0); i < 8; ++i)
542 : {
543 800 : CATCH_REQUIRE(expected[i] == l.f_value[i]);
544 : }
545 :
546 100 : a |= b;
547 900 : for(int i(0); i < 8; ++i)
548 : {
549 800 : CATCH_REQUIRE(expected[i] == a.f_value[i]);
550 : }
551 : }
552 :
553 : // XOR
554 : {
555 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
556 100 : SNAP_CATCH2_NAMESPACE::rand512(b);
557 :
558 100 : std::uint64_t expected[8];
559 900 : for(int i(0); i < 8; ++i)
560 : {
561 800 : expected[i] = a.f_value[i] ^ b.f_value[i];
562 : }
563 :
564 100 : std::uint64_t const e(SNAP_CATCH2_NAMESPACE::rand64());
565 100 : prinbee::uint512_t const d(a ^ e);
566 100 : std::uint64_t const expected_uint64(a.f_value[0] ^ e);
567 100 : CATCH_REQUIRE(expected_uint64 == d.f_value[0]);
568 100 : CATCH_REQUIRE(a.f_value[1] == d.f_value[1]);
569 100 : CATCH_REQUIRE(a.f_value[2] == d.f_value[2]);
570 100 : CATCH_REQUIRE(a.f_value[3] == d.f_value[3]);
571 100 : CATCH_REQUIRE(a.f_value[4] == d.f_value[4]);
572 100 : CATCH_REQUIRE(a.f_value[5] == d.f_value[5]);
573 100 : CATCH_REQUIRE(a.f_value[6] == d.f_value[6]);
574 100 : CATCH_REQUIRE(a.f_value[7] == d.f_value[7]);
575 :
576 100 : prinbee::uint512_t l;
577 100 : l = a ^ b;
578 900 : for(int i(0); i < 8; ++i)
579 : {
580 800 : CATCH_REQUIRE(expected[i] == l.f_value[i]);
581 : }
582 :
583 100 : a ^= b;
584 900 : for(int i(0); i < 8; ++i)
585 : {
586 800 : CATCH_REQUIRE(expected[i] == a.f_value[i]);
587 : }
588 : }
589 : }
590 : }
591 13 : CATCH_END_SECTION()
592 :
593 14 : CATCH_START_SECTION("bigint: copying")
594 : {
595 11 : for(int count(0); count < 10; ++count)
596 : {
597 10 : prinbee::uint512_t a;
598 10 : prinbee::int512_t b;
599 110 : for(int n(0); n < 10; ++n)
600 : {
601 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
602 100 : SNAP_CATCH2_NAMESPACE::rand512(b);
603 :
604 100 : prinbee::uint512_t a1(a);
605 100 : CATCH_REQUIRE(a.f_value[0] == a1.f_value[0]);
606 100 : CATCH_REQUIRE(a.f_value[1] == a1.f_value[1]);
607 100 : CATCH_REQUIRE(a.f_value[2] == a1.f_value[2]);
608 100 : CATCH_REQUIRE(a.f_value[3] == a1.f_value[3]);
609 100 : CATCH_REQUIRE(a.f_value[4] == a1.f_value[4]);
610 100 : CATCH_REQUIRE(a.f_value[5] == a1.f_value[5]);
611 100 : CATCH_REQUIRE(a.f_value[6] == a1.f_value[6]);
612 100 : CATCH_REQUIRE(a.f_value[7] == a1.f_value[7]);
613 :
614 100 : CATCH_REQUIRE(a >= a1);
615 100 : CATCH_REQUIRE_FALSE(a > a1);
616 100 : CATCH_REQUIRE(a <= a1);
617 100 : CATCH_REQUIRE_FALSE(a < a1);
618 :
619 100 : prinbee::int512_t a2(a);
620 100 : CATCH_REQUIRE(a.f_value[0] == a2.f_value[0]);
621 100 : CATCH_REQUIRE(a.f_value[1] == a2.f_value[1]);
622 100 : CATCH_REQUIRE(a.f_value[2] == a2.f_value[2]);
623 100 : CATCH_REQUIRE(a.f_value[3] == a2.f_value[3]);
624 100 : CATCH_REQUIRE(a.f_value[4] == a2.f_value[4]);
625 100 : CATCH_REQUIRE(a.f_value[5] == a2.f_value[5]);
626 100 : CATCH_REQUIRE(a.f_value[6] == a2.f_value[6]);
627 100 : CATCH_REQUIRE(a.f_value[7] == static_cast<std::uint64_t>(a2.f_high_value));
628 :
629 100 : prinbee::uint512_t a3({
630 100 : a.f_value[0],
631 100 : a.f_value[1],
632 100 : a.f_value[2],
633 100 : a.f_value[3],
634 100 : a.f_value[4],
635 100 : a.f_value[5],
636 100 : a.f_value[6],
637 100 : a.f_value[7],
638 100 : });
639 100 : CATCH_REQUIRE(a.f_value[0] == a3.f_value[0]);
640 100 : CATCH_REQUIRE(a.f_value[1] == a3.f_value[1]);
641 100 : CATCH_REQUIRE(a.f_value[2] == a3.f_value[2]);
642 100 : CATCH_REQUIRE(a.f_value[3] == a3.f_value[3]);
643 100 : CATCH_REQUIRE(a.f_value[4] == a3.f_value[4]);
644 100 : CATCH_REQUIRE(a.f_value[5] == a3.f_value[5]);
645 100 : CATCH_REQUIRE(a.f_value[6] == a3.f_value[6]);
646 100 : CATCH_REQUIRE(a.f_value[7] == a3.f_value[7]);
647 :
648 100 : prinbee::uint512_t a4({
649 100 : a.f_value[4],
650 100 : a.f_value[5],
651 100 : a.f_value[6],
652 100 : a.f_value[7],
653 100 : });
654 100 : CATCH_REQUIRE(a.f_value[4] == a4.f_value[0]);
655 100 : CATCH_REQUIRE(a.f_value[5] == a4.f_value[1]);
656 100 : CATCH_REQUIRE(a.f_value[6] == a4.f_value[2]);
657 100 : CATCH_REQUIRE(a.f_value[7] == a4.f_value[3]);
658 100 : CATCH_REQUIRE(0 == a4.f_value[4]);
659 100 : CATCH_REQUIRE(0 == a4.f_value[5]);
660 100 : CATCH_REQUIRE(0 == a4.f_value[6]);
661 100 : CATCH_REQUIRE(0 == a4.f_value[7]);
662 :
663 100 : prinbee::uint512_t a5;
664 100 : a5 = a;
665 100 : CATCH_REQUIRE(a.f_value[0] == a5.f_value[0]);
666 100 : CATCH_REQUIRE(a.f_value[1] == a5.f_value[1]);
667 100 : CATCH_REQUIRE(a.f_value[2] == a5.f_value[2]);
668 100 : CATCH_REQUIRE(a.f_value[3] == a5.f_value[3]);
669 100 : CATCH_REQUIRE(a.f_value[4] == a5.f_value[4]);
670 100 : CATCH_REQUIRE(a.f_value[5] == a5.f_value[5]);
671 100 : CATCH_REQUIRE(a.f_value[6] == a5.f_value[6]);
672 100 : CATCH_REQUIRE(a.f_value[7] == a5.f_value[7]);
673 :
674 100 : prinbee::uint512_t a6;
675 100 : a6 = b;
676 100 : CATCH_REQUIRE(b.f_value[0] == a6.f_value[0]);
677 100 : CATCH_REQUIRE(b.f_value[1] == a6.f_value[1]);
678 100 : CATCH_REQUIRE(b.f_value[2] == a6.f_value[2]);
679 100 : CATCH_REQUIRE(b.f_value[3] == a6.f_value[3]);
680 100 : CATCH_REQUIRE(b.f_value[4] == a6.f_value[4]);
681 100 : CATCH_REQUIRE(b.f_value[5] == a6.f_value[5]);
682 100 : CATCH_REQUIRE(b.f_value[6] == a6.f_value[6]);
683 100 : CATCH_REQUIRE(static_cast<std::uint64_t>(b.f_high_value) == a6.f_value[7]);
684 :
685 100 : prinbee::uint512_t b1(b);
686 100 : CATCH_REQUIRE(b.f_value[0] == b1.f_value[0]);
687 100 : CATCH_REQUIRE(b.f_value[1] == b1.f_value[1]);
688 100 : CATCH_REQUIRE(b.f_value[2] == b1.f_value[2]);
689 100 : CATCH_REQUIRE(b.f_value[3] == b1.f_value[3]);
690 100 : CATCH_REQUIRE(b.f_value[4] == b1.f_value[4]);
691 100 : CATCH_REQUIRE(b.f_value[5] == b1.f_value[5]);
692 100 : CATCH_REQUIRE(b.f_value[6] == b1.f_value[6]);
693 100 : CATCH_REQUIRE(static_cast<std::uint64_t>(b.f_high_value) == b1.f_value[7]);
694 :
695 100 : prinbee::int512_t b2(b);
696 100 : CATCH_REQUIRE(b.f_value[0] == b2.f_value[0]);
697 100 : CATCH_REQUIRE(b.f_value[1] == b2.f_value[1]);
698 100 : CATCH_REQUIRE(b.f_value[2] == b2.f_value[2]);
699 100 : CATCH_REQUIRE(b.f_value[3] == b2.f_value[3]);
700 100 : CATCH_REQUIRE(b.f_value[4] == b2.f_value[4]);
701 100 : CATCH_REQUIRE(b.f_value[5] == b2.f_value[5]);
702 100 : CATCH_REQUIRE(b.f_value[6] == b2.f_value[6]);
703 100 : CATCH_REQUIRE(b.f_high_value == b2.f_high_value);
704 :
705 100 : CATCH_REQUIRE(b == b2);
706 100 : CATCH_REQUIRE_FALSE(b != b2);
707 100 : CATCH_REQUIRE(b <= b2);
708 100 : CATCH_REQUIRE_FALSE(b < b2);
709 100 : CATCH_REQUIRE(b >= b2);
710 100 : CATCH_REQUIRE_FALSE(b > b2);
711 :
712 100 : prinbee::uint512_t b3({
713 100 : b.f_value[0],
714 100 : b.f_value[1],
715 100 : b.f_value[2],
716 100 : b.f_value[3],
717 100 : b.f_value[4],
718 100 : b.f_value[5],
719 100 : b.f_value[6],
720 100 : static_cast<std::uint64_t>(b.f_high_value),
721 100 : });
722 100 : CATCH_REQUIRE(b.f_value[0] == b3.f_value[0]);
723 100 : CATCH_REQUIRE(b.f_value[1] == b3.f_value[1]);
724 100 : CATCH_REQUIRE(b.f_value[2] == b3.f_value[2]);
725 100 : CATCH_REQUIRE(b.f_value[3] == b3.f_value[3]);
726 100 : CATCH_REQUIRE(b.f_value[4] == b3.f_value[4]);
727 100 : CATCH_REQUIRE(b.f_value[5] == b3.f_value[5]);
728 100 : CATCH_REQUIRE(b.f_value[6] == b3.f_value[6]);
729 100 : CATCH_REQUIRE(b.f_high_value == static_cast<std::int64_t>(b3.f_value[7]));
730 :
731 100 : prinbee::int512_t b4({
732 100 : b.f_value[4],
733 100 : b.f_value[5],
734 100 : b.f_value[6],
735 100 : static_cast<std::uint64_t>(b.f_high_value),
736 100 : });
737 100 : CATCH_REQUIRE(b.f_value[4] == b4.f_value[0]);
738 100 : CATCH_REQUIRE(b.f_value[5] == b4.f_value[1]);
739 100 : CATCH_REQUIRE(b.f_value[6] == b4.f_value[2]);
740 100 : CATCH_REQUIRE(static_cast<std::uint64_t>(b.f_high_value) == b4.f_value[3]);
741 100 : CATCH_REQUIRE(0 == b4.f_value[4]);
742 100 : CATCH_REQUIRE(0 == b4.f_value[5]);
743 100 : CATCH_REQUIRE(0 == b4.f_value[6]);
744 100 : CATCH_REQUIRE(0 == b4.f_high_value);
745 :
746 100 : prinbee::int512_t b5;
747 100 : b5 = b;
748 100 : CATCH_REQUIRE(b.f_value[0] == b5.f_value[0]);
749 100 : CATCH_REQUIRE(b.f_value[1] == b5.f_value[1]);
750 100 : CATCH_REQUIRE(b.f_value[2] == b5.f_value[2]);
751 100 : CATCH_REQUIRE(b.f_value[3] == b5.f_value[3]);
752 100 : CATCH_REQUIRE(b.f_value[4] == b5.f_value[4]);
753 100 : CATCH_REQUIRE(b.f_value[5] == b5.f_value[5]);
754 100 : CATCH_REQUIRE(b.f_value[6] == b5.f_value[6]);
755 100 : CATCH_REQUIRE(b.f_high_value == b5.f_high_value);
756 :
757 100 : prinbee::int512_t b6;
758 100 : b6 = a;
759 100 : CATCH_REQUIRE(a.f_value[0] == b6.f_value[0]);
760 100 : CATCH_REQUIRE(a.f_value[1] == b6.f_value[1]);
761 100 : CATCH_REQUIRE(a.f_value[2] == b6.f_value[2]);
762 100 : CATCH_REQUIRE(a.f_value[3] == b6.f_value[3]);
763 100 : CATCH_REQUIRE(a.f_value[4] == b6.f_value[4]);
764 100 : CATCH_REQUIRE(a.f_value[5] == b6.f_value[5]);
765 100 : CATCH_REQUIRE(a.f_value[6] == b6.f_value[6]);
766 100 : CATCH_REQUIRE(a.f_value[7] == static_cast<std::uint64_t>(b6.f_high_value));
767 :
768 100 : prinbee::uint512_t diff;
769 100 : int overflow(prinbee::sub(diff.f_value, a.f_value, b3.f_value, 8));
770 100 : if(overflow == 0)
771 : {
772 : // no overflow means a >= b3
773 : //
774 45 : CATCH_REQUIRE(a >= b3);
775 :
776 45 : overflow = prinbee::sub(diff.f_value, b3.f_value, a.f_value, 8);
777 45 : if(overflow == 1)
778 : {
779 : // overflow the other way, then it's not equal so a > b3
780 : //
781 45 : CATCH_REQUIRE(a > b3);
782 : }
783 : }
784 : else
785 : {
786 : // overflow means a < b3
787 : //
788 55 : CATCH_REQUIRE(a < b3);
789 : }
790 : }
791 : }
792 : }
793 13 : CATCH_END_SECTION()
794 :
795 14 : CATCH_START_SECTION("bigint: additions")
796 : {
797 11 : for(int count(0); count < 10; ++count)
798 : {
799 10 : std::size_t const size(rand() % 128 + 16);
800 30 : std::vector<std::uint64_t> a(size);
801 30 : std::vector<std::uint64_t> b(size);
802 30 : std::vector<std::uint64_t> c(size);
803 30 : std::vector<std::uint64_t> d(size);
804 :
805 110 : for(int n(0); n < 10; ++n)
806 : {
807 100 : int carry(0);
808 9960 : for(std::size_t i(0); i < size; ++i)
809 : {
810 9860 : a[i] = SNAP_CATCH2_NAMESPACE::rand64();
811 9860 : b[i] = SNAP_CATCH2_NAMESPACE::rand64();
812 :
813 : // "manually" compute the sum
814 9860 : c[i] = a[i] + b[i] + carry;
815 9860 : carry = c[i] < a[i] || c[i] < b[i] ? 1 : 0;
816 : }
817 :
818 : // very large number addition
819 : //
820 100 : int const overflow(prinbee::add(d.data(), a.data(), b.data(), size));
821 :
822 100 : CATCH_REQUIRE(overflow == carry);
823 9960 : for(std::size_t i(0); i < size; ++i)
824 : {
825 9860 : CATCH_REQUIRE(d[i] == c[i]);
826 : }
827 :
828 : // 128 bits addition
829 : //
830 100 : d = a;
831 100 : prinbee::add128(d.data(), b.data());
832 100 : CATCH_REQUIRE(d[0] == c[0]);
833 100 : CATCH_REQUIRE(d[1] == c[1]);
834 :
835 : // 256 bits addition
836 : //
837 100 : d = a;
838 100 : prinbee::add256(d.data(), b.data());
839 100 : CATCH_REQUIRE(d[0] == c[0]);
840 100 : CATCH_REQUIRE(d[1] == c[1]);
841 100 : CATCH_REQUIRE(d[2] == c[2]);
842 100 : CATCH_REQUIRE(d[3] == c[3]);
843 :
844 : // 512 bits addition
845 : //
846 100 : d = a;
847 100 : prinbee::add512(d.data(), b.data());
848 100 : CATCH_REQUIRE(d[0] == c[0]);
849 100 : CATCH_REQUIRE(d[1] == c[1]);
850 100 : CATCH_REQUIRE(d[2] == c[2]);
851 100 : CATCH_REQUIRE(d[3] == c[3]);
852 100 : CATCH_REQUIRE(d[4] == c[4]);
853 100 : CATCH_REQUIRE(d[5] == c[5]);
854 100 : CATCH_REQUIRE(d[6] == c[6]);
855 100 : CATCH_REQUIRE(d[7] == c[7]);
856 :
857 100 : prinbee::uint512_t ai;
858 100 : ai.f_value[0] = a[0];
859 100 : ai.f_value[1] = a[1];
860 100 : ai.f_value[2] = a[2];
861 100 : ai.f_value[3] = a[3];
862 100 : ai.f_value[4] = a[4];
863 100 : ai.f_value[5] = a[5];
864 100 : ai.f_value[6] = a[6];
865 100 : ai.f_value[7] = a[7];
866 :
867 100 : prinbee::uint512_t bi;
868 100 : bi.f_value[0] = b[0];
869 100 : bi.f_value[1] = b[1];
870 100 : bi.f_value[2] = b[2];
871 100 : bi.f_value[3] = b[3];
872 100 : bi.f_value[4] = b[4];
873 100 : bi.f_value[5] = b[5];
874 100 : bi.f_value[6] = b[6];
875 100 : bi.f_value[7] = b[7];
876 :
877 100 : prinbee::int512_t as(ai);
878 100 : prinbee::int512_t bs(bi);
879 :
880 : // operator + ()
881 100 : prinbee::uint512_t di(ai + bi);
882 100 : CATCH_REQUIRE(c[0] == di.f_value[0]);
883 100 : CATCH_REQUIRE(c[1] == di.f_value[1]);
884 100 : CATCH_REQUIRE(c[2] == di.f_value[2]);
885 100 : CATCH_REQUIRE(c[3] == di.f_value[3]);
886 100 : CATCH_REQUIRE(c[4] == di.f_value[4]);
887 100 : CATCH_REQUIRE(c[5] == di.f_value[5]);
888 100 : CATCH_REQUIRE(c[6] == di.f_value[6]);
889 100 : CATCH_REQUIRE(c[7] == di.f_value[7]);
890 :
891 : // operator += ()
892 100 : ai += bi;
893 100 : CATCH_REQUIRE(c[0] == ai.f_value[0]);
894 100 : CATCH_REQUIRE(c[1] == ai.f_value[1]);
895 100 : CATCH_REQUIRE(c[2] == ai.f_value[2]);
896 100 : CATCH_REQUIRE(c[3] == ai.f_value[3]);
897 100 : CATCH_REQUIRE(c[4] == ai.f_value[4]);
898 100 : CATCH_REQUIRE(c[5] == ai.f_value[5]);
899 100 : CATCH_REQUIRE(c[6] == ai.f_value[6]);
900 100 : CATCH_REQUIRE(c[7] == ai.f_value[7]);
901 :
902 : // operator + ()
903 : // TODO
904 : //prinbee::int512_t ds(as + bs);
905 : //CATCH_REQUIRE(c[0] == ds.f_value[0]);
906 : //CATCH_REQUIRE(c[1] == ds.f_value[1]);
907 : //CATCH_REQUIRE(c[2] == ds.f_value[2]);
908 : //CATCH_REQUIRE(c[3] == ds.f_value[3]);
909 : //CATCH_REQUIRE(c[4] == ds.f_value[4]);
910 : //CATCH_REQUIRE(c[5] == ds.f_value[5]);
911 : //CATCH_REQUIRE(c[6] == ds.f_value[6]);
912 : //CATCH_REQUIRE(c[7] == static_cast<std::uint64_t>(ds.f_high_value));
913 :
914 : // operator += ()
915 100 : as += bs;
916 100 : CATCH_REQUIRE(c[0] == as.f_value[0]);
917 100 : CATCH_REQUIRE(c[1] == as.f_value[1]);
918 100 : CATCH_REQUIRE(c[2] == as.f_value[2]);
919 100 : CATCH_REQUIRE(c[3] == as.f_value[3]);
920 100 : CATCH_REQUIRE(c[4] == as.f_value[4]);
921 100 : CATCH_REQUIRE(c[5] == as.f_value[5]);
922 100 : CATCH_REQUIRE(c[6] == as.f_value[6]);
923 100 : CATCH_REQUIRE(c[7] == static_cast<std::uint64_t>(as.f_high_value));
924 : }
925 10 : }
926 : }
927 13 : CATCH_END_SECTION()
928 :
929 14 : CATCH_START_SECTION("bigint: substractions")
930 : {
931 11 : for(int count(0); count < 10; ++count)
932 : {
933 10 : std::size_t const size(rand() % 128 + 16);
934 30 : std::vector<std::uint64_t> a(size);
935 30 : std::vector<std::uint64_t> b(size);
936 30 : std::vector<std::uint64_t> c(size);
937 30 : std::vector<std::uint64_t> d(size);
938 :
939 110 : for(int n(0); n < 10; ++n)
940 : {
941 100 : int borrow(0);
942 7480 : for(std::size_t i(0); i < size; ++i)
943 : {
944 7380 : a[i] = SNAP_CATCH2_NAMESPACE::rand64();
945 7380 : b[i] = SNAP_CATCH2_NAMESPACE::rand64();
946 :
947 : // "manually" compute the difference
948 7380 : c[i] = a[i] - b[i] - borrow;
949 7380 : borrow = a[i] < b[i] ? 1 : 0;
950 : }
951 :
952 100 : int const overflow(prinbee::sub(d.data(), a.data(), b.data(), size));
953 :
954 100 : CATCH_REQUIRE(overflow == borrow);
955 7480 : for(std::size_t i(0); i < size; ++i)
956 : {
957 7380 : CATCH_REQUIRE(d[i] == c[i]);
958 : }
959 :
960 : // 128 bits addition
961 : //
962 100 : d = a;
963 100 : prinbee::sub128(d.data(), b.data());
964 100 : CATCH_REQUIRE(d[0] == c[0]);
965 100 : CATCH_REQUIRE(d[1] == c[1]);
966 :
967 : // 256 bits addition
968 : //
969 100 : d = a;
970 100 : prinbee::sub256(d.data(), b.data());
971 100 : CATCH_REQUIRE(d[0] == c[0]);
972 100 : CATCH_REQUIRE(d[1] == c[1]);
973 100 : CATCH_REQUIRE(d[2] == c[2]);
974 100 : CATCH_REQUIRE(d[3] == c[3]);
975 :
976 : // 512 bits addition
977 : //
978 100 : d = a;
979 100 : prinbee::sub512(d.data(), b.data());
980 100 : CATCH_REQUIRE(d[0] == c[0]);
981 100 : CATCH_REQUIRE(d[1] == c[1]);
982 100 : CATCH_REQUIRE(d[2] == c[2]);
983 100 : CATCH_REQUIRE(d[3] == c[3]);
984 100 : CATCH_REQUIRE(d[4] == c[4]);
985 100 : CATCH_REQUIRE(d[5] == c[5]);
986 100 : CATCH_REQUIRE(d[6] == c[6]);
987 100 : CATCH_REQUIRE(d[7] == c[7]);
988 :
989 100 : prinbee::uint512_t ai;
990 100 : ai.f_value[0] = a[0];
991 100 : ai.f_value[1] = a[1];
992 100 : ai.f_value[2] = a[2];
993 100 : ai.f_value[3] = a[3];
994 100 : ai.f_value[4] = a[4];
995 100 : ai.f_value[5] = a[5];
996 100 : ai.f_value[6] = a[6];
997 100 : ai.f_value[7] = a[7];
998 :
999 100 : prinbee::uint512_t bi;
1000 100 : bi.f_value[0] = b[0];
1001 100 : bi.f_value[1] = b[1];
1002 100 : bi.f_value[2] = b[2];
1003 100 : bi.f_value[3] = b[3];
1004 100 : bi.f_value[4] = b[4];
1005 100 : bi.f_value[5] = b[5];
1006 100 : bi.f_value[6] = b[6];
1007 100 : bi.f_value[7] = b[7];
1008 :
1009 100 : if(a[0] == b[0]
1010 0 : && a[1] == b[1]
1011 0 : && a[2] == b[2]
1012 0 : && a[3] == b[3]
1013 0 : && a[4] == b[4]
1014 0 : && a[5] == b[5]
1015 0 : && a[6] == b[6]
1016 100 : && a[7] == b[7])
1017 : {
1018 : // this is incredibly unlikely since we randomly generate
1019 : // a and b values
1020 : //
1021 0 : CATCH_REQUIRE(ai == bi);
1022 0 : CATCH_REQUIRE_FALSE(ai != bi);
1023 : }
1024 : else
1025 : {
1026 100 : CATCH_REQUIRE_FALSE(ai == bi);
1027 100 : CATCH_REQUIRE(ai != bi);
1028 : }
1029 :
1030 : // operator - ()
1031 100 : prinbee::uint512_t di(ai - bi);
1032 100 : CATCH_REQUIRE(c[0] == di.f_value[0]);
1033 100 : CATCH_REQUIRE(c[1] == di.f_value[1]);
1034 100 : CATCH_REQUIRE(c[2] == di.f_value[2]);
1035 100 : CATCH_REQUIRE(c[3] == di.f_value[3]);
1036 100 : CATCH_REQUIRE(c[4] == di.f_value[4]);
1037 100 : CATCH_REQUIRE(c[5] == di.f_value[5]);
1038 100 : CATCH_REQUIRE(c[6] == di.f_value[6]);
1039 100 : CATCH_REQUIRE(c[7] == di.f_value[7]);
1040 :
1041 : // operator -= ()
1042 100 : ai -= bi;
1043 100 : CATCH_REQUIRE(c[0] == ai.f_value[0]);
1044 100 : CATCH_REQUIRE(c[1] == ai.f_value[1]);
1045 100 : CATCH_REQUIRE(c[2] == ai.f_value[2]);
1046 100 : CATCH_REQUIRE(c[3] == ai.f_value[3]);
1047 100 : CATCH_REQUIRE(c[4] == ai.f_value[4]);
1048 100 : CATCH_REQUIRE(c[5] == ai.f_value[5]);
1049 100 : CATCH_REQUIRE(c[6] == ai.f_value[6]);
1050 100 : CATCH_REQUIRE(c[7] == ai.f_value[7]);
1051 :
1052 : // operator == () and operator != ()
1053 100 : CATCH_REQUIRE(ai == ai);
1054 100 : CATCH_REQUIRE_FALSE(ai != ai);
1055 :
1056 100 : if(bi.f_value[1] != 0
1057 0 : || bi.f_value[2] != 0
1058 0 : || bi.f_value[3] != 0
1059 0 : || bi.f_value[4] != 0
1060 0 : || bi.f_value[5] != 0
1061 0 : || bi.f_value[6] != 0
1062 0 : || bi.f_value[7] != 0)
1063 : {
1064 100 : CATCH_REQUIRE_FALSE(bi == bi.f_value[0]);
1065 100 : CATCH_REQUIRE(bi != bi.f_value[0]);
1066 : }
1067 :
1068 100 : bi.f_value[1] = 0;
1069 100 : bi.f_value[2] = 0;
1070 100 : bi.f_value[3] = 0;
1071 100 : bi.f_value[4] = 0;
1072 100 : bi.f_value[5] = 0;
1073 100 : bi.f_value[6] = 0;
1074 100 : bi.f_value[7] = 0;
1075 :
1076 100 : CATCH_REQUIRE(bi == bi.f_value[0]);
1077 100 : CATCH_REQUIRE_FALSE(bi != bi.f_value[0]);
1078 : }
1079 10 : }
1080 : }
1081 13 : CATCH_END_SECTION()
1082 :
1083 14 : CATCH_START_SECTION("bigint: not/neg")
1084 : {
1085 11 : for(int n(0); n < 10; ++n)
1086 : {
1087 10 : prinbee::uint512_t a;
1088 10 : SNAP_CATCH2_NAMESPACE::rand512(a);
1089 :
1090 30 : std::vector<std::uint64_t> not_a(8);
1091 30 : std::vector<std::uint64_t> neg_a(8);
1092 10 : int carry(1);
1093 90 : for(std::size_t i(0); i < 8; ++i)
1094 : {
1095 80 : not_a[i] = ~a.f_value[i];
1096 80 : neg_a[i] = not_a[i] + carry;
1097 80 : carry = neg_a[i] == 0 ? 1 : 0;
1098 : }
1099 :
1100 10 : prinbee::uint512_t b;
1101 10 : b = ~a;
1102 :
1103 10 : CATCH_REQUIRE(b.f_value[0] == not_a[0]);
1104 10 : CATCH_REQUIRE(b.f_value[1] == not_a[1]);
1105 10 : CATCH_REQUIRE(b.f_value[2] == not_a[2]);
1106 10 : CATCH_REQUIRE(b.f_value[3] == not_a[3]);
1107 10 : CATCH_REQUIRE(b.f_value[4] == not_a[4]);
1108 10 : CATCH_REQUIRE(b.f_value[5] == not_a[5]);
1109 10 : CATCH_REQUIRE(b.f_value[6] == not_a[6]);
1110 10 : CATCH_REQUIRE(b.f_value[7] == not_a[7]);
1111 :
1112 10 : prinbee::uint512_t c;
1113 10 : c = -a;
1114 :
1115 10 : CATCH_REQUIRE(c.f_value[0] == neg_a[0]);
1116 10 : CATCH_REQUIRE(c.f_value[1] == neg_a[1]);
1117 10 : CATCH_REQUIRE(c.f_value[2] == neg_a[2]);
1118 10 : CATCH_REQUIRE(c.f_value[3] == neg_a[3]);
1119 10 : CATCH_REQUIRE(c.f_value[4] == neg_a[4]);
1120 10 : CATCH_REQUIRE(c.f_value[5] == neg_a[5]);
1121 10 : CATCH_REQUIRE(c.f_value[6] == neg_a[6]);
1122 10 : CATCH_REQUIRE(c.f_value[7] == neg_a[7]);
1123 10 : }
1124 : }
1125 13 : CATCH_END_SECTION()
1126 :
1127 14 : CATCH_START_SECTION("bigint: multiplication")
1128 : {
1129 11 : for(int count(0); count < 10; ++count)
1130 : {
1131 10 : prinbee::uint512_t a;
1132 10 : prinbee::uint512_t b;
1133 10 : prinbee::uint512_t c;
1134 :
1135 110 : for(int n(0); n < 10; ++n)
1136 : {
1137 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
1138 100 : SNAP_CATCH2_NAMESPACE::rand512(b);
1139 :
1140 100 : c = a;
1141 100 : c *= b;
1142 :
1143 100 : Num na(a.f_value, a.f_value + 8);
1144 100 : Num nb(b.f_value, b.f_value + 8);
1145 100 : Num nd(na * nb);
1146 :
1147 100 : int idx(0);
1148 900 : while(idx < std::min(static_cast<int>(nd.words.size()), 8))
1149 : {
1150 800 : CATCH_REQUIRE(nd.words[idx] == c.f_value[idx]);
1151 800 : ++idx;
1152 : }
1153 100 : while(idx < 8) // the rest must be zeroes
1154 : {
1155 0 : CATCH_REQUIRE(0 == c.f_value[idx]);
1156 0 : ++idx;
1157 : }
1158 100 : }
1159 : }
1160 : }
1161 13 : CATCH_END_SECTION()
1162 :
1163 14 : CATCH_START_SECTION("bigint: division by 64 bit number")
1164 : {
1165 11 : for(int count(0); count < 10; ++count)
1166 : {
1167 10 : prinbee::uint512_t a;
1168 10 : std::int64_t b(0);
1169 10 : prinbee::uint512_t c;
1170 10 : prinbee::uint512_t d;
1171 :
1172 110 : for(int n(0); n < 10; ++n)
1173 : {
1174 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
1175 100 : SNAP_CATCH2_NAMESPACE::random(b);
1176 :
1177 100 : c = a;
1178 100 : c /= b;
1179 :
1180 100 : d = a / b;
1181 100 : CATCH_REQUIRE(c == d);
1182 :
1183 100 : Num na(a.f_value, a.f_value + 8);
1184 100 : Num nb(1, b, false);
1185 100 : Num nd(na / nb);
1186 :
1187 100 : int idx(0);
1188 852 : while(idx < static_cast<int>(nd.words.size()))
1189 : {
1190 752 : CATCH_REQUIRE(nd.words[idx] == c.f_value[idx]);
1191 752 : ++idx;
1192 : }
1193 148 : while(idx < 8) // the rest must be zeroes
1194 : {
1195 48 : CATCH_REQUIRE(0 == c.f_value[idx]);
1196 48 : ++idx;
1197 : }
1198 100 : }
1199 : }
1200 : }
1201 13 : CATCH_END_SECTION()
1202 :
1203 14 : CATCH_START_SECTION("bigint: division")
1204 : {
1205 11 : for(int count(0); count < 10; ++count)
1206 : {
1207 10 : prinbee::uint512_t a;
1208 10 : prinbee::uint512_t b;
1209 10 : prinbee::uint512_t c;
1210 10 : prinbee::uint512_t d;
1211 :
1212 110 : for(int n(0); n < 10; ++n)
1213 : {
1214 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
1215 100 : SNAP_CATCH2_NAMESPACE::rand512(b);
1216 :
1217 100 : prinbee::uint512_t const one(a / a);
1218 100 : CATCH_REQUIRE(one.f_value[0] == 1);
1219 100 : CATCH_REQUIRE(one.f_value[1] == 0);
1220 100 : CATCH_REQUIRE(one.f_value[2] == 0);
1221 100 : CATCH_REQUIRE(one.f_value[3] == 0);
1222 100 : CATCH_REQUIRE(one.f_value[4] == 0);
1223 100 : CATCH_REQUIRE(one.f_value[5] == 0);
1224 100 : CATCH_REQUIRE(one.f_value[6] == 0);
1225 100 : CATCH_REQUIRE(one.f_value[7] == 0);
1226 :
1227 100 : c = a;
1228 100 : c /= b;
1229 :
1230 100 : d = a / b;
1231 100 : CATCH_REQUIRE(c == d);
1232 :
1233 100 : Num na(a.f_value, a.f_value + 8);
1234 100 : Num nb(b.f_value, b.f_value + 8);
1235 100 : Num nd(na / nb);
1236 :
1237 100 : int idx(0);
1238 156 : while(idx < static_cast<int>(nd.words.size()))
1239 : {
1240 56 : CATCH_REQUIRE(nd.words[idx] == c.f_value[idx]);
1241 56 : ++idx;
1242 : }
1243 844 : while(idx < 8) // the rest must be zeroes
1244 : {
1245 744 : CATCH_REQUIRE(0 == c.f_value[idx]);
1246 744 : ++idx;
1247 : }
1248 :
1249 100 : c = a;
1250 100 : c %= b;
1251 100 : nd = na % nb;
1252 100 : idx = 0;
1253 900 : while(idx < static_cast<int>(nd.words.size()))
1254 : {
1255 800 : CATCH_REQUIRE(nd.words[idx] == c.f_value[idx]);
1256 800 : ++idx;
1257 : }
1258 100 : while(idx < 8) // the rest must be zeroes
1259 : {
1260 0 : CATCH_REQUIRE(0 == c.f_value[idx]);
1261 0 : ++idx;
1262 : }
1263 100 : }
1264 : }
1265 : }
1266 13 : CATCH_END_SECTION()
1267 12 : }
1268 :
1269 :
1270 1 : CATCH_TEST_CASE("bigint_string", "[bigint] [valid]")
1271 : {
1272 3 : CATCH_START_SECTION("bigint_string: to_string()")
1273 : {
1274 : // first try some small numbers
1275 : //
1276 22 : for(int number(-10); number <= 10; ++number)
1277 : {
1278 21 : std::string const expected(std::to_string(number));
1279 21 : if(number >= 0)
1280 : {
1281 11 : prinbee::uint512_t const a(number);
1282 11 : std::string const as(prinbee::to_string(a));
1283 11 : CATCH_REQUIRE(expected == as);
1284 :
1285 : {
1286 11 : std::stringstream ss;
1287 11 : ss << a;
1288 11 : CATCH_REQUIRE(expected == ss.str());
1289 11 : }
1290 :
1291 : {
1292 11 : std::stringstream ss;
1293 11 : ss << std::showpos << a;
1294 11 : CATCH_REQUIRE('+' + expected == ss.str());
1295 11 : }
1296 :
1297 : {
1298 11 : std::stringstream ss, e;
1299 11 : ss << std::hex << a;
1300 11 : e << std::hex << number;
1301 11 : CATCH_REQUIRE(e.str() == ss.str());
1302 11 : }
1303 :
1304 : {
1305 11 : std::stringstream ss, e;
1306 11 : ss << std::uppercase << std::hex << a;
1307 11 : e << std::uppercase << std::hex << number;
1308 11 : CATCH_REQUIRE(e.str() == ss.str());
1309 11 : }
1310 :
1311 : {
1312 11 : std::stringstream ss, e;
1313 11 : ss << std::showbase << std::hex << a;
1314 11 : e << std::showbase << std::hex << number;
1315 11 : CATCH_REQUIRE(e.str() == ss.str());
1316 11 : }
1317 :
1318 : {
1319 11 : std::stringstream ss, e;
1320 11 : ss << std::oct << a;
1321 11 : e << std::oct << number;
1322 11 : CATCH_REQUIRE(e.str() == ss.str());
1323 11 : }
1324 :
1325 : {
1326 11 : std::stringstream ss, e;
1327 11 : ss << std::showbase << std::oct << a;
1328 11 : e << std::showbase << std::oct << number;
1329 11 : CATCH_REQUIRE(e.str() == ss.str());
1330 11 : }
1331 :
1332 : {
1333 11 : std::stringstream ss, e;
1334 11 : int n(number);
1335 11 : if(n < 0)
1336 : {
1337 0 : e << '-';
1338 0 : n = -n;
1339 : }
1340 11 : if(n == 0)
1341 : {
1342 1 : e << '0';
1343 : }
1344 : else
1345 : {
1346 10 : char buf[520];
1347 10 : int p(519);
1348 10 : buf[p] = '\0';
1349 39 : while(n != 0)
1350 : {
1351 29 : --p;
1352 29 : if((n & 1) != 0)
1353 : {
1354 17 : buf[p] = '1';
1355 : }
1356 : else
1357 : {
1358 12 : buf[p] = '0';
1359 : }
1360 29 : n >>= 1;
1361 : }
1362 10 : e << buf + p;
1363 : }
1364 :
1365 11 : std::string const s1(a.to_string(2, false, false));
1366 11 : std::string const s2(a.to_string(2, false, true));
1367 11 : CATCH_REQUIRE(e.str() == s1);
1368 11 : CATCH_REQUIRE(e.str() == s2);
1369 :
1370 11 : std::string const s3(a.to_string(2, true, false));
1371 11 : std::string const s4(a.to_string(2, true, true));
1372 11 : if(number == 0)
1373 : {
1374 1 : CATCH_REQUIRE(e.str() == s3);
1375 1 : CATCH_REQUIRE(e.str() == s4);
1376 : }
1377 : else
1378 : {
1379 10 : CATCH_REQUIRE("0b" + e.str() == s3);
1380 10 : CATCH_REQUIRE("0B" + e.str() == s4);
1381 : }
1382 11 : }
1383 11 : }
1384 :
1385 : {
1386 21 : prinbee::int512_t const b(number);
1387 21 : std::string const bs(prinbee::to_string(b));
1388 21 : CATCH_REQUIRE(expected == bs);
1389 :
1390 21 : std::stringstream ss;
1391 21 : ss << b;
1392 21 : CATCH_REQUIRE(expected == ss.str());
1393 21 : }
1394 21 : }
1395 :
1396 : // now try with random numbers
1397 : //
1398 101 : for(int count(0); count < 100; ++count)
1399 : {
1400 100 : prinbee::uint512_t a;
1401 100 : prinbee::int512_t b;
1402 :
1403 : do
1404 : {
1405 100 : SNAP_CATCH2_NAMESPACE::rand512(a);
1406 : }
1407 100 : while(a.is_zero());
1408 :
1409 : do
1410 : {
1411 100 : SNAP_CATCH2_NAMESPACE::rand512(b);
1412 : }
1413 100 : while(b.is_zero());
1414 :
1415 100 : std::string const as(prinbee::to_string(a));
1416 100 : std::string const bs(prinbee::to_string(b));
1417 :
1418 : // use bc to convert hex to decimal to verify that our code
1419 : // works as expected
1420 : //
1421 : {
1422 300 : std::string cmd("echo \"ibase=16;");
1423 :
1424 : // bin_to_hex expects a string in big endian
1425 : //
1426 100 : std::string bin;
1427 900 : for(int idx(0); idx < 8; ++idx)
1428 : {
1429 7200 : for(int j(0); j < 8; ++j)
1430 : {
1431 6400 : bin.append(1, a.f_value[7 - idx] >> ((7 - j) * 8));
1432 : }
1433 : }
1434 100 : std::string hex(snapdev::bin_to_hex(bin, true));
1435 104 : while(hex.length() > 0 && hex[0] == '0')
1436 : {
1437 4 : hex = hex.substr(1);
1438 : }
1439 :
1440 100 : cmd += hex;
1441 100 : cmd += "\"|BC_LINE_LENGTH=0 bc";
1442 100 : FILE * p(popen(cmd.c_str(), "r"));
1443 100 : CATCH_REQUIRE(p != nullptr);
1444 100 : char buf[256] = {};
1445 100 : std::size_t sz(fread(buf, 1, sizeof(buf), p));
1446 100 : CATCH_REQUIRE(sz >= 1);
1447 100 : CATCH_REQUIRE(sz < sizeof(buf));
1448 100 : if(buf[sz - 1] == '\n')
1449 : {
1450 100 : --sz;
1451 : }
1452 100 : buf[sz] = '\0';
1453 300 : std::string const expected(buf);
1454 100 : CATCH_REQUIRE(pclose(p) == 0);
1455 100 : CATCH_REQUIRE(expected == as);
1456 :
1457 : {
1458 100 : std::stringstream ss;
1459 100 : ss << a;
1460 100 : CATCH_REQUIRE(expected == ss.str());
1461 100 : }
1462 : {
1463 100 : std::stringstream ss;
1464 100 : ss << std::showpos << a;
1465 100 : CATCH_REQUIRE('+' + expected == ss.str());
1466 100 : }
1467 : {
1468 100 : std::stringstream ss;
1469 100 : ss << std::uppercase << std::hex << a;
1470 100 : CATCH_REQUIRE(hex == ss.str());
1471 :
1472 100 : std::stringstream sb;
1473 100 : sb << std::uppercase << std::hex << std::showbase << a;
1474 100 : CATCH_REQUIRE("0X" + hex == sb.str());
1475 100 : }
1476 : {
1477 100 : std::string lower(hex);
1478 12896 : for(auto & c : lower)
1479 : {
1480 12796 : if(c >= 'A' && c <= 'F')
1481 : {
1482 4768 : c |= 0x20;
1483 : }
1484 : }
1485 100 : std::stringstream ss;
1486 100 : ss << std::showbase << std::hex << a;
1487 100 : CATCH_REQUIRE("0x" + lower == ss.str());
1488 100 : }
1489 : {
1490 100 : std::string oct;
1491 100 : bool found(false);
1492 100 : int bit(513);
1493 17200 : while(bit > 0)
1494 : {
1495 17100 : bit -= 3;
1496 17100 : prinbee::uint512_t n(a);
1497 17100 : n >>= bit;
1498 17100 : if(found || n != 0)
1499 : {
1500 17074 : found = true;
1501 17074 : oct += (n.f_value[0] & 7) + '0';
1502 : }
1503 : }
1504 :
1505 100 : std::stringstream ss;
1506 100 : ss << std::oct << a;
1507 100 : CATCH_REQUIRE(oct == ss.str());
1508 :
1509 100 : std::stringstream sb;
1510 100 : sb << std::showbase << std::oct << a;
1511 100 : CATCH_REQUIRE("0" + oct == sb.str());
1512 100 : }
1513 3500 : for(int base(3); base <= 36; ++base)
1514 : {
1515 : // base == 2
1516 3400 : if(base == 8
1517 3300 : || base == 10
1518 3200 : || base == 16)
1519 : {
1520 300 : continue;
1521 : }
1522 :
1523 9300 : std::string cmd_base("echo \"obase=");
1524 3100 : cmd_base += std::to_string(base);
1525 3100 : cmd_base += ";ibase=16;";
1526 3100 : cmd_base += hex;
1527 3100 : cmd_base += "\"|BC_LINE_LENGTH=0 bc";
1528 3100 : FILE * pb(popen(cmd_base.c_str(), "r"));
1529 3100 : CATCH_REQUIRE(pb != nullptr);
1530 3100 : char buf_base[520] = {};
1531 3100 : sz = fread(buf_base, 1, sizeof(buf_base), pb);
1532 3100 : CATCH_REQUIRE(sz >= 1);
1533 3100 : CATCH_REQUIRE(sz < sizeof(buf_base));
1534 3100 : if(buf_base[sz - 1] == '\n')
1535 : {
1536 3100 : --sz;
1537 : }
1538 3100 : buf_base[sz] = '\0';
1539 3100 : std::string expected_base;
1540 3100 : if(base <= 16)
1541 : {
1542 1100 : expected_base = buf_base;
1543 : }
1544 : else
1545 : {
1546 : // bc converts numbers with a base over 16 to a string
1547 : // of decimal numbers separated by a space which the
1548 : // strtol() handles on its own
1549 : //
1550 2000 : char const * s(buf_base);
1551 221805 : while(s != nullptr && *s != '\0')
1552 : {
1553 219805 : char * e(nullptr);
1554 219805 : int const v(strtol(s, &e, 10));
1555 219805 : if(v < 10)
1556 : {
1557 89466 : expected_base += v + '0';
1558 : }
1559 : else
1560 : {
1561 130339 : expected_base += v + ('A' - 10);
1562 : }
1563 219805 : s = e;
1564 : }
1565 : }
1566 3100 : CATCH_REQUIRE(pclose(pb) == 0);
1567 :
1568 3100 : std::string const any_base(a.to_string(base, false, true));
1569 3100 : CATCH_REQUIRE(expected_base == any_base);
1570 3100 : }
1571 100 : }
1572 : {
1573 300 : std::string cmd("echo \"ibase=16;");
1574 :
1575 : // bin_to_hex expects a string in big endian
1576 : //
1577 100 : prinbee::int512_t c(b);
1578 100 : if(c < 0)
1579 : {
1580 54 : c = -c;
1581 : }
1582 100 : std::string bin;
1583 900 : for(int idx(0); idx < 8; ++idx)
1584 : {
1585 7200 : for(int j(0); j < 8; ++j)
1586 : {
1587 : // WARNING: this works in little endian because
1588 : // f_high_value is right after f_value[]
1589 : //
1590 6400 : bin.append(1, c.f_value[7 - idx] >> ((7 - j) * 8));
1591 : }
1592 : }
1593 100 : std::string hex(snapdev::bin_to_hex(bin, true));
1594 114 : while(hex.length() > 0 && hex[0] == '0')
1595 : {
1596 14 : hex = hex.substr(1);
1597 : }
1598 :
1599 100 : cmd += hex;
1600 100 : cmd += "\"|BC_LINE_LENGTH=0 bc";
1601 100 : FILE * p(popen(cmd.c_str(), "r"));
1602 100 : CATCH_REQUIRE(p != nullptr);
1603 100 : char buf[520] = {};
1604 100 : if(b < 0)
1605 : {
1606 54 : buf[0] = '-';
1607 : }
1608 100 : std::size_t sz(fread(buf + (b < 0 ? 1 : 0), 1, sizeof(buf) - 1, p));
1609 100 : CATCH_REQUIRE(sz >= 1);
1610 100 : CATCH_REQUIRE(sz < sizeof(buf) - 1);
1611 100 : if(buf[sz - 1] == '\n')
1612 : {
1613 46 : --sz;
1614 : }
1615 100 : buf[sz] = '\0';
1616 300 : std::string const expected(buf);
1617 100 : CATCH_REQUIRE(pclose(p) == 0);
1618 100 : CATCH_REQUIRE(expected == bs);
1619 :
1620 : {
1621 100 : std::stringstream ss;
1622 100 : if(b < 0)
1623 : {
1624 54 : ss << '-';
1625 : }
1626 100 : ss << c;
1627 100 : CATCH_REQUIRE(expected == ss.str());
1628 100 : }
1629 : {
1630 100 : std::stringstream ss;
1631 100 : ss << std::showpos << b;
1632 100 : CATCH_REQUIRE((b >= 0 ? "+" : "") + expected == ss.str());
1633 100 : }
1634 : {
1635 100 : std::stringstream ss;
1636 100 : ss << std::uppercase << std::hex << b;
1637 100 : CATCH_REQUIRE((b < 0 ? "-" : "") + hex == ss.str());
1638 :
1639 100 : std::stringstream sb;
1640 100 : sb << std::uppercase << std::hex << std::showbase << b;
1641 100 : CATCH_REQUIRE((b < 0 ? "-0X" : "0X") + hex == sb.str());
1642 100 : }
1643 : {
1644 100 : std::string lower(hex);
1645 12886 : for(auto & h : lower)
1646 : {
1647 12786 : if(h >= 'A' && h <= 'F')
1648 : {
1649 4832 : h |= 0x20;
1650 : }
1651 : }
1652 100 : std::stringstream ss;
1653 100 : ss << std::showbase << std::hex << b;
1654 100 : CATCH_REQUIRE((b < 0 ? "-0x" : "0x") + lower == ss.str());
1655 100 : }
1656 : {
1657 100 : std::string oct;
1658 100 : bool found(false);
1659 100 : int bit(513);
1660 17200 : while(bit > 0)
1661 : {
1662 17100 : bit -= 3;
1663 17100 : prinbee::uint512_t n(c);
1664 17100 : n = (n >> bit) & 7;
1665 17100 : if(found || n != 0)
1666 : {
1667 17043 : found = true;
1668 17043 : oct += n.f_value[0] + '0';
1669 : }
1670 : }
1671 :
1672 100 : std::stringstream ss;
1673 100 : ss << std::oct << b;
1674 100 : CATCH_REQUIRE((b < 0 ? "-" : "") + oct == ss.str());
1675 :
1676 100 : std::stringstream sb;
1677 100 : sb << std::showbase << std::oct << b;
1678 100 : CATCH_REQUIRE((b < 0 ? "-0" : "0") + oct == sb.str());
1679 100 : }
1680 3500 : for(int base(3); base <= 36; ++base)
1681 : {
1682 : // base == 2
1683 3400 : if(base == 8
1684 3300 : || base == 10
1685 3200 : || base == 16)
1686 : {
1687 300 : continue;
1688 : }
1689 :
1690 9300 : std::string cmd_base("echo \"obase=");
1691 3100 : cmd_base += std::to_string(base);
1692 3100 : cmd_base += ";ibase=16;";
1693 3100 : cmd_base += hex;
1694 3100 : cmd_base += "\"|BC_LINE_LENGTH=0 bc";
1695 3100 : FILE * pb(popen(cmd_base.c_str(), "r"));
1696 3100 : CATCH_REQUIRE(pb != nullptr);
1697 3100 : char buf_base[520] = {};
1698 3100 : if(b < 0)
1699 : {
1700 1674 : buf_base[0] = '-';
1701 : }
1702 3100 : sz = fread(buf_base + (b < 0 ? 1 : 0), 1, sizeof(buf) - 1, pb);
1703 3100 : CATCH_REQUIRE(sz >= 1);
1704 3100 : CATCH_REQUIRE(sz < sizeof(buf_base) - 1);
1705 3100 : if(buf_base[sz - 1] == '\n')
1706 : {
1707 1426 : --sz;
1708 : }
1709 3100 : buf_base[sz] = '\0';
1710 3100 : std::string expected_base;
1711 3100 : if(base <= 16)
1712 : {
1713 1100 : expected_base = buf_base;
1714 : }
1715 : else
1716 : {
1717 : // bc converts numbers with a base over 16 to a string
1718 : // of decimal numbers separated by a space which the
1719 : // strtol() handles on its own
1720 : //
1721 2000 : char const * s(buf_base);
1722 2000 : if(*s == '-')
1723 : {
1724 1080 : expected_base += '-';
1725 1080 : ++s;
1726 : }
1727 221355 : while(s != nullptr && *s != '\0')
1728 : {
1729 219355 : char * e(nullptr);
1730 219355 : int const v(strtol(s, &e, 10));
1731 219355 : if(v < 10)
1732 : {
1733 89164 : expected_base += v + '0';
1734 : }
1735 : else
1736 : {
1737 130191 : expected_base += v + ('A' - 10);
1738 : }
1739 219355 : s = e;
1740 : }
1741 : }
1742 3100 : CATCH_REQUIRE(pclose(pb) == 0);
1743 :
1744 3100 : std::string const any_base(b.to_string(base, false, true));
1745 3100 : CATCH_REQUIRE(expected_base == any_base);
1746 3100 : }
1747 100 : }
1748 100 : }
1749 : }
1750 2 : CATCH_END_SECTION()
1751 1 : }
1752 :
1753 :
1754 3 : CATCH_TEST_CASE("bigint_rounding", "[round] [valid]")
1755 : {
1756 5 : CATCH_START_SECTION("bigint_rounding: round down")
1757 : {
1758 1 : std::uint64_t const multiple(rand() % 512 + 512);
1759 1 : std::uint64_t const max(multiple * 5 + multiple / 2);
1760 1 : std::uint64_t current(-multiple);
1761 4599 : for(std::uint64_t value(0); value < max; ++value)
1762 : {
1763 4598 : if((value % multiple) == 0)
1764 : {
1765 6 : current += multiple;
1766 : }
1767 4598 : CATCH_REQUIRE(current == prinbee::round_down(value, multiple));
1768 : }
1769 : }
1770 4 : CATCH_END_SECTION()
1771 :
1772 5 : CATCH_START_SECTION("bigint_rounding: round up")
1773 : {
1774 1 : std::uint64_t const multiple(rand() % 512 + 512);
1775 1 : std::uint64_t const max(multiple * 5 + multiple / 2);
1776 1 : std::uint64_t current(0);
1777 3675 : for(std::uint64_t value(0); value < max; ++value)
1778 : {
1779 3674 : CATCH_REQUIRE(current == prinbee::round_up(value, multiple));
1780 3674 : if((value % multiple) == 0)
1781 : {
1782 6 : current += multiple;
1783 : }
1784 : }
1785 : }
1786 4 : CATCH_END_SECTION()
1787 :
1788 5 : CATCH_START_SECTION("bigint_rounding: divide round up")
1789 : {
1790 1 : std::uint64_t const multiple(rand() % 512 + 512);
1791 1 : std::uint64_t const max(multiple * 5 + multiple / 2);
1792 1 : std::uint64_t current(0);
1793 4516 : for(std::uint64_t value(0); value < max; ++value)
1794 : {
1795 4515 : CATCH_REQUIRE(current == prinbee::divide_rounded_up(value, multiple));
1796 4515 : if((value % multiple) == 0)
1797 : {
1798 6 : ++current;
1799 : }
1800 : }
1801 : }
1802 4 : CATCH_END_SECTION()
1803 3 : }
1804 :
1805 :
1806 4 : CATCH_TEST_CASE("bigint_invalid", "[bigint] [invalid]")
1807 : {
1808 6 : CATCH_START_SECTION("bigint_invalid: input too large")
1809 : {
1810 5 : CATCH_REQUIRE_THROWS_MATCHES(
1811 : prinbee::int512_t({1, 2, 3, 4, 5, 6, 7, 8, 9})
1812 : , prinbee::out_of_range
1813 : , Catch::Matchers::ExceptionMessage("out_of_range: rhs array too large for int512_t constructor (9 > 8)."));
1814 :
1815 5 : CATCH_REQUIRE_THROWS_MATCHES(
1816 : prinbee::uint512_t({1, 2, 3, 4, 5, 6, 7, 8, 9})
1817 : , prinbee::out_of_range
1818 : , Catch::Matchers::ExceptionMessage("out_of_range: rhs array too large for uint512_t constructor (9 > 8)."));
1819 : }
1820 5 : CATCH_END_SECTION()
1821 :
1822 6 : CATCH_START_SECTION("bigint_invalid: negative shift")
1823 : {
1824 1 : prinbee::uint512_t a({1, 2, 3, 4, 5, 6, 7, 8});
1825 11 : for(int i(-10); i < 0; ++i)
1826 : {
1827 10 : CATCH_REQUIRE_THROWS_MATCHES(
1828 : a.lsl(i)
1829 : , prinbee::out_of_range
1830 : , Catch::Matchers::ExceptionMessage(
1831 : "out_of_range: lsl() cannot be called with a negative value ("
1832 : + std::to_string(i)
1833 : + ")."));
1834 :
1835 10 : CATCH_REQUIRE_THROWS_MATCHES(
1836 : a.lsr(i)
1837 : , prinbee::out_of_range
1838 : , Catch::Matchers::ExceptionMessage(
1839 : "out_of_range: lsr() cannot be called with a negative value ("
1840 : + std::to_string(i)
1841 : + ")."));
1842 : }
1843 : }
1844 5 : CATCH_END_SECTION()
1845 :
1846 6 : CATCH_START_SECTION("bigint_invalid: divide by zero")
1847 : {
1848 1 : prinbee::uint512_t a({1, 2, 3, 4, 5, 6, 7, 8});
1849 1 : prinbee::uint512_t b;
1850 :
1851 : // 0 / n = 0
1852 1 : prinbee::uint512_t zero(b / a);
1853 1 : CATCH_REQUIRE(zero.is_zero());
1854 :
1855 : // n / 0 is undefined
1856 4 : CATCH_REQUIRE_THROWS_MATCHES(
1857 : a / b
1858 : , prinbee::logic_error
1859 : , Catch::Matchers::ExceptionMessage(
1860 : "logic_error: uint512_t: division by zero not allowed."));
1861 : }
1862 5 : CATCH_END_SECTION()
1863 :
1864 6 : CATCH_START_SECTION("bigint_invalid: invalid base")
1865 : {
1866 61 : for(int i(-10); i < 50; ++i)
1867 : {
1868 60 : if(i < 2 || i > 36)
1869 : {
1870 25 : prinbee::uint512_t a;
1871 : do
1872 : {
1873 25 : SNAP_CATCH2_NAMESPACE::rand512(a);
1874 : }
1875 25 : while(a == 0);
1876 50 : CATCH_REQUIRE_THROWS_MATCHES(
1877 : a.to_string(i)
1878 : , prinbee::conversion_unavailable
1879 : , Catch::Matchers::ExceptionMessage(
1880 : "prinbee_exception: base "
1881 : + std::to_string(i)
1882 : + " not supported."));
1883 : }
1884 : }
1885 : }
1886 5 : CATCH_END_SECTION()
1887 4 : }
1888 :
1889 :
1890 :
1891 : // vim: ts=4 sw=4 et
|