Home | History | Annotate | Line # | Download | only in core
      1 /* 128 bit integer arithmetic.
      2  *
      3  * Not optimized for speed.
      4  *
      5  * Copyright: Copyright D Language Foundation 2022.
      6  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
      7  * Authors:   Walter Bright
      8  * Source:    $(DRUNTIMESRC core/_int128.d)
      9  */
     10 
     11 module core.int128;
     12 
     13 nothrow:
     14 @safe:
     15 @nogc:
     16 
     17 alias I = long;
     18 alias U = ulong;
     19 enum Ubits = uint(U.sizeof * 8);
     20 
     21 version (X86_64) private enum Cent_alignment = 16;
     22 else             private enum Cent_alignment = (size_t.sizeof * 2);
     23 
     24 align(Cent_alignment) struct Cent
     25 {
     26     version (LittleEndian)
     27     {
     28         U lo;  // low 64 bits
     29         U hi;  // high 64 bits
     30     }
     31     else
     32     {
     33         U hi;  // high 64 bits
     34         U lo;  // low 64 bits
     35     }
     36 }
     37 
     38 enum Cent One = { lo:1 };
     39 enum Cent Zero = { lo:0 };
     40 enum Cent MinusOne = neg(One);
     41 
     42 /*****************************
     43  * Test against 0
     44  * Params:
     45  *      c = Cent to test
     46  * Returns:
     47  *      true if != 0
     48  */
     49 pure
     50 bool tst(Cent c)
     51 {
     52     return c.hi || c.lo;
     53 }
     54 
     55 
     56 /*****************************
     57  * Complement
     58  * Params:
     59  *      c = Cent to complement
     60  * Returns:
     61  *      complemented value
     62  */
     63 pure
     64 Cent com(Cent c)
     65 {
     66     c.lo = ~c.lo;
     67     c.hi = ~c.hi;
     68     return c;
     69 }
     70 
     71 /*****************************
     72  * Negate
     73  * Params:
     74  *      c = Cent to negate
     75  * Returns:
     76  *      negated value
     77  */
     78 pure
     79 Cent neg(Cent c)
     80 {
     81     if (c.lo == 0)
     82         c.hi = -c.hi;
     83     else
     84     {
     85         c.lo = -c.lo;
     86         c.hi = ~c.hi;
     87     }
     88     return c;
     89 }
     90 
     91 /*****************************
     92  * Increment
     93  * Params:
     94  *      c = Cent to increment
     95  * Returns:
     96  *      incremented value
     97  */
     98 pure
     99 Cent inc(Cent c)
    100 {
    101     return add(c, One);
    102 }
    103 
    104 /*****************************
    105  * Decrement
    106  * Params:
    107  *      c = Cent to decrement
    108  * Returns:
    109  *      incremented value
    110  */
    111 pure
    112 Cent dec(Cent c)
    113 {
    114     return sub(c, One);
    115 }
    116 
    117 /*****************************
    118  * Shift left one bit
    119  * Params:
    120  *      c = Cent to shift
    121  * Returns:
    122  *      shifted value
    123  */
    124 pure
    125 Cent shl1(Cent c)
    126 {
    127     c.hi = (c.hi << 1) | (cast(I)c.lo < 0);
    128     c.lo <<= 1;
    129     return c;
    130 }
    131 
    132 /*****************************
    133  * Unsigned shift right one bit
    134  * Params:
    135  *      c = Cent to shift
    136  * Returns:
    137  *      shifted value
    138  */
    139 pure
    140 Cent shr1(Cent c)
    141 {
    142     c.lo = (c.lo >> 1) | ((c.hi & 1) << (Ubits - 1));
    143     c.hi >>= 1;
    144     return c;
    145 }
    146 
    147 
    148 /*****************************
    149  * Arithmetic shift right one bit
    150  * Params:
    151  *      c = Cent to shift
    152  * Returns:
    153  *      shifted value
    154  */
    155 pure
    156 Cent sar1(Cent c)
    157 {
    158     c.lo = (c.lo >> 1) | ((c.hi & 1) << (Ubits - 1));
    159     c.hi = cast(I)c.hi >> 1;
    160     return c;
    161 }
    162 
    163 /*****************************
    164  * Shift left n bits
    165  * Params:
    166  *      c = Cent to shift
    167  *      n = number of bits to shift
    168  * Returns:
    169  *      shifted value
    170  */
    171 pure
    172 Cent shl(Cent c, uint n)
    173 {
    174     if (n >= Ubits * 2)
    175         return Zero;
    176 
    177     if (n >= Ubits)
    178     {
    179         c.hi = c.lo << (n - Ubits);
    180         c.lo = 0;
    181     }
    182     else
    183     {
    184         c.hi = ((c.hi << n) | (c.lo >> (Ubits - n - 1) >> 1));
    185         c.lo = c.lo << n;
    186     }
    187     return c;
    188 }
    189 
    190 /*****************************
    191  * Unsigned shift right n bits
    192  * Params:
    193  *      c = Cent to shift
    194  *      n = number of bits to shift
    195  * Returns:
    196  *      shifted value
    197  */
    198 pure
    199 Cent shr(Cent c, uint n)
    200 {
    201     if (n >= Ubits * 2)
    202         return Zero;
    203 
    204     if (n >= Ubits)
    205     {
    206         c.lo = c.hi >> (n - Ubits);
    207         c.hi = 0;
    208     }
    209     else
    210     {
    211         c.lo = ((c.lo >> n) | (c.hi << (Ubits - n - 1) << 1));
    212         c.hi = c.hi >> n;
    213     }
    214     return c;
    215 }
    216 
    217 /*****************************
    218  * Arithmetic shift right n bits
    219  * Params:
    220  *      c = Cent to shift
    221  *      n = number of bits to shift
    222  * Returns:
    223  *      shifted value
    224  */
    225 pure
    226 Cent sar(Cent c, uint n)
    227 {
    228     const signmask = -(c.hi >> (Ubits - 1));
    229     const signshift = (Ubits * 2) - n;
    230     c = shr(c, n);
    231 
    232     // Sign extend all bits beyond the precision of Cent.
    233     if (n >= Ubits * 2)
    234     {
    235         c.hi = signmask;
    236         c.lo = signmask;
    237     }
    238     else if (signshift >= Ubits * 2)
    239     {
    240     }
    241     else if (signshift >= Ubits)
    242     {
    243         c.hi &= ~(U.max << (signshift - Ubits));
    244         c.hi |= signmask << (signshift - Ubits);
    245     }
    246     else
    247     {
    248         c.hi = signmask;
    249         c.lo &= ~(U.max << signshift);
    250         c.lo |= signmask << signshift;
    251     }
    252     return c;
    253 }
    254 
    255 /*****************************
    256  * Rotate left one bit
    257  * Params:
    258  *      c = Cent to rotate
    259  * Returns:
    260  *      rotated value
    261  */
    262 pure
    263 Cent rol1(Cent c)
    264 {
    265     int carry = cast(I)c.hi < 0;
    266 
    267     c.hi = (c.hi << 1) | (cast(I)c.lo < 0);
    268     c.lo = (c.lo << 1) | carry;
    269     return c;
    270 }
    271 
    272 /*****************************
    273  * Rotate right one bit
    274  * Params:
    275  *      c = Cent to rotate
    276  * Returns:
    277  *      rotated value
    278  */
    279 pure
    280 Cent ror1(Cent c)
    281 {
    282     int carry = c.lo & 1;
    283     c.lo = (c.lo >> 1) | (cast(U)(c.hi & 1) << (Ubits - 1));
    284     c.hi = (c.hi >> 1) | (cast(U)carry << (Ubits - 1));
    285     return c;
    286 }
    287 
    288 
    289 /*****************************
    290  * Rotate left n bits
    291  * Params:
    292  *      c = Cent to rotate
    293  *      n = number of bits to rotate
    294  * Returns:
    295  *      rotated value
    296  */
    297 pure
    298 Cent rol(Cent c, uint n)
    299 {
    300     n &= Ubits * 2 - 1;
    301     Cent l = shl(c, n);
    302     Cent r = shr(c, Ubits * 2 - n);
    303     return or(l, r);
    304 }
    305 
    306 /*****************************
    307  * Rotate right n bits
    308  * Params:
    309  *      c = Cent to rotate
    310  *      n = number of bits to rotate
    311  * Returns:
    312  *      rotated value
    313  */
    314 pure
    315 Cent ror(Cent c, uint n)
    316 {
    317     n &= Ubits * 2 - 1;
    318     Cent r = shr(c, n);
    319     Cent l = shl(c, Ubits * 2 - n);
    320     return or(r, l);
    321 }
    322 
    323 /****************************
    324  * And c1 & c2.
    325  * Params:
    326  *      c1 = operand 1
    327  *      c2 = operand 2
    328  * Returns:
    329  *      c1 & c2
    330  */
    331 pure
    332 Cent and(Cent c1, Cent c2)
    333 {
    334     const Cent ret = { lo:c1.lo & c2.lo, hi:c1.hi & c2.hi };
    335     return ret;
    336 }
    337 
    338 /****************************
    339  * Or c1 | c2.
    340  * Params:
    341  *      c1 = operand 1
    342  *      c2 = operand 2
    343  * Returns:
    344  *      c1 | c2
    345  */
    346 pure
    347 Cent or(Cent c1, Cent c2)
    348 {
    349     const Cent ret = { lo:c1.lo | c2.lo, hi:c1.hi | c2.hi };
    350     return ret;
    351 }
    352 
    353 /****************************
    354  * Xor c1 ^ c2.
    355  * Params:
    356  *      c1 = operand 1
    357  *      c2 = operand 2
    358  * Returns:
    359  *      c1 ^ c2
    360  */
    361 pure
    362 Cent xor(Cent c1, Cent c2)
    363 {
    364     const Cent ret = { lo:c1.lo ^ c2.lo, hi:c1.hi ^ c2.hi };
    365     return ret;
    366 }
    367 
    368 /****************************
    369  * Add c1 to c2.
    370  * Params:
    371  *      c1 = operand 1
    372  *      c2 = operand 2
    373  * Returns:
    374  *      c1 + c2
    375  */
    376 pure
    377 Cent add(Cent c1, Cent c2)
    378 {
    379     U r = cast(U)(c1.lo + c2.lo);
    380     const Cent ret = { lo:r, hi:cast(U)(c1.hi + c2.hi + (r < c1.lo)) };
    381     return ret;
    382 }
    383 
    384 /****************************
    385  * Subtract c2 from c1.
    386  * Params:
    387  *      c1 = operand 1
    388  *      c2 = operand 2
    389  * Returns:
    390  *      c1 - c2
    391  */
    392 pure
    393 Cent sub(Cent c1, Cent c2)
    394 {
    395     return add(c1, neg(c2));
    396 }
    397 
    398 /****************************
    399  * Multiply c1 * c2.
    400  * Params:
    401  *      c1 = operand 1
    402  *      c2 = operand 2
    403  * Returns:
    404  *      c1 * c2
    405  */
    406 pure
    407 Cent mul(Cent c1, Cent c2)
    408 {
    409     enum mulmask = (1UL << (Ubits / 2)) - 1;
    410     enum mulshift = Ubits / 2;
    411 
    412     // This algorithm splits the operands into 4 words, then computes and sums
    413     // the partial products of each part.
    414     const c2l0 = c2.lo & mulmask;
    415     const c2l1 = c2.lo >> mulshift;
    416     const c2h0 = c2.hi & mulmask;
    417     const c2h1 = c2.hi >> mulshift;
    418 
    419     const c1l0 = c1.lo & mulmask;
    420     U r0 = c1l0 * c2l0;
    421     U r1 = c1l0 * c2l1 + (r0 >> mulshift);
    422     U r2 = c1l0 * c2h0 + (r1 >> mulshift);
    423     U r3 = c1l0 * c2h1 + (r2 >> mulshift);
    424 
    425     const c1l1 = c1.lo >> mulshift;
    426     r1 = c1l1 * c2l0 + (r1 & mulmask);
    427     r2 = c1l1 * c2l1 + (r2 & mulmask) + (r1 >> mulshift);
    428     r3 = c1l1 * c2h0 + (r3 & mulmask) + (r2 >> mulshift);
    429 
    430     const c1h0 = c1.hi & mulmask;
    431     r2 = c1h0 * c2l0 + (r2 & mulmask);
    432     r3 = c1h0 * c2l1 + (r3 & mulmask) + (r2 >> mulshift);
    433 
    434     const c1h1 = c1.hi >> mulshift;
    435     r3 = c1h1 * c2l0 + (r3 & mulmask);
    436 
    437     const Cent ret = { lo:(r0 & mulmask) + (r1 & mulmask) * (mulmask + 1),
    438                        hi:(r2 & mulmask) + (r3 & mulmask) * (mulmask + 1) };
    439     return ret;
    440 }
    441 
    442 
    443 /****************************
    444  * Unsigned divide c1 / c2.
    445  * Params:
    446  *      c1 = dividend
    447  *      c2 = divisor
    448  * Returns:
    449  *      quotient c1 / c2
    450  */
    451 pure
    452 Cent udiv(Cent c1, Cent c2)
    453 {
    454     Cent modulus;
    455     return udivmod(c1, c2, modulus);
    456 }
    457 
    458 /****************************
    459  * Unsigned divide c1 / c2. The remainder after division is stored to modulus.
    460  * Params:
    461  *      c1 = dividend
    462  *      c2 = divisor
    463  *      modulus = set to c1 % c2
    464  * Returns:
    465  *      quotient c1 / c2
    466  */
    467 pure
    468 Cent udivmod(Cent c1, Cent c2, out Cent modulus)
    469 {
    470     //printf("udiv c1(%llx,%llx) c2(%llx,%llx)\n", c1.lo, c1.hi, c2.lo, c2.hi);
    471     // Based on "Unsigned Doubleword Division" in Hacker's Delight
    472     import core.bitop;
    473 
    474     // Divides a 128-bit dividend by a 64-bit divisor.
    475     // The result must fit in 64 bits.
    476     static U udivmod128_64(Cent c1, U c2, out U modulus)
    477     {
    478         // We work in base 2^^32
    479         enum base = 1UL << 32;
    480         enum divmask = (1UL << (Ubits / 2)) - 1;
    481         enum divshift = Ubits / 2;
    482 
    483         // Check for overflow and divide by 0
    484         if (c1.hi >= c2)
    485         {
    486             modulus = 0UL;
    487             return ~0UL;
    488         }
    489 
    490         // Computes [num1 num0] / den
    491         static uint udiv96_64(U num1, uint num0, U den)
    492         {
    493             // Extract both digits of the denominator
    494             const den1 = cast(uint)(den >> divshift);
    495             const den0 = cast(uint)(den & divmask);
    496             // Estimate ret as num1 / den1, and then correct it
    497             U ret = num1 / den1;
    498             const t2 = (num1 % den1) * base + num0;
    499             const t1 = ret * den0;
    500             if (t1 > t2)
    501                 ret -= (t1 - t2 > den) ? 2 : 1;
    502             return cast(uint)ret;
    503         }
    504 
    505         // Determine the normalization factor. We multiply c2 by this, so that its leading
    506         // digit is at least half base. In binary this means just shifting left by the number
    507         // of leading zeros, so that there's a 1 in the MSB.
    508         // We also shift number by the same amount. This cannot overflow because c1.hi < c2.
    509         const shift = (Ubits - 1) - bsr(c2);
    510         c2 <<= shift;
    511         U num2 = c1.hi;
    512         num2 <<= shift;
    513         num2 |= (c1.lo >> (-shift & 63)) & (-cast(I)shift >> 63);
    514         c1.lo <<= shift;
    515 
    516         // Extract the low digits of the numerator (after normalizing)
    517         const num1 = cast(uint)(c1.lo >> divshift);
    518         const num0 = cast(uint)(c1.lo & divmask);
    519 
    520         // Compute q1 = [num2 num1] / c2
    521         const q1 = udiv96_64(num2, num1, c2);
    522         // Compute the true (partial) remainder
    523         const rem = num2 * base + num1 - q1 * c2;
    524         // Compute q0 = [rem num0] / c2
    525         const q0 = udiv96_64(rem, num0, c2);
    526 
    527         modulus = (rem * base + num0 - q0 * c2) >> shift;
    528         return (cast(U)q1 << divshift) | q0;
    529     }
    530 
    531     // Special cases
    532     if (!tst(c2))
    533     {
    534         // Divide by zero
    535         modulus = Zero;
    536         return com(modulus);
    537     }
    538     if (c1.hi == 0 && c2.hi == 0)
    539     {
    540         // Single precision divide
    541         const Cent rem = { lo:c1.lo % c2.lo };
    542         modulus = rem;
    543         const Cent ret = { lo:c1.lo / c2.lo };
    544         return ret;
    545     }
    546     if (c1.hi == 0)
    547     {
    548         // Numerator is smaller than the divisor
    549         modulus = c1;
    550         return Zero;
    551     }
    552     if (c2.hi == 0)
    553     {
    554         // Divisor is a 64-bit value, so we just need one 128/64 division.
    555         // If c1 / c2 would overflow, break c1 up into two halves.
    556         const q1 = (c1.hi < c2.lo) ? 0 : (c1.hi / c2.lo);
    557         if (q1)
    558             c1.hi = c1.hi % c2.lo;
    559         Cent rem;
    560         const q0 = udivmod128_64(c1, c2.lo, rem.lo);
    561         modulus = rem;
    562         const Cent ret = { lo:q0, hi:q1 };
    563         return ret;
    564     }
    565 
    566     // Full cent precision division.
    567     // Here c2 >= 2^^64
    568     // We know that c2.hi != 0, so count leading zeros is OK
    569     // We have 0 <= shift <= 63
    570     const shift = (Ubits - 1) - bsr(c2.hi);
    571 
    572     // Normalize the divisor so its MSB is 1
    573     // v1 = (c2 << shift) >> 64
    574     U v1 = shl(c2, shift).hi;
    575 
    576     // To ensure no overflow.
    577     Cent u1 = shr1(c1);
    578 
    579     // Get quotient from divide unsigned operation.
    580     U rem_ignored;
    581     const Cent q1 = { lo:udivmod128_64(u1, v1, rem_ignored) };
    582 
    583     // Undo normalization and division of c1 by 2.
    584     Cent quotient = shr(shl(q1, shift), 63);
    585 
    586     // Make quotient correct or too small by 1
    587     if (tst(quotient))
    588         quotient = dec(quotient);
    589 
    590     // Now quotient is correct.
    591     // Compute rem = c1 - (quotient * c2);
    592     Cent rem = sub(c1, mul(quotient, c2));
    593 
    594     // Check if remainder is larger than the divisor
    595     if (uge(rem, c2))
    596     {
    597         // Increment quotient
    598         quotient = inc(quotient);
    599         // Subtract c2 from remainder
    600         rem = sub(rem, c2);
    601     }
    602     modulus = rem;
    603     //printf("quotient "); print(quotient);
    604     //printf("modulus  "); print(modulus);
    605     return quotient;
    606 }
    607 
    608 
    609 /****************************
    610  * Signed divide c1 / c2.
    611  * Params:
    612  *      c1 = dividend
    613  *      c2 = divisor
    614  * Returns:
    615  *      quotient c1 / c2
    616  */
    617 pure
    618 Cent div(Cent c1, Cent c2)
    619 {
    620     Cent modulus;
    621     return divmod(c1, c2, modulus);
    622 }
    623 
    624 /****************************
    625  * Signed divide c1 / c2. The remainder after division is stored to modulus.
    626  * Params:
    627  *      c1 = dividend
    628  *      c2 = divisor
    629  *      modulus = set to c1 % c2
    630  * Returns:
    631  *      quotient c1 / c2
    632  */
    633 pure
    634 Cent divmod(Cent c1, Cent c2, out Cent modulus)
    635 {
    636     /* Muck about with the signs so we can use the unsigned divide
    637      */
    638     if (cast(I)c1.hi < 0)
    639     {
    640         if (cast(I)c2.hi < 0)
    641         {
    642             Cent r = udivmod(neg(c1), neg(c2), modulus);
    643             modulus = neg(modulus);
    644             return r;
    645         }
    646         Cent r = neg(udivmod(neg(c1), c2, modulus));
    647         modulus = neg(modulus);
    648         return r;
    649     }
    650     else if (cast(I)c2.hi < 0)
    651     {
    652         return neg(udivmod(c1, neg(c2), modulus));
    653     }
    654     else
    655         return udivmod(c1, c2, modulus);
    656 }
    657 
    658 /****************************
    659  * If c1 > c2 unsigned
    660  * Params:
    661  *      c1 = operand 1
    662  *      c2 = operand 2
    663  * Returns:
    664  *      true if c1 > c2
    665  */
    666 pure
    667 bool ugt(Cent c1, Cent c2)
    668 {
    669     return (c1.hi == c2.hi) ? (c1.lo > c2.lo) : (c1.hi > c2.hi);
    670 }
    671 
    672 /****************************
    673  * If c1 >= c2 unsigned
    674  * Params:
    675  *      c1 = operand 1
    676  *      c2 = operand 2
    677  * Returns:
    678  *      true if c1 >= c2
    679  */
    680 pure
    681 bool uge(Cent c1, Cent c2)
    682 {
    683     return !ugt(c2, c1);
    684 }
    685 
    686 /****************************
    687  * If c1 < c2 unsigned
    688  * Params:
    689  *      c1 = operand 1
    690  *      c2 = operand 2
    691  * Returns:
    692  *      true if c1 < c2
    693  */
    694 pure
    695 bool ult(Cent c1, Cent c2)
    696 {
    697     return ugt(c2, c1);
    698 }
    699 
    700 /****************************
    701  * If c1 <= c2 unsigned
    702  * Params:
    703  *      c1 = operand 1
    704  *      c2 = operand 2
    705  * Returns:
    706  *      true if c1 <= c2
    707  */
    708 pure
    709 bool ule(Cent c1, Cent c2)
    710 {
    711     return !ugt(c1, c2);
    712 }
    713 
    714 /****************************
    715  * If c1 > c2 signed
    716  * Params:
    717  *      c1 = operand 1
    718  *      c2 = operand 2
    719  * Returns:
    720  *      true if c1 > c2
    721  */
    722 pure
    723 bool gt(Cent c1, Cent c2)
    724 {
    725     return (c1.hi == c2.hi)
    726         ? (c1.lo > c2.lo)
    727         : (cast(I)c1.hi > cast(I)c2.hi);
    728 }
    729 
    730 /****************************
    731  * If c1 >= c2 signed
    732  * Params:
    733  *      c1 = operand 1
    734  *      c2 = operand 2
    735  * Returns:
    736  *      true if c1 >= c2
    737  */
    738 pure
    739 bool ge(Cent c1, Cent c2)
    740 {
    741     return !gt(c2, c1);
    742 }
    743 
    744 /****************************
    745  * If c1 < c2 signed
    746  * Params:
    747  *      c1 = operand 1
    748  *      c2 = operand 2
    749  * Returns:
    750  *      true if c1 < c2
    751  */
    752 pure
    753 bool lt(Cent c1, Cent c2)
    754 {
    755     return gt(c2, c1);
    756 }
    757 
    758 /****************************
    759  * If c1 <= c2 signed
    760  * Params:
    761  *      c1 = operand 1
    762  *      c2 = operand 2
    763  * Returns:
    764  *      true if c1 <= c2
    765  */
    766 pure
    767 bool le(Cent c1, Cent c2)
    768 {
    769     return !gt(c1, c2);
    770 }
    771 
    772 /*******************************************************/
    773 
    774 version (unittest)
    775 {
    776     version (none)
    777     {
    778         import core.stdc.stdio;
    779 
    780         @trusted
    781         void print(Cent c)
    782         {
    783             printf("%lld, %lld\n", cast(ulong)c.lo, cast(ulong)c.hi);
    784             printf("x%llx, x%llx\n", cast(ulong)c.lo, cast(ulong)c.hi);
    785         }
    786     }
    787 }
    788 
    789 unittest
    790 {
    791     const Cent C0 = Zero;
    792     const Cent C1 = One;
    793     const Cent C2 = { lo:2 };
    794     const Cent C3 = { lo:3 };
    795     const Cent C5 = { lo:5 };
    796     const Cent C10 = { lo:10 };
    797     const Cent C20 = { lo:20 };
    798     const Cent C30 = { lo:30 };
    799     const Cent C100 = { lo:100 };
    800 
    801     const Cent Cm1 =  neg(One);
    802     const Cent Cm3 =  neg(C3);
    803     const Cent Cm10 = neg(C10);
    804 
    805     const Cent C3_1 = { lo:1, hi:3 };
    806     const Cent C3_2 = { lo:2, hi:3 };
    807     const Cent C4_8  = { lo:8, hi:4 };
    808     const Cent C5_0  = { lo:0, hi:5 };
    809     const Cent C7_1 = { lo:1, hi:7 };
    810     const Cent C7_9 = { lo:9, hi:7 };
    811     const Cent C9_3 = { lo:3, hi:9 };
    812     const Cent C10_0 = { lo:0, hi:10 };
    813     const Cent C10_1 = { lo:1, hi:10 };
    814     const Cent C10_3 = { lo:3, hi:10 };
    815     const Cent C11_3 = { lo:3, hi:11 };
    816     const Cent C20_0 = { lo:0, hi:20 };
    817     const Cent C90_30 = { lo:30, hi:90 };
    818 
    819     const Cent Cm10_0 = inc(com(C10_0)); // Cent(lo=0,  hi=-10);
    820     const Cent Cm10_1 = inc(com(C10_1)); // Cent(lo=-1, hi=-11);
    821     const Cent Cm10_3 = inc(com(C10_3)); // Cent(lo=-3, hi=-11);
    822     const Cent Cm20_0 = inc(com(C20_0)); // Cent(lo=0,  hi=-20);
    823 
    824     enum Cent Cs_3 = { lo:3, hi:I.min };
    825 
    826     const Cent Cbig_1 = { lo:0xa3ccac1832952398, hi:0xc3ac542864f652f8 };
    827     const Cent Cbig_2 = { lo:0x5267b85f8a42fc20, hi:0 };
    828     const Cent Cbig_3 = { lo:0xf0000000ffffffff, hi:0 };
    829 
    830     /************************/
    831 
    832     assert( ugt(C1, C0) );
    833     assert( ult(C1, C2) );
    834     assert( uge(C1, C0) );
    835     assert( ule(C1, C2) );
    836 
    837     assert( !ugt(C0, C1) );
    838     assert( !ult(C2, C1) );
    839     assert( !uge(C0, C1) );
    840     assert( !ule(C2, C1) );
    841 
    842     assert( !ugt(C1, C1) );
    843     assert( !ult(C1, C1) );
    844     assert( uge(C1, C1) );
    845     assert( ule(C2, C2) );
    846 
    847     assert( ugt(C10_3, C10_1) );
    848     assert( ugt(C11_3, C10_3) );
    849     assert( !ugt(C9_3, C10_3) );
    850     assert( !ugt(C9_3, C9_3) );
    851 
    852     assert( gt(C2, C1) );
    853     assert( !gt(C1, C2) );
    854     assert( !gt(C1, C1) );
    855     assert( gt(C0, Cm1) );
    856     assert( gt(Cm1, neg(C10)));
    857     assert( !gt(Cm1, Cm1) );
    858     assert( !gt(Cm1, C0) );
    859 
    860     assert( !lt(C2, C1) );
    861     assert( !le(C2, C1) );
    862     assert( ge(C2, C1) );
    863 
    864     assert(neg(C10_0) == Cm10_0);
    865     assert(neg(C10_1) == Cm10_1);
    866     assert(neg(C10_3) == Cm10_3);
    867 
    868     assert(add(C7_1,C3_2) == C10_3);
    869     assert(sub(C1,C2) == Cm1);
    870 
    871     assert(inc(C3_1) == C3_2);
    872     assert(dec(C3_2) == C3_1);
    873 
    874     assert(shl(C10,0) == C10);
    875     assert(shl(C10,Ubits) == C10_0);
    876     assert(shl(C10,1) == C20);
    877     assert(shl(C10,Ubits * 2) == C0);
    878     assert(shr(C10_0,0) == C10_0);
    879     assert(shr(C10_0,Ubits) == C10);
    880     assert(shr(C10_0,Ubits - 1) == C20);
    881     assert(shr(C10_0,Ubits + 1) == C5);
    882     assert(shr(C10_0,Ubits * 2) == C0);
    883     assert(sar(C10_0,0) == C10_0);
    884     assert(sar(C10_0,Ubits) == C10);
    885     assert(sar(C10_0,Ubits - 1) == C20);
    886     assert(sar(C10_0,Ubits + 1) == C5);
    887     assert(sar(C10_0,Ubits * 2) == C0);
    888     assert(sar(Cm1,Ubits * 2) == Cm1);
    889 
    890     assert(shl1(C10) == C20);
    891     assert(shr1(C10_0) == C5_0);
    892     assert(sar1(C10_0) == C5_0);
    893     assert(sar1(Cm1) == Cm1);
    894 
    895     Cent modulus;
    896 
    897     assert(udiv(C10,C2) == C5);
    898     assert(udivmod(C10,C2, modulus) ==  C5);   assert(modulus == C0);
    899     assert(udivmod(C10,C3, modulus) ==  C3);   assert(modulus == C1);
    900     assert(udivmod(C10,C0, modulus) == Cm1);   assert(modulus == C0);
    901     assert(udivmod(C2,C90_30, modulus) == C0); assert(modulus == C2);
    902     assert(udiv(mul(C90_30, C2), C2) == C90_30);
    903     assert(udiv(mul(C90_30, C2), C90_30) == C2);
    904 
    905     assert(div(C10,C3) == C3);
    906     assert(divmod( C10,  C3, modulus) ==  C3); assert(modulus ==  C1);
    907     assert(divmod(Cm10,  C3, modulus) == Cm3); assert(modulus == Cm1);
    908     assert(divmod( C10, Cm3, modulus) == Cm3); assert(modulus ==  C1);
    909     assert(divmod(Cm10, Cm3, modulus) ==  C3); assert(modulus == Cm1);
    910     assert(divmod(C2, C90_30, modulus) == C0); assert(modulus == C2);
    911     assert(div(mul(C90_30, C2), C2) == C90_30);
    912     assert(div(mul(C90_30, C2), C90_30) == C2);
    913 
    914     const Cent Cb1divb2 = { lo:0x4496aa309d4d4a2f, hi:U.max };
    915     const Cent Cb1modb2 = { lo:0xd83203d0fdc799b8, hi:U.max };
    916     assert(divmod(Cbig_1, Cbig_2, modulus) == Cb1divb2);
    917     assert(modulus == Cb1modb2);
    918 
    919     const Cent Cb1udivb2 = { lo:0x5fe0e9bace2bedad, hi:2 };
    920     const Cent Cb1umodb2 = { lo:0x2c923125a68721f8, hi:0 };
    921     assert(udivmod(Cbig_1, Cbig_2, modulus) == Cb1udivb2);
    922     assert(modulus == Cb1umodb2);
    923 
    924     const Cent Cb1divb3 = { lo:0xbfa6c02b5aff8b86, hi:U.max };
    925     const Cent Cb1udivb3 = { lo:0xd0b7d13b48cb350f, hi:0 };
    926     assert(div(Cbig_1, Cbig_3) == Cb1divb3);
    927     assert(udiv(Cbig_1, Cbig_3) == Cb1udivb3);
    928 
    929     assert(mul(Cm10, C1) == Cm10);
    930     assert(mul(C1, Cm10) == Cm10);
    931     assert(mul(C9_3, C10) == C90_30);
    932     assert(mul(Cs_3, C10) == C30);
    933     assert(mul(Cm10, Cm10) == C100);
    934     assert(mul(C20_0, Cm1) == Cm20_0);
    935 
    936     assert( or(C4_8, C3_1) == C7_9);
    937     assert(and(C4_8, C7_9) == C4_8);
    938     assert(xor(C4_8, C7_9) == C3_1);
    939 
    940     assert(rol(Cm1,  1) == Cm1);
    941     assert(ror(Cm1, 45) == Cm1);
    942     assert(rol(ror(C7_9, 5), 5) == C7_9);
    943     assert(rol(C7_9, 1) == rol1(C7_9));
    944     assert(ror(C7_9, 1) == ror1(C7_9));
    945 }
    946 
    947 
    948