LCOV - code coverage report
Current view: top level - src - bigint.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 266 281 94.7 %
Date: 2026-08-20 23:47:58 Functions: 26 27 96.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 136 174 78.2 %

           Branch data     Line data    Source code
       1                 :            : // Copyright 2019-2026 David Robillard <d@drobilla.net>
       2                 :            : // SPDX-License-Identifier: ISC
       3                 :            : 
       4                 :            : #include "bigint.h"
       5                 :            : #include "macros.h"
       6                 :            : 
       7                 :            : #include "int_math.h"
       8                 :            : 
       9                 :            : #include <assert.h>
      10                 :            : #include <stdbool.h>
      11                 :            : #include <stdlib.h>
      12                 :            : 
      13                 :            : typedef uint64_t Hugit;
      14                 :            : 
      15                 :            : static const uint32_t bigit_mask = ~0U;
      16                 :            : static const uint64_t carry_mask = (uint64_t)~0U << 32U;
      17                 :            : 
      18                 :            : typedef struct {
      19                 :            :   unsigned bigits;
      20                 :            :   unsigned bits;
      21                 :            : } Offset;
      22                 :            : 
      23                 :            : static inline Offset
      24                 :    1414992 : make_offset(const unsigned i)
      25                 :            : {
      26                 :    1414992 :   const unsigned bigits = i / BIGINT_BIGIT_BITS;
      27                 :    1414992 :   const unsigned bits   = i % BIGINT_BIGIT_BITS;
      28                 :            : 
      29                 :    1414992 :   const Offset offset = {bigits, bits};
      30                 :    1414992 :   return offset;
      31                 :            : }
      32                 :            : 
      33                 :            : #ifndef NDEBUG
      34                 :            : static inline bool
      35                 :    6065009 : exess_bigint_is_clamped(const ExessBigint* num)
      36                 :            : {
      37   [ +  +  +  - ]:    6065009 :   return num->n_bigits == 0 || num->bigits[num->n_bigits - 1];
      38                 :            : }
      39                 :            : #endif
      40                 :            : 
      41                 :            : EXESS_I_NONBLOCKING void
      42                 :     975372 : exess_bigint_shift_left(ExessBigint* num, const unsigned amount)
      43                 :            : {
      44         [ -  + ]:     975372 :   assert(exess_bigint_is_clamped(num));
      45   [ +  +  -  + ]:     975372 :   if (amount == 0 || num->n_bigits == 0) {
      46                 :     428872 :     return;
      47                 :            :   }
      48                 :            : 
      49                 :     546500 :   const Offset offset = make_offset(amount);
      50                 :            : 
      51         [ -  + ]:     546500 :   assert(num->n_bigits + offset.bigits < BIGINT_MAX_BIGITS);
      52                 :     546500 :   num->n_bigits += offset.bigits + (bool)offset.bits;
      53                 :            : 
      54         [ +  + ]:     546500 :   if (offset.bits == 0) { // Simple bigit-aligned shift
      55         [ +  + ]:       8086 :     for (unsigned i = num->n_bigits - 1; i >= offset.bigits; --i) {
      56                 :       6131 :       num->bigits[i] = num->bigits[i - offset.bigits];
      57                 :            :     }
      58                 :            :   } else { // Bigit + sub-bigit bit offset shift
      59                 :     544545 :     const unsigned right_shift = BIGINT_BIGIT_BITS - offset.bits;
      60         [ +  + ]:    4767316 :     for (unsigned i = num->n_bigits - offset.bigits - 1; i > 0; --i) {
      61                 :    4222771 :       num->bigits[i + offset.bigits] =
      62                 :    4222771 :         (num->bigits[i] << offset.bits) | (num->bigits[i - 1] >> right_shift);
      63                 :            :     }
      64                 :            : 
      65                 :     544545 :     num->bigits[offset.bigits] = num->bigits[0] << offset.bits;
      66                 :            :   }
      67                 :            : 
      68                 :            :   // Zero LSBs
      69         [ +  + ]:     844628 :   for (unsigned i = 0; i < offset.bigits; ++i) {
      70                 :     298128 :     num->bigits[i] = 0;
      71                 :            :   }
      72                 :            : 
      73                 :     546500 :   exess_bigint_clamp(num);
      74         [ -  + ]:     546500 :   assert(exess_bigint_is_clamped(num));
      75                 :            : }
      76                 :            : 
      77                 :            : EXESS_I_NONBLOCKING void
      78                 :      78158 : exess_bigint_zero(ExessBigint* num)
      79                 :            : {
      80                 :      78158 :   EXESS_I_CONSTEXPR ExessBigint zero = {{0}, 0};
      81                 :            : 
      82                 :      78158 :   *num = zero;
      83                 :      78158 : }
      84                 :            : 
      85                 :            : EXESS_I_NONBLOCKING void
      86                 :      13939 : exess_bigint_set(ExessBigint* num, const ExessBigint* value)
      87                 :            : {
      88                 :      13939 :   *num = *value;
      89                 :      13939 : }
      90                 :            : 
      91                 :            : EXESS_I_NONBLOCKING void
      92                 :      61368 : exess_bigint_set_u32(ExessBigint* num, const uint32_t value)
      93                 :            : {
      94                 :      61368 :   exess_bigint_zero(num);
      95                 :            : 
      96                 :      61368 :   num->bigits[0] = value;
      97                 :      61368 :   num->n_bigits  = (bool)value;
      98                 :      61368 : }
      99                 :            : 
     100                 :            : EXESS_I_NONBLOCKING void
     101                 :    1695799 : exess_bigint_clamp(ExessBigint* num)
     102                 :            : {
     103   [ +  +  +  + ]:    2247961 :   while (num->n_bigits > 0 && num->bigits[num->n_bigits - 1] == 0) {
     104                 :     552162 :     --num->n_bigits;
     105                 :            :   }
     106                 :    1695799 : }
     107                 :            : 
     108                 :            : EXESS_I_NONBLOCKING void
     109                 :      16760 : exess_bigint_set_u64(ExessBigint* num, const uint64_t value)
     110                 :            : {
     111                 :      16760 :   exess_bigint_zero(num);
     112                 :            : 
     113                 :      16760 :   num->bigits[0] = (Bigit)(value & bigit_mask);
     114                 :      16760 :   num->bigits[1] = (Bigit)(value >> BIGINT_BIGIT_BITS);
     115   [ -  +  -  - ]:      16760 :   num->n_bigits  = num->bigits[1] ? 2U : num->bigits[0] ? 1U : 0U;
     116                 :      16760 : }
     117                 :            : 
     118                 :            : EXESS_I_NONBLOCKING void
     119                 :      30669 : exess_bigint_set_pow10(ExessBigint* num, const unsigned exponent)
     120                 :            : {
     121                 :      30669 :   exess_bigint_set_u32(num, 1);
     122                 :      30669 :   exess_bigint_multiply_pow10(num, exponent);
     123                 :      30669 : }
     124                 :            : 
     125                 :            : static EXESS_I_NONBLOCKING uint32_t
     126                 :         83 : read_u32(const char* const str, uint32_t* result, uint32_t* n_digits)
     127                 :            : {
     128                 :         83 :   EXESS_I_CONSTEXPR size_t uint32_digits10 = 9;
     129                 :            : 
     130                 :         83 :   *result = *n_digits = 0;
     131                 :            : 
     132                 :         83 :   uint32_t i = 0;
     133   [ +  +  +  -  :        504 :   for (; str[i] >= '0' && str[i] <= '9' && *n_digits < uint32_digits10; ++i) {
                   +  + ]
     134                 :        421 :     *result = (*result * 10U) + (unsigned)(str[i] - '0');
     135                 :        421 :     *n_digits += 1;
     136                 :            :   }
     137                 :            : 
     138                 :         83 :   return i;
     139                 :            : }
     140                 :            : 
     141                 :            : EXESS_I_NONBLOCKING void
     142                 :         30 : exess_bigint_set_decimal_string(ExessBigint* num, const char* const str)
     143                 :            : {
     144                 :         30 :   exess_bigint_zero(num);
     145                 :            : 
     146                 :         30 :   uint32_t pos      = 0;
     147                 :         30 :   uint32_t n_digits = 0;
     148                 :         30 :   uint32_t n_read   = 0;
     149                 :         30 :   uint32_t word     = 0;
     150         [ +  + ]:         83 :   while ((n_read = read_u32(str + pos, &word, &n_digits))) {
     151                 :         53 :     exess_bigint_multiply_u32(num, (uint32_t)POW10[n_digits]);
     152                 :         53 :     exess_bigint_add_u32(num, word);
     153                 :         53 :     pos += n_read;
     154                 :            :   }
     155                 :            : 
     156                 :         30 :   exess_bigint_clamp(num);
     157                 :         30 : }
     158                 :            : 
     159                 :            : EXESS_I_NONBLOCKING void
     160                 :     880920 : exess_bigint_multiply_u32(ExessBigint* num, const uint32_t factor)
     161                 :            : {
     162      [ -  +  + ]:     880920 :   switch (factor) {
     163                 :          0 :   case 0:
     164                 :          0 :     exess_bigint_zero(num);
     165                 :          0 :     return;
     166                 :       2847 :   case 1:
     167                 :       2847 :     return;
     168                 :     878073 :   default:
     169                 :     878073 :     break;
     170                 :            :   }
     171                 :            : 
     172                 :     878073 :   Hugit carry = 0;
     173         [ +  + ]:    7998926 :   for (unsigned i = 0; i < num->n_bigits; ++i) {
     174                 :    7120853 :     const Hugit p     = (Hugit)factor * num->bigits[i];
     175                 :    7120853 :     const Hugit hugit = p + (carry & bigit_mask);
     176                 :            : 
     177                 :    7120853 :     num->bigits[i] = (Bigit)(hugit & bigit_mask);
     178                 :            : 
     179                 :    7120853 :     carry = (hugit >> 32U) + (carry >> 32U);
     180                 :            :   }
     181                 :            : 
     182         [ +  + ]:     993233 :   for (; carry; carry >>= 32U) {
     183         [ -  + ]:     115160 :     assert(num->n_bigits + 1 <= BIGINT_MAX_BIGITS);
     184                 :     115160 :     num->bigits[num->n_bigits++] = (Bigit)carry;
     185                 :            :   }
     186                 :            : }
     187                 :            : 
     188                 :            : EXESS_I_NONBLOCKING void
     189                 :      68077 : exess_bigint_multiply_u64(ExessBigint* num, const uint64_t factor)
     190                 :            : {
     191      [ -  +  + ]:      68077 :   switch (factor) {
     192                 :          0 :   case 0:
     193                 :          0 :     exess_bigint_zero(num);
     194                 :          0 :     return;
     195                 :          2 :   case 1:
     196                 :          2 :     return;
     197                 :      68075 :   default:
     198                 :      68075 :     break;
     199                 :            :   }
     200                 :            : 
     201                 :      68075 :   const Hugit f_lo = factor & bigit_mask;
     202                 :      68075 :   const Hugit f_hi = factor >> 32U;
     203                 :            : 
     204                 :      68075 :   Hugit carry = 0;
     205         [ +  + ]:     354396 :   for (unsigned i = 0; i < num->n_bigits; ++i) {
     206                 :     286321 :     const Hugit p_lo  = f_lo * num->bigits[i];
     207                 :     286321 :     const Hugit p_hi  = f_hi * num->bigits[i];
     208                 :     286321 :     const Hugit hugit = p_lo + (carry & bigit_mask);
     209                 :            : 
     210                 :     286321 :     num->bigits[i] = (Bigit)(hugit & bigit_mask);
     211                 :     286321 :     carry          = p_hi + (hugit >> 32U) + (carry >> 32U);
     212                 :            :   }
     213                 :            : 
     214         [ +  + ]:     180308 :   for (; carry; carry >>= 32U) {
     215         [ -  + ]:     112233 :     assert(num->n_bigits + 1 <= BIGINT_MAX_BIGITS);
     216                 :     112233 :     num->bigits[num->n_bigits++] = (Bigit)(carry & bigit_mask);
     217                 :            :   }
     218                 :            : }
     219                 :            : 
     220                 :            : EXESS_I_NONBLOCKING void
     221                 :      30699 : exess_bigint_multiply_pow10(ExessBigint* num, const unsigned exponent)
     222                 :            : {
     223                 :            :   /* To reduce multiplication, we exploit 10^e = (2*5)^e = 2^e * 5^e to
     224                 :            :      factor out an exponentiation by 5 instead of 10.  So, we first multiply
     225                 :            :      by 5^e (hard), then by 2^e (just a single left shift). */
     226                 :            : 
     227                 :            :   // 5^27, the largest power of 5 that fits in 64 bits
     228                 :      30699 :   EXESS_I_CONSTEXPR uint64_t pow5_27 = 7450580596923828125ULL;
     229                 :            : 
     230                 :            :   // Powers of 5 up to 5^13, the largest that fits in 32 bits
     231                 :      30699 :   EXESS_I_CONSTEXPR uint32_t pow5[] = {
     232                 :            :     1,
     233                 :            :     5,
     234                 :            :     5 * 5,
     235                 :            :     5 * 5 * 5,
     236                 :            :     5 * 5 * 5 * 5,
     237                 :            :     5 * 5 * 5 * 5 * 5,
     238                 :            :     5 * 5 * 5 * 5 * 5 * 5,
     239                 :            :     5 * 5 * 5 * 5 * 5 * 5 * 5,
     240                 :            :     5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
     241                 :            :     5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
     242                 :            :     5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
     243                 :            :     5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
     244                 :            :     5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
     245                 :            :     5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
     246                 :            :   };
     247                 :            : 
     248   [ +  +  -  + ]:      30699 :   if (exponent == 0 || num->n_bigits == 0) {
     249                 :        373 :     return;
     250                 :            :   }
     251                 :            : 
     252                 :            :   // Multiply by 5^27 until e < 27 so we can switch to 32 bits
     253                 :      30326 :   unsigned e = exponent;
     254         [ +  + ]:      84464 :   while (e >= 27) {
     255                 :      54138 :     exess_bigint_multiply_u64(num, pow5_27);
     256                 :      54138 :     e -= 27;
     257                 :            :   }
     258                 :            : 
     259                 :            :   // Multiply by 5^13 until e < 13 so we have only one multiplication left
     260         [ +  + ]:      45534 :   while (e >= 13) {
     261                 :      15208 :     exess_bigint_multiply_u32(num, pow5[13]);
     262                 :      15208 :     e -= 13;
     263                 :            :   }
     264                 :            : 
     265                 :            :   // Multiply by the final 5^e (which may be zero, making this a noop)
     266                 :      30326 :   exess_bigint_multiply_u32(num, pow5[e]);
     267                 :            : 
     268                 :            :   // Finally multiply by 2^e
     269                 :      30326 :   exess_bigint_shift_left(num, exponent);
     270                 :            : }
     271                 :            : 
     272                 :            : EXESS_I_NONBLOCKING int
     273                 :    2840482 : exess_bigint_compare(const ExessBigint* lhs, const ExessBigint* rhs)
     274                 :            : {
     275         [ +  + ]:    2840482 :   if (lhs->n_bigits < rhs->n_bigits) {
     276                 :       3536 :     return -1;
     277                 :            :   }
     278                 :            : 
     279         [ +  + ]:    2836946 :   if (lhs->n_bigits > rhs->n_bigits) {
     280                 :     331345 :     return 1;
     281                 :            :   }
     282                 :            : 
     283         [ +  + ]:    2552363 :   for (int i = (int)lhs->n_bigits - 1; i >= 0; --i) {
     284                 :    2549332 :     const Bigit bigit_l = lhs->bigits[i];
     285                 :    2549332 :     const Bigit bigit_r = rhs->bigits[i];
     286         [ +  + ]:    2549332 :     if (bigit_l < bigit_r) {
     287                 :     165804 :       return -1;
     288                 :            :     }
     289                 :            : 
     290         [ +  + ]:    2383528 :     if (bigit_l > bigit_r) {
     291                 :    2336766 :       return 1;
     292                 :            :     }
     293                 :            :   }
     294                 :            : 
     295                 :       3031 :   return 0;
     296                 :            : }
     297                 :            : 
     298                 :            : static int
     299                 :     446155 : exess_bigint_plus_compare_internal(const ExessBigint* const l,
     300                 :            :                                    const ExessBigint* const p,
     301                 :            :                                    const ExessBigint* const c)
     302                 :            : {
     303         [ +  + ]:     446155 :   if (l->n_bigits + 1 < c->n_bigits) {
     304                 :         36 :     return -1;
     305                 :            :   }
     306                 :            : 
     307         [ +  + ]:     446119 :   if (l->n_bigits > c->n_bigits) {
     308                 :        924 :     return 1;
     309                 :            :   }
     310                 :            : 
     311   [ +  +  +  + ]:     445195 :   if (p->n_bigits < l->n_bigits && l->n_bigits < c->n_bigits) {
     312                 :      11170 :     return -1;
     313                 :            :   }
     314                 :            : 
     315                 :     434025 :   Hugit borrow = 0;
     316         [ +  + ]:     454829 :   for (int i = (int)c->n_bigits - 1; i >= 0; --i) {
     317                 :     454786 :     const Bigit ai  = l->bigits[i];
     318                 :     454786 :     const Bigit bi  = p->bigits[i];
     319                 :     454786 :     const Bigit ci  = c->bigits[i];
     320                 :     454786 :     const Hugit sum = (Hugit)ai + bi;
     321                 :            : 
     322         [ +  + ]:     454786 :     if (sum > ci + borrow) {
     323                 :      33757 :       return 1;
     324                 :            :     }
     325                 :            : 
     326                 :     421029 :     borrow += ci - sum;
     327         [ +  + ]:     421029 :     if (borrow > 1) {
     328                 :     400225 :       return -1;
     329                 :            :     }
     330                 :            : 
     331                 :      20804 :     borrow <<= 32U;
     332                 :            :   }
     333                 :            : 
     334         [ -  + ]:         43 :   return borrow ? -1 : 0;
     335                 :            : }
     336                 :            : 
     337                 :            : EXESS_I_NONBLOCKING int
     338                 :     446155 : exess_bigint_plus_compare(const ExessBigint* const l,
     339                 :            :                           const ExessBigint* const p,
     340                 :            :                           const ExessBigint* const c)
     341                 :            : {
     342         [ -  + ]:     446155 :   assert(exess_bigint_is_clamped(l));
     343         [ -  + ]:     446155 :   assert(exess_bigint_is_clamped(p));
     344         [ -  + ]:     446155 :   assert(exess_bigint_is_clamped(c));
     345                 :            : 
     346                 :     446155 :   return (l->n_bigits < p->n_bigits)
     347                 :       2323 :            ? exess_bigint_plus_compare_internal(p, l, c)
     348         [ +  + ]:     448478 :            : exess_bigint_plus_compare_internal(l, p, c);
     349                 :            : }
     350                 :            : 
     351                 :            : static unsigned
     352                 :      30692 : exess_bigint_add_carry(ExessBigint* lhs, unsigned i, bool carry)
     353                 :            : {
     354         [ +  + ]:      31148 :   for (; carry; ++i) {
     355                 :        456 :     const Hugit sum = (Hugit)carry + lhs->bigits[i];
     356                 :        456 :     lhs->bigits[i]  = (Bigit)(sum & bigit_mask);
     357                 :        456 :     carry           = (Bigit)((sum & carry_mask) >> 32U);
     358                 :            :   }
     359                 :            : 
     360                 :      30692 :   return i;
     361                 :            : }
     362                 :            : 
     363                 :            : EXESS_I_NONBLOCKING void
     364                 :         53 : exess_bigint_add_u32(ExessBigint* lhs, const uint32_t rhs)
     365                 :            : {
     366         [ +  + ]:         53 :   if (lhs->n_bigits == 0) {
     367                 :         30 :     exess_bigint_set_u32(lhs, rhs);
     368                 :         30 :     return;
     369                 :            :   }
     370                 :            : 
     371                 :         23 :   Hugit sum   = (Hugit)lhs->bigits[0] + rhs;
     372                 :         23 :   Bigit carry = (Bigit)(sum >> 32U);
     373                 :            : 
     374                 :         23 :   lhs->bigits[0] = (Bigit)(sum & bigit_mask);
     375                 :            : 
     376                 :         23 :   const unsigned i = exess_bigint_add_carry(lhs, 1U, carry);
     377                 :         23 :   lhs->n_bigits    = MAX(i, lhs->n_bigits);
     378         [ -  + ]:         23 :   assert(exess_bigint_is_clamped(lhs));
     379                 :            : }
     380                 :            : 
     381                 :            : EXESS_I_NONBLOCKING void
     382                 :      30669 : exess_bigint_add(ExessBigint* lhs, const ExessBigint* rhs)
     383                 :            : {
     384         [ -  + ]:      30669 :   assert(MAX(lhs->n_bigits, rhs->n_bigits) + 1 <= BIGINT_MAX_BIGITS);
     385                 :            : 
     386                 :      30669 :   bool     carry = 0;
     387                 :      30669 :   unsigned i     = 0;
     388         [ +  + ]:     215981 :   for (; i < rhs->n_bigits; ++i) {
     389                 :     185312 :     const Hugit sum = (Hugit)lhs->bigits[i] + rhs->bigits[i] + carry;
     390                 :            : 
     391                 :     185312 :     lhs->bigits[i] = (Bigit)(sum & bigit_mask);
     392                 :     185312 :     carry          = (sum & carry_mask) >> 32U;
     393                 :            :   }
     394                 :            : 
     395                 :      30669 :   i             = exess_bigint_add_carry(lhs, i, carry);
     396                 :      30669 :   lhs->n_bigits = MAX(i, lhs->n_bigits);
     397         [ -  + ]:      30669 :   assert(exess_bigint_is_clamped(lhs));
     398                 :      30669 : }
     399                 :            : 
     400                 :            : static unsigned
     401                 :    1149269 : exess_bigint_subtract_borrow(ExessBigint* lhs, unsigned i, bool borrow)
     402                 :            : {
     403         [ +  + ]:    1162342 :   for (; borrow; ++i) {
     404                 :      13073 :     const Bigit l = lhs->bigits[i];
     405                 :            : 
     406                 :      13073 :     lhs->bigits[i] -= borrow;
     407                 :            : 
     408                 :      13073 :     borrow = l == 0;
     409                 :            :   }
     410                 :            : 
     411                 :    1149269 :   return i;
     412                 :            : }
     413                 :            : 
     414                 :            : EXESS_I_NONBLOCKING void
     415                 :     280777 : exess_bigint_subtract(ExessBigint* lhs, const ExessBigint* rhs)
     416                 :            : {
     417         [ -  + ]:     280777 :   assert(exess_bigint_is_clamped(lhs));
     418         [ -  + ]:     280777 :   assert(exess_bigint_is_clamped(rhs));
     419         [ -  + ]:     280777 :   assert(exess_bigint_compare(lhs, rhs) >= 0);
     420                 :            : 
     421                 :     280777 :   bool     borrow = 0;
     422                 :     280777 :   unsigned i      = 0;
     423         [ +  + ]:    2713879 :   for (i = 0; i < rhs->n_bigits; ++i) {
     424                 :    2433102 :     const Bigit l = lhs->bigits[i];
     425                 :    2433102 :     const Bigit r = rhs->bigits[i];
     426                 :            : 
     427                 :    2433102 :     lhs->bigits[i] = l - r - borrow;
     428   [ +  +  +  +  :    2433102 :     borrow         = l < r || (l == r && borrow);
                   -  + ]
     429                 :            :   }
     430                 :            : 
     431                 :     280777 :   exess_bigint_subtract_borrow(lhs, i, borrow);
     432                 :     280777 :   exess_bigint_clamp(lhs);
     433                 :     280777 : }
     434                 :            : 
     435                 :            : static unsigned
     436                 :    1584953 : exess_bigint_leading_zeros(const ExessBigint* num)
     437                 :            : {
     438         [ -  + ]:    1584953 :   assert(num->n_bigits);
     439                 :    3169906 :   return (32 * (BIGINT_MAX_BIGITS - num->n_bigits)) +
     440                 :    1584953 :          exess_clz32(num->bigits[num->n_bigits - 1]);
     441                 :            : }
     442                 :            : 
     443                 :            : static Bigit
     444                 :    7883094 : exess_bigint_left_shifted_bigit_i(const ExessBigint* num,
     445                 :            :                                   const Offset       amount,
     446                 :            :                                   const unsigned     index)
     447                 :            : {
     448   [ +  -  +  + ]:    7883094 :   if (amount.bigits == 0 && amount.bits == 0) {
     449                 :    3685902 :     return num->bigits[index];
     450                 :            :   }
     451                 :            : 
     452         [ -  + ]:    4197192 :   if (index < amount.bigits) {
     453                 :          0 :     return 0;
     454                 :            :   }
     455                 :            : 
     456         [ -  + ]:    4197192 :   if (amount.bits == 0) { // Simple bigit-aligned shift
     457                 :          0 :     return num->bigits[index - amount.bigits];
     458                 :            :   }
     459                 :            : 
     460         [ +  + ]:    4197192 :   if (index == amount.bigits) { // Last non-zero bigit
     461                 :     439697 :     return num->bigits[0] << amount.bits;
     462                 :            :   }
     463                 :            : 
     464                 :            :   // Bigit + sub-bigit bit offset shift
     465                 :    3757495 :   const unsigned right_shift = BIGINT_BIGIT_BITS - amount.bits;
     466                 :    3757495 :   return (num->bigits[index - amount.bigits] << amount.bits) |
     467                 :    3757495 :          (num->bigits[index - amount.bigits - 1] >> right_shift);
     468                 :            : }
     469                 :            : 
     470                 :            : EXESS_I_NONBLOCKING Bigit
     471                 :          0 : exess_bigint_left_shifted_bigit(const ExessBigint* num,
     472                 :            :                                 const unsigned     amount,
     473                 :            :                                 const unsigned     index)
     474                 :            : {
     475                 :          0 :   return exess_bigint_left_shifted_bigit_i(num, make_offset(amount), index);
     476                 :            : }
     477                 :            : 
     478                 :            : EXESS_I_NONBLOCKING void
     479                 :     868492 : exess_bigint_subtract_left_shifted(ExessBigint*       lhs,
     480                 :            :                                    const ExessBigint* rhs,
     481                 :            :                                    const unsigned     amount)
     482                 :            : {
     483         [ -  + ]:     868492 :   assert(exess_bigint_is_clamped(lhs));
     484         [ -  + ]:     868492 :   assert(exess_bigint_is_clamped(rhs));
     485                 :            : #ifndef NDEBUG
     486                 :            :   {
     487                 :     868492 :     ExessBigint check_rhs = *rhs;
     488                 :     868492 :     exess_bigint_shift_left(&check_rhs, amount);
     489         [ -  + ]:     868492 :     assert(exess_bigint_compare(lhs, &check_rhs) >= 0);
     490                 :            :   }
     491                 :            : #endif
     492                 :            : 
     493                 :     868492 :   const Offset   offset     = make_offset(amount);
     494                 :     868492 :   const unsigned r_n_bigits = rhs->n_bigits + offset.bigits + (bool)offset.bits;
     495                 :            : 
     496                 :     868492 :   bool     borrow = 0;
     497                 :     868492 :   unsigned i      = 0;
     498         [ +  + ]:    8751586 :   for (i = 0; i < r_n_bigits; ++i) {
     499                 :    7883094 :     const Bigit l = lhs->bigits[i];
     500                 :    7883094 :     const Bigit r = exess_bigint_left_shifted_bigit_i(rhs, offset, i);
     501                 :            : 
     502                 :    7883094 :     lhs->bigits[i] = l - r - borrow;
     503   [ +  +  +  +  :    7883094 :     borrow         = l < r || ((l == r) && borrow);
                   +  + ]
     504                 :            :   }
     505                 :            : 
     506                 :     868492 :   exess_bigint_subtract_borrow(lhs, i, borrow);
     507                 :     868492 :   exess_bigint_clamp(lhs);
     508                 :     868492 : }
     509                 :            : 
     510                 :            : EXESS_I_NONBLOCKING uint32_t
     511                 :     437721 : exess_bigint_divmod(ExessBigint* lhs, const ExessBigint* rhs)
     512                 :            : {
     513         [ -  + ]:     437721 :   assert(exess_bigint_is_clamped(lhs));
     514         [ -  + ]:     437721 :   assert(exess_bigint_is_clamped(rhs));
     515         [ -  + ]:     437721 :   assert(rhs->n_bigits > 0);
     516         [ +  + ]:     437721 :   if (lhs->n_bigits < rhs->n_bigits) {
     517                 :       2037 :     return 0;
     518                 :            :   }
     519                 :            : 
     520                 :     435684 :   uint32_t       result = 0;
     521                 :     435684 :   const Bigit    r0     = rhs->bigits[rhs->n_bigits - 1];
     522                 :     435684 :   const unsigned rlz    = exess_bigint_leading_zeros(rhs);
     523                 :            : 
     524                 :            :   // Shift and subtract until the LHS does not have more bigits
     525         [ +  + ]:     486398 :   while (lhs->n_bigits > rhs->n_bigits) {
     526                 :      50714 :     const unsigned llz   = exess_bigint_leading_zeros(lhs);
     527                 :      50714 :     const unsigned shift = rlz - llz - 1;
     528                 :            : 
     529                 :      50714 :     result += 1U << shift;
     530                 :      50714 :     exess_bigint_subtract_left_shifted(lhs, rhs, shift);
     531                 :            :   }
     532                 :            : 
     533                 :            :   // Handle simple termination cases
     534                 :     435684 :   int cmp = exess_bigint_compare(lhs, rhs);
     535         [ +  + ]:     435684 :   if (cmp < 0) {
     536                 :      39321 :     return result;
     537                 :            :   }
     538                 :            : 
     539   [ +  +  -  + ]:     396363 :   if (cmp > 0 && lhs->n_bigits == 1) {
     540         [ #  # ]:          0 :     assert(rhs->n_bigits == 1);
     541                 :          0 :     const Bigit l0 = lhs->bigits[lhs->n_bigits - 1];
     542                 :            : 
     543                 :          0 :     lhs->bigits[lhs->n_bigits - 1] = l0 % r0;
     544                 :          0 :     lhs->n_bigits -= (lhs->bigits[lhs->n_bigits - 1] == 0);
     545                 :          0 :     return result + (l0 / r0);
     546                 :            :   }
     547                 :            : 
     548                 :            :   // Both now have the same number of digits, finish with subtraction
     549         [ +  + ]:    1214141 :   for (; cmp >= 0; cmp = exess_bigint_compare(lhs, rhs)) {
     550                 :    1098555 :     const unsigned llz = exess_bigint_leading_zeros(lhs);
     551         [ +  + ]:    1098555 :     if (rlz == llz) {
     552                 :            :       // Both have the same number of leading zeros, just subtract
     553                 :     280777 :       exess_bigint_subtract(lhs, rhs);
     554                 :     280777 :       return result + 1;
     555                 :            :     }
     556                 :            : 
     557                 :     817778 :     const unsigned shift = rlz - llz - 1;
     558                 :     817778 :     result += 1U << shift;
     559                 :     817778 :     exess_bigint_subtract_left_shifted(lhs, rhs, shift);
     560                 :            :   }
     561                 :            : 
     562                 :     115586 :   return result;
     563                 :            : }

Generated by: LCOV version 1.16