Skip to content

Commit 9b9f158

Browse files
author
Stefan Krah
authored
bpo-41369 Update to libmpdec-2.5.1: new features (GH-21593)
1 parent 653f420 commit 9b9f158

File tree

2 files changed

+377
-0
lines changed

2 files changed

+377
-0
lines changed

Modules/_decimal/libmpdec/mpdecimal.c

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8656,3 +8656,355 @@ mpd_qimport_u32(mpd_t *result,
86568656
mpd_qresize(result, result->len, status);
86578657
mpd_qfinalize(result, ctx, status);
86588658
}
8659+
8660+
8661+
/******************************************************************************/
8662+
/* From triple */
8663+
/******************************************************************************/
8664+
8665+
#if defined(CONFIG_64) && defined(__SIZEOF_INT128__)
8666+
static mpd_ssize_t
8667+
_set_coeff(uint64_t data[3], uint64_t hi, uint64_t lo)
8668+
{
8669+
__uint128_t d = ((__uint128_t)hi << 64) + lo;
8670+
__uint128_t q, r;
8671+
8672+
q = d / MPD_RADIX;
8673+
r = d % MPD_RADIX;
8674+
data[0] = (uint64_t)r;
8675+
d = q;
8676+
8677+
q = d / MPD_RADIX;
8678+
r = d % MPD_RADIX;
8679+
data[1] = (uint64_t)r;
8680+
d = q;
8681+
8682+
q = d / MPD_RADIX;
8683+
r = d % MPD_RADIX;
8684+
data[2] = (uint64_t)r;
8685+
8686+
if (q != 0) {
8687+
abort(); /* GCOV_NOT_REACHED */
8688+
}
8689+
8690+
return data[2] != 0 ? 3 : (data[1] != 0 ? 2 : 1);
8691+
}
8692+
#else
8693+
static size_t
8694+
_uint_from_u16(mpd_uint_t *w, mpd_ssize_t wlen, const uint16_t *u, size_t ulen)
8695+
{
8696+
const mpd_uint_t ubase = 1U<<16;
8697+
mpd_ssize_t n = 0;
8698+
mpd_uint_t carry;
8699+
8700+
assert(wlen > 0 && ulen > 0);
8701+
8702+
w[n++] = u[--ulen];
8703+
while (--ulen != SIZE_MAX) {
8704+
carry = _mpd_shortmul_c(w, w, n, ubase);
8705+
if (carry) {
8706+
if (n >= wlen) {
8707+
abort(); /* GCOV_NOT_REACHED */
8708+
}
8709+
w[n++] = carry;
8710+
}
8711+
carry = _mpd_shortadd(w, n, u[ulen]);
8712+
if (carry) {
8713+
if (n >= wlen) {
8714+
abort(); /* GCOV_NOT_REACHED */
8715+
}
8716+
w[n++] = carry;
8717+
}
8718+
}
8719+
8720+
return n;
8721+
}
8722+
8723+
static mpd_ssize_t
8724+
_set_coeff(mpd_uint_t *data, mpd_ssize_t len, uint64_t hi, uint64_t lo)
8725+
{
8726+
uint16_t u16[8] = {0};
8727+
8728+
u16[7] = (uint16_t)((hi & 0xFFFF000000000000ULL) >> 48);
8729+
u16[6] = (uint16_t)((hi & 0x0000FFFF00000000ULL) >> 32);
8730+
u16[5] = (uint16_t)((hi & 0x00000000FFFF0000ULL) >> 16);
8731+
u16[4] = (uint16_t) (hi & 0x000000000000FFFFULL);
8732+
8733+
u16[3] = (uint16_t)((lo & 0xFFFF000000000000ULL) >> 48);
8734+
u16[2] = (uint16_t)((lo & 0x0000FFFF00000000ULL) >> 32);
8735+
u16[1] = (uint16_t)((lo & 0x00000000FFFF0000ULL) >> 16);
8736+
u16[0] = (uint16_t) (lo & 0x000000000000FFFFULL);
8737+
8738+
return (mpd_ssize_t)_uint_from_u16(data, len, u16, 8);
8739+
}
8740+
#endif
8741+
8742+
static int
8743+
_set_uint128_coeff_exp(mpd_t *result, uint64_t hi, uint64_t lo, mpd_ssize_t exp)
8744+
{
8745+
mpd_uint_t data[5] = {0};
8746+
uint32_t status = 0;
8747+
mpd_ssize_t len;
8748+
8749+
#if defined(CONFIG_64) && defined(__SIZEOF_INT128__)
8750+
len = _set_coeff(data, hi, lo);
8751+
#else
8752+
len = _set_coeff(data, 5, hi, lo);
8753+
#endif
8754+
8755+
if (!mpd_qresize(result, len, &status)) {
8756+
return -1;
8757+
}
8758+
8759+
for (mpd_ssize_t i = 0; i < len; i++) {
8760+
result->data[i] = data[i];
8761+
}
8762+
8763+
result->exp = exp;
8764+
result->len = len;
8765+
mpd_setdigits(result);
8766+
8767+
return 0;
8768+
}
8769+
8770+
int
8771+
mpd_from_uint128_triple(mpd_t *result, const mpd_uint128_triple_t *triple, uint32_t *status)
8772+
{
8773+
static const mpd_context_t maxcontext = {
8774+
.prec=MPD_MAX_PREC,
8775+
.emax=MPD_MAX_EMAX,
8776+
.emin=MPD_MIN_EMIN,
8777+
.round=MPD_ROUND_HALF_EVEN,
8778+
.traps=MPD_Traps,
8779+
.status=0,
8780+
.newtrap=0,
8781+
.clamp=0,
8782+
.allcr=1,
8783+
};
8784+
const enum mpd_triple_class tag = triple->tag;
8785+
const uint8_t sign = triple->sign;
8786+
const uint64_t hi = triple->hi;
8787+
const uint64_t lo = triple->lo;
8788+
mpd_ssize_t exp;
8789+
8790+
#ifdef CONFIG_32
8791+
if (triple->exp < MPD_SSIZE_MIN || triple->exp > MPD_SSIZE_MAX) {
8792+
goto conversion_error;
8793+
}
8794+
#endif
8795+
exp = (mpd_ssize_t)triple->exp;
8796+
8797+
switch (tag) {
8798+
case MPD_TRIPLE_QNAN: case MPD_TRIPLE_SNAN: {
8799+
if (sign > 1 || exp != 0) {
8800+
goto conversion_error;
8801+
}
8802+
8803+
const uint8_t flags = tag == MPD_TRIPLE_QNAN ? MPD_NAN : MPD_SNAN;
8804+
mpd_setspecial(result, sign, flags);
8805+
8806+
if (hi == 0 && lo == 0) { /* no payload */
8807+
return 0;
8808+
}
8809+
8810+
if (_set_uint128_coeff_exp(result, hi, lo, exp) < 0) {
8811+
goto malloc_error;
8812+
}
8813+
8814+
return 0;
8815+
}
8816+
8817+
case MPD_TRIPLE_INF: {
8818+
if (sign > 1 || hi != 0 || lo != 0 || exp != 0) {
8819+
goto conversion_error;
8820+
}
8821+
8822+
mpd_setspecial(result, sign, MPD_INF);
8823+
8824+
return 0;
8825+
}
8826+
8827+
case MPD_TRIPLE_NORMAL: {
8828+
if (sign > 1) {
8829+
goto conversion_error;
8830+
}
8831+
8832+
const uint8_t flags = sign ? MPD_NEG : MPD_POS;
8833+
mpd_set_flags(result, flags);
8834+
8835+
if (exp > MPD_EXP_INF) {
8836+
exp = MPD_EXP_INF;
8837+
}
8838+
if (exp == MPD_SSIZE_MIN) {
8839+
exp = MPD_SSIZE_MIN+1;
8840+
}
8841+
8842+
if (_set_uint128_coeff_exp(result, hi, lo, exp) < 0) {
8843+
goto malloc_error;
8844+
}
8845+
8846+
uint32_t workstatus = 0;
8847+
mpd_qfinalize(result, &maxcontext, &workstatus);
8848+
if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
8849+
goto conversion_error;
8850+
}
8851+
8852+
return 0;
8853+
}
8854+
8855+
default:
8856+
goto conversion_error;
8857+
}
8858+
8859+
conversion_error:
8860+
mpd_seterror(result, MPD_Conversion_syntax, status);
8861+
return -1;
8862+
8863+
malloc_error:
8864+
mpd_seterror(result, MPD_Malloc_error, status);
8865+
return -1;
8866+
}
8867+
8868+
8869+
/******************************************************************************/
8870+
/* As triple */
8871+
/******************************************************************************/
8872+
8873+
#if defined(CONFIG_64) && defined(__SIZEOF_INT128__)
8874+
static void
8875+
_get_coeff(uint64_t *hi, uint64_t *lo, const mpd_t *a)
8876+
{
8877+
__uint128_t u128 = 0;
8878+
8879+
switch (a->len) {
8880+
case 3:
8881+
u128 = a->data[2]; /* fall through */
8882+
case 2:
8883+
u128 = u128 * MPD_RADIX + a->data[1]; /* fall through */
8884+
case 1:
8885+
u128 = u128 * MPD_RADIX + a->data[0];
8886+
break;
8887+
default:
8888+
abort(); /* GCOV_NOT_REACHED */
8889+
}
8890+
8891+
*hi = u128 >> 64;
8892+
*lo = (uint64_t)u128;
8893+
}
8894+
#else
8895+
static size_t
8896+
_uint_to_u16(uint16_t w[8], mpd_uint_t *u, mpd_ssize_t ulen)
8897+
{
8898+
const mpd_uint_t wbase = 1U<<16;
8899+
size_t n = 0;
8900+
8901+
assert(ulen > 0);
8902+
8903+
do {
8904+
if (n >= 8) {
8905+
abort(); /* GCOV_NOT_REACHED */
8906+
}
8907+
w[n++] = (uint16_t)_mpd_shortdiv(u, u, ulen, wbase);
8908+
/* ulen is at least 1. u[ulen-1] can only be zero if ulen == 1. */
8909+
ulen = _mpd_real_size(u, ulen);
8910+
8911+
} while (u[ulen-1] != 0);
8912+
8913+
return n;
8914+
}
8915+
8916+
static void
8917+
_get_coeff(uint64_t *hi, uint64_t *lo, const mpd_t *a)
8918+
{
8919+
uint16_t u16[8] = {0};
8920+
mpd_uint_t data[5] = {0};
8921+
8922+
switch (a->len) {
8923+
case 5:
8924+
data[4] = a->data[4]; /* fall through */
8925+
case 4:
8926+
data[3] = a->data[3]; /* fall through */
8927+
case 3:
8928+
data[2] = a->data[2]; /* fall through */
8929+
case 2:
8930+
data[1] = a->data[1]; /* fall through */
8931+
case 1:
8932+
data[0] = a->data[0];
8933+
break;
8934+
default:
8935+
abort(); /* GCOV_NOT_REACHED */
8936+
}
8937+
8938+
_uint_to_u16(u16, data, a->len);
8939+
8940+
*hi = (uint64_t)u16[7] << 48;
8941+
*hi |= (uint64_t)u16[6] << 32;
8942+
*hi |= (uint64_t)u16[5] << 16;
8943+
*hi |= (uint64_t)u16[4];
8944+
8945+
*lo = (uint64_t)u16[3] << 48;
8946+
*lo |= (uint64_t)u16[2] << 32;
8947+
*lo |= (uint64_t)u16[1] << 16;
8948+
*lo |= (uint64_t)u16[0];
8949+
}
8950+
#endif
8951+
8952+
static enum mpd_triple_class
8953+
_coeff_as_uint128(uint64_t *hi, uint64_t *lo, const mpd_t *a)
8954+
{
8955+
#ifdef CONFIG_64
8956+
static mpd_uint_t uint128_max_data[3] = { 3374607431768211455ULL, 4028236692093846346ULL, 3ULL };
8957+
static const mpd_t uint128_max = { MPD_STATIC|MPD_CONST_DATA, 0, 39, 3, 3, uint128_max_data };
8958+
#else
8959+
static mpd_uint_t uint128_max_data[5] = { 768211455U, 374607431U, 938463463U, 282366920U, 340U };
8960+
static const mpd_t uint128_max = { MPD_STATIC|MPD_CONST_DATA, 0, 39, 5, 5, uint128_max_data };
8961+
#endif
8962+
enum mpd_triple_class ret = MPD_TRIPLE_NORMAL;
8963+
uint32_t status = 0;
8964+
mpd_t coeff;
8965+
8966+
*hi = *lo = 0ULL;
8967+
8968+
if (mpd_isspecial(a)) {
8969+
if (mpd_isinfinite(a)) {
8970+
return MPD_TRIPLE_INF;
8971+
}
8972+
8973+
ret = mpd_isqnan(a) ? MPD_TRIPLE_QNAN : MPD_TRIPLE_SNAN;
8974+
if (a->len == 0) { /* no payload */
8975+
return ret;
8976+
}
8977+
}
8978+
else if (mpd_iszero(a)) {
8979+
return ret;
8980+
}
8981+
8982+
_mpd_copy_shared(&coeff, a);
8983+
mpd_set_flags(&coeff, 0);
8984+
coeff.exp = 0;
8985+
8986+
if (mpd_qcmp(&coeff, &uint128_max, &status) > 0) {
8987+
return MPD_TRIPLE_ERROR;
8988+
}
8989+
8990+
_get_coeff(hi, lo, &coeff);
8991+
return ret;
8992+
}
8993+
8994+
mpd_uint128_triple_t
8995+
mpd_as_uint128_triple(const mpd_t *a)
8996+
{
8997+
mpd_uint128_triple_t triple = { MPD_TRIPLE_ERROR, 0, 0, 0, 0 };
8998+
8999+
triple.tag = _coeff_as_uint128(&triple.hi, &triple.lo, a);
9000+
if (triple.tag == MPD_TRIPLE_ERROR) {
9001+
return triple;
9002+
}
9003+
9004+
triple.sign = !!mpd_isnegative(a);
9005+
if (triple.tag == MPD_TRIPLE_NORMAL) {
9006+
triple.exp = a->exp;
9007+
}
9008+
9009+
return triple;
9010+
}

Modules/_decimal/libmpdec/mpdecimal.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,31 @@ typedef struct mpd_t {
371371
typedef unsigned char uchar;
372372

373373

374+
/******************************************************************************/
375+
/* Triple */
376+
/******************************************************************************/
377+
378+
/* status cases for getting a triple */
379+
enum mpd_triple_class {
380+
MPD_TRIPLE_NORMAL,
381+
MPD_TRIPLE_INF,
382+
MPD_TRIPLE_QNAN,
383+
MPD_TRIPLE_SNAN,
384+
MPD_TRIPLE_ERROR,
385+
};
386+
387+
typedef struct {
388+
enum mpd_triple_class tag;
389+
uint8_t sign;
390+
uint64_t hi;
391+
uint64_t lo;
392+
int64_t exp;
393+
} mpd_uint128_triple_t;
394+
395+
int mpd_from_uint128_triple(mpd_t *result, const mpd_uint128_triple_t *triple, uint32_t *status);
396+
mpd_uint128_triple_t mpd_as_uint128_triple(const mpd_t *a);
397+
398+
374399
/******************************************************************************/
375400
/* Quiet, thread-safe functions */
376401
/******************************************************************************/

0 commit comments

Comments
 (0)