diff --git a/Lib/decimal.py b/Lib/decimal.py index 96d9df4a8c8..9f37e4fa48e 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -140,6 +140,7 @@ __all__ = [ __version__ = '1.70' # Highest version of the spec this complies with # See http://speleotrove.com/decimal/ +__libmpdec_version__ = "2.4.0" # compatible libmpdec version import copy as _copy import math as _math diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 71b93a661b6..54a3615e9cd 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -4150,6 +4150,7 @@ class CheckAttributes(unittest.TestCase): self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False) self.assertEqual(C.__version__, P.__version__) + self.assertEqual(C.__libmpdec_version__, P.__libmpdec_version__) x = dir(C) y = [s for s in dir(P) if '__' in s or not s.startswith('_')] diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 06c2c395b87..ac20308953a 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -39,6 +39,11 @@ #include "memory.h" +#if MPD_MAJOR_VERSION != 2 + #error "libmpdec major version 2 required" +#endif + + /* * Type sizes with assertions in mpdecimal.h and pyport.h: * sizeof(size_t) == sizeof(Py_ssize_t) @@ -5730,7 +5735,8 @@ PyInit__decimal(void) } /* Add specification version number */ - CHECK_INT(PyModule_AddStringConstant(m, "__version__", " 1.70")); + CHECK_INT(PyModule_AddStringConstant(m, "__version__", "1.70")); + CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version())); return m; diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c index c63a1a08e49..287a77ed302 100644 --- a/Modules/_decimal/libmpdec/mpdecimal.c +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -97,6 +97,8 @@ static void _settriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp); static inline mpd_ssize_t _mpd_real_size(mpd_uint_t *data, mpd_ssize_t size); +static int _mpd_cmp_abs(const mpd_t *a, const mpd_t *b); + static void _mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); static inline void _mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, @@ -110,6 +112,17 @@ static inline void _mpd_qpow_uint(mpd_t *result, const mpd_t *base, static mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n); +/******************************************************************************/ +/* Version */ +/******************************************************************************/ + +const char * +mpd_version(void) +{ + return MPD_VERSION; +} + + /******************************************************************************/ /* Performance critical inline functions */ /******************************************************************************/ @@ -1345,6 +1358,91 @@ mpd_qget_ssize(const mpd_t *a, uint32_t *status) return MPD_SSIZE_MAX; } +#if defined(CONFIG_32) && !defined(LEGACY_COMPILER) +/* + * Quietly get a uint64_t from a decimal. If the operation is impossible, + * MPD_Invalid_operation is set. + */ +static uint64_t +_c32_qget_u64(int use_sign, const mpd_t *a, uint32_t *status) +{ + MPD_NEW_STATIC(tmp,0,0,20,3); + mpd_context_t maxcontext; + uint64_t ret; + + tmp_data[0] = 709551615; + tmp_data[1] = 446744073; + tmp_data[2] = 18; + + if (mpd_isspecial(a)) { + *status |= MPD_Invalid_operation; + return UINT64_MAX; + } + if (mpd_iszero(a)) { + return 0; + } + if (use_sign && mpd_isnegative(a)) { + *status |= MPD_Invalid_operation; + return UINT64_MAX; + } + if (!_mpd_isint(a)) { + *status |= MPD_Invalid_operation; + return UINT64_MAX; + } + + if (_mpd_cmp_abs(a, &tmp) > 0) { + *status |= MPD_Invalid_operation; + return UINT64_MAX; + } + + mpd_maxcontext(&maxcontext); + mpd_qrescale(&tmp, a, 0, &maxcontext, &maxcontext.status); + maxcontext.status &= ~MPD_Rounded; + if (maxcontext.status != 0) { + *status |= (maxcontext.status|MPD_Invalid_operation); /* GCOV_NOT_REACHED */ + return UINT64_MAX; /* GCOV_NOT_REACHED */ + } + + ret = 0; + switch (tmp.len) { + case 3: + ret += (uint64_t)tmp_data[2] * 1000000000000000000ULL; + case 2: + ret += (uint64_t)tmp_data[1] * 1000000000ULL; + case 1: + ret += tmp_data[0]; + break; + default: + abort(); /* GCOV_NOT_REACHED */ + } + + return ret; +} + +static int64_t +_c32_qget_i64(const mpd_t *a, uint32_t *status) +{ + uint64_t u; + int isneg; + + u = _c32_qget_u64(0, a, status); + if (*status&MPD_Invalid_operation) { + return INT64_MAX; + } + + isneg = mpd_isnegative(a); + if (u <= INT64_MAX) { + return isneg ? -((int64_t)u) : (int64_t)u; + } + else if (isneg && u+(INT64_MIN+INT64_MAX) == INT64_MAX) { + return INT64_MIN; + } + + *status |= MPD_Invalid_operation; + return INT64_MAX; +} +#endif /* CONFIG_32 && !LEGACY_COMPILER */ + #ifdef CONFIG_64 /* quietly get a uint64_t from a decimal */ uint64_t @@ -1359,7 +1457,57 @@ mpd_qget_i64(const mpd_t *a, uint32_t *status) { return mpd_qget_ssize(a, status); } + +/* quietly get a uint32_t from a decimal */ +uint32_t +mpd_qget_u32(const mpd_t *a, uint32_t *status) +{ + uint64_t x = mpd_qget_uint(a, status); + + if (*status&MPD_Invalid_operation) { + return UINT32_MAX; + } + if (x > UINT32_MAX) { + *status |= MPD_Invalid_operation; + return UINT32_MAX; + } + + return (uint32_t)x; +} + +/* quietly get an int32_t from a decimal */ +int32_t +mpd_qget_i32(const mpd_t *a, uint32_t *status) +{ + int64_t x = mpd_qget_ssize(a, status); + + if (*status&MPD_Invalid_operation) { + return INT32_MAX; + } + if (x < INT32_MIN || x > INT32_MAX) { + *status |= MPD_Invalid_operation; + return INT32_MAX; + } + + return (int32_t)x; +} #else +#ifndef LEGACY_COMPILER +/* quietly get a uint64_t from a decimal */ +uint64_t +mpd_qget_u64(const mpd_t *a, uint32_t *status) +{ + return _c32_qget_u64(1, a, status); +} + +/* quietly get an int64_t from a decimal */ +int64_t +mpd_qget_i64(const mpd_t *a, uint32_t *status) +{ + return _c32_qget_i64(a, status); +} +#endif + /* quietly get a uint32_t from a decimal */ uint32_t mpd_qget_u32(const mpd_t *a, uint32_t *status) @@ -3386,6 +3534,34 @@ mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, { mpd_qadd_uint(result, a, b, ctx, status); } +#elif !defined(LEGACY_COMPILER) +/* Add decimal and int64_t. */ +void +mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qset_i64(&bb, b, &maxcontext, status); + mpd_qadd(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Add decimal and uint64_t. */ +void +mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qset_u64(&bb, b, &maxcontext, status); + mpd_qadd(result, a, &bb, ctx, status); + mpd_del(&bb); +} #endif /* Subtract int32_t from decimal. */ @@ -3420,6 +3596,34 @@ mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, { mpd_qsub_uint(result, a, b, ctx, status); } +#elif !defined(LEGACY_COMPILER) +/* Subtract int64_t from decimal. */ +void +mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qset_i64(&bb, b, &maxcontext, status); + mpd_qsub(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Subtract uint64_t from decimal. */ +void +mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qset_u64(&bb, b, &maxcontext, status); + mpd_qsub(result, a, &bb, ctx, status); + mpd_del(&bb); +} #endif @@ -3871,6 +4075,34 @@ mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, { mpd_qdiv_uint(result, a, b, ctx, status); } +#elif !defined(LEGACY_COMPILER) +/* Divide decimal by int64_t. */ +void +mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qset_i64(&bb, b, &maxcontext, status); + mpd_qdiv(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Divide decimal by uint64_t. */ +void +mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qset_u64(&bb, b, &maxcontext, status); + mpd_qdiv(result, a, &bb, ctx, status); + mpd_del(&bb); +} #endif /* Pad the result with trailing zeros if it has fewer digits than prec. */ @@ -5664,6 +5896,34 @@ mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, { mpd_qmul_uint(result, a, b, ctx, status); } +#elif !defined(LEGACY_COMPILER) +/* Multiply decimal and int64_t. */ +void +mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qset_i64(&bb, b, &maxcontext, status); + mpd_qmul(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Multiply decimal and uint64_t. */ +void +mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qset_u64(&bb, b, &maxcontext, status); + mpd_qmul(result, a, &bb, ctx, status); + mpd_del(&bb); +} #endif /* Like the minus operator. */ diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h index 06f54708dc5..0f31733cb75 100644 --- a/Modules/_decimal/libmpdec/mpdecimal.h +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -32,7 +32,6 @@ #ifdef __cplusplus extern "C" { -#define __STDC_LIMIT_MACROS #endif @@ -56,12 +55,18 @@ extern "C" { #define MPD_HIDE_SYMBOLS_END #define EXTINLINE extern inline #else - #ifdef HAVE_STDINT_H - #include - #endif #ifdef HAVE_INTTYPES_H #include #endif + #ifdef HAVE_STDINT_H + #if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS) + #define __STDC_LIMIT_MACROS + #include + #undef __STDC_LIMIT_MACROS + #else + #include + #endif + #endif #ifndef __GNUC_STDC_INLINE__ #define __GNUC_STDC_INLINE__ 1 #endif @@ -99,6 +104,19 @@ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) #endif +/******************************************************************************/ +/* Version */ +/******************************************************************************/ + +#define MPD_MAJOR_VERSION 2 +#define MPD_MINOR_VERSION 4 +#define MPD_MICRO_VERSION 0 + +#define MPD_VERSION "2.4.0" + +const char *mpd_version(void); + + /******************************************************************************/ /* Configuration */ /******************************************************************************/ @@ -241,7 +259,7 @@ extern const char *mpd_round_string[MPD_ROUND_GUARD]; extern const char *mpd_clamp_string[MPD_CLAMP_GUARD]; -typedef struct { +typedef struct mpd_context_t { mpd_ssize_t prec; /* precision */ mpd_ssize_t emax; /* max positive exp */ mpd_ssize_t emin; /* min negative exp */ @@ -353,7 +371,7 @@ void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags); #define MPD_DATAFLAGS (MPD_STATIC_DATA|MPD_SHARED_DATA|MPD_CONST_DATA) /* mpd_t */ -typedef struct { +typedef struct mpd_t { uint8_t flags; mpd_ssize_t exp; mpd_ssize_t digits; @@ -371,7 +389,7 @@ typedef unsigned char uchar; /******************************************************************************/ /* format specification */ -typedef struct { +typedef struct mpd_spec_t { mpd_ssize_t min_width; /* minimum field width */ mpd_ssize_t prec; /* fraction digits or significant digits */ char type; /* conversion specifier */ @@ -437,6 +455,12 @@ mpd_ssize_t mpd_qget_ssize(const mpd_t *dec, uint32_t *status); mpd_uint_t mpd_qget_uint(const mpd_t *dec, uint32_t *status); mpd_uint_t mpd_qabs_uint(const mpd_t *dec, uint32_t *status); +int32_t mpd_qget_i32(const mpd_t *dec, uint32_t *status); +uint32_t mpd_qget_u32(const mpd_t *dec, uint32_t *status); +#ifndef LEGACY_COMPILER +int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status); +uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status); +#endif /* quiet functions */ int mpd_qcheck_nan(mpd_t *nanresult, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); @@ -528,6 +552,17 @@ void mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_ void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +#ifndef LEGACY_COMPILER +void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +#endif + size_t mpd_sizeinbase(const mpd_t *a, uint32_t base); void mpd_qimport_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, @@ -571,6 +606,12 @@ void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx); mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx); mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx); +int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx); +uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx); +#ifndef LEGACY_COMPILER +int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx); +uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx); +#endif void mpd_and(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_canonical(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); @@ -641,31 +682,7 @@ void mpd_ceil(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_sqrt(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_invroot(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); - -/******************************************************************************/ -/* Configuration specific */ -/******************************************************************************/ - -#ifdef CONFIG_64 -void mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); -void mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); -int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status); -uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status); - -void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); -void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); -void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); -void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); -void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); -void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); -void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); -void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); - -void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); -void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); -int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx); -uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx); - +#ifndef LEGACY_COMPILER void mpd_add_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); void mpd_add_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); void mpd_sub_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); @@ -674,11 +691,18 @@ void mpd_div_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); void mpd_div_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); void mpd_mul_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); void mpd_mul_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); -#else -int32_t mpd_qget_i32(const mpd_t *dec, uint32_t *status); -uint32_t mpd_qget_u32(const mpd_t *dec, uint32_t *status); -int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx); -uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx); +#endif + + +/******************************************************************************/ +/* Configuration specific */ +/******************************************************************************/ + +#ifdef CONFIG_64 +void mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); +void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); #endif diff --git a/setup.py b/setup.py index 19a7b291e13..906401404df 100644 --- a/setup.py +++ b/setup.py @@ -1945,7 +1945,7 @@ class PyBuildExt(build_ext): undef_macros = [] if '--with-system-libmpdec' in sysconfig.get_config_var("CONFIG_ARGS"): include_dirs = [] - libraries = ['mpdec'] + libraries = [':libmpdec.so.2'] sources = ['_decimal/_decimal.c'] depends = ['_decimal/docstrings.h'] else: