Skip to content

Commit

Permalink
[ISSUE-0046]: biguint128_mulXXX and biguint128_divXXX functions becam…
Browse files Browse the repository at this point in the history
…e not static (again)
  • Loading branch information
SzigetiJ committed Dec 11, 2023
1 parent 0dede02 commit 7dd416b
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 71 deletions.
68 changes: 68 additions & 0 deletions src/biguint128.c
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,74 @@ buint_size_t biguint128_export(const BigUInt128 *a, char *dest) {
return BIGUINT128_CELLS * UINT_BYTES;
}

// Auxiliary divisions and multiplications by special numbers
BigUIntTinyPair128 biguint128_div1024(const BigUInt128 *a) {
BigUIntTinyPair128 retv;
retv.first= biguint128_shr(a, 10);
retv.second= (a->dat[0]) & (UInt)0x3FF;
return retv;
}

BigUInt128 biguint128_mul100(const BigUInt128 *a) {
BigUInt128 a6 = biguint128_shl(a,6);
BigUInt128 a5 = biguint128_shl(a,5);
BigUInt128 a2 = biguint128_shl(a,2);
biguint128_add_assign(&a6, &a5);
biguint128_add_assign(&a6, &a2);
return a6;
}

BigUInt128 biguint128_mul1000(const BigUInt128 *a) {
BigUInt128 a10 = biguint128_shl(a,10);
BigUInt128 a4 = biguint128_shl(a,4);
BigUInt128 a3 = biguint128_shl(a,3);
biguint128_sub_assign(&a10, &a4);
biguint128_sub_assign(&a10, &a3);
return a10;
}


BigUIntPair128 biguint128_div1000(const BigUInt128 *a) {
// The procedure goes like this:
// We have to containers (retv.first, retv.second), and at the end
// these will store the quotient and the remainder, respectively.
// Initially, retv.first is empty and retv.second stores the whole amount of a.
// Step-by-step retv.first is increased while retv.second is decreased.
// Note that 1000 * retv.first + retv.second = *a remains invariant
// during the whole process.
// In phase #1 we exploit that
// a = 1024*b + c = (1000*b) + (24*b+c)
// and reduce retv.second iteratively until it gets small enough.
// In phase #2 we just subtract 1000 from the remainder if it is still too high.
// Well, the while loop is an overkill for this limit (2000).
static const BigUInt128 x1000={{0x3E8}};
static const BigUInt128 x2000={{0x7D0}};

BigUIntPair128 retv= {biguint128_ctor_default(), biguint128_ctor_copy(a)};
// Phase 1:
while (biguint128_lt(&x2000, &retv.second)) {
BigUIntTinyPair128 x= biguint128_div1024(&retv.second);
biguint128_add_assign(&retv.first, &x.first);
BigUInt128 d_mul8= biguint128_shl(&x.first, 3);
BigUInt128 d_mul16= biguint128_shl(&x.first, 4);
retv.second = biguint128_add(&d_mul8, &d_mul16);
biguint128_add_tiny(&retv.second, x.second);
}
// Phase 2:
while (!biguint128_lt(&retv.second, &x1000)) {
biguint128_add_tiny(&retv.first, 1);
biguint128_sub_tiny(&retv.second, x1000.dat[0]);
}
return retv;
}

BigUInt128 biguint128_mul10(const BigUInt128 *a) {
BigUInt128 a3 = biguint128_shl(a,3);
BigUInt128 a1 = biguint128_shl(a,1);
biguint128_add_assign(&a3, &a1);
return a3;
}

// cleanup
#undef FOREACHCELL
#undef UINT_BYTES
Expand Down
77 changes: 6 additions & 71 deletions src/biguint128.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,6 @@ typedef struct {
} BigUIntTinyPair128;


static inline BigUIntTinyPair128 biguint128_div1024(const BigUInt128 *a);
static inline BigUIntPair128 biguint128_div1000(const BigUInt128 *a);
static inline BigUInt128 biguint128_mul10(const BigUInt128 *a);
static inline BigUInt128 biguint128_mul100(const BigUInt128 *a);
static inline BigUInt128 biguint128_mul1000(const BigUInt128 *a);


// constructors
/**
@brief Generates BigUInt128 instance initialized to 0.
Expand Down Expand Up @@ -334,7 +327,7 @@ buint_size_t bigint128_print_dec(const BigUInt128 *a, char *buf, buint_size_t bu
*/
buint_size_t biguint128_export(const BigUInt128 *a, char *dest);


// Auxiliary divisions and multiplications by special numbers
/**
* Division by 1000. Definitely faster than biguint128_div().
* The decimal printer function HEX->DEC conversion,
Expand All @@ -345,40 +338,7 @@ buint_size_t biguint128_export(const BigUInt128 *a, char *dest);
* @param a Divident.
* @return Pair of quotient and remainder.
*/
static inline BigUIntPair128 biguint128_div1000(const BigUInt128 *a) {
// The procedure goes like this:
// We have to containers (retv.first, retv.second), and at the end
// these will store the quotient and the remainder, respectively.
// Initially, retv.first is empty and retv.second stores the whole amount of a.
// Step-by-step retv.first is increased while retv.second is decreased.
// Note that 1000 * retv.first + retv.second = *a remains invariant
// during the whole process.
// In phase #1 we exploit that
// a = 1024*b + c = (1000*b) + (24*b+c)
// and reduce retv.second iteratively until it gets small enough.
// In phase #2 we just subtract 1000 from the remainder if it is still too high.
// Well, the while loop is an overkill for this limit (2000).
static const BigUInt128 x1000={{0x3E8}};
static const BigUInt128 x2000={{0x7D0}};

BigUIntPair128 retv= {biguint128_ctor_default(), biguint128_ctor_copy(a)};
// Phase 1:
while (biguint128_lt(&x2000, &retv.second)) {
BigUIntTinyPair128 x= biguint128_div1024(&retv.second);
biguint128_add_assign(&retv.first, &x.first);
BigUInt128 d_mul8= biguint128_shl(&x.first, 3);
BigUInt128 d_mul16= biguint128_shl(&x.first, 4);
retv.second = biguint128_add(&d_mul8, &d_mul16);
biguint128_add_tiny(&retv.second, x.second);
}
// Phase 2:
while (!biguint128_lt(&retv.second, &x1000)) {
biguint128_add_tiny(&retv.first, 1);
biguint128_sub_tiny(&retv.second, x1000.dat[0]);
}
return retv;
}

BigUIntPair128 biguint128_div1000(const BigUInt128 *a);

/**
* Adapts biguint128_div1000 to signed values.
Expand All @@ -388,49 +348,24 @@ BigUIntPair128 bigint128_div1000(const BigUInt128 *a);
/**
* Multiplication by 10 (= 8 + 2).
*/
static inline BigUInt128 biguint128_mul10(const BigUInt128 *a) {
BigUInt128 a3 = biguint128_shl(a,3);
BigUInt128 a1 = biguint128_shl(a,1);
biguint128_add_assign(&a3, &a1);
return a3;
}
BigUInt128 biguint128_mul10(const BigUInt128 *a);

/**
* Division by 1024. Division by 1000 relies on this function.
* @param a Divident.
* @return Pair of quotient and remainder.
*/
static inline BigUIntTinyPair128 biguint128_div1024(const BigUInt128 *a) {
BigUIntTinyPair128 retv;
retv.first= biguint128_shr(a, 10);
retv.second= (a->dat[0]) & (UInt)0x3FF;
return retv;
}
BigUIntTinyPair128 biguint128_div1024(const BigUInt128 *a);

/**
* Multiplication by 100 (= 64 + 32 + 4).
*/
static inline BigUInt128 biguint128_mul100(const BigUInt128 *a) {
BigUInt128 a6 = biguint128_shl(a,6);
BigUInt128 a5 = biguint128_shl(a,5);
BigUInt128 a2 = biguint128_shl(a,2);
biguint128_add_assign(&a6, &a5);
biguint128_add_assign(&a6, &a2);
return a6;
}
BigUInt128 biguint128_mul100(const BigUInt128 *a);

/**
* Multiplication by 1000 (= 1024 - 16 - 8).
*/
static inline BigUInt128 biguint128_mul1000(const BigUInt128 *a) {
BigUInt128 a10 = biguint128_shl(a,10);
BigUInt128 a4 = biguint128_shl(a,4);
BigUInt128 a3 = biguint128_shl(a,3);
biguint128_sub_assign(&a10, &a4);
biguint128_sub_assign(&a10, &a3);
return a10;
}

BigUInt128 biguint128_mul1000(const BigUInt128 *a);

#endif

0 comments on commit 7dd416b

Please sign in to comment.