LCOV - code coverage report
Current view: top level - tests - catch_bigint.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1067 1101 96.9 %
Date: 2024-02-03 18:59:18 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14

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