LCOV - code coverage report
Current view: top level - tests - catch_bigint.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.0 % 1126 1092
Test Date: 2025-06-19 11:28:46 Functions: 100.0 % 4 4
Legend: Lines: hit not hit

            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
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions