cosmopolitan/third_party/python/Modules/_decimal/libmpdec/mpdecimal.c

7359 lines
214 KiB
C
Raw Normal View History

Undiamond Python headers This change gets the Python codebase into a state where it conforms to the conventions of this codebase. It's now possible to include headers from Python, without worrying about ordering. Python has traditionally solved that problem by "diamonding" everything in Python.h, but that's problematic since it means any change to any Python header invalidates all the build artifacts. Lastly it makes tooling not work. Since it is hard to explain to Emacs when I press C-c C-h to add an import line it shouldn't add the header that actually defines the symbol, and instead do follow the nonstandard Python convention. Progress has been made on letting Python load source code from the zip executable structure via the standard C library APIs. System calss now recognizes zip!FILENAME alternative URIs as equivalent to zip:FILENAME since Python uses colon as its delimiter. Some progress has been made on embedding the notice license terms into the Python object code. This is easier said than done since Python has an extremely complicated ownership story. - Some termios APIs have been added - Implement rewinddir() dirstream API - GetCpuCount() API added to Cosmopolitan Libc - More bugs in Cosmopolitan Libc have been fixed - zipobj.com now has flags for mangling the path - Fixed bug a priori with sendfile() on certain BSDs - Polyfill F_DUPFD and F_DUPFD_CLOEXEC across platforms - FIOCLEX / FIONCLEX now polyfilled for fast O_CLOEXEC changes - APE now supports a hybrid solution to no-self-modify for builds - Many BSD-only magnums added, e.g. O_SEARCH, O_SHLOCK, SF_NODISKIO
2021-08-12 07:42:14 +00:00
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi
Undiamond Python headers This change gets the Python codebase into a state where it conforms to the conventions of this codebase. It's now possible to include headers from Python, without worrying about ordering. Python has traditionally solved that problem by "diamonding" everything in Python.h, but that's problematic since it means any change to any Python header invalidates all the build artifacts. Lastly it makes tooling not work. Since it is hard to explain to Emacs when I press C-c C-h to add an import line it shouldn't add the header that actually defines the symbol, and instead do follow the nonstandard Python convention. Progress has been made on letting Python load source code from the zip executable structure via the standard C library APIs. System calss now recognizes zip!FILENAME alternative URIs as equivalent to zip:FILENAME since Python uses colon as its delimiter. Some progress has been made on embedding the notice license terms into the Python object code. This is easier said than done since Python has an extremely complicated ownership story. - Some termios APIs have been added - Implement rewinddir() dirstream API - GetCpuCount() API added to Cosmopolitan Libc - More bugs in Cosmopolitan Libc have been fixed - zipobj.com now has flags for mangling the path - Fixed bug a priori with sendfile() on certain BSDs - Polyfill F_DUPFD and F_DUPFD_CLOEXEC across platforms - FIOCLEX / FIONCLEX now polyfilled for fast O_CLOEXEC changes - APE now supports a hybrid solution to no-self-modify for builds - Many BSD-only magnums added, e.g. O_SEARCH, O_SHLOCK, SF_NODISKIO
2021-08-12 07:42:14 +00:00
Copyright (c) 2008-2016 Stefan Krah. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/python/Modules/_decimal/libmpdec/mpdecimal.h"
Undiamond Python headers This change gets the Python codebase into a state where it conforms to the conventions of this codebase. It's now possible to include headers from Python, without worrying about ordering. Python has traditionally solved that problem by "diamonding" everything in Python.h, but that's problematic since it means any change to any Python header invalidates all the build artifacts. Lastly it makes tooling not work. Since it is hard to explain to Emacs when I press C-c C-h to add an import line it shouldn't add the header that actually defines the symbol, and instead do follow the nonstandard Python convention. Progress has been made on letting Python load source code from the zip executable structure via the standard C library APIs. System calss now recognizes zip!FILENAME alternative URIs as equivalent to zip:FILENAME since Python uses colon as its delimiter. Some progress has been made on embedding the notice license terms into the Python object code. This is easier said than done since Python has an extremely complicated ownership story. - Some termios APIs have been added - Implement rewinddir() dirstream API - GetCpuCount() API added to Cosmopolitan Libc - More bugs in Cosmopolitan Libc have been fixed - zipobj.com now has flags for mangling the path - Fixed bug a priori with sendfile() on certain BSDs - Polyfill F_DUPFD and F_DUPFD_CLOEXEC across platforms - FIOCLEX / FIONCLEX now polyfilled for fast O_CLOEXEC changes - APE now supports a hybrid solution to no-self-modify for builds - Many BSD-only magnums added, e.g. O_SEARCH, O_SHLOCK, SF_NODISKIO
2021-08-12 07:42:14 +00:00
#include "libc/math.h"
#include "third_party/python/Modules/_decimal/libmpdec/basearith.h"
#include "third_party/python/Modules/_decimal/libmpdec/bits.h"
#include "third_party/python/Modules/_decimal/libmpdec/convolute.h"
#include "third_party/python/Modules/_decimal/libmpdec/crt.h"
#include "third_party/python/Modules/_decimal/libmpdec/mpalloc.h"
#include "third_party/python/Modules/_decimal/libmpdec/typearith.h"
#include "third_party/python/Modules/_decimal/libmpdec/umodarith.h"
Release Cosmopolitan v3.3 This change upgrades to GCC 12.3 and GNU binutils 2.42. The GNU linker appears to have changed things so that only a single de-duplicated str table is present in the binary, and it gets placed wherever the linker wants, regardless of what the linker script says. To cope with that we need to stop using .ident to embed licenses. As such, this change does significant work to revamp how third party licenses are defined in the codebase, using `.section .notice,"aR",@progbits`. This new GCC 12.3 toolchain has support for GNU indirect functions. It lets us support __target_clones__ for the first time. This is used for optimizing the performance of libc string functions such as strlen and friends so far on x86, by ensuring AVX systems favor a second codepath that uses VEX encoding. It shaves some latency off certain operations. It's a useful feature to have for scientific computing for the reasons explained by the test/libcxx/openmp_test.cc example which compiles for fifteen different microarchitectures. Thanks to the upgrades, it's now also possible to use newer instruction sets, such as AVX512FP16, VNNI. Cosmo now uses the %gs register on x86 by default for TLS. Doing it is helpful for any program that links `cosmo_dlopen()`. Such programs had to recompile their binaries at startup to change the TLS instructions. That's not great, since it means every page in the executable needs to be faulted. The work of rewriting TLS-related x86 opcodes, is moved to fixupobj.com instead. This is great news for MacOS x86 users, since we previously needed to morph the binary every time for that platform but now that's no longer necessary. The only platforms where we need fixup of TLS x86 opcodes at runtime are now Windows, OpenBSD, and NetBSD. On Windows we morph TLS to point deeper into the TIB, based on a TlsAlloc assignment, and on OpenBSD/NetBSD we morph %gs back into %fs since the kernels do not allow us to specify a value for the %gs register. OpenBSD users are now required to use APE Loader to run Cosmo binaries and assimilation is no longer possible. OpenBSD kernel needs to change to allow programs to specify a value for the %gs register, or it needs to stop marking executable pages loaded by the kernel as mimmutable(). This release fixes __constructor__, .ctor, .init_array, and lastly the .preinit_array so they behave the exact same way as glibc. We no longer use hex constants to define math.h symbols like M_PI.
2024-02-20 19:12:09 +00:00
__static_yoink("libmpdec_notice");
#define MPD_NEWTONDIV_CUTOFF 1024L
#define MPD_NEW_STATIC(name, flags, exp, digits, len) \
mpd_uint_t name##_data[MPD_MINALLOC_MAX]; \
mpd_t name = {flags|MPD_STATIC|MPD_STATIC_DATA, exp, digits, \
len, MPD_MINALLOC_MAX, name##_data}
#define MPD_NEW_CONST(name, flags, exp, digits, len, alloc, initval) \
mpd_uint_t name##_data[alloc] = {initval}; \
mpd_t name = {flags|MPD_STATIC|MPD_CONST_DATA, exp, digits, \
len, alloc, name##_data}
#define MPD_NEW_SHARED(name, a) \
mpd_t name = {(a->flags&~MPD_DATAFLAGS)|MPD_STATIC|MPD_SHARED_DATA, \
a->exp, a->digits, a->len, a->alloc, a->data}
static mpd_uint_t data_one[1] = {1};
static mpd_uint_t data_zero[1] = {0};
static const mpd_t one = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_one};
static const mpd_t minus_one = {MPD_NEG|MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1,
data_one};
static const mpd_t zero = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_zero};
static inline void _mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx,
uint32_t *status);
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,
const mpd_context_t *ctx, uint32_t *status);
static void _mpd_base_ndivmod(mpd_t *q, mpd_t *r, const mpd_t *a,
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
const mpd_t *, uint32_t *);
static inline void _mpd_qpow_uint(mpd_t *, const mpd_t *,
mpd_uint_t , uint8_t,
const mpd_context_t *, uint32_t *);
static mpd_uint_t mpd_qsshiftr(mpd_t *, const mpd_t *, mpd_ssize_t);
/******************************************************************************/
/* Version */
/******************************************************************************/
const char *
mpd_version(void)
{
return MPD_VERSION;
}
/******************************************************************************/
/* Performance critical inline functions */
/******************************************************************************/
/* Digits in a word, primarily useful for the most significant word. */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_word_digits(mpd_uint_t word)
{
if (word < mpd_pow10[9]) {
if (word < mpd_pow10[4]) {
if (word < mpd_pow10[2]) {
return (word < mpd_pow10[1]) ? 1 : 2;
}
return (word < mpd_pow10[3]) ? 3 : 4;
}
if (word < mpd_pow10[6]) {
return (word < mpd_pow10[5]) ? 5 : 6;
}
if (word < mpd_pow10[8]) {
return (word < mpd_pow10[7]) ? 7 : 8;
}
return 9;
}
if (word < mpd_pow10[14]) {
if (word < mpd_pow10[11]) {
return (word < mpd_pow10[10]) ? 10 : 11;
}
if (word < mpd_pow10[13]) {
return (word < mpd_pow10[12]) ? 12 : 13;
}
return 14;
}
if (word < mpd_pow10[18]) {
if (word < mpd_pow10[16]) {
return (word < mpd_pow10[15]) ? 15 : 16;
}
return (word < mpd_pow10[17]) ? 17 : 18;
}
return (word < mpd_pow10[19]) ? 19 : 20;
}
/* Adjusted exponent */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) mpd_ssize_t
mpd_adjexp(const mpd_t *dec)
{
return (dec->exp + dec->digits) - 1;
}
/* Etiny */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) mpd_ssize_t
mpd_etiny(const mpd_context_t *ctx)
{
return ctx->emin - (ctx->prec - 1);
}
/* Etop: used for folding down in IEEE clamping */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) mpd_ssize_t
mpd_etop(const mpd_context_t *ctx)
{
return ctx->emax - (ctx->prec - 1);
}
/* Most significant word */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) mpd_uint_t
mpd_msword(const mpd_t *dec)
{
assert(dec->len > 0);
return dec->data[dec->len-1];
}
/* Most significant digit of a word */
inline mpd_uint_t
mpd_msd(mpd_uint_t word)
{
int n;
n = mpd_word_digits(word);
return word / mpd_pow10[n-1];
}
/* Least significant digit of a word */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) mpd_uint_t
mpd_lsd(mpd_uint_t word)
{
return word % 10;
}
/* Coefficient size needed to store 'digits' */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) mpd_ssize_t
mpd_digits_to_size(mpd_ssize_t digits)
{
mpd_ssize_t q, r;
_mpd_idiv_word(&q, &r, digits, MPD_RDIGITS);
return (r == 0) ? q : q+1;
}
/* Number of digits in the exponent. Not defined for MPD_SSIZE_MIN. */
inline int
mpd_exp_digits(mpd_ssize_t exp)
{
exp = (exp < 0) ? -exp : exp;
return mpd_word_digits(exp);
}
/* Canonical */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_iscanonical(const mpd_t *dec)
{
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
(void)dec;
return 1;
}
/* Finite */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isfinite(const mpd_t *dec)
{
return !(dec->flags & MPD_SPECIAL);
}
/* Infinite */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isinfinite(const mpd_t *dec)
{
return dec->flags & MPD_INF;
}
/* NaN */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isnan(const mpd_t *dec)
{
return dec->flags & (MPD_NAN|MPD_SNAN);
}
/* Negative */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isnegative(const mpd_t *dec)
{
return dec->flags & MPD_NEG;
}
/* Positive */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_ispositive(const mpd_t *dec)
{
return !(dec->flags & MPD_NEG);
}
/* qNaN */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isqnan(const mpd_t *dec)
{
return dec->flags & MPD_NAN;
}
/* Signed */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_issigned(const mpd_t *dec)
{
return dec->flags & MPD_NEG;
}
/* sNaN */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_issnan(const mpd_t *dec)
{
return dec->flags & MPD_SNAN;
}
/* Special */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isspecial(const mpd_t *dec)
{
return dec->flags & MPD_SPECIAL;
}
/* Zero */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_iszero(const mpd_t *dec)
{
return !mpd_isspecial(dec) && mpd_msword(dec) == 0;
}
/* Test for zero when specials have been ruled out already */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_iszerocoeff(const mpd_t *dec)
{
return mpd_msword(dec) == 0;
}
/* Normal */
inline int
mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx)
{
if (mpd_isspecial(dec)) return 0;
if (mpd_iszerocoeff(dec)) return 0;
return mpd_adjexp(dec) >= ctx->emin;
}
/* Subnormal */
inline int
mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx)
{
if (mpd_isspecial(dec)) return 0;
if (mpd_iszerocoeff(dec)) return 0;
return mpd_adjexp(dec) < ctx->emin;
}
/* Odd word */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isoddword(mpd_uint_t word)
{
return word & 1;
}
/* Odd coefficient */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isoddcoeff(const mpd_t *dec)
{
return mpd_isoddword(dec->data[0]);
}
/* 0 if dec is positive, 1 if dec is negative */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) uint8_t
mpd_sign(const mpd_t *dec)
{
return dec->flags & MPD_NEG;
}
/* 1 if dec is positive, -1 if dec is negative */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_arith_sign(const mpd_t *dec)
{
return 1 - 2 * mpd_isnegative(dec);
}
/* Radix */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) long
mpd_radix(void)
{
return 10;
}
/* Dynamic decimal */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isdynamic(const mpd_t *dec)
{
return !(dec->flags & MPD_STATIC);
}
/* Static decimal */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isstatic(const mpd_t *dec)
{
return dec->flags & MPD_STATIC;
}
/* Data of decimal is dynamic */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isdynamic_data(const mpd_t *dec)
{
return !(dec->flags & MPD_DATAFLAGS);
}
/* Data of decimal is static */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isstatic_data(const mpd_t *dec)
{
return dec->flags & MPD_STATIC_DATA;
}
/* Data of decimal is shared */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isshared_data(const mpd_t *dec)
{
return dec->flags & MPD_SHARED_DATA;
}
/* Data of decimal is const */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_isconst_data(const mpd_t *dec)
{
return dec->flags & MPD_CONST_DATA;
}
/******************************************************************************/
/* Inline memory handling */
/******************************************************************************/
/* Fill destination with zeros */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len)
{
mpd_size_t i;
for (i = 0; i < len; i++) {
dest[i] = 0;
}
}
/* Free a decimal */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_del(mpd_t *dec)
{
if (mpd_isdynamic_data(dec)) {
mpd_free(dec->data);
}
if (mpd_isdynamic(dec)) {
mpd_free(dec);
}
}
/*
* Resize the coefficient. Existing data up to 'nwords' is left untouched.
* Return 1 on success, 0 otherwise.
*
* Input invariant: MPD_MINALLOC <= result->alloc.
*
* Case nwords == result->alloc:
* 'result' is unchanged. Return 1.
*
* Case nwords > result->alloc:
* Case realloc success:
* The value of 'result' does not change. Return 1.
* Case realloc failure:
* 'result' is NaN, status is updated with MPD_Malloc_error. Return 0.
*
* Case nwords < result->alloc:
* Case is_static_data or realloc failure [1]:
* 'result' is unchanged. Return 1.
* Case realloc success:
* The value of result is undefined (expected). Return 1.
*
*
* [1] In that case the old (now oversized) area is still valid.
*/
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_qresize(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
{
assert(!mpd_isconst_data(result)); /* illegal operation for a const */
assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
assert(MPD_MINALLOC <= result->alloc);
nwords = (nwords <= MPD_MINALLOC) ? MPD_MINALLOC : nwords;
if (nwords == result->alloc) {
return 1;
}
if (mpd_isstatic_data(result)) {
if (nwords > result->alloc) {
return mpd_switch_to_dyn(result, nwords, status);
}
return 1;
}
return mpd_realloc_dyn(result, nwords, status);
}
/* Same as mpd_qresize, but the complete coefficient (including the old
* memory area!) is initialized to zero. */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) int
mpd_qresize_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
{
assert(!mpd_isconst_data(result)); /* illegal operation for a const */
assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
assert(MPD_MINALLOC <= result->alloc);
nwords = (nwords <= MPD_MINALLOC) ? MPD_MINALLOC : nwords;
if (nwords != result->alloc) {
if (mpd_isstatic_data(result)) {
if (nwords > result->alloc) {
return mpd_switch_to_dyn_zero(result, nwords, status);
}
}
else if (!mpd_realloc_dyn(result, nwords, status)) {
return 0;
}
}
mpd_uint_zero(result->data, nwords);
return 1;
}
/*
* Reduce memory size for the coefficient to MPD_MINALLOC. In theory,
* realloc may fail even when reducing the memory size. But in that case
* the old memory area is always big enough, so checking for MPD_Malloc_error
* is not imperative.
*/
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_minalloc(mpd_t *result)
{
assert(!mpd_isconst_data(result)); /* illegal operation for a const */
assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
if (!mpd_isstatic_data(result) && result->alloc > MPD_MINALLOC) {
uint8_t err = 0;
result->data = mpd_realloc(result->data, MPD_MINALLOC,
sizeof *result->data, &err);
if (!err) {
result->alloc = MPD_MINALLOC;
}
}
}
int
mpd_resize(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx)
{
uint32_t status = 0;
if (!mpd_qresize(result, nwords, &status)) {
mpd_addstatus_raise(ctx, status);
return 0;
}
return 1;
}
int
mpd_resize_zero(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx)
{
uint32_t status = 0;
if (!mpd_qresize_zero(result, nwords, &status)) {
mpd_addstatus_raise(ctx, status);
return 0;
}
return 1;
}
/******************************************************************************/
/* Set attributes of a decimal */
/******************************************************************************/
/* Set digits. Assumption: result->len is initialized and > 0. */
inline void
mpd_setdigits(mpd_t *result)
{
mpd_ssize_t wdigits = mpd_word_digits(mpd_msword(result));
result->digits = wdigits + (result->len-1) * MPD_RDIGITS;
}
/* Set sign */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_sign(mpd_t *result, uint8_t sign)
{
result->flags &= ~MPD_NEG;
result->flags |= sign;
}
/* Copy sign from another decimal */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_signcpy(mpd_t *result, const mpd_t *a)
{
uint8_t sign = a->flags&MPD_NEG;
result->flags &= ~MPD_NEG;
result->flags |= sign;
}
/* Set infinity */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_infinity(mpd_t *result)
{
result->flags &= ~MPD_SPECIAL;
result->flags |= MPD_INF;
}
/* Set qNaN */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_qnan(mpd_t *result)
{
result->flags &= ~MPD_SPECIAL;
result->flags |= MPD_NAN;
}
/* Set sNaN */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_snan(mpd_t *result)
{
result->flags &= ~MPD_SPECIAL;
result->flags |= MPD_SNAN;
}
/* Set to negative */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_negative(mpd_t *result)
{
result->flags |= MPD_NEG;
}
/* Set to positive */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_positive(mpd_t *result)
{
result->flags &= ~MPD_NEG;
}
/* Set to dynamic */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_dynamic(mpd_t *result)
{
result->flags &= ~MPD_STATIC;
}
/* Set to static */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_static(mpd_t *result)
{
result->flags |= MPD_STATIC;
}
/* Set data to dynamic */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_dynamic_data(mpd_t *result)
{
result->flags &= ~MPD_DATAFLAGS;
}
/* Set data to static */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_static_data(mpd_t *result)
{
result->flags &= ~MPD_DATAFLAGS;
result->flags |= MPD_STATIC_DATA;
}
/* Set data to shared */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_shared_data(mpd_t *result)
{
result->flags &= ~MPD_DATAFLAGS;
result->flags |= MPD_SHARED_DATA;
}
/* Set data to const */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_const_data(mpd_t *result)
{
result->flags &= ~MPD_DATAFLAGS;
result->flags |= MPD_CONST_DATA;
}
/* Clear flags, preserving memory attributes. */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_clear_flags(mpd_t *result)
{
result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
}
/* Set flags, preserving memory attributes. */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_set_flags(mpd_t *result, uint8_t flags)
{
result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
result->flags |= flags;
}
/* Copy flags, preserving memory attributes of result. */
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
__inline __attribute__((__always_inline__)) void
mpd_copy_flags(mpd_t *result, const mpd_t *a)
{
uint8_t aflags = a->flags;
result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
result->flags |= (aflags & ~(MPD_STATIC|MPD_DATAFLAGS));
}
/* Initialize a workcontext from ctx. Set traps, flags and newtrap to 0. */
static inline void
mpd_workcontext(mpd_context_t *workctx, const mpd_context_t *ctx)
{
workctx->prec = ctx->prec;
workctx->emax = ctx->emax;
workctx->emin = ctx->emin;
workctx->round = ctx->round;
workctx->traps = 0;
workctx->status = 0;
workctx->newtrap = 0;
workctx->clamp = ctx->clamp;
workctx->allcr = ctx->allcr;
}
/******************************************************************************/
/* Getting and setting parts of decimals */
/******************************************************************************/
/* Flip the sign of a decimal */
static inline void
_mpd_negate(mpd_t *dec)
{
dec->flags ^= MPD_NEG;
}
/* Set coefficient to zero */
void
mpd_zerocoeff(mpd_t *result)
{
mpd_minalloc(result);
result->digits = 1;
result->len = 1;
result->data[0] = 0;
}
/* Set the coefficient to all nines. */
void
mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status)
{
mpd_ssize_t len, r;
_mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS);
len = (r == 0) ? len : len+1;
if (!mpd_qresize(result, len, status)) {
return;
}
result->len = len;
result->digits = ctx->prec;
--len;
if (r > 0) {
result->data[len--] = mpd_pow10[r]-1;
}
for (; len >= 0; --len) {
result->data[len] = MPD_RADIX-1;
}
}
/*
* Cut off the most significant digits so that the rest fits in ctx->prec.
* Cannot fail.
*/
static void
_mpd_cap(mpd_t *result, const mpd_context_t *ctx)
{
uint32_t dummy;
mpd_ssize_t len, r;
if (result->len > 0 && result->digits > ctx->prec) {
_mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS);
len = (r == 0) ? len : len+1;
if (r != 0) {
result->data[len-1] %= mpd_pow10[r];
}
len = _mpd_real_size(result->data, len);
/* resize to fewer words cannot fail */
mpd_qresize(result, len, &dummy);
result->len = len;
mpd_setdigits(result);
}
if (mpd_iszero(result)) {
_settriple(result, mpd_sign(result), 0, result->exp);
}
}
/*
* Cut off the most significant digits of a NaN payload so that the rest
* fits in ctx->prec - ctx->clamp. Cannot fail.
*/
static void
_mpd_fix_nan(mpd_t *result, const mpd_context_t *ctx)
{
uint32_t dummy;
mpd_ssize_t prec;
mpd_ssize_t len, r;
prec = ctx->prec - ctx->clamp;
if (result->len > 0 && result->digits > prec) {
if (prec == 0) {
mpd_minalloc(result);
result->len = result->digits = 0;
}
else {
_mpd_idiv_word(&len, &r, prec, MPD_RDIGITS);
len = (r == 0) ? len : len+1;
if (r != 0) {
result->data[len-1] %= mpd_pow10[r];
}
len = _mpd_real_size(result->data, len);
/* resize to fewer words cannot fail */
mpd_qresize(result, len, &dummy);
result->len = len;
mpd_setdigits(result);
if (mpd_iszerocoeff(result)) {
/* NaN0 is not a valid representation */
result->len = result->digits = 0;
}
}
}
}
/*
* Get n most significant digits from a decimal, where 0 < n <= MPD_UINT_DIGITS.
* Assumes MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for 32 and 64 bit
* machines.
*
* The result of the operation will be in lo. If the operation is impossible,
* hi will be nonzero. This is used to indicate an error.
*/
static inline void
_mpd_get_msdigits(mpd_uint_t *hi, mpd_uint_t *lo, const mpd_t *dec,
unsigned int n)
{
mpd_uint_t r, tmp;
assert(0 < n && n <= MPD_RDIGITS+1);
_mpd_div_word(&tmp, &r, dec->digits, MPD_RDIGITS);
r = (r == 0) ? MPD_RDIGITS : r; /* digits in the most significant word */
*hi = 0;
*lo = dec->data[dec->len-1];
if (n <= r) {
*lo /= mpd_pow10[r-n];
}
else if (dec->len > 1) {
/* at this point 1 <= r < n <= MPD_RDIGITS+1 */
_mpd_mul_words(hi, lo, *lo, mpd_pow10[n-r]);
tmp = dec->data[dec->len-2] / mpd_pow10[MPD_RDIGITS-(n-r)];
*lo = *lo + tmp;
if (*lo < tmp) (*hi)++;
}
}
/******************************************************************************/
/* Gathering information about a decimal */
/******************************************************************************/
/* The real size of the coefficient without leading zero words. */
static inline mpd_ssize_t
_mpd_real_size(mpd_uint_t *data, mpd_ssize_t size)
{
while (size > 1 && data[size-1] == 0) {
size--;
}
return size;
}
/* Return number of trailing zeros. No errors are possible. */
mpd_ssize_t
mpd_trail_zeros(const mpd_t *dec)
{
mpd_uint_t word;
mpd_ssize_t i, tz = 0;
for (i=0; i < dec->len; ++i) {
if (dec->data[i] != 0) {
word = dec->data[i];
tz = i * MPD_RDIGITS;
while (word % 10 == 0) {
word /= 10;
tz++;
}
break;
}
}
return tz;
}
/* Integer: Undefined for specials */
static int
_mpd_isint(const mpd_t *dec)
{
mpd_ssize_t tz;
if (mpd_iszerocoeff(dec)) {
return 1;
}
tz = mpd_trail_zeros(dec);
return (dec->exp + tz >= 0);
}
/* Integer */
int
mpd_isinteger(const mpd_t *dec)
{
if (mpd_isspecial(dec)) {
return 0;
}
return _mpd_isint(dec);
}
/* Word is a power of 10 */
static int
mpd_word_ispow10(mpd_uint_t word)
{
int n;
n = mpd_word_digits(word);
if (word == mpd_pow10[n-1]) {
return 1;
}
return 0;
}
/* Coefficient is a power of 10 */
static int
mpd_coeff_ispow10(const mpd_t *dec)
{
if (mpd_word_ispow10(mpd_msword(dec))) {
if (_mpd_isallzero(dec->data, dec->len-1)) {
return 1;
}
}
return 0;
}
/* All digits of a word are nines */
static int
mpd_word_isallnine(mpd_uint_t word)
{
int n;
n = mpd_word_digits(word);
if (word == mpd_pow10[n]-1) {
return 1;
}
return 0;
}
/* All digits of the coefficient are nines */
static int
mpd_coeff_isallnine(const mpd_t *dec)
{
if (mpd_word_isallnine(mpd_msword(dec))) {
if (_mpd_isallnine(dec->data, dec->len-1)) {
return 1;
}
}
return 0;
}
/* Odd decimal: Undefined for non-integers! */
int
mpd_isodd(const mpd_t *dec)
{
mpd_uint_t q, r;
assert(mpd_isinteger(dec));
if (mpd_iszerocoeff(dec)) return 0;
if (dec->exp < 0) {
_mpd_div_word(&q, &r, -dec->exp, MPD_RDIGITS);
q = dec->data[q] / mpd_pow10[r];
return mpd_isoddword(q);
}
return dec->exp == 0 && mpd_isoddword(dec->data[0]);
}
/* Even: Undefined for non-integers! */
int
mpd_iseven(const mpd_t *dec)
{
return !mpd_isodd(dec);
}
/******************************************************************************/
/* Getting and setting decimals */
/******************************************************************************/
/* Internal function: Set a static decimal from a triple, no error checking. */
static void
_ssettriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp)
{
mpd_set_flags(result, sign);
result->exp = exp;
_mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX);
result->len = (result->data[1] == 0) ? 1 : 2;
mpd_setdigits(result);
}
/* Internal function: Set a decimal from a triple, no error checking. */
static void
_settriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp)
{
mpd_minalloc(result);
mpd_set_flags(result, sign);
result->exp = exp;
_mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX);
result->len = (result->data[1] == 0) ? 1 : 2;
mpd_setdigits(result);
}
/* Set a special number from a triple */
void
mpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type)
{
mpd_minalloc(result);
result->flags &= ~(MPD_NEG|MPD_SPECIAL);
result->flags |= (sign|type);
result->exp = result->digits = result->len = 0;
}
/* Set result of NaN with an error status */
void
mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status)
{
mpd_minalloc(result);
mpd_set_qnan(result);
mpd_set_positive(result);
result->exp = result->digits = result->len = 0;
*status |= flags;
}
/* quietly set a static decimal from an mpd_ssize_t */
void
mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_uint_t u;
uint8_t sign = MPD_POS;
if (a < 0) {
if (a == MPD_SSIZE_MIN) {
u = (mpd_uint_t)MPD_SSIZE_MAX +
(-(MPD_SSIZE_MIN+MPD_SSIZE_MAX));
}
else {
u = -a;
}
sign = MPD_NEG;
}
else {
u = a;
}
_ssettriple(result, sign, u, 0);
mpd_qfinalize(result, ctx, status);
}
/* quietly set a static decimal from an mpd_uint_t */
void
mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx,
uint32_t *status)
{
_ssettriple(result, MPD_POS, a, 0);
mpd_qfinalize(result, ctx, status);
}
/* quietly set a static decimal from an int32_t */
void
mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_qsset_ssize(result, a, ctx, status);
}
/* quietly set a static decimal from a uint32_t */
void
mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_qsset_uint(result, a, ctx, status);
}
/* quietly set a static decimal from an int64_t */
void
mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_qsset_ssize(result, a, ctx, status);
}
/* quietly set a static decimal from a uint64_t */
void
mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_qsset_uint(result, a, ctx, status);
}
/* quietly set a decimal from an mpd_ssize_t */
void
mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_minalloc(result);
mpd_qsset_ssize(result, a, ctx, status);
}
/* quietly set a decimal from an mpd_uint_t */
void
mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx,
uint32_t *status)
{
_settriple(result, MPD_POS, a, 0);
mpd_qfinalize(result, ctx, status);
}
/* quietly set a decimal from an int32_t */
void
mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_qset_ssize(result, a, ctx, status);
}
/* quietly set a decimal from a uint32_t */
void
mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_qset_uint(result, a, ctx, status);
}
/* quietly set a decimal from an int64_t */
void
mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_qset_ssize(result, a, ctx, status);
}
/* quietly set a decimal from a uint64_t */
void
mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_qset_uint(result, a, ctx, status);
}
/*
* Quietly get an mpd_uint_t from a decimal. Assumes
* MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for
* 32 and 64 bit machines.
*
* If the operation is impossible, MPD_Invalid_operation is set.
*/
static mpd_uint_t
_mpd_qget_uint(int use_sign, const mpd_t *a, uint32_t *status)
{
mpd_t tmp;
mpd_uint_t tmp_data[2];
mpd_uint_t lo, hi;
if (mpd_isspecial(a)) {
*status |= MPD_Invalid_operation;
return MPD_UINT_MAX;
}
if (mpd_iszero(a)) {
return 0;
}
if (use_sign && mpd_isnegative(a)) {
*status |= MPD_Invalid_operation;
return MPD_UINT_MAX;
}
if (a->digits+a->exp > MPD_RDIGITS+1) {
*status |= MPD_Invalid_operation;
return MPD_UINT_MAX;
}
if (a->exp < 0) {
if (!_mpd_isint(a)) {
*status |= MPD_Invalid_operation;
return MPD_UINT_MAX;
}
/* At this point a->digits+a->exp <= MPD_RDIGITS+1,
* so the shift fits. */
tmp.data = tmp_data;
tmp.flags = MPD_STATIC|MPD_STATIC_DATA;
tmp.alloc = 2;
mpd_qsshiftr(&tmp, a, -a->exp);
tmp.exp = 0;
a = &tmp;
}
_mpd_get_msdigits(&hi, &lo, a, MPD_RDIGITS+1);
if (hi) {
*status |= MPD_Invalid_operation;
return MPD_UINT_MAX;
}
if (a->exp > 0) {
_mpd_mul_words(&hi, &lo, lo, mpd_pow10[a->exp]);
if (hi) {
*status |= MPD_Invalid_operation;
return MPD_UINT_MAX;
}
}
return lo;
}
/*
* Sets Invalid_operation for:
* - specials
* - negative numbers (except negative zero)
* - non-integers
* - overflow
*/
mpd_uint_t
mpd_qget_uint(const mpd_t *a, uint32_t *status)
{
return _mpd_qget_uint(1, a, status);
}
/* Same as above, but gets the absolute value, i.e. the sign is ignored. */
mpd_uint_t
mpd_qabs_uint(const mpd_t *a, uint32_t *status)
{
return _mpd_qget_uint(0, a, status);
}
/* quietly get an mpd_ssize_t from a decimal */
mpd_ssize_t
mpd_qget_ssize(const mpd_t *a, uint32_t *status)
{
mpd_uint_t u;
int isneg;
u = mpd_qabs_uint(a, status);
if (*status&MPD_Invalid_operation) {
return MPD_SSIZE_MAX;
}
isneg = mpd_isnegative(a);
if (u <= MPD_SSIZE_MAX) {
return isneg ? -((mpd_ssize_t)u) : (mpd_ssize_t)u;
}
else if (isneg && u+(MPD_SSIZE_MIN+MPD_SSIZE_MAX) == MPD_SSIZE_MAX) {
return MPD_SSIZE_MIN;
}
*status |= MPD_Invalid_operation;
return MPD_SSIZE_MAX;
}
/* quietly get a uint64_t from a decimal */
uint64_t
mpd_qget_u64(const mpd_t *a, uint32_t *status)
{
return mpd_qget_uint(a, status);
}
/* quietly get an int64_t from a decimal */
int64_t
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;
}
/******************************************************************************/
/* Filtering input of functions, finalizing output of functions */
/******************************************************************************/
/*
* Check if the operand is NaN, copy to result and return 1 if this is
* the case. Copying can fail since NaNs are allowed to have a payload that
* does not fit in MPD_MINALLOC.
*/
int
mpd_qcheck_nan(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
if (mpd_isnan(a)) {
*status |= mpd_issnan(a) ? MPD_Invalid_operation : 0;
mpd_qcopy(result, a, status);
mpd_set_qnan(result);
_mpd_fix_nan(result, ctx);
return 1;
}
return 0;
}
/*
* Check if either operand is NaN, copy to result and return 1 if this
* is the case. Copying can fail since NaNs are allowed to have a payload
* that does not fit in MPD_MINALLOC.
*/
int
mpd_qcheck_nans(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
if ((a->flags|b->flags)&(MPD_NAN|MPD_SNAN)) {
const mpd_t *choice = b;
if (mpd_issnan(a)) {
choice = a;
*status |= MPD_Invalid_operation;
}
else if (mpd_issnan(b)) {
*status |= MPD_Invalid_operation;
}
else if (mpd_isqnan(a)) {
choice = a;
}
mpd_qcopy(result, choice, status);
mpd_set_qnan(result);
_mpd_fix_nan(result, ctx);
return 1;
}
return 0;
}
/*
* Check if one of the operands is NaN, copy to result and return 1 if this
* is the case. Copying can fail since NaNs are allowed to have a payload
* that does not fit in MPD_MINALLOC.
*/
static int
mpd_qcheck_3nans(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c,
const mpd_context_t *ctx, uint32_t *status)
{
if ((a->flags|b->flags|c->flags)&(MPD_NAN|MPD_SNAN)) {
const mpd_t *choice = c;
if (mpd_issnan(a)) {
choice = a;
*status |= MPD_Invalid_operation;
}
else if (mpd_issnan(b)) {
choice = b;
*status |= MPD_Invalid_operation;
}
else if (mpd_issnan(c)) {
*status |= MPD_Invalid_operation;
}
else if (mpd_isqnan(a)) {
choice = a;
}
else if (mpd_isqnan(b)) {
choice = b;
}
mpd_qcopy(result, choice, status);
mpd_set_qnan(result);
_mpd_fix_nan(result, ctx);
return 1;
}
return 0;
}
/* Check if rounding digit 'rnd' leads to an increment. */
static inline int
_mpd_rnd_incr(const mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx)
{
int ld;
switch (ctx->round) {
case MPD_ROUND_DOWN: case MPD_ROUND_TRUNC:
return 0;
case MPD_ROUND_HALF_UP:
return (rnd >= 5);
case MPD_ROUND_HALF_EVEN:
return (rnd > 5) || ((rnd == 5) && mpd_isoddcoeff(dec));
case MPD_ROUND_CEILING:
return !(rnd == 0 || mpd_isnegative(dec));
case MPD_ROUND_FLOOR:
return !(rnd == 0 || mpd_ispositive(dec));
case MPD_ROUND_HALF_DOWN:
return (rnd > 5);
case MPD_ROUND_UP:
return !(rnd == 0);
case MPD_ROUND_05UP:
ld = (int)mpd_lsd(dec->data[0]);
return (!(rnd == 0) && (ld == 0 || ld == 5));
default:
/* Without a valid context, further results will be undefined. */
return 0; /* GCOV_NOT_REACHED */
}
}
/*
* Apply rounding to a decimal that has been right-shifted into a full
* precision decimal. If an increment leads to an overflow of the precision,
* adjust the coefficient and the exponent and check the new exponent for
* overflow.
*/
static inline void
_mpd_apply_round(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
uint32_t *status)
{
if (_mpd_rnd_incr(dec, rnd, ctx)) {
/* We have a number with exactly ctx->prec digits. The increment
* can only lead to an overflow if the decimal is all nines. In
* that case, the result is a power of ten with prec+1 digits.
*
* If the precision is a multiple of MPD_RDIGITS, this situation is
* detected by _mpd_baseincr returning a carry.
* If the precision is not a multiple of MPD_RDIGITS, we have to
* check if the result has one digit too many.
*/
mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
if (carry) {
dec->data[dec->len-1] = mpd_pow10[MPD_RDIGITS-1];
dec->exp += 1;
_mpd_check_exp(dec, ctx, status);
return;
}
mpd_setdigits(dec);
if (dec->digits > ctx->prec) {
mpd_qshiftr_inplace(dec, 1);
dec->exp += 1;
dec->digits = ctx->prec;
_mpd_check_exp(dec, ctx, status);
}
}
}
/*
* Apply rounding to a decimal. Allow overflow of the precision.
*/
static inline void
_mpd_apply_round_excess(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
uint32_t *status)
{
if (_mpd_rnd_incr(dec, rnd, ctx)) {
mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
if (carry) {
if (!mpd_qresize(dec, dec->len+1, status)) {
return;
}
dec->data[dec->len] = 1;
dec->len += 1;
}
mpd_setdigits(dec);
}
}
/*
* Apply rounding to a decimal that has been right-shifted into a decimal
* with full precision or less. Return failure if an increment would
* overflow the precision.
*/
static inline int
_mpd_apply_round_fit(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
uint32_t *status)
{
if (_mpd_rnd_incr(dec, rnd, ctx)) {
mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
if (carry) {
if (!mpd_qresize(dec, dec->len+1, status)) {
return 0;
}
dec->data[dec->len] = 1;
dec->len += 1;
}
mpd_setdigits(dec);
if (dec->digits > ctx->prec) {
mpd_seterror(dec, MPD_Invalid_operation, status);
return 0;
}
}
return 1;
}
/* Check a normal number for overflow, underflow, clamping. If the operand
is modified, it will be zero, special or (sub)normal with a coefficient
that fits into the current context precision. */
static inline void
_mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
{
mpd_ssize_t adjexp, etiny, shift;
int rnd;
adjexp = mpd_adjexp(dec);
if (adjexp > ctx->emax) {
if (mpd_iszerocoeff(dec)) {
dec->exp = ctx->emax;
if (ctx->clamp) {
dec->exp -= (ctx->prec-1);
}
mpd_zerocoeff(dec);
*status |= MPD_Clamped;
return;
}
switch (ctx->round) {
case MPD_ROUND_HALF_UP: case MPD_ROUND_HALF_EVEN:
case MPD_ROUND_HALF_DOWN: case MPD_ROUND_UP:
case MPD_ROUND_TRUNC:
mpd_setspecial(dec, mpd_sign(dec), MPD_INF);
break;
case MPD_ROUND_DOWN: case MPD_ROUND_05UP:
mpd_qmaxcoeff(dec, ctx, status);
dec->exp = ctx->emax - ctx->prec + 1;
break;
case MPD_ROUND_CEILING:
if (mpd_isnegative(dec)) {
mpd_qmaxcoeff(dec, ctx, status);
dec->exp = ctx->emax - ctx->prec + 1;
}
else {
mpd_setspecial(dec, MPD_POS, MPD_INF);
}
break;
case MPD_ROUND_FLOOR:
if (mpd_ispositive(dec)) {
mpd_qmaxcoeff(dec, ctx, status);
dec->exp = ctx->emax - ctx->prec + 1;
}
else {
mpd_setspecial(dec, MPD_NEG, MPD_INF);
}
break;
default: /* debug */
abort(); /* GCOV_NOT_REACHED */
}
*status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
} /* fold down */
else if (ctx->clamp && dec->exp > mpd_etop(ctx)) {
/* At this point adjexp=exp+digits-1 <= emax and exp > etop=emax-prec+1:
* (1) shift = exp -emax+prec-1 > 0
* (2) digits+shift = exp+digits-1 - emax + prec <= prec */
shift = dec->exp - mpd_etop(ctx);
if (!mpd_qshiftl(dec, dec, shift, status)) {
return;
}
dec->exp -= shift;
*status |= MPD_Clamped;
if (!mpd_iszerocoeff(dec) && adjexp < ctx->emin) {
/* Underflow is impossible, since exp < etiny=emin-prec+1
* and exp > etop=emax-prec+1 would imply emax < emin. */
*status |= MPD_Subnormal;
}
}
else if (adjexp < ctx->emin) {
etiny = mpd_etiny(ctx);
if (mpd_iszerocoeff(dec)) {
if (dec->exp < etiny) {
dec->exp = etiny;
mpd_zerocoeff(dec);
*status |= MPD_Clamped;
}
return;
}
*status |= MPD_Subnormal;
if (dec->exp < etiny) {
/* At this point adjexp=exp+digits-1 < emin and exp < etiny=emin-prec+1:
* (1) shift = emin-prec+1 - exp > 0
* (2) digits-shift = exp+digits-1 - emin + prec < prec */
shift = etiny - dec->exp;
rnd = (int)mpd_qshiftr_inplace(dec, shift);
dec->exp = etiny;
/* We always have a spare digit in case of an increment. */
_mpd_apply_round_excess(dec, rnd, ctx, status);
*status |= MPD_Rounded;
if (rnd) {
*status |= (MPD_Inexact|MPD_Underflow);
if (mpd_iszerocoeff(dec)) {
mpd_zerocoeff(dec);
*status |= MPD_Clamped;
}
}
}
/* Case exp >= etiny=emin-prec+1:
* (1) adjexp=exp+digits-1 < emin
* (2) digits < emin-exp+1 <= prec */
}
}
/* Transcendental functions do not always set Underflow reliably,
* since they only use as much precision as is necessary for correct
* rounding. If a result like 1.0000000000e-101 is finalized, there
* is no rounding digit that would trigger Underflow. But we can
* assume Inexact, so a short check suffices. */
static inline void
mpd_check_underflow(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
{
if (mpd_adjexp(dec) < ctx->emin && !mpd_iszero(dec) &&
dec->exp < mpd_etiny(ctx)) {
*status |= MPD_Underflow;
}
}
/* Check if a normal number must be rounded after the exponent has been checked. */
static inline void
_mpd_check_round(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
{
mpd_uint_t rnd;
mpd_ssize_t shift;
/* must handle specials: _mpd_check_exp() can produce infinities or NaNs */
if (mpd_isspecial(dec)) {
return;
}
if (dec->digits > ctx->prec) {
shift = dec->digits - ctx->prec;
rnd = mpd_qshiftr_inplace(dec, shift);
dec->exp += shift;
_mpd_apply_round(dec, rnd, ctx, status);
*status |= MPD_Rounded;
if (rnd) {
*status |= MPD_Inexact;
}
}
}
/* Finalize all operations. */
void
mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status)
{
if (mpd_isspecial(result)) {
if (mpd_isnan(result)) {
_mpd_fix_nan(result, ctx);
}
return;
}
_mpd_check_exp(result, ctx, status);
_mpd_check_round(result, ctx, status);
}
/******************************************************************************/
/* Copying */
/******************************************************************************/
/* Internal function: Copy a decimal, share data with src: USE WITH CARE! */
static inline void
_mpd_copy_shared(mpd_t *dest, const mpd_t *src)
{
dest->flags = src->flags;
dest->exp = src->exp;
dest->digits = src->digits;
dest->len = src->len;
dest->alloc = src->alloc;
dest->data = src->data;
mpd_set_shared_data(dest);
}
/*
* Copy a decimal. In case of an error, status is set to MPD_Malloc_error.
*/
int
mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status)
{
if (result == a) return 1;
if (!mpd_qresize(result, a->len, status)) {
return 0;
}
mpd_copy_flags(result, a);
result->exp = a->exp;
result->digits = a->digits;
result->len = a->len;
memcpy(result->data, a->data, a->len * (sizeof *result->data));
return 1;
}
/*
* Copy to a decimal with a static buffer. The caller has to make sure that
* the buffer is big enough. Cannot fail.
*/
static void
mpd_qcopy_static(mpd_t *result, const mpd_t *a)
{
if (result == a) return;
memcpy(result->data, a->data, a->len * (sizeof *result->data));
mpd_copy_flags(result, a);
result->exp = a->exp;
result->digits = a->digits;
result->len = a->len;
}
/*
* Return a newly allocated copy of the operand. In case of an error,
* status is set to MPD_Malloc_error and the return value is NULL.
*/
mpd_t *
mpd_qncopy(const mpd_t *a)
{
mpd_t *result;
if ((result = mpd_qnew_size(a->len)) == NULL) {
return NULL;
}
memcpy(result->data, a->data, a->len * (sizeof *result->data));
mpd_copy_flags(result, a);
result->exp = a->exp;
result->digits = a->digits;
result->len = a->len;
return result;
}
/*
* Copy a decimal and set the sign to positive. In case of an error, the
* status is set to MPD_Malloc_error.
*/
int
mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status)
{
if (!mpd_qcopy(result, a, status)) {
return 0;
}
mpd_set_positive(result);
return 1;
}
/*
* Copy a decimal and negate the sign. In case of an error, the
* status is set to MPD_Malloc_error.
*/
int
mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status)
{
if (!mpd_qcopy(result, a, status)) {
return 0;
}
_mpd_negate(result);
return 1;
}
/*
* Copy a decimal, setting the sign of the first operand to the sign of the
* second operand. In case of an error, the status is set to MPD_Malloc_error.
*/
int
mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status)
{
uint8_t sign_b = mpd_sign(b); /* result may equal b! */
if (!mpd_qcopy(result, a, status)) {
return 0;
}
mpd_set_sign(result, sign_b);
return 1;
}
/******************************************************************************/
/* Comparisons */
/******************************************************************************/
/*
* For all functions that compare two operands and return an int the usual
* convention applies to the return value:
*
* -1 if op1 < op2
* 0 if op1 == op2
* 1 if op1 > op2
*
* INT_MAX for error
*/
/* Convenience macro. If a and b are not equal, return from the calling
* function with the correct comparison value. */
#define CMP_EQUAL_OR_RETURN(a, b) \
if (a != b) { \
if (a < b) { \
return -1; \
} \
return 1; \
}
/*
* Compare the data of big and small. This function does the equivalent
* of first shifting small to the left and then comparing the data of
* big and small, except that no allocation for the left shift is needed.
*/
static int
_mpd_basecmp(mpd_uint_t *big, mpd_uint_t *small, mpd_size_t n, mpd_size_t m,
mpd_size_t shift)
{
/* spurious uninitialized warnings */
mpd_uint_t l=l, lprev=lprev, h=h;
mpd_uint_t q, r;
mpd_uint_t ph, x;
assert(m > 0 && n >= m && shift > 0);
_mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS);
if (r != 0) {
ph = mpd_pow10[r];
--m; --n;
_mpd_divmod_pow10(&h, &lprev, small[m--], MPD_RDIGITS-r);
if (h != 0) {
CMP_EQUAL_OR_RETURN(big[n], h)
--n;
}
for (; m != MPD_SIZE_MAX; m--,n--) {
_mpd_divmod_pow10(&h, &l, small[m], MPD_RDIGITS-r);
x = ph * lprev + h;
CMP_EQUAL_OR_RETURN(big[n], x)
lprev = l;
}
x = ph * lprev;
CMP_EQUAL_OR_RETURN(big[q], x)
}
else {
while (--m != MPD_SIZE_MAX) {
CMP_EQUAL_OR_RETURN(big[m+q], small[m])
}
}
return !_mpd_isallzero(big, q);
}
/* Compare two decimals with the same adjusted exponent. */
static int
_mpd_cmp_same_adjexp(const mpd_t *a, const mpd_t *b)
{
mpd_ssize_t shift, i;
if (a->exp != b->exp) {
/* Cannot wrap: a->exp + a->digits = b->exp + b->digits, so
* a->exp - b->exp = b->digits - a->digits. */
shift = a->exp - b->exp;
if (shift > 0) {
return -1 * _mpd_basecmp(b->data, a->data, b->len, a->len, shift);
}
else {
return _mpd_basecmp(a->data, b->data, a->len, b->len, -shift);
}
}
/*
* At this point adjexp(a) == adjexp(b) and a->exp == b->exp,
* so a->digits == b->digits, therefore a->len == b->len.
*/
for (i = a->len-1; i >= 0; --i) {
CMP_EQUAL_OR_RETURN(a->data[i], b->data[i])
}
return 0;
}
/* Compare two numerical values. */
static int
_mpd_cmp(const mpd_t *a, const mpd_t *b)
{
mpd_ssize_t adjexp_a, adjexp_b;
/* equal pointers */
if (a == b) {
return 0;
}
/* infinities */
if (mpd_isinfinite(a)) {
if (mpd_isinfinite(b)) {
return mpd_isnegative(b) - mpd_isnegative(a);
}
return mpd_arith_sign(a);
}
if (mpd_isinfinite(b)) {
return -mpd_arith_sign(b);
}
/* zeros */
if (mpd_iszerocoeff(a)) {
if (mpd_iszerocoeff(b)) {
return 0;
}
return -mpd_arith_sign(b);
}
if (mpd_iszerocoeff(b)) {
return mpd_arith_sign(a);
}
/* different signs */
if (mpd_sign(a) != mpd_sign(b)) {
return mpd_sign(b) - mpd_sign(a);
}
/* different adjusted exponents */
adjexp_a = mpd_adjexp(a);
adjexp_b = mpd_adjexp(b);
if (adjexp_a != adjexp_b) {
if (adjexp_a < adjexp_b) {
return -1 * mpd_arith_sign(a);
}
return mpd_arith_sign(a);
}
/* same adjusted exponents */
return _mpd_cmp_same_adjexp(a, b) * mpd_arith_sign(a);
}
/* Compare the absolutes of two numerical values. */
static int
_mpd_cmp_abs(const mpd_t *a, const mpd_t *b)
{
mpd_ssize_t adjexp_a, adjexp_b;
/* equal pointers */
if (a == b) {
return 0;
}
/* infinities */
if (mpd_isinfinite(a)) {
if (mpd_isinfinite(b)) {
return 0;
}
return 1;
}
if (mpd_isinfinite(b)) {
return -1;
}
/* zeros */
if (mpd_iszerocoeff(a)) {
if (mpd_iszerocoeff(b)) {
return 0;
}
return -1;
}
if (mpd_iszerocoeff(b)) {
return 1;
}
/* different adjusted exponents */
adjexp_a = mpd_adjexp(a);
adjexp_b = mpd_adjexp(b);
if (adjexp_a != adjexp_b) {
if (adjexp_a < adjexp_b) {
return -1;
}
return 1;
}
/* same adjusted exponents */
return _mpd_cmp_same_adjexp(a, b);
}
/* Compare two values and return an integer result. */
int
mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status)
{
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_isnan(a) || mpd_isnan(b)) {
*status |= MPD_Invalid_operation;
return INT_MAX;
}
}
return _mpd_cmp(a, b);
}
/*
* Compare a and b, convert the usual integer result to a decimal and
* store it in 'result'. For convenience, the integer result of the comparison
* is returned. Comparisons involving NaNs return NaN/INT_MAX.
*/
int
mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
int c;
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return INT_MAX;
}
}
c = _mpd_cmp(a, b);
_settriple(result, (c < 0), (c != 0), 0);
return c;
}
/* Same as mpd_compare(), but signal for all NaNs, i.e. also for quiet NaNs. */
int
mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
int c;
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
*status |= MPD_Invalid_operation;
return INT_MAX;
}
}
c = _mpd_cmp(a, b);
_settriple(result, (c < 0), (c != 0), 0);
return c;
}
/* Compare the operands using a total order. */
int
mpd_cmp_total(const mpd_t *a, const mpd_t *b)
{
mpd_t aa, bb;
int nan_a, nan_b;
int c;
if (mpd_sign(a) != mpd_sign(b)) {
return mpd_sign(b) - mpd_sign(a);
}
if (mpd_isnan(a)) {
c = 1;
if (mpd_isnan(b)) {
nan_a = (mpd_isqnan(a)) ? 1 : 0;
nan_b = (mpd_isqnan(b)) ? 1 : 0;
if (nan_b == nan_a) {
if (a->len > 0 && b->len > 0) {
_mpd_copy_shared(&aa, a);
_mpd_copy_shared(&bb, b);
aa.exp = bb.exp = 0;
/* compare payload */
c = _mpd_cmp_abs(&aa, &bb);
}
else {
c = (a->len > 0) - (b->len > 0);
}
}
else {
c = nan_a - nan_b;
}
}
}
else if (mpd_isnan(b)) {
c = -1;
}
else {
c = _mpd_cmp_abs(a, b);
if (c == 0 && a->exp != b->exp) {
c = (a->exp < b->exp) ? -1 : 1;
}
}
return c * mpd_arith_sign(a);
}
/*
* Compare a and b according to a total order, convert the usual integer result
* to a decimal and store it in 'result'. For convenience, the integer result
* of the comparison is returned.
*/
int
mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b)
{
int c;
c = mpd_cmp_total(a, b);
_settriple(result, (c < 0), (c != 0), 0);
return c;
}
/* Compare the magnitude of the operands using a total order. */
int
mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b)
{
mpd_t aa, bb;
_mpd_copy_shared(&aa, a);
_mpd_copy_shared(&bb, b);
mpd_set_positive(&aa);
mpd_set_positive(&bb);
return mpd_cmp_total(&aa, &bb);
}
/*
* Compare the magnitude of a and b according to a total order, convert the
* the usual integer result to a decimal and store it in 'result'.
* For convenience, the integer result of the comparison is returned.
*/
int
mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b)
{
int c;
c = mpd_cmp_total_mag(a, b);
_settriple(result, (c < 0), (c != 0), 0);
return c;
}
/* Determine an ordering for operands that are numerically equal. */
static inline int
_mpd_cmp_numequal(const mpd_t *a, const mpd_t *b)
{
int sign_a, sign_b;
int c;
sign_a = mpd_sign(a);
sign_b = mpd_sign(b);
if (sign_a != sign_b) {
c = sign_b - sign_a;
}
else {
c = (a->exp < b->exp) ? -1 : 1;
c *= mpd_arith_sign(a);
}
return c;
}
/******************************************************************************/
/* Shifting the coefficient */
/******************************************************************************/
/*
* Shift the coefficient of the operand to the left, no check for specials.
* Both operands may be the same pointer. If the result length has to be
* increased, mpd_qresize() might fail with MPD_Malloc_error.
*/
int
mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status)
{
mpd_ssize_t size;
assert(!mpd_isspecial(a));
assert(n >= 0);
if (mpd_iszerocoeff(a) || n == 0) {
return mpd_qcopy(result, a, status);
}
size = mpd_digits_to_size(a->digits+n);
if (!mpd_qresize(result, size, status)) {
return 0; /* result is NaN */
}
_mpd_baseshiftl(result->data, a->data, size, a->len, n);
mpd_copy_flags(result, a);
result->exp = a->exp;
result->digits = a->digits+n;
result->len = size;
return 1;
}
/* Determine the rounding indicator if all digits of the coefficient are shifted
* out of the picture. */
static mpd_uint_t
_mpd_get_rnd(const mpd_uint_t *data, mpd_ssize_t len, int use_msd)
{
mpd_uint_t rnd = 0, rest = 0, word;
word = data[len-1];
/* special treatment for the most significant digit if shift == digits */
if (use_msd) {
_mpd_divmod_pow10(&rnd, &rest, word, mpd_word_digits(word)-1);
if (len > 1 && rest == 0) {
rest = !_mpd_isallzero(data, len-1);
}
}
else {
rest = !_mpd_isallzero(data, len);
}
return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd;
}
/*
* Same as mpd_qshiftr(), but 'result' is an mpd_t with a static coefficient.
* It is the caller's responsibility to ensure that the coefficient is big
* enough. The function cannot fail.
*/
static mpd_uint_t
mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n)
{
mpd_uint_t rnd;
mpd_ssize_t size;
assert(!mpd_isspecial(a));
assert(n >= 0);
if (mpd_iszerocoeff(a) || n == 0) {
mpd_qcopy_static(result, a);
return 0;
}
if (n >= a->digits) {
rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits));
mpd_zerocoeff(result);
}
else {
result->digits = a->digits-n;
size = mpd_digits_to_size(result->digits);
rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
result->len = size;
}
mpd_copy_flags(result, a);
result->exp = a->exp;
return rnd;
}
/*
* Inplace shift of the coefficient to the right, no check for specials.
* Returns the rounding indicator for mpd_rnd_incr().
* The function cannot fail.
*/
mpd_uint_t
mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n)
{
uint32_t dummy;
mpd_uint_t rnd;
mpd_ssize_t size;
assert(!mpd_isspecial(result));
assert(n >= 0);
if (mpd_iszerocoeff(result) || n == 0) {
return 0;
}
if (n >= result->digits) {
rnd = _mpd_get_rnd(result->data, result->len, (n==result->digits));
mpd_zerocoeff(result);
}
else {
rnd = _mpd_baseshiftr(result->data, result->data, result->len, n);
result->digits -= n;
size = mpd_digits_to_size(result->digits);
/* reducing the size cannot fail */
mpd_qresize(result, size, &dummy);
result->len = size;
}
return rnd;
}
/*
* Shift the coefficient of the operand to the right, no check for specials.
* Both operands may be the same pointer. Returns the rounding indicator to
* be used by mpd_rnd_incr(). If the result length has to be increased,
* mpd_qcopy() or mpd_qresize() might fail with MPD_Malloc_error. In those
* cases, MPD_UINT_MAX is returned.
*/
mpd_uint_t
mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status)
{
mpd_uint_t rnd;
mpd_ssize_t size;
assert(!mpd_isspecial(a));
assert(n >= 0);
if (mpd_iszerocoeff(a) || n == 0) {
if (!mpd_qcopy(result, a, status)) {
return MPD_UINT_MAX;
}
return 0;
}
if (n >= a->digits) {
rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits));
mpd_zerocoeff(result);
}
else {
result->digits = a->digits-n;
size = mpd_digits_to_size(result->digits);
if (result == a) {
rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
/* reducing the size cannot fail */
mpd_qresize(result, size, status);
}
else {
if (!mpd_qresize(result, size, status)) {
return MPD_UINT_MAX;
}
rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
}
result->len = size;
}
mpd_copy_flags(result, a);
result->exp = a->exp;
return rnd;
}
/******************************************************************************/
/* Miscellaneous operations */
/******************************************************************************/
/* Logical And */
void
mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
const mpd_t *big = a, *small = b;
mpd_uint_t x, y, z, xbit, ybit;
int k, mswdigits;
mpd_ssize_t i;
if (mpd_isspecial(a) || mpd_isspecial(b) ||
mpd_isnegative(a) || mpd_isnegative(b) ||
a->exp != 0 || b->exp != 0) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (b->digits > a->digits) {
big = b;
small = a;
}
if (!mpd_qresize(result, big->len, status)) {
return;
}
/* full words */
for (i = 0; i < small->len-1; i++) {
x = small->data[i];
y = big->data[i];
z = 0;
for (k = 0; k < MPD_RDIGITS; k++) {
xbit = x % 10;
x /= 10;
ybit = y % 10;
y /= 10;
if (xbit > 1 || ybit > 1) {
goto invalid_operation;
}
z += (xbit&ybit) ? mpd_pow10[k] : 0;
}
result->data[i] = z;
}
/* most significant word of small */
x = small->data[i];
y = big->data[i];
z = 0;
mswdigits = mpd_word_digits(x);
for (k = 0; k < mswdigits; k++) {
xbit = x % 10;
x /= 10;
ybit = y % 10;
y /= 10;
if (xbit > 1 || ybit > 1) {
goto invalid_operation;
}
z += (xbit&ybit) ? mpd_pow10[k] : 0;
}
result->data[i++] = z;
/* scan the rest of y for digits > 1 */
for (; k < MPD_RDIGITS; k++) {
ybit = y % 10;
y /= 10;
if (ybit > 1) {
goto invalid_operation;
}
}
/* scan the rest of big for digits > 1 */
for (; i < big->len; i++) {
y = big->data[i];
for (k = 0; k < MPD_RDIGITS; k++) {
ybit = y % 10;
y /= 10;
if (ybit > 1) {
goto invalid_operation;
}
}
}
mpd_clear_flags(result);
result->exp = 0;
result->len = _mpd_real_size(result->data, small->len);
mpd_qresize(result, result->len, status);
mpd_setdigits(result);
_mpd_cap(result, ctx);
return;
invalid_operation:
mpd_seterror(result, MPD_Invalid_operation, status);
}
/* Class of an operand. Returns a pointer to the constant name. */
const char *
mpd_class(const mpd_t *a, const mpd_context_t *ctx)
{
if (mpd_isnan(a)) {
if (mpd_isqnan(a))
return "NaN";
else
return "sNaN";
}
else if (mpd_ispositive(a)) {
if (mpd_isinfinite(a))
return "+Infinity";
else if (mpd_iszero(a))
return "+Zero";
else if (mpd_isnormal(a, ctx))
return "+Normal";
else
return "+Subnormal";
}
else {
if (mpd_isinfinite(a))
return "-Infinity";
else if (mpd_iszero(a))
return "-Zero";
else if (mpd_isnormal(a, ctx))
return "-Normal";
else
return "-Subnormal";
}
}
/* Logical Xor */
void
mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_uint_t x, z, xbit;
mpd_ssize_t i, digits, len;
mpd_ssize_t q, r;
int k;
if (mpd_isspecial(a) || mpd_isnegative(a) || a->exp != 0) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
digits = (a->digits < ctx->prec) ? ctx->prec : a->digits;
_mpd_idiv_word(&q, &r, digits, MPD_RDIGITS);
len = (r == 0) ? q : q+1;
if (!mpd_qresize(result, len, status)) {
return;
}
for (i = 0; i < len; i++) {
x = (i < a->len) ? a->data[i] : 0;
z = 0;
for (k = 0; k < MPD_RDIGITS; k++) {
xbit = x % 10;
x /= 10;
if (xbit > 1) {
goto invalid_operation;
}
z += !xbit ? mpd_pow10[k] : 0;
}
result->data[i] = z;
}
mpd_clear_flags(result);
result->exp = 0;
result->len = _mpd_real_size(result->data, len);
mpd_qresize(result, result->len, status);
mpd_setdigits(result);
_mpd_cap(result, ctx);
return;
invalid_operation:
mpd_seterror(result, MPD_Invalid_operation, status);
}
/* Exponent of the magnitude of the most significant digit of the operand. */
void
mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
mpd_setspecial(result, MPD_POS, MPD_INF);
}
else if (mpd_iszerocoeff(a)) {
mpd_setspecial(result, MPD_NEG, MPD_INF);
*status |= MPD_Division_by_zero;
}
else {
mpd_qset_ssize(result, mpd_adjexp(a), ctx, status);
}
}
/* Logical Or */
void
mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
const mpd_t *big = a, *small = b;
mpd_uint_t x, y, z, xbit, ybit;
int k, mswdigits;
mpd_ssize_t i;
if (mpd_isspecial(a) || mpd_isspecial(b) ||
mpd_isnegative(a) || mpd_isnegative(b) ||
a->exp != 0 || b->exp != 0) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (b->digits > a->digits) {
big = b;
small = a;
}
if (!mpd_qresize(result, big->len, status)) {
return;
}
/* full words */
for (i = 0; i < small->len-1; i++) {
x = small->data[i];
y = big->data[i];
z = 0;
for (k = 0; k < MPD_RDIGITS; k++) {
xbit = x % 10;
x /= 10;
ybit = y % 10;
y /= 10;
if (xbit > 1 || ybit > 1) {
goto invalid_operation;
}
z += (xbit|ybit) ? mpd_pow10[k] : 0;
}
result->data[i] = z;
}
/* most significant word of small */
x = small->data[i];
y = big->data[i];
z = 0;
mswdigits = mpd_word_digits(x);
for (k = 0; k < mswdigits; k++) {
xbit = x % 10;
x /= 10;
ybit = y % 10;
y /= 10;
if (xbit > 1 || ybit > 1) {
goto invalid_operation;
}
z += (xbit|ybit) ? mpd_pow10[k] : 0;
}
/* scan for digits > 1 and copy the rest of y */
for (; k < MPD_RDIGITS; k++) {
ybit = y % 10;
y /= 10;
if (ybit > 1) {
goto invalid_operation;
}
z += ybit*mpd_pow10[k];
}
result->data[i++] = z;
/* scan for digits > 1 and copy the rest of big */
for (; i < big->len; i++) {
y = big->data[i];
for (k = 0; k < MPD_RDIGITS; k++) {
ybit = y % 10;
y /= 10;
if (ybit > 1) {
goto invalid_operation;
}
}
result->data[i] = big->data[i];
}
mpd_clear_flags(result);
result->exp = 0;
result->len = _mpd_real_size(result->data, big->len);
mpd_qresize(result, result->len, status);
mpd_setdigits(result);
_mpd_cap(result, ctx);
return;
invalid_operation:
mpd_seterror(result, MPD_Invalid_operation, status);
}
/*
* Rotate the coefficient of 'a' by 'b' digits. 'b' must be an integer with
* exponent 0.
*/
void
mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
MPD_NEW_STATIC(tmp,0,0,0,0);
MPD_NEW_STATIC(big,0,0,0,0);
MPD_NEW_STATIC(small,0,0,0,0);
mpd_ssize_t n, lshift, rshift;
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
}
if (b->exp != 0 || mpd_isinfinite(b)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
n = mpd_qget_ssize(b, &workstatus);
if (workstatus&MPD_Invalid_operation) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (n > ctx->prec || n < -ctx->prec) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (mpd_isinfinite(a)) {
mpd_qcopy(result, a, status);
return;
}
if (n >= 0) {
lshift = n;
rshift = ctx->prec-n;
}
else {
lshift = ctx->prec+n;
rshift = -n;
}
if (a->digits > ctx->prec) {
if (!mpd_qcopy(&tmp, a, status)) {
mpd_seterror(result, MPD_Malloc_error, status);
goto finish;
}
_mpd_cap(&tmp, ctx);
a = &tmp;
}
if (!mpd_qshiftl(&big, a, lshift, status)) {
mpd_seterror(result, MPD_Malloc_error, status);
goto finish;
}
_mpd_cap(&big, ctx);
if (mpd_qshiftr(&small, a, rshift, status) == MPD_UINT_MAX) {
mpd_seterror(result, MPD_Malloc_error, status);
goto finish;
}
_mpd_qadd(result, &big, &small, ctx, status);
finish:
mpd_del(&tmp);
mpd_del(&big);
mpd_del(&small);
}
/*
* b must be an integer with exponent 0 and in the range +-2*(emax + prec).
* XXX: In my opinion +-(2*emax + prec) would be more sensible.
* The result is a with the value of b added to its exponent.
*/
void
mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_uint_t n, maxjump;
int64_t exp;
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
}
if (b->exp != 0 || mpd_isinfinite(b)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
n = mpd_qabs_uint(b, &workstatus);
/* the spec demands this */
maxjump = 2 * (mpd_uint_t)(ctx->emax + ctx->prec);
if (n > maxjump || workstatus&MPD_Invalid_operation) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (mpd_isinfinite(a)) {
mpd_qcopy(result, a, status);
return;
}
exp = a->exp + (int64_t)n * mpd_arith_sign(b);
exp = (exp > MPD_EXP_INF) ? MPD_EXP_INF : exp;
exp = (exp < MPD_EXP_CLAMP) ? MPD_EXP_CLAMP : exp;
mpd_qcopy(result, a, status);
result->exp = (mpd_ssize_t)exp;
mpd_qfinalize(result, ctx, status);
}
/*
* Shift the coefficient by n digits, positive n is a left shift. In the case
* of a left shift, the result is decapitated to fit the context precision. If
* you don't want that, use mpd_shiftl().
*/
void
mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx,
uint32_t *status)
{
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
mpd_qcopy(result, a, status);
return;
}
if (n >= 0 && n <= ctx->prec) {
mpd_qshiftl(result, a, n, status);
_mpd_cap(result, ctx);
}
else if (n < 0 && n >= -ctx->prec) {
if (!mpd_qcopy(result, a, status)) {
return;
}
_mpd_cap(result, ctx);
mpd_qshiftr_inplace(result, -n);
}
else {
mpd_seterror(result, MPD_Invalid_operation, status);
}
}
/*
* Same as mpd_shiftn(), but the shift is specified by the decimal b, which
* must be an integer with a zero exponent. Infinities remain infinities.
*/
void
mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx,
uint32_t *status)
{
uint32_t workstatus = 0;
mpd_ssize_t n;
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
}
if (b->exp != 0 || mpd_isinfinite(b)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
n = mpd_qget_ssize(b, &workstatus);
if (workstatus&MPD_Invalid_operation) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (n > ctx->prec || n < -ctx->prec) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (mpd_isinfinite(a)) {
mpd_qcopy(result, a, status);
return;
}
if (n >= 0) {
mpd_qshiftl(result, a, n, status);
_mpd_cap(result, ctx);
}
else {
if (!mpd_qcopy(result, a, status)) {
return;
}
_mpd_cap(result, ctx);
mpd_qshiftr_inplace(result, -n);
}
}
/* Logical Xor */
void
mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
const mpd_t *big = a, *small = b;
mpd_uint_t x, y, z, xbit, ybit;
int k, mswdigits;
mpd_ssize_t i;
if (mpd_isspecial(a) || mpd_isspecial(b) ||
mpd_isnegative(a) || mpd_isnegative(b) ||
a->exp != 0 || b->exp != 0) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (b->digits > a->digits) {
big = b;
small = a;
}
if (!mpd_qresize(result, big->len, status)) {
return;
}
/* full words */
for (i = 0; i < small->len-1; i++) {
x = small->data[i];
y = big->data[i];
z = 0;
for (k = 0; k < MPD_RDIGITS; k++) {
xbit = x % 10;
x /= 10;
ybit = y % 10;
y /= 10;
if (xbit > 1 || ybit > 1) {
goto invalid_operation;
}
z += (xbit^ybit) ? mpd_pow10[k] : 0;
}
result->data[i] = z;
}
/* most significant word of small */
x = small->data[i];
y = big->data[i];
z = 0;
mswdigits = mpd_word_digits(x);
for (k = 0; k < mswdigits; k++) {
xbit = x % 10;
x /= 10;
ybit = y % 10;
y /= 10;
if (xbit > 1 || ybit > 1) {
goto invalid_operation;
}
z += (xbit^ybit) ? mpd_pow10[k] : 0;
}
/* scan for digits > 1 and copy the rest of y */
for (; k < MPD_RDIGITS; k++) {
ybit = y % 10;
y /= 10;
if (ybit > 1) {
goto invalid_operation;
}
z += ybit*mpd_pow10[k];
}
result->data[i++] = z;
/* scan for digits > 1 and copy the rest of big */
for (; i < big->len; i++) {
y = big->data[i];
for (k = 0; k < MPD_RDIGITS; k++) {
ybit = y % 10;
y /= 10;
if (ybit > 1) {
goto invalid_operation;
}
}
result->data[i] = big->data[i];
}
mpd_clear_flags(result);
result->exp = 0;
result->len = _mpd_real_size(result->data, big->len);
mpd_qresize(result, result->len, status);
mpd_setdigits(result);
_mpd_cap(result, ctx);
return;
invalid_operation:
mpd_seterror(result, MPD_Invalid_operation, status);
}
/******************************************************************************/
/* Arithmetic operations */
/******************************************************************************/
/*
* The absolute value of a. If a is negative, the result is the same
* as the result of the minus operation. Otherwise, the result is the
* result of the plus operation.
*/
void
mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
}
if (mpd_isnegative(a)) {
mpd_qminus(result, a, ctx, status);
}
else {
mpd_qplus(result, a, ctx, status);
}
}
static inline void
_mpd_ptrswap(const mpd_t **a, const mpd_t **b)
{
const mpd_t *t = *a;
*a = *b;
*b = t;
}
/* Add or subtract infinities. */
static void
_mpd_qaddsub_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b,
uint32_t *status)
{
if (mpd_isinfinite(a)) {
if (mpd_sign(a) != sign_b && mpd_isinfinite(b)) {
mpd_seterror(result, MPD_Invalid_operation, status);
}
else {
mpd_setspecial(result, mpd_sign(a), MPD_INF);
}
return;
}
assert(mpd_isinfinite(b));
mpd_setspecial(result, sign_b, MPD_INF);
}
/* Add or subtract non-special numbers. */
static void
_mpd_qaddsub(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b,
const mpd_context_t *ctx, uint32_t *status)
{
const mpd_t *big, *small;
MPD_NEW_STATIC(big_aligned,0,0,0,0);
MPD_NEW_CONST(tiny,0,0,1,1,1,1);
mpd_uint_t carry;
mpd_ssize_t newsize, shift;
mpd_ssize_t exp, i;
int swap = 0;
/* compare exponents */
big = a; small = b;
if (big->exp != small->exp) {
if (small->exp > big->exp) {
_mpd_ptrswap(&big, &small);
swap++;
}
/* align the coefficients */
if (!mpd_iszerocoeff(big)) {
exp = big->exp - 1;
exp += (big->digits > ctx->prec) ? 0 : big->digits-ctx->prec-1;
if (mpd_adjexp(small) < exp) {
/*
* Avoid huge shifts by substituting a value for small that is
* guaranteed to produce the same results.
*
* adjexp(small) < exp if and only if:
*
* bdigits <= prec AND
* bdigits+shift >= prec+2+sdigits AND
* exp = bexp+bdigits-prec-2
*
* 1234567000000000 -> bdigits + shift
* ----------XX1234 -> sdigits
* ----------X1 -> tiny-digits
* |- prec -|
*
* OR
*
* bdigits > prec AND
* shift > sdigits AND
* exp = bexp-1
*
* 1234567892100000 -> bdigits + shift
* ----------XX1234 -> sdigits
* ----------X1 -> tiny-digits
* |- prec -|
*
* If tiny is zero, adding or subtracting is a no-op.
* Otherwise, adding tiny generates a non-zero digit either
* below the rounding digit or the least significant digit
* of big. When subtracting, tiny is in the same position as
* the carry that would be generated by subtracting sdigits.
*/
mpd_copy_flags(&tiny, small);
tiny.exp = exp;
tiny.digits = 1;
tiny.len = 1;
tiny.data[0] = mpd_iszerocoeff(small) ? 0 : 1;
small = &tiny;
}
/* This cannot wrap: the difference is positive and <= maxprec */
shift = big->exp - small->exp;
if (!mpd_qshiftl(&big_aligned, big, shift, status)) {
mpd_seterror(result, MPD_Malloc_error, status);
goto finish;
}
big = &big_aligned;
}
}
result->exp = small->exp;
/* compare length of coefficients */
if (big->len < small->len) {
_mpd_ptrswap(&big, &small);
swap++;
}
newsize = big->len;
if (!mpd_qresize(result, newsize, status)) {
goto finish;
}
if (mpd_sign(a) == sign_b) {
carry = _mpd_baseadd(result->data, big->data, small->data,
big->len, small->len);
if (carry) {
newsize = big->len + 1;
if (!mpd_qresize(result, newsize, status)) {
goto finish;
}
result->data[newsize-1] = carry;
}
result->len = newsize;
mpd_set_flags(result, sign_b);
}
else {
if (big->len == small->len) {
for (i=big->len-1; i >= 0; --i) {
if (big->data[i] != small->data[i]) {
if (big->data[i] < small->data[i]) {
_mpd_ptrswap(&big, &small);
swap++;
}
break;
}
}
}
_mpd_basesub(result->data, big->data, small->data,
big->len, small->len);
newsize = _mpd_real_size(result->data, big->len);
/* resize to smaller cannot fail */
(void)mpd_qresize(result, newsize, status);
result->len = newsize;
sign_b = (swap & 1) ? sign_b : mpd_sign(a);
mpd_set_flags(result, sign_b);
if (mpd_iszerocoeff(result)) {
mpd_set_positive(result);
if (ctx->round == MPD_ROUND_FLOOR) {
mpd_set_negative(result);
}
}
}
mpd_setdigits(result);
finish:
mpd_del(&big_aligned);
}
/* Add a and b. No specials, no finalizing. */
static void
_mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
_mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status);
}
/* Subtract b from a. No specials, no finalizing. */
static void
_mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
_mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status);
}
/* Add a and b. */
void
mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
_mpd_qaddsub_inf(result, a, b, mpd_sign(b), status);
return;
}
_mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status);
mpd_qfinalize(result, ctx, status);
}
/* Add a and b. Set NaN/Invalid_operation if the result is inexact. */
static void
_mpd_qadd_exact(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_qadd(result, a, b, ctx, &workstatus);
*status |= workstatus;
if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
mpd_seterror(result, MPD_Invalid_operation, status);
}
}
/* Subtract b from a. */
void
mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
_mpd_qaddsub_inf(result, a, b, !mpd_sign(b), status);
return;
}
_mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status);
mpd_qfinalize(result, ctx, status);
}
/* Subtract b from a. Set NaN/Invalid_operation if the result is inexact. */
static void
_mpd_qsub_exact(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_qsub(result, a, b, ctx, &workstatus);
*status |= workstatus;
if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
mpd_seterror(result, MPD_Invalid_operation, status);
}
}
/* Add decimal and mpd_ssize_t. */
void
mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_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_qsset_ssize(&bb, b, &maxcontext, status);
mpd_qadd(result, a, &bb, ctx, status);
mpd_del(&bb);
}
/* Add decimal and mpd_uint_t. */
void
mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_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_qsset_uint(&bb, b, &maxcontext, status);
mpd_qadd(result, a, &bb, ctx, status);
mpd_del(&bb);
}
/* Subtract mpd_ssize_t from decimal. */
void
mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_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_qsset_ssize(&bb, b, &maxcontext, status);
mpd_qsub(result, a, &bb, ctx, status);
mpd_del(&bb);
}
/* Subtract mpd_uint_t from decimal. */
void
mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_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_qsset_uint(&bb, b, &maxcontext, status);
mpd_qsub(result, a, &bb, ctx, status);
mpd_del(&bb);
}
/* Add decimal and int32_t. */
void
mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qadd_ssize(result, a, b, ctx, status);
}
/* Add decimal and uint32_t. */
void
mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qadd_uint(result, a, b, ctx, status);
}
/* 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_qadd_ssize(result, a, b, ctx, status);
}
/* 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_qadd_uint(result, a, b, ctx, status);
}
/* Subtract int32_t from decimal. */
void
mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qsub_ssize(result, a, b, ctx, status);
}
/* Subtract uint32_t from decimal. */
void
mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qsub_uint(result, a, b, ctx, status);
}
/* 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_qsub_ssize(result, a, b, ctx, status);
}
/* 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_qsub_uint(result, a, b, ctx, status);
}
/* Divide infinities. */
static void
_mpd_qdiv_inf(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
if (mpd_isinfinite(a)) {
if (mpd_isinfinite(b)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
return;
}
assert(mpd_isinfinite(b));
_settriple(result, mpd_sign(a)^mpd_sign(b), 0, mpd_etiny(ctx));
*status |= MPD_Clamped;
}
enum {NO_IDEAL_EXP, SET_IDEAL_EXP};
/* Divide a by b. */
static void
_mpd_qdiv(int action, mpd_t *q, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
MPD_NEW_STATIC(aligned,0,0,0,0);
mpd_uint_t ld;
mpd_ssize_t shift, exp, tz;
mpd_ssize_t newsize;
mpd_ssize_t ideal_exp;
mpd_uint_t rem;
uint8_t sign_a = mpd_sign(a);
uint8_t sign_b = mpd_sign(b);
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(q, a, b, ctx, status)) {
return;
}
_mpd_qdiv_inf(q, a, b, ctx, status);
return;
}
if (mpd_iszerocoeff(b)) {
if (mpd_iszerocoeff(a)) {
mpd_seterror(q, MPD_Division_undefined, status);
}
else {
mpd_setspecial(q, sign_a^sign_b, MPD_INF);
*status |= MPD_Division_by_zero;
}
return;
}
if (mpd_iszerocoeff(a)) {
exp = a->exp - b->exp;
_settriple(q, sign_a^sign_b, 0, exp);
mpd_qfinalize(q, ctx, status);
return;
}
shift = (b->digits - a->digits) + ctx->prec + 1;
ideal_exp = a->exp - b->exp;
exp = ideal_exp - shift;
if (shift > 0) {
if (!mpd_qshiftl(&aligned, a, shift, status)) {
mpd_seterror(q, MPD_Malloc_error, status);
goto finish;
}
a = &aligned;
}
else if (shift < 0) {
shift = -shift;
if (!mpd_qshiftl(&aligned, b, shift, status)) {
mpd_seterror(q, MPD_Malloc_error, status);
goto finish;
}
b = &aligned;
}
newsize = a->len - b->len + 1;
if ((q != b && q != a) || (q == b && newsize > b->len)) {
if (!mpd_qresize(q, newsize, status)) {
mpd_seterror(q, MPD_Malloc_error, status);
goto finish;
}
}
if (b->len == 1) {
rem = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]);
}
else if (b->len <= MPD_NEWTONDIV_CUTOFF) {
int ret = _mpd_basedivmod(q->data, NULL, a->data, b->data,
a->len, b->len);
if (ret < 0) {
mpd_seterror(q, MPD_Malloc_error, status);
goto finish;
}
rem = ret;
}
else {
MPD_NEW_STATIC(r,0,0,0,0);
_mpd_base_ndivmod(q, &r, a, b, status);
if (mpd_isspecial(q) || mpd_isspecial(&r)) {
mpd_setspecial(q, MPD_POS, MPD_NAN);
mpd_del(&r);
goto finish;
}
rem = !mpd_iszerocoeff(&r);
mpd_del(&r);
newsize = q->len;
}
newsize = _mpd_real_size(q->data, newsize);
/* resize to smaller cannot fail */
mpd_qresize(q, newsize, status);
mpd_set_flags(q, sign_a^sign_b);
q->len = newsize;
mpd_setdigits(q);
shift = ideal_exp - exp;
if (rem) {
ld = mpd_lsd(q->data[0]);
if (ld == 0 || ld == 5) {
q->data[0] += 1;
}
}
else if (action == SET_IDEAL_EXP && shift > 0) {
tz = mpd_trail_zeros(q);
shift = (tz > shift) ? shift : tz;
mpd_qshiftr_inplace(q, shift);
exp += shift;
}
q->exp = exp;
finish:
mpd_del(&aligned);
mpd_qfinalize(q, ctx, status);
}
/* Divide a by b. */
void
mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
_mpd_qdiv(SET_IDEAL_EXP, q, a, b, ctx, status);
}
/* Internal function. */
static void
_mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
MPD_NEW_STATIC(aligned,0,0,0,0);
mpd_ssize_t qsize, rsize;
mpd_ssize_t ideal_exp, expdiff, shift;
uint8_t sign_a = mpd_sign(a);
uint8_t sign_ab = mpd_sign(a)^mpd_sign(b);
ideal_exp = (a->exp > b->exp) ? b->exp : a->exp;
if (mpd_iszerocoeff(a)) {
if (!mpd_qcopy(r, a, status)) {
goto nanresult; /* GCOV_NOT_REACHED */
}
r->exp = ideal_exp;
_settriple(q, sign_ab, 0, 0);
return;
}
expdiff = mpd_adjexp(a) - mpd_adjexp(b);
if (expdiff < 0) {
if (a->exp > b->exp) {
/* positive and less than b->digits - a->digits */
shift = a->exp - b->exp;
if (!mpd_qshiftl(r, a, shift, status)) {
goto nanresult;
}
r->exp = ideal_exp;
}
else {
if (!mpd_qcopy(r, a, status)) {
goto nanresult;
}
}
_settriple(q, sign_ab, 0, 0);
return;
}
if (expdiff > ctx->prec) {
*status |= MPD_Division_impossible;
goto nanresult;
}
/*
* At this point we have:
* (1) 0 <= a->exp + a->digits - b->exp - b->digits <= prec
* (2) a->exp - b->exp >= b->digits - a->digits
* (3) a->exp - b->exp <= prec + b->digits - a->digits
*/
if (a->exp != b->exp) {
shift = a->exp - b->exp;
if (shift > 0) {
/* by (3), after the shift a->digits <= prec + b->digits */
if (!mpd_qshiftl(&aligned, a, shift, status)) {
goto nanresult;
}
a = &aligned;
}
else {
shift = -shift;
/* by (2), after the shift b->digits <= a->digits */
if (!mpd_qshiftl(&aligned, b, shift, status)) {
goto nanresult;
}
b = &aligned;
}
}
qsize = a->len - b->len + 1;
if (!(q == a && qsize < a->len) && !(q == b && qsize < b->len)) {
if (!mpd_qresize(q, qsize, status)) {
goto nanresult;
}
}
rsize = b->len;
if (!(r == a && rsize < a->len)) {
if (!mpd_qresize(r, rsize, status)) {
goto nanresult;
}
}
if (b->len == 1) {
if (a->len == 1) {
_mpd_div_word(&q->data[0], &r->data[0], a->data[0], b->data[0]);
}
else {
r->data[0] = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]);
}
}
else if (b->len <= MPD_NEWTONDIV_CUTOFF) {
int ret;
ret = _mpd_basedivmod(q->data, r->data, a->data, b->data,
a->len, b->len);
if (ret == -1) {
*status |= MPD_Malloc_error;
goto nanresult;
}
}
else {
_mpd_base_ndivmod(q, r, a, b, status);
if (mpd_isspecial(q) || mpd_isspecial(r)) {
goto nanresult;
}
qsize = q->len;
rsize = r->len;
}
qsize = _mpd_real_size(q->data, qsize);
/* resize to smaller cannot fail */
mpd_qresize(q, qsize, status);
q->len = qsize;
mpd_setdigits(q);
mpd_set_flags(q, sign_ab);
q->exp = 0;
if (q->digits > ctx->prec) {
*status |= MPD_Division_impossible;
goto nanresult;
}
rsize = _mpd_real_size(r->data, rsize);
/* resize to smaller cannot fail */
mpd_qresize(r, rsize, status);
r->len = rsize;
mpd_setdigits(r);
mpd_set_flags(r, sign_a);
r->exp = ideal_exp;
out:
mpd_del(&aligned);
return;
nanresult:
mpd_setspecial(q, MPD_POS, MPD_NAN);
mpd_setspecial(r, MPD_POS, MPD_NAN);
goto out;
}
/* Integer division with remainder. */
void
mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
uint8_t sign = mpd_sign(a)^mpd_sign(b);
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(q, a, b, ctx, status)) {
mpd_qcopy(r, q, status);
return;
}
if (mpd_isinfinite(a)) {
if (mpd_isinfinite(b)) {
mpd_setspecial(q, MPD_POS, MPD_NAN);
}
else {
mpd_setspecial(q, sign, MPD_INF);
}
mpd_setspecial(r, MPD_POS, MPD_NAN);
*status |= MPD_Invalid_operation;
return;
}
if (mpd_isinfinite(b)) {
if (!mpd_qcopy(r, a, status)) {
mpd_seterror(q, MPD_Malloc_error, status);
return;
}
mpd_qfinalize(r, ctx, status);
_settriple(q, sign, 0, 0);
return;
}
/* debug */
abort(); /* GCOV_NOT_REACHED */
}
if (mpd_iszerocoeff(b)) {
if (mpd_iszerocoeff(a)) {
mpd_setspecial(q, MPD_POS, MPD_NAN);
mpd_setspecial(r, MPD_POS, MPD_NAN);
*status |= MPD_Division_undefined;
}
else {
mpd_setspecial(q, sign, MPD_INF);
mpd_setspecial(r, MPD_POS, MPD_NAN);
*status |= (MPD_Division_by_zero|MPD_Invalid_operation);
}
return;
}
_mpd_qdivmod(q, r, a, b, ctx, status);
mpd_qfinalize(q, ctx, status);
mpd_qfinalize(r, ctx, status);
}
void
mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
MPD_NEW_STATIC(r,0,0,0,0);
uint8_t sign = mpd_sign(a)^mpd_sign(b);
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(q, a, b, ctx, status)) {
return;
}
if (mpd_isinfinite(a) && mpd_isinfinite(b)) {
mpd_seterror(q, MPD_Invalid_operation, status);
return;
}
if (mpd_isinfinite(a)) {
mpd_setspecial(q, sign, MPD_INF);
return;
}
if (mpd_isinfinite(b)) {
_settriple(q, sign, 0, 0);
return;
}
__builtin_unreachable();
}
if (mpd_iszerocoeff(b)) {
if (mpd_iszerocoeff(a)) {
mpd_seterror(q, MPD_Division_undefined, status);
}
else {
mpd_setspecial(q, sign, MPD_INF);
*status |= MPD_Division_by_zero;
}
return;
}
_mpd_qdivmod(q, &r, a, b, ctx, status);
mpd_del(&r);
mpd_qfinalize(q, ctx, status);
}
/* Divide decimal by mpd_ssize_t. */
void
mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_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_qsset_ssize(&bb, b, &maxcontext, status);
mpd_qdiv(result, a, &bb, ctx, status);
mpd_del(&bb);
}
/* Divide decimal by mpd_uint_t. */
void
mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_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_qsset_uint(&bb, b, &maxcontext, status);
mpd_qdiv(result, a, &bb, ctx, status);
mpd_del(&bb);
}
/* Divide decimal by int32_t. */
void
mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qdiv_ssize(result, a, b, ctx, status);
}
/* Divide decimal by uint32_t. */
void
mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qdiv_uint(result, a, b, ctx, status);
}
/* 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_qdiv_ssize(result, a, b, ctx, status);
}
/* 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_qdiv_uint(result, a, b, ctx, status);
}
/* Pad the result with trailing zeros if it has fewer digits than prec. */
static void
_mpd_zeropad(mpd_t *result, const mpd_context_t *ctx, uint32_t *status)
{
if (!mpd_isspecial(result) && !mpd_iszero(result) &&
result->digits < ctx->prec) {
mpd_ssize_t shift = ctx->prec - result->digits;
mpd_qshiftl(result, result, shift, status);
result->exp -= shift;
}
}
/* Check if the result is guaranteed to be one. */
static int
_mpd_qexp_check_one(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
MPD_NEW_CONST(lim,0,-(ctx->prec+1),1,1,1,9);
MPD_NEW_SHARED(aa, a);
mpd_set_positive(&aa);
/* abs(a) <= 9 * 10**(-prec-1) */
if (_mpd_cmp(&aa, &lim) <= 0) {
_settriple(result, 0, 1, 0);
*status |= MPD_Rounded|MPD_Inexact;
return 1;
}
return 0;
}
/*
* Get the number of iterations for the Horner scheme in _mpd_qexp().
*/
static inline mpd_ssize_t
_mpd_get_exp_iterations(const mpd_t *r, mpd_ssize_t p)
{
mpd_ssize_t log10pbyr; /* lower bound for log10(p / abs(r)) */
mpd_ssize_t n;
assert(p >= 10);
assert(!mpd_iszero(r));
assert(-p < mpd_adjexp(r) && mpd_adjexp(r) <= -1);
if (p > (mpd_ssize_t)(1ULL<<52)) {
return MPD_SSIZE_MAX;
}
/*
* Lower bound for log10(p / abs(r)): adjexp(p) - (adjexp(r) + 1)
* At this point (for CONFIG_64, CONFIG_32 is not problematic):
* 1) 10 <= p <= 2**52
* 2) -p < adjexp(r) <= -1
* 3) 1 <= log10pbyr <= 2**52 + 14
*/
log10pbyr = (mpd_word_digits(p)-1) - (mpd_adjexp(r)+1);
/*
* The numerator in the paper is 1.435 * p - 1.182, calculated
* exactly. We compensate for rounding errors by using 1.43503.
* ACL2 proofs:
* 1) exp-iter-approx-lower-bound: The term below evaluated
* in 53-bit floating point arithmetic is greater than or
* equal to the exact term used in the paper.
* 2) exp-iter-approx-upper-bound: The term below is less than
* or equal to 3/2 * p <= 3/2 * 2**52.
*/
n = (mpd_ssize_t)ceil((1.43503*(double)p - 1.182) / (double)log10pbyr);
return n >= 3 ? n : 3;
}
/*
* Internal function, specials have been dealt with. Apart from Overflow
* and Underflow, two cases must be considered for the error of the result:
*
* 1) abs(a) <= 9 * 10**(-prec-1) ==> result == 1
*
* Absolute error: abs(1 - e**x) < 10**(-prec)
* -------------------------------------------
*
* 2) abs(a) > 9 * 10**(-prec-1)
*
* Relative error: abs(result - e**x) < 0.5 * 10**(-prec) * e**x
* -------------------------------------------------------------
*
* The algorithm is from Hull&Abrham, Variable Precision Exponential Function,
* ACM Transactions on Mathematical Software, Vol. 12, No. 2, June 1986.
*
* Main differences:
*
* - The number of iterations for the Horner scheme is calculated using
* 53-bit floating point arithmetic.
*
* - In the error analysis for ER (relative error accumulated in the
* evaluation of the truncated series) the reduced operand r may
* have any number of digits.
* ACL2 proof: exponent-relative-error
*
* - The analysis for early abortion has been adapted for the mpd_t
* ranges.
*/
static void
_mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx;
MPD_NEW_STATIC(tmp,0,0,0,0);
MPD_NEW_STATIC(sum,0,0,0,0);
MPD_NEW_CONST(word,0,0,1,1,1,1);
mpd_ssize_t j, n, t;
assert(!mpd_isspecial(a));
if (mpd_iszerocoeff(a)) {
_settriple(result, MPD_POS, 1, 0);
return;
}
/*
* We are calculating e^x = e^(r*10^t) = (e^r)^(10^t), where abs(r) < 1 and t >= 0.
*
* If t > 0, we have:
*
* (1) 0.1 <= r < 1, so e^0.1 <= e^r. If t > MAX_T, overflow occurs:
*
* MAX-EMAX+1 < log10(e^(0.1*10*t)) <= log10(e^(r*10^t)) < adjexp(e^(r*10^t))+1
*
* (2) -1 < r <= -0.1, so e^r <= e^-0.1. If t > MAX_T, underflow occurs:
*
* adjexp(e^(r*10^t)) <= log10(e^(r*10^t)) <= log10(e^(-0.1*10^t)) < MIN-ETINY
*/
#define MPD_EXP_MAX_T 19
t = a->digits + a->exp;
t = (t > 0) ? t : 0;
if (t > MPD_EXP_MAX_T) {
if (mpd_ispositive(a)) {
mpd_setspecial(result, MPD_POS, MPD_INF);
*status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
}
else {
_settriple(result, MPD_POS, 0, mpd_etiny(ctx));
*status |= (MPD_Inexact|MPD_Rounded|MPD_Subnormal|
MPD_Underflow|MPD_Clamped);
}
return;
}
/* abs(a) <= 9 * 10**(-prec-1) */
if (_mpd_qexp_check_one(result, a, ctx, status)) {
return;
}
mpd_maxcontext(&workctx);
workctx.prec = ctx->prec + t + 2;
workctx.prec = (workctx.prec < 10) ? 10 : workctx.prec;
workctx.round = MPD_ROUND_HALF_EVEN;
if (!mpd_qcopy(result, a, status)) {
return;
}
result->exp -= t;
/*
* At this point:
* 1) 9 * 10**(-prec-1) < abs(a)
* 2) 9 * 10**(-prec-t-1) < abs(r)
* 3) log10(9) - prec - t - 1 < log10(abs(r)) < adjexp(abs(r)) + 1
* 4) - prec - t - 2 < adjexp(abs(r)) <= -1
*/
n = _mpd_get_exp_iterations(result, workctx.prec);
if (n == MPD_SSIZE_MAX) {
mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_UNLIKELY */
return; /* GCOV_UNLIKELY */
}
_settriple(&sum, MPD_POS, 1, 0);
for (j = n-1; j >= 1; j--) {
word.data[0] = j;
mpd_setdigits(&word);
mpd_qdiv(&tmp, result, &word, &workctx, &workctx.status);
mpd_qfma(&sum, &sum, &tmp, &one, &workctx, &workctx.status);
}
_mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status);
mpd_del(&tmp);
mpd_del(&sum);
*status |= (workctx.status&MPD_Errors);
*status |= (MPD_Inexact|MPD_Rounded);
}
/* exp(a) */
void
mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx;
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
if (mpd_isnegative(a)) {
_settriple(result, MPD_POS, 0, 0);
}
else {
mpd_setspecial(result, MPD_POS, MPD_INF);
}
return;
}
if (mpd_iszerocoeff(a)) {
_settriple(result, MPD_POS, 1, 0);
return;
}
workctx = *ctx;
workctx.round = MPD_ROUND_HALF_EVEN;
if (ctx->allcr) {
MPD_NEW_STATIC(t1, 0,0,0,0);
MPD_NEW_STATIC(t2, 0,0,0,0);
MPD_NEW_STATIC(ulp, 0,0,0,0);
MPD_NEW_STATIC(aa, 0,0,0,0);
mpd_ssize_t prec;
mpd_ssize_t ulpexp;
uint32_t workstatus;
if (result == a) {
if (!mpd_qcopy(&aa, a, status)) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
a = &aa;
}
workctx.clamp = 0;
prec = ctx->prec + 3;
while (1) {
workctx.prec = prec;
workstatus = 0;
_mpd_qexp(result, a, &workctx, &workstatus);
*status |= workstatus;
ulpexp = result->exp + result->digits - workctx.prec;
if (workstatus & MPD_Underflow) {
/* The effective work precision is result->digits. */
ulpexp = result->exp;
}
_ssettriple(&ulp, MPD_POS, 1, ulpexp);
/*
* At this point [1]:
* 1) abs(result - e**x) < 0.5 * 10**(-prec) * e**x
* 2) result - ulp < e**x < result + ulp
* 3) result - ulp < result < result + ulp
*
* If round(result-ulp)==round(result+ulp), then
* round(result)==round(e**x). Therefore the result
* is correctly rounded.
*
* [1] If abs(a) <= 9 * 10**(-prec-1), use the absolute
* error for a similar argument.
*/
workctx.prec = ctx->prec;
mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
mpd_qcmp(&t1, &t2, status) == 0) {
workctx.clamp = ctx->clamp;
_mpd_zeropad(result, &workctx, status);
mpd_check_underflow(result, &workctx, status);
mpd_qfinalize(result, &workctx, status);
break;
}
prec += MPD_RDIGITS;
}
mpd_del(&t1);
mpd_del(&t2);
mpd_del(&ulp);
mpd_del(&aa);
}
else {
_mpd_qexp(result, a, &workctx, status);
_mpd_zeropad(result, &workctx, status);
mpd_check_underflow(result, &workctx, status);
mpd_qfinalize(result, &workctx, status);
}
}
/* Fused multiply-add: (a * b) + c, with a single final rounding. */
void
mpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_t *cc = NULL;
if (result == c) {
if ((cc = mpd_qncopy(c)) == NULL) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
c = cc;
}
_mpd_qmul(result, a, b, ctx, &workstatus);
if (!(workstatus&MPD_Invalid_operation)) {
mpd_qadd(result, result, c, ctx, &workstatus);
}
if (cc) mpd_del(cc);
*status |= workstatus;
}
/*
* Schedule the optimal precision increase for the Newton iteration.
* v := input operand
* z_0 := initial approximation
* initprec := natural number such that abs(log(v) - z_0) < 10**-initprec
* maxprec := target precision
*
* For convenience the output klist contains the elements in reverse order:
* klist := [k_n-1, ..., k_0], where
* 1) k_0 <= initprec and
* 2) abs(log(v) - result) < 10**(-2*k_n-1 + 1) <= 10**-maxprec.
*/
static inline int
ln_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], mpd_ssize_t maxprec,
mpd_ssize_t initprec)
{
mpd_ssize_t k;
int i;
assert(maxprec >= 2 && initprec >= 2);
if (maxprec <= initprec) return -1;
i = 0; k = maxprec;
do {
k = (k+2) / 2;
klist[i++] = k;
} while (k > initprec);
return i-1;
}
#if MPD_RDIGITS != 19
#error "mpdecimal.c: MPD_RDIGITS must be 19."
#endif
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
/* The constants have been verified with both decimal.py and mpfr. */
static const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = {
6983716328982174407ULL, 9089704281976336583ULL, 1515961135648465461ULL,
4416816335727555703ULL, 2900988039194170265ULL, 2307925037472986509ULL,
107598438319191292ULL, 3466624107184669231ULL, 4450099781311469159ULL,
9807828059751193854ULL, 7713456862091670584ULL, 1492198849978748873ULL,
6528728696511086257ULL, 2385392051446341972ULL, 8692180205189339507ULL,
6518769751037497088ULL, 2375253577097505395ULL, 9095610299291824318ULL,
982748238504564801ULL, 5438635917781170543ULL, 7547331541421808427ULL,
752371033310119785ULL, 3171643095059950878ULL, 9785265383207606726ULL,
2932258279850258550ULL, 5497347726624257094ULL, 2976979522110718264ULL,
9221477656763693866ULL, 1979650047149510504ULL, 6674183485704422507ULL,
9702766860595249671ULL, 9278096762712757753ULL, 9314848524948644871ULL,
6826928280848118428ULL, 754403708474699401ULL, 230105703089634572ULL,
1929203337658714166ULL, 7589402567763113569ULL, 4208241314695689016ULL,
2922455440575892572ULL, 9356734206705811364ULL, 2684916746550586856ULL,
644507064800027750ULL, 9476834636167921018ULL, 5659121373450747856ULL,
2835522011480466371ULL, 6470806855677432162ULL, 7141748003688084012ULL,
9619404400222105101ULL, 5504893431493939147ULL, 6674744042432743651ULL,
2287698219886746543ULL, 7773262884616336622ULL, 1985283935053089653ULL,
4680843799894826233ULL, 8168948290720832555ULL, 8067566662873690987ULL,
6248633409525465082ULL, 9829834196778404228ULL, 3524802359972050895ULL,
3327900967572609677ULL, 110148862877297603ULL, 179914546843642076ULL,
2302585092994045684ULL
};
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
/* _mpd_ln10 is used directly for precisions smaller than MINALLOC_MAX*RDIGITS.
Otherwise, it serves as the initial approximation for calculating ln(10). */
static const mpd_t _mpd_ln10 = {
MPD_STATIC|MPD_CONST_DATA, -(MPD_MINALLOC_MAX*MPD_RDIGITS-1),
MPD_MINALLOC_MAX*MPD_RDIGITS, MPD_MINALLOC_MAX, MPD_MINALLOC_MAX,
(mpd_uint_t *)mpd_ln10_data
};
/*
* Set 'result' to log(10).
* Ulp error: abs(result - log(10)) < ulp(log(10))
* Relative error: abs(result - log(10)) < 5 * 10**-prec * log(10)
*
* NOTE: The relative error is not derived from the ulp error, but
* calculated separately using the fact that 23/10 < log(10) < 24/10.
*/
void
mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status)
{
mpd_context_t varcontext, maxcontext;
MPD_NEW_STATIC(tmp, 0,0,0,0);
MPD_NEW_CONST(static10, 0,0,2,1,1,10);
mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
mpd_uint_t rnd;
mpd_ssize_t shift;
int i;
assert(prec >= 1);
shift = MPD_MINALLOC_MAX*MPD_RDIGITS-prec;
shift = shift < 0 ? 0 : shift;
rnd = mpd_qshiftr(result, &_mpd_ln10, shift, status);
if (rnd == MPD_UINT_MAX) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
result->exp = -(result->digits-1);
mpd_maxcontext(&maxcontext);
if (prec < MPD_MINALLOC_MAX*MPD_RDIGITS) {
maxcontext.prec = prec;
_mpd_apply_round_excess(result, rnd, &maxcontext, status);
*status |= (MPD_Inexact|MPD_Rounded);
return;
}
mpd_maxcontext(&varcontext);
varcontext.round = MPD_ROUND_TRUNC;
i = ln_schedule_prec(klist, prec+2, -result->exp);
for (; i >= 0; i--) {
varcontext.prec = 2*klist[i]+3;
result->flags ^= MPD_NEG;
_mpd_qexp(&tmp, result, &varcontext, status);
result->flags ^= MPD_NEG;
mpd_qmul(&tmp, &static10, &tmp, &varcontext, status);
mpd_qsub(&tmp, &tmp, &one, &maxcontext, status);
mpd_qadd(result, result, &tmp, &maxcontext, status);
if (mpd_isspecial(result)) {
break;
}
}
mpd_del(&tmp);
maxcontext.prec = prec;
mpd_qfinalize(result, &maxcontext, status);
}
/*
* Initial approximations for the ln() iteration. The values have the
* following properties (established with both decimal.py and mpfr):
*
* Index 0 - 400, logarithms of x in [1.00, 5.00]:
* abs(lnapprox[i] * 10**-3 - log((i+100)/100)) < 10**-2
* abs(lnapprox[i] * 10**-3 - log((i+1+100)/100)) < 10**-2
*
* Index 401 - 899, logarithms of x in (0.500, 0.999]:
* abs(-lnapprox[i] * 10**-3 - log((i+100)/1000)) < 10**-2
* abs(-lnapprox[i] * 10**-3 - log((i+1+100)/1000)) < 10**-2
*/
static const uint16_t lnapprox[900] = {
/* index 0 - 400: log((i+100)/100) * 1000 */
0, 10, 20, 30, 39, 49, 58, 68, 77, 86, 95, 104, 113, 122, 131, 140, 148, 157,
166, 174, 182, 191, 199, 207, 215, 223, 231, 239, 247, 255, 262, 270, 278,
285, 293, 300, 308, 315, 322, 329, 336, 344, 351, 358, 365, 372, 378, 385,
392, 399, 406, 412, 419, 425, 432, 438, 445, 451, 457, 464, 470, 476, 482,
489, 495, 501, 507, 513, 519, 525, 531, 536, 542, 548, 554, 560, 565, 571,
577, 582, 588, 593, 599, 604, 610, 615, 621, 626, 631, 637, 642, 647, 652,
658, 663, 668, 673, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728,
732, 737, 742, 747, 751, 756, 761, 766, 770, 775, 779, 784, 788, 793, 798,
802, 806, 811, 815, 820, 824, 829, 833, 837, 842, 846, 850, 854, 859, 863,
867, 871, 876, 880, 884, 888, 892, 896, 900, 904, 908, 912, 916, 920, 924,
928, 932, 936, 940, 944, 948, 952, 956, 959, 963, 967, 971, 975, 978, 982,
986, 990, 993, 997, 1001, 1004, 1008, 1012, 1015, 1019, 1022, 1026, 1030,
1033, 1037, 1040, 1044, 1047, 1051, 1054, 1058, 1061, 1065, 1068, 1072, 1075,
1078, 1082, 1085, 1089, 1092, 1095, 1099, 1102, 1105, 1109, 1112, 1115, 1118,
1122, 1125, 1128, 1131, 1135, 1138, 1141, 1144, 1147, 1151, 1154, 1157, 1160,
1163, 1166, 1169, 1172, 1176, 1179, 1182, 1185, 1188, 1191, 1194, 1197, 1200,
1203, 1206, 1209, 1212, 1215, 1218, 1221, 1224, 1227, 1230, 1233, 1235, 1238,
1241, 1244, 1247, 1250, 1253, 1256, 1258, 1261, 1264, 1267, 1270, 1273, 1275,
1278, 1281, 1284, 1286, 1289, 1292, 1295, 1297, 1300, 1303, 1306, 1308, 1311,
1314, 1316, 1319, 1322, 1324, 1327, 1330, 1332, 1335, 1338, 1340, 1343, 1345,
1348, 1351, 1353, 1356, 1358, 1361, 1364, 1366, 1369, 1371, 1374, 1376, 1379,
1381, 1384, 1386, 1389, 1391, 1394, 1396, 1399, 1401, 1404, 1406, 1409, 1411,
1413, 1416, 1418, 1421, 1423, 1426, 1428, 1430, 1433, 1435, 1437, 1440, 1442,
1445, 1447, 1449, 1452, 1454, 1456, 1459, 1461, 1463, 1466, 1468, 1470, 1472,
1475, 1477, 1479, 1482, 1484, 1486, 1488, 1491, 1493, 1495, 1497, 1500, 1502,
1504, 1506, 1509, 1511, 1513, 1515, 1517, 1520, 1522, 1524, 1526, 1528, 1530,
1533, 1535, 1537, 1539, 1541, 1543, 1545, 1548, 1550, 1552, 1554, 1556, 1558,
1560, 1562, 1564, 1567, 1569, 1571, 1573, 1575, 1577, 1579, 1581, 1583, 1585,
1587, 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1609,
/* index 401 - 899: -log((i+100)/1000) * 1000 */
691, 689, 687, 685, 683, 681, 679, 677, 675, 673, 671, 669, 668, 666, 664,
662, 660, 658, 656, 654, 652, 650, 648, 646, 644, 642, 641, 639, 637, 635,
633, 631, 629, 627, 626, 624, 622, 620, 618, 616, 614, 612, 611, 609, 607,
605, 603, 602, 600, 598, 596, 594, 592, 591, 589, 587, 585, 583, 582, 580,
578, 576, 574, 573, 571, 569, 567, 566, 564, 562, 560, 559, 557, 555, 553,
552, 550, 548, 546, 545, 543, 541, 540, 538, 536, 534, 533, 531, 529, 528,
526, 524, 523, 521, 519, 518, 516, 514, 512, 511, 509, 508, 506, 504, 502,
501, 499, 498, 496, 494, 493, 491, 489, 488, 486, 484, 483, 481, 480, 478,
476, 475, 473, 472, 470, 468, 467, 465, 464, 462, 460, 459, 457, 456, 454,
453, 451, 449, 448, 446, 445, 443, 442, 440, 438, 437, 435, 434, 432, 431,
429, 428, 426, 425, 423, 422, 420, 419, 417, 416, 414, 412, 411, 410, 408,
406, 405, 404, 402, 400, 399, 398, 396, 394, 393, 392, 390, 389, 387, 386,
384, 383, 381, 380, 378, 377, 375, 374, 372, 371, 370, 368, 367, 365, 364,
362, 361, 360, 358, 357, 355, 354, 352, 351, 350, 348, 347, 345, 344, 342,
341, 340, 338, 337, 336, 334, 333, 331, 330, 328, 327, 326, 324, 323, 322,
320, 319, 318, 316, 315, 313, 312, 311, 309, 308, 306, 305, 304, 302, 301,
300, 298, 297, 296, 294, 293, 292, 290, 289, 288, 286, 285, 284, 282, 281,
280, 278, 277, 276, 274, 273, 272, 270, 269, 268, 267, 265, 264, 263, 261,
260, 259, 258, 256, 255, 254, 252, 251, 250, 248, 247, 246, 245, 243, 242,
241, 240, 238, 237, 236, 234, 233, 232, 231, 229, 228, 227, 226, 224, 223,
222, 221, 219, 218, 217, 216, 214, 213, 212, 211, 210, 208, 207, 206, 205,
203, 202, 201, 200, 198, 197, 196, 195, 194, 192, 191, 190, 189, 188, 186,
185, 184, 183, 182, 180, 179, 178, 177, 176, 174, 173, 172, 171, 170, 168,
167, 166, 165, 164, 162, 161, 160, 159, 158, 157, 156, 154, 153, 152, 151,
150, 148, 147, 146, 145, 144, 143, 142, 140, 139, 138, 137, 136, 135, 134,
132, 131, 130, 129, 128, 127, 126, 124, 123, 122, 121, 120, 119, 118, 116,
115, 114, 113, 112, 111, 110, 109, 108, 106, 105, 104, 103, 102, 101, 100,
99, 98, 97, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 84, 83, 82, 81, 80, 79,
78, 77, 76, 75, 74, 73, 72, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59,
58, 57, 56, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39,
38, 37, 36, 35, 34, 33, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
};
/*
* Internal ln() function that does not check for specials, zero or one.
* Relative error: abs(result - log(a)) < 0.1 * 10**-prec * abs(log(a))
*/
static void
_mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t varcontext, maxcontext;
mpd_t *z = (mpd_t *) result;
MPD_NEW_STATIC(v,0,0,0,0);
MPD_NEW_STATIC(vtmp,0,0,0,0);
MPD_NEW_STATIC(tmp,0,0,0,0);
mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
mpd_ssize_t maxprec, shift, t;
mpd_ssize_t a_digits, a_exp;
mpd_uint_t dummy, x;
int i;
assert(!mpd_isspecial(a) && !mpd_iszerocoeff(a));
/*
* We are calculating ln(a) = ln(v * 10^t) = ln(v) + t*ln(10),
* where 0.5 < v <= 5.
*/
if (!mpd_qcopy(&v, a, status)) {
mpd_seterror(result, MPD_Malloc_error, status);
goto finish;
}
/* Initial approximation: we have at least one non-zero digit */
_mpd_get_msdigits(&dummy, &x, &v, 3);
if (x < 10) x *= 10;
if (x < 100) x *= 10;
x -= 100;
/* a may equal z */
a_digits = a->digits;
a_exp = a->exp;
mpd_minalloc(z);
mpd_clear_flags(z);
z->data[0] = lnapprox[x];
z->len = 1;
z->exp = -3;
mpd_setdigits(z);
if (x <= 400) {
/* Reduce the input operand to 1.00 <= v <= 5.00. Let y = x + 100,
* so 100 <= y <= 500. Since y contains the most significant digits
* of v, y/100 <= v < (y+1)/100 and abs(z - log(v)) < 10**-2. */
v.exp = -(a_digits - 1);
t = a_exp + a_digits - 1;
}
else {
/* Reduce the input operand to 0.500 < v <= 0.999. Let y = x + 100,
* so 500 < y <= 999. Since y contains the most significant digits
* of v, y/1000 <= v < (y+1)/1000 and abs(z - log(v)) < 10**-2. */
v.exp = -a_digits;
t = a_exp + a_digits;
mpd_set_negative(z);
}
mpd_maxcontext(&maxcontext);
mpd_maxcontext(&varcontext);
varcontext.round = MPD_ROUND_TRUNC;
maxprec = ctx->prec + 2;
if (t == 0 && (x <= 15 || x >= 800)) {
/* 0.900 <= v <= 1.15: Estimate the magnitude of the logarithm.
* If ln(v) will underflow, skip the loop. Otherwise, adjust the
* precision upwards in order to obtain a sufficient number of
* significant digits.
*
* Case v > 1:
* abs((v-1)/10) < abs((v-1)/v) < abs(ln(v)) < abs(v-1)
* Case v < 1:
* abs(v-1) < abs(ln(v)) < abs((v-1)/v) < abs((v-1)*10)
*/
int cmp = _mpd_cmp(&v, &one);
/* Upper bound (assume v > 1): abs(v-1), unrounded */
_mpd_qsub(&tmp, &v, &one, &maxcontext, &maxcontext.status);
if (maxcontext.status & MPD_Errors) {
mpd_seterror(result, MPD_Malloc_error, status);
goto finish;
}
if (cmp < 0) {
/* v < 1: abs((v-1)*10) */
tmp.exp += 1;
}
if (mpd_adjexp(&tmp) < mpd_etiny(ctx)) {
/* The upper bound is less than etiny: Underflow to zero */
_settriple(result, (cmp<0), 1, mpd_etiny(ctx)-1);
goto finish;
}
/* Lower bound: abs((v-1)/10) or abs(v-1) */
tmp.exp -= 1;
if (mpd_adjexp(&tmp) < 0) {
/* Absolute error of the loop: abs(z - log(v)) < 10**-p. If
* p = ctx->prec+2-adjexp(lower), then the relative error of
* the result is (using 10**adjexp(x) <= abs(x)):
*
* abs(z - log(v)) / abs(log(v)) < 10**-p / abs(log(v))
* <= 10**(-ctx->prec-2)
*/
maxprec = maxprec - mpd_adjexp(&tmp);
}
}
i = ln_schedule_prec(klist, maxprec, 2);
for (; i >= 0; i--) {
varcontext.prec = 2*klist[i]+3;
z->flags ^= MPD_NEG;
_mpd_qexp(&tmp, z, &varcontext, status);
z->flags ^= MPD_NEG;
if (v.digits > varcontext.prec) {
shift = v.digits - varcontext.prec;
mpd_qshiftr(&vtmp, &v, shift, status);
vtmp.exp += shift;
mpd_qmul(&tmp, &vtmp, &tmp, &varcontext, status);
}
else {
mpd_qmul(&tmp, &v, &tmp, &varcontext, status);
}
mpd_qsub(&tmp, &tmp, &one, &maxcontext, status);
mpd_qadd(z, z, &tmp, &maxcontext, status);
if (mpd_isspecial(z)) {
break;
}
}
/*
* Case t == 0:
* t * log(10) == 0, the result does not change and the analysis
* above applies. If v < 0.900 or v > 1.15, the relative error is
* less than 10**(-ctx.prec-1).
* Case t != 0:
* z := approx(log(v))
* y := approx(log(10))
* p := maxprec = ctx->prec + 2
* Absolute errors:
* 1) abs(z - log(v)) < 10**-p
* 2) abs(y - log(10)) < 10**-p
* The multiplication is exact, so:
* 3) abs(t*y - t*log(10)) < t*10**-p
* The sum is exact, so:
* 4) abs((z + t*y) - (log(v) + t*log(10))) < (abs(t) + 1) * 10**-p
* Bounds for log(v) and log(10):
* 5) -7/10 < log(v) < 17/10
* 6) 23/10 < log(10) < 24/10
* Using 4), 5), 6) and t != 0, the relative error is:
*
* 7) relerr < ((abs(t) + 1)*10**-p) / abs(log(v) + t*log(10))
* < 0.5 * 10**(-p + 1) = 0.5 * 10**(-ctx->prec-1)
*/
mpd_qln10(&v, maxprec+1, status);
mpd_qmul_ssize(&tmp, &v, t, &maxcontext, status);
mpd_qadd(result, &tmp, z, &maxcontext, status);
finish:
*status |= (MPD_Inexact|MPD_Rounded);
mpd_del(&v);
mpd_del(&vtmp);
mpd_del(&tmp);
}
/* ln(a) */
void
mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx;
mpd_ssize_t adjexp, t;
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
if (mpd_isnegative(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
mpd_setspecial(result, MPD_POS, MPD_INF);
return;
}
if (mpd_iszerocoeff(a)) {
mpd_setspecial(result, MPD_NEG, MPD_INF);
return;
}
if (mpd_isnegative(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (_mpd_cmp(a, &one) == 0) {
_settriple(result, MPD_POS, 0, 0);
return;
}
/*
* Check if the result will overflow (0 < x, x != 1):
* 1) log10(x) < 0 iff adjexp(x) < 0
* 2) 0 < x /\ x <= y ==> adjexp(x) <= adjexp(y)
* 3) 0 < x /\ x != 1 ==> 2 * abs(log10(x)) < abs(log(x))
* 4) adjexp(x) <= log10(x) < adjexp(x) + 1
*
* Case adjexp(x) >= 0:
* 5) 2 * adjexp(x) < abs(log(x))
* Case adjexp(x) > 0:
* 6) adjexp(2 * adjexp(x)) <= adjexp(abs(log(x)))
* Case adjexp(x) == 0:
* mpd_exp_digits(t)-1 == 0 <= emax (the shortcut is not triggered)
*
* Case adjexp(x) < 0:
* 7) 2 * (-adjexp(x) - 1) < abs(log(x))
* Case adjexp(x) < -1:
* 8) adjexp(2 * (-adjexp(x) - 1)) <= adjexp(abs(log(x)))
* Case adjexp(x) == -1:
* mpd_exp_digits(t)-1 == 0 <= emax (the shortcut is not triggered)
*/
adjexp = mpd_adjexp(a);
t = (adjexp < 0) ? -adjexp-1 : adjexp;
t *= 2;
if (mpd_exp_digits(t)-1 > ctx->emax) {
*status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
mpd_setspecial(result, (adjexp<0), MPD_INF);
return;
}
workctx = *ctx;
workctx.round = MPD_ROUND_HALF_EVEN;
if (ctx->allcr) {
MPD_NEW_STATIC(t1, 0,0,0,0);
MPD_NEW_STATIC(t2, 0,0,0,0);
MPD_NEW_STATIC(ulp, 0,0,0,0);
MPD_NEW_STATIC(aa, 0,0,0,0);
mpd_ssize_t prec;
if (result == a) {
if (!mpd_qcopy(&aa, a, status)) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
a = &aa;
}
workctx.clamp = 0;
prec = ctx->prec + 3;
while (1) {
workctx.prec = prec;
_mpd_qln(result, a, &workctx, status);
_ssettriple(&ulp, MPD_POS, 1,
result->exp + result->digits-workctx.prec);
workctx.prec = ctx->prec;
mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
mpd_qcmp(&t1, &t2, status) == 0) {
workctx.clamp = ctx->clamp;
mpd_check_underflow(result, &workctx, status);
mpd_qfinalize(result, &workctx, status);
break;
}
prec += MPD_RDIGITS;
}
mpd_del(&t1);
mpd_del(&t2);
mpd_del(&ulp);
mpd_del(&aa);
}
else {
_mpd_qln(result, a, &workctx, status);
mpd_check_underflow(result, &workctx, status);
mpd_qfinalize(result, &workctx, status);
}
}
/*
* Internal log10() function that does not check for specials, zero or one.
* Case SKIP_FINALIZE:
* Relative error: abs(result - log10(a)) < 0.1 * 10**-prec * abs(log10(a))
* Case DO_FINALIZE:
* Ulp error: abs(result - log10(a)) < ulp(log10(a))
*/
enum {SKIP_FINALIZE, DO_FINALIZE};
static void
_mpd_qlog10(int action, mpd_t *result, const mpd_t *a,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_context_t workctx;
MPD_NEW_STATIC(ln10,0,0,0,0);
mpd_maxcontext(&workctx);
workctx.prec = ctx->prec + 3;
/* relative error: 0.1 * 10**(-p-3). The specific underflow shortcut
* in _mpd_qln() does not change the final result. */
_mpd_qln(result, a, &workctx, status);
/* relative error: 5 * 10**(-p-3) */
mpd_qln10(&ln10, workctx.prec, status);
if (action == DO_FINALIZE) {
workctx = *ctx;
workctx.round = MPD_ROUND_HALF_EVEN;
}
/* SKIP_FINALIZE: relative error: 5 * 10**(-p-3) */
_mpd_qdiv(NO_IDEAL_EXP, result, result, &ln10, &workctx, status);
mpd_del(&ln10);
}
/* log10(a) */
void
mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx;
mpd_ssize_t adjexp, t;
workctx = *ctx;
workctx.round = MPD_ROUND_HALF_EVEN;
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
if (mpd_isnegative(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
mpd_setspecial(result, MPD_POS, MPD_INF);
return;
}
if (mpd_iszerocoeff(a)) {
mpd_setspecial(result, MPD_NEG, MPD_INF);
return;
}
if (mpd_isnegative(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (mpd_coeff_ispow10(a)) {
uint8_t sign = 0;
adjexp = mpd_adjexp(a);
if (adjexp < 0) {
sign = 1;
adjexp = -adjexp;
}
_settriple(result, sign, adjexp, 0);
mpd_qfinalize(result, &workctx, status);
return;
}
/*
* Check if the result will overflow (0 < x, x != 1):
* 1) log10(x) < 0 iff adjexp(x) < 0
* 2) 0 < x /\ x <= y ==> adjexp(x) <= adjexp(y)
* 3) adjexp(x) <= log10(x) < adjexp(x) + 1
*
* Case adjexp(x) >= 0:
* 4) adjexp(x) <= abs(log10(x))
* Case adjexp(x) > 0:
* 5) adjexp(adjexp(x)) <= adjexp(abs(log10(x)))
* Case adjexp(x) == 0:
* mpd_exp_digits(t)-1 == 0 <= emax (the shortcut is not triggered)
*
* Case adjexp(x) < 0:
* 6) -adjexp(x) - 1 < abs(log10(x))
* Case adjexp(x) < -1:
* 7) adjexp(-adjexp(x) - 1) <= adjexp(abs(log(x)))
* Case adjexp(x) == -1:
* mpd_exp_digits(t)-1 == 0 <= emax (the shortcut is not triggered)
*/
adjexp = mpd_adjexp(a);
t = (adjexp < 0) ? -adjexp-1 : adjexp;
if (mpd_exp_digits(t)-1 > ctx->emax) {
*status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
mpd_setspecial(result, (adjexp<0), MPD_INF);
return;
}
if (ctx->allcr) {
MPD_NEW_STATIC(t1, 0,0,0,0);
MPD_NEW_STATIC(t2, 0,0,0,0);
MPD_NEW_STATIC(ulp, 0,0,0,0);
MPD_NEW_STATIC(aa, 0,0,0,0);
mpd_ssize_t prec;
if (result == a) {
if (!mpd_qcopy(&aa, a, status)) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
a = &aa;
}
workctx.clamp = 0;
prec = ctx->prec + 3;
while (1) {
workctx.prec = prec;
_mpd_qlog10(SKIP_FINALIZE, result, a, &workctx, status);
_ssettriple(&ulp, MPD_POS, 1,
result->exp + result->digits-workctx.prec);
workctx.prec = ctx->prec;
mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
mpd_qcmp(&t1, &t2, status) == 0) {
workctx.clamp = ctx->clamp;
mpd_check_underflow(result, &workctx, status);
mpd_qfinalize(result, &workctx, status);
break;
}
prec += MPD_RDIGITS;
}
mpd_del(&t1);
mpd_del(&t2);
mpd_del(&ulp);
mpd_del(&aa);
}
else {
_mpd_qlog10(DO_FINALIZE, result, a, &workctx, status);
mpd_check_underflow(result, &workctx, status);
}
}
/*
* Maximum of the two operands. Attention: If one operand is a quiet NaN and the
* other is numeric, the numeric operand is returned. This may not be what one
* expects.
*/
void
mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
int c;
if (mpd_isqnan(a) && !mpd_isnan(b)) {
mpd_qcopy(result, b, status);
}
else if (mpd_isqnan(b) && !mpd_isnan(a)) {
mpd_qcopy(result, a, status);
}
else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
else {
c = _mpd_cmp(a, b);
if (c == 0) {
c = _mpd_cmp_numequal(a, b);
}
if (c < 0) {
mpd_qcopy(result, b, status);
}
else {
mpd_qcopy(result, a, status);
}
}
mpd_qfinalize(result, ctx, status);
}
/*
* Maximum magnitude: Same as mpd_max(), but compares the operands with their
* sign ignored.
*/
void
mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
int c;
if (mpd_isqnan(a) && !mpd_isnan(b)) {
mpd_qcopy(result, b, status);
}
else if (mpd_isqnan(b) && !mpd_isnan(a)) {
mpd_qcopy(result, a, status);
}
else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
else {
c = _mpd_cmp_abs(a, b);
if (c == 0) {
c = _mpd_cmp_numequal(a, b);
}
if (c < 0) {
mpd_qcopy(result, b, status);
}
else {
mpd_qcopy(result, a, status);
}
}
mpd_qfinalize(result, ctx, status);
}
/*
* Minimum of the two operands. Attention: If one operand is a quiet NaN and the
* other is numeric, the numeric operand is returned. This may not be what one
* expects.
*/
void
mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
int c;
if (mpd_isqnan(a) && !mpd_isnan(b)) {
mpd_qcopy(result, b, status);
}
else if (mpd_isqnan(b) && !mpd_isnan(a)) {
mpd_qcopy(result, a, status);
}
else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
else {
c = _mpd_cmp(a, b);
if (c == 0) {
c = _mpd_cmp_numequal(a, b);
}
if (c < 0) {
mpd_qcopy(result, a, status);
}
else {
mpd_qcopy(result, b, status);
}
}
mpd_qfinalize(result, ctx, status);
}
/*
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
* Minimum magnitude: Same as mpd_min(), but compares the operands with
* their sign ignored.
*/
void
mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
int c;
if (mpd_isqnan(a) && !mpd_isnan(b)) {
mpd_qcopy(result, b, status);
}
else if (mpd_isqnan(b) && !mpd_isnan(a)) {
mpd_qcopy(result, a, status);
}
else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
else {
c = _mpd_cmp_abs(a, b);
if (c == 0) {
c = _mpd_cmp_numequal(a, b);
}
if (c < 0) {
mpd_qcopy(result, a, status);
}
else {
mpd_qcopy(result, b, status);
}
}
mpd_qfinalize(result, ctx, status);
}
/* Minimum space needed for the result array in _karatsuba_rec(). */
static inline mpd_size_t
_kmul_resultsize(mpd_size_t la, mpd_size_t lb)
{
mpd_size_t n, m;
n = add_size_t(la, lb);
n = add_size_t(n, 1);
m = (la+1)/2 + 1;
m = mul_size_t(m, 3);
return (m > n) ? m : n;
}
/* Work space needed in _karatsuba_rec(). lim >= 4 */
static inline mpd_size_t
_kmul_worksize(mpd_size_t n, mpd_size_t lim)
{
mpd_size_t m;
if (n <= lim) {
return 0;
}
m = (n+1)/2 + 1;
return add_size_t(mul_size_t(m, 2), _kmul_worksize(m, lim));
}
#define MPD_KARATSUBA_BASECASE 16 /* must be >= 4 */
/*
* Add the product of a and b to c.
* c must be _kmul_resultsize(la, lb) in size.
* w is used as a work array and must be _kmul_worksize(a, lim) in size.
* Roman E. Maeder, Storage Allocation for the Karatsuba Integer Multiplication
* Algorithm. In "Design and implementation of symbolic computation systems",
* Springer, 1993, ISBN 354057235X, 9783540572350.
*/
static void
_karatsuba_rec(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b,
mpd_uint_t *w, mpd_size_t la, mpd_size_t lb)
{
mpd_size_t m, lt;
assert(la >= lb && lb > 0);
assert(la <= MPD_KARATSUBA_BASECASE || w != NULL);
if (la <= MPD_KARATSUBA_BASECASE) {
_mpd_basemul(c, a, b, la, lb);
return;
}
m = (la+1)/2; /* ceil(la/2) */
/* lb <= m < la */
if (lb <= m) {
/* lb can now be larger than la-m */
if (lb > la-m) {
lt = lb + lb + 1; /* space needed for result array */
mpd_uint_zero(w, lt); /* clear result array */
_karatsuba_rec(w, b, a+m, w+lt, lb, la-m); /* b*ah */
}
else {
lt = (la-m) + (la-m) + 1; /* space needed for result array */
mpd_uint_zero(w, lt); /* clear result array */
_karatsuba_rec(w, a+m, b, w+lt, la-m, lb); /* ah*b */
}
_mpd_baseaddto(c+m, w, (la-m)+lb); /* add ah*b*B**m */
lt = m + m + 1; /* space needed for the result array */
mpd_uint_zero(w, lt); /* clear result array */
_karatsuba_rec(w, a, b, w+lt, m, lb); /* al*b */
_mpd_baseaddto(c, w, m+lb); /* add al*b */
return;
}
/* la >= lb > m */
memcpy(w, a, m * sizeof *w);
w[m] = 0;
_mpd_baseaddto(w, a+m, la-m);
memcpy(w+(m+1), b, m * sizeof *w);
w[m+1+m] = 0;
_mpd_baseaddto(w+(m+1), b+m, lb-m);
_karatsuba_rec(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1);
lt = (la-m) + (la-m) + 1;
mpd_uint_zero(w, lt);
_karatsuba_rec(w, a+m, b+m, w+lt, la-m, lb-m);
_mpd_baseaddto(c+2*m, w, (la-m) + (lb-m));
_mpd_basesubfrom(c+m, w, (la-m) + (lb-m));
lt = m + m + 1;
mpd_uint_zero(w, lt);
_karatsuba_rec(w, a, b, w+lt, m, m);
_mpd_baseaddto(c, w, m+m);
_mpd_basesubfrom(c+m, w, m+m);
return;
}
/*
* Multiply u and v, using Karatsuba multiplication. Returns a pointer
* to the result or NULL in case of failure (malloc error).
* Conditions: ulen >= vlen, ulen >= 4
*/
static mpd_uint_t *
_mpd_kmul(const mpd_uint_t *u, const mpd_uint_t *v,
mpd_size_t ulen, mpd_size_t vlen,
mpd_size_t *rsize)
{
mpd_uint_t *result = NULL, *w = NULL;
mpd_size_t m;
assert(ulen >= 4);
assert(ulen >= vlen);
*rsize = _kmul_resultsize(ulen, vlen);
if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) {
return NULL;
}
m = _kmul_worksize(ulen, MPD_KARATSUBA_BASECASE);
if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) {
mpd_free(result);
return NULL;
}
_karatsuba_rec(result, u, v, w, ulen, vlen);
if (w) mpd_free(w);
return result;
}
/*
* Determine the minimum length for the number theoretic transform. Valid
* transform lengths are 2**n or 3*2**n, where 2**n <= MPD_MAXTRANSFORM_2N.
* The function finds the shortest length m such that rsize <= m.
*/
static inline mpd_size_t
_mpd_get_transform_len(mpd_size_t rsize)
{
mpd_size_t log2rsize;
mpd_size_t x, step;
assert(rsize >= 4);
log2rsize = mpd_bsr(rsize);
if (rsize <= 1024) {
/* 2**n is faster in this range. */
x = ((mpd_size_t)1)<<log2rsize;
return (rsize == x) ? x : x<<1;
}
else if (rsize <= MPD_MAXTRANSFORM_2N) {
x = ((mpd_size_t)1)<<log2rsize;
if (rsize == x) return x;
step = x>>1;
x += step;
return (rsize <= x) ? x : x + step;
}
else if (rsize <= MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2) {
return MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2;
}
else if (rsize <= 3*MPD_MAXTRANSFORM_2N) {
return 3*MPD_MAXTRANSFORM_2N;
}
else {
return MPD_SIZE_MAX;
}
}
/*
* Multiply u and v, using the fast number theoretic transform. Returns
* a pointer to the result or NULL in case of failure (malloc error).
*/
static mpd_uint_t *
_mpd_fntmul(const mpd_uint_t *u, const mpd_uint_t *v,
mpd_size_t ulen, mpd_size_t vlen,
mpd_size_t *rsize)
{
mpd_uint_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *vtmp = NULL;
mpd_size_t n;
*rsize = add_size_t(ulen, vlen);
if ((n = _mpd_get_transform_len(*rsize)) == MPD_SIZE_MAX) {
goto malloc_error;
}
if ((c1 = mpd_calloc(n, sizeof *c1)) == NULL) {
goto malloc_error;
}
if ((c2 = mpd_calloc(n, sizeof *c2)) == NULL) {
goto malloc_error;
}
if ((c3 = mpd_calloc(n, sizeof *c3)) == NULL) {
goto malloc_error;
}
memcpy(c1, u, ulen * (sizeof *c1));
memcpy(c2, u, ulen * (sizeof *c2));
memcpy(c3, u, ulen * (sizeof *c3));
if (u == v) {
if (!fnt_autoconvolute(c1, n, P1) ||
!fnt_autoconvolute(c2, n, P2) ||
!fnt_autoconvolute(c3, n, P3)) {
goto malloc_error;
}
}
else {
if ((vtmp = mpd_calloc(n, sizeof *vtmp)) == NULL) {
goto malloc_error;
}
memcpy(vtmp, v, vlen * (sizeof *vtmp));
if (!fnt_convolute(c1, vtmp, n, P1)) {
mpd_free(vtmp);
goto malloc_error;
}
memcpy(vtmp, v, vlen * (sizeof *vtmp));
mpd_uint_zero(vtmp+vlen, n-vlen);
if (!fnt_convolute(c2, vtmp, n, P2)) {
mpd_free(vtmp);
goto malloc_error;
}
memcpy(vtmp, v, vlen * (sizeof *vtmp));
mpd_uint_zero(vtmp+vlen, n-vlen);
if (!fnt_convolute(c3, vtmp, n, P3)) {
mpd_free(vtmp);
goto malloc_error;
}
mpd_free(vtmp);
}
crt3(c1, c2, c3, *rsize);
out:
if (c2) mpd_free(c2);
if (c3) mpd_free(c3);
return c1;
malloc_error:
if (c1) mpd_free(c1);
c1 = NULL;
goto out;
}
/*
* Karatsuba multiplication with FNT/basemul as the base case.
*/
static int
_karatsuba_rec_fnt(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b,
mpd_uint_t *w, mpd_size_t la, mpd_size_t lb)
{
mpd_size_t m, lt;
assert(la >= lb && lb > 0);
assert(la <= 3*(MPD_MAXTRANSFORM_2N/2) || w != NULL);
if (la <= 3*(MPD_MAXTRANSFORM_2N/2)) {
if (lb <= 192) {
_mpd_basemul(c, b, a, lb, la);
}
else {
mpd_uint_t *result;
mpd_size_t dummy;
if ((result = _mpd_fntmul(a, b, la, lb, &dummy)) == NULL) {
return 0;
}
memcpy(c, result, (la+lb) * (sizeof *result));
mpd_free(result);
}
return 1;
}
m = (la+1)/2; /* ceil(la/2) */
/* lb <= m < la */
if (lb <= m) {
/* lb can now be larger than la-m */
if (lb > la-m) {
lt = lb + lb + 1; /* space needed for result array */
mpd_uint_zero(w, lt); /* clear result array */
if (!_karatsuba_rec_fnt(w, b, a+m, w+lt, lb, la-m)) { /* b*ah */
return 0; /* GCOV_UNLIKELY */
}
}
else {
lt = (la-m) + (la-m) + 1; /* space needed for result array */
mpd_uint_zero(w, lt); /* clear result array */
if (!_karatsuba_rec_fnt(w, a+m, b, w+lt, la-m, lb)) { /* ah*b */
return 0; /* GCOV_UNLIKELY */
}
}
_mpd_baseaddto(c+m, w, (la-m)+lb); /* add ah*b*B**m */
lt = m + m + 1; /* space needed for the result array */
mpd_uint_zero(w, lt); /* clear result array */
if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, lb)) { /* al*b */
return 0; /* GCOV_UNLIKELY */
}
_mpd_baseaddto(c, w, m+lb); /* add al*b */
return 1;
}
/* la >= lb > m */
memcpy(w, a, m * sizeof *w);
w[m] = 0;
_mpd_baseaddto(w, a+m, la-m);
memcpy(w+(m+1), b, m * sizeof *w);
w[m+1+m] = 0;
_mpd_baseaddto(w+(m+1), b+m, lb-m);
if (!_karatsuba_rec_fnt(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1)) {
return 0; /* GCOV_UNLIKELY */
}
lt = (la-m) + (la-m) + 1;
mpd_uint_zero(w, lt);
if (!_karatsuba_rec_fnt(w, a+m, b+m, w+lt, la-m, lb-m)) {
return 0; /* GCOV_UNLIKELY */
}
_mpd_baseaddto(c+2*m, w, (la-m) + (lb-m));
_mpd_basesubfrom(c+m, w, (la-m) + (lb-m));
lt = m + m + 1;
mpd_uint_zero(w, lt);
if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, m)) {
return 0; /* GCOV_UNLIKELY */
}
_mpd_baseaddto(c, w, m+m);
_mpd_basesubfrom(c+m, w, m+m);
return 1;
}
/*
* Multiply u and v, using Karatsuba multiplication with the FNT as the
* base case. Returns a pointer to the result or NULL in case of failure
* (malloc error). Conditions: ulen >= vlen, ulen >= 4.
*/
static mpd_uint_t *
_mpd_kmul_fnt(const mpd_uint_t *u, const mpd_uint_t *v,
mpd_size_t ulen, mpd_size_t vlen,
mpd_size_t *rsize)
{
mpd_uint_t *result = NULL, *w = NULL;
mpd_size_t m;
assert(ulen >= 4);
assert(ulen >= vlen);
*rsize = _kmul_resultsize(ulen, vlen);
if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) {
return NULL;
}
m = _kmul_worksize(ulen, 3*(MPD_MAXTRANSFORM_2N/2));
if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) {
mpd_free(result); /* GCOV_UNLIKELY */
return NULL; /* GCOV_UNLIKELY */
}
if (!_karatsuba_rec_fnt(result, u, v, w, ulen, vlen)) {
mpd_free(result);
result = NULL;
}
if (w) mpd_free(w);
return result;
}
/* Deal with the special cases of multiplying infinities. */
static void
_mpd_qmul_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status)
{
if (mpd_isinfinite(a)) {
if (mpd_iszero(b)) {
mpd_seterror(result, MPD_Invalid_operation, status);
}
else {
mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
}
return;
}
assert(mpd_isinfinite(b));
if (mpd_iszero(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
}
else {
mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
}
}
/*
* Internal function: Multiply a and b. _mpd_qmul deals with specials but
* does NOT finalize the result. This is for use in mpd_fma().
*/
static inline void
_mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
const mpd_t *big = a, *small = b;
mpd_uint_t *rdata = NULL;
mpd_uint_t rbuf[MPD_MINALLOC_MAX];
mpd_size_t rsize, i;
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
_mpd_qmul_inf(result, a, b, status);
return;
}
if (small->len > big->len) {
_mpd_ptrswap(&big, &small);
}
rsize = big->len + small->len;
if (big->len == 1) {
_mpd_singlemul(result->data, big->data[0], small->data[0]);
goto finish;
}
if (rsize <= (mpd_size_t)MPD_MINALLOC_MAX) {
if (big->len == 2) {
_mpd_mul_2_le2(rbuf, big->data, small->data, small->len);
}
else {
mpd_uint_zero(rbuf, rsize);
if (small->len == 1) {
_mpd_shortmul(rbuf, big->data, big->len, small->data[0]);
}
else {
_mpd_basemul(rbuf, small->data, big->data, small->len, big->len);
}
}
if (!mpd_qresize(result, rsize, status)) {
return;
}
for(i = 0; i < rsize; i++) {
result->data[i] = rbuf[i];
}
goto finish;
}
if (small->len <= 256) {
rdata = mpd_calloc(rsize, sizeof *rdata);
if (rdata != NULL) {
if (small->len == 1) {
_mpd_shortmul(rdata, big->data, big->len, small->data[0]);
}
else {
_mpd_basemul(rdata, small->data, big->data, small->len, big->len);
}
}
}
else if (rsize <= 1024) {
rdata = _mpd_kmul(big->data, small->data, big->len, small->len, &rsize);
}
else if (rsize <= 3*MPD_MAXTRANSFORM_2N) {
rdata = _mpd_fntmul(big->data, small->data, big->len, small->len, &rsize);
}
else {
rdata = _mpd_kmul_fnt(big->data, small->data, big->len, small->len, &rsize);
}
if (rdata == NULL) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
if (mpd_isdynamic_data(result)) {
mpd_free(result->data);
}
result->data = rdata;
result->alloc = rsize;
mpd_set_dynamic_data(result);
finish:
mpd_set_flags(result, mpd_sign(a)^mpd_sign(b));
result->exp = big->exp + small->exp;
result->len = _mpd_real_size(result->data, rsize);
/* resize to smaller cannot fail */
mpd_qresize(result, result->len, status);
mpd_setdigits(result);
}
/* Multiply a and b. */
void
mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
_mpd_qmul(result, a, b, ctx, status);
mpd_qfinalize(result, ctx, status);
}
/* Multiply a and b. Set NaN/Invalid_operation if the result is inexact. */
static void
_mpd_qmul_exact(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_qmul(result, a, b, ctx, &workstatus);
*status |= workstatus;
if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
mpd_seterror(result, MPD_Invalid_operation, status);
}
}
/* Multiply decimal and mpd_ssize_t. */
void
mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_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_qsset_ssize(&bb, b, &maxcontext, status);
mpd_qmul(result, a, &bb, ctx, status);
mpd_del(&bb);
}
/* Multiply decimal and mpd_uint_t. */
void
mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_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_qsset_uint(&bb, b, &maxcontext, status);
mpd_qmul(result, a, &bb, ctx, status);
mpd_del(&bb);
}
void
mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qmul_ssize(result, a, b, ctx, status);
}
void
mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qmul_uint(result, a, b, ctx, status);
}
void
mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qmul_ssize(result, a, b, ctx, status);
}
void
mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_qmul_uint(result, a, b, ctx, status);
}
/* Like the minus operator. */
void
mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
}
if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) {
mpd_qcopy_abs(result, a, status);
}
else {
mpd_qcopy_negate(result, a, status);
}
mpd_qfinalize(result, ctx, status);
}
/* Like the plus operator. */
void
mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
}
if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) {
mpd_qcopy_abs(result, a, status);
}
else {
mpd_qcopy(result, a, status);
}
mpd_qfinalize(result, ctx, status);
}
/* The largest representable number that is smaller than the operand. */
void
mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx;
MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1);
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
assert(mpd_isinfinite(a));
if (mpd_isnegative(a)) {
mpd_qcopy(result, a, status);
return;
}
else {
mpd_clear_flags(result);
mpd_qmaxcoeff(result, ctx, status);
if (mpd_isnan(result)) {
return;
}
result->exp = mpd_etop(ctx);
return;
}
}
mpd_workcontext(&workctx, ctx);
workctx.round = MPD_ROUND_FLOOR;
if (!mpd_qcopy(result, a, status)) {
return;
}
mpd_qfinalize(result, &workctx, &workctx.status);
if (workctx.status&(MPD_Inexact|MPD_Errors)) {
*status |= (workctx.status&MPD_Errors);
return;
}
workctx.status = 0;
mpd_qsub(result, a, &tiny, &workctx, &workctx.status);
*status |= (workctx.status&MPD_Errors);
}
/* The smallest representable number that is larger than the operand. */
void
mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx;
MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1);
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
assert(mpd_isinfinite(a));
if (mpd_ispositive(a)) {
mpd_qcopy(result, a, status);
}
else {
mpd_clear_flags(result);
mpd_qmaxcoeff(result, ctx, status);
if (mpd_isnan(result)) {
return;
}
mpd_set_flags(result, MPD_NEG);
result->exp = mpd_etop(ctx);
}
return;
}
mpd_workcontext(&workctx, ctx);
workctx.round = MPD_ROUND_CEILING;
if (!mpd_qcopy(result, a, status)) {
return;
}
mpd_qfinalize(result, &workctx, &workctx.status);
if (workctx.status & (MPD_Inexact|MPD_Errors)) {
*status |= (workctx.status&MPD_Errors);
return;
}
workctx.status = 0;
mpd_qadd(result, a, &tiny, &workctx, &workctx.status);
*status |= (workctx.status&MPD_Errors);
}
/*
* The number closest to the first operand that is in the direction towards
* the second operand.
*/
void
mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
int c;
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
c = _mpd_cmp(a, b);
if (c == 0) {
mpd_qcopy_sign(result, a, b, status);
return;
}
if (c < 0) {
mpd_qnext_plus(result, a, ctx, status);
}
else {
mpd_qnext_minus(result, a, ctx, status);
}
if (mpd_isinfinite(result)) {
*status |= (MPD_Overflow|MPD_Rounded|MPD_Inexact);
}
else if (mpd_adjexp(result) < ctx->emin) {
*status |= (MPD_Underflow|MPD_Subnormal|MPD_Rounded|MPD_Inexact);
if (mpd_iszero(result)) {
*status |= MPD_Clamped;
}
}
}
/*
* Internal function: Integer power with mpd_uint_t exponent. The function
* can fail with MPD_Malloc_error.
*
* The error is equal to the error incurred in k-1 multiplications. Assuming
* the upper bound for the relative error in each operation:
*
* abs(err) = 5 * 10**-prec
* result = x**k * (1 + err)**(k-1)
*/
static inline void
_mpd_qpow_uint(mpd_t *result, const mpd_t *base, mpd_uint_t exp,
uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_uint_t n;
if (exp == 0) {
_settriple(result, resultsign, 1, 0); /* GCOV_NOT_REACHED */
return; /* GCOV_NOT_REACHED */
}
if (!mpd_qcopy(result, base, status)) {
return;
}
n = mpd_bits[mpd_bsr(exp)];
while (n >>= 1) {
mpd_qmul(result, result, result, ctx, &workstatus);
if (exp & n) {
mpd_qmul(result, result, base, ctx, &workstatus);
}
if (mpd_isspecial(result) ||
(mpd_iszerocoeff(result) && (workstatus & MPD_Clamped))) {
break;
}
}
*status |= workstatus;
mpd_set_sign(result, resultsign);
}
/*
* Internal function: Integer power with mpd_t exponent, tbase and texp
* are modified!! Function can fail with MPD_Malloc_error.
*
* The error is equal to the error incurred in k multiplications. Assuming
* the upper bound for the relative error in each operation:
*
* abs(err) = 5 * 10**-prec
* result = x**k * (1 + err)**k
*/
static inline void
_mpd_qpow_mpd(mpd_t *result, mpd_t *tbase, mpd_t *texp, uint8_t resultsign,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_context_t maxctx;
MPD_NEW_CONST(two,0,0,1,1,1,2);
mpd_maxcontext(&maxctx);
/* resize to smaller cannot fail */
mpd_qcopy(result, &one, status);
while (!mpd_iszero(texp)) {
if (mpd_isodd(texp)) {
mpd_qmul(result, result, tbase, ctx, &workstatus);
*status |= workstatus;
if (mpd_isspecial(result) ||
(mpd_iszerocoeff(result) && (workstatus & MPD_Clamped))) {
break;
}
}
mpd_qmul(tbase, tbase, tbase, ctx, &workstatus);
mpd_qdivint(texp, texp, &two, &maxctx, &workstatus);
if (mpd_isnan(tbase) || mpd_isnan(texp)) {
mpd_seterror(result, workstatus&MPD_Errors, status);
return;
}
}
mpd_set_sign(result, resultsign);
}
/*
* The power function for integer exponents. Relative error _before_ the
* final rounding to prec:
* abs(result - base**exp) < 0.1 * 10**-prec * abs(base**exp)
*/
static void
_mpd_qpow_int(mpd_t *result, const mpd_t *base, const mpd_t *exp,
uint8_t resultsign,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_context_t workctx;
MPD_NEW_STATIC(tbase,0,0,0,0);
MPD_NEW_STATIC(texp,0,0,0,0);
mpd_ssize_t n;
mpd_workcontext(&workctx, ctx);
workctx.prec += (exp->digits + exp->exp + 2);
workctx.round = MPD_ROUND_HALF_EVEN;
workctx.clamp = 0;
if (mpd_isnegative(exp)) {
workctx.prec += 1;
mpd_qdiv(&tbase, &one, base, &workctx, status);
if (*status&MPD_Errors) {
mpd_setspecial(result, MPD_POS, MPD_NAN);
goto finish;
}
}
else {
if (!mpd_qcopy(&tbase, base, status)) {
mpd_setspecial(result, MPD_POS, MPD_NAN);
goto finish;
}
}
n = mpd_qabs_uint(exp, &workctx.status);
if (workctx.status&MPD_Invalid_operation) {
if (!mpd_qcopy(&texp, exp, status)) {
mpd_setspecial(result, MPD_POS, MPD_NAN); /* GCOV_UNLIKELY */
goto finish; /* GCOV_UNLIKELY */
}
_mpd_qpow_mpd(result, &tbase, &texp, resultsign, &workctx, status);
}
else {
_mpd_qpow_uint(result, &tbase, n, resultsign, &workctx, status);
}
if (mpd_isinfinite(result)) {
/* for ROUND_DOWN, ROUND_FLOOR, etc. */
_settriple(result, resultsign, 1, MPD_EXP_INF);
}
finish:
mpd_del(&tbase);
mpd_del(&texp);
mpd_qfinalize(result, ctx, status);
}
/*
* If the exponent is infinite and base equals one, the result is one
* with a coefficient of length prec. Otherwise, result is undefined.
* Return the value of the comparison against one.
*/
static int
_qcheck_pow_one_inf(mpd_t *result, const mpd_t *base, uint8_t resultsign,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_ssize_t shift;
int cmp;
if ((cmp = _mpd_cmp(base, &one)) == 0) {
shift = ctx->prec-1;
mpd_qshiftl(result, &one, shift, status);
result->exp = -shift;
mpd_set_flags(result, resultsign);
*status |= (MPD_Inexact|MPD_Rounded);
}
return cmp;
}
/*
* If abs(base) equals one, calculate the correct power of one result.
* Otherwise, result is undefined. Return the value of the comparison
* against 1.
*
* This is an internal function that does not check for specials.
*/
static int
_qcheck_pow_one(mpd_t *result, const mpd_t *base, const mpd_t *exp,
uint8_t resultsign,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_ssize_t shift;
int cmp;
if ((cmp = _mpd_cmp_abs(base, &one)) == 0) {
if (_mpd_isint(exp)) {
if (mpd_isnegative(exp)) {
_settriple(result, resultsign, 1, 0);
return 0;
}
/* 1.000**3 = 1.000000000 */
mpd_qmul_ssize(result, exp, -base->exp, ctx, &workstatus);
if (workstatus&MPD_Errors) {
*status |= (workstatus&MPD_Errors);
return 0;
}
/* digits-1 after exponentiation */
shift = mpd_qget_ssize(result, &workstatus);
/* shift is MPD_SSIZE_MAX if result is too large */
if (shift > ctx->prec-1) {
shift = ctx->prec-1;
*status |= MPD_Rounded;
}
}
else if (mpd_ispositive(base)) {
shift = ctx->prec-1;
*status |= (MPD_Inexact|MPD_Rounded);
}
else {
return -2; /* GCOV_NOT_REACHED */
}
if (!mpd_qshiftl(result, &one, shift, status)) {
return 0;
}
result->exp = -shift;
mpd_set_flags(result, resultsign);
}
return cmp;
}
/*
* Detect certain over/underflow of x**y.
* ACL2 proof: pow-bounds.lisp.
*
* Symbols:
*
* e: EXP_INF or EXP_CLAMP
* x: base
* y: exponent
*
* omega(e) = log10(abs(e))
* zeta(x) = log10(abs(log10(x)))
* theta(y) = log10(abs(y))
*
* Upper and lower bounds:
*
* ub_omega(e) = ceil(log10(abs(e)))
* lb_theta(y) = floor(log10(abs(y)))
*
* | floor(log10(floor(abs(log10(x))))) if x < 1/10 or x >= 10
* lb_zeta(x) = | floor(log10(abs(x-1)/10)) if 1/10 <= x < 1
* | floor(log10(abs((x-1)/100))) if 1 < x < 10
*
* ub_omega(e) and lb_theta(y) are obviously upper and lower bounds
* for omega(e) and theta(y).
*
* lb_zeta is a lower bound for zeta(x):
*
* x < 1/10 or x >= 10:
*
* abs(log10(x)) >= 1, so the outer log10 is well defined. Since log10
* is strictly increasing, the end result is a lower bound.
*
* 1/10 <= x < 1:
*
* We use: log10(x) <= (x-1)/log(10)
* abs(log10(x)) >= abs(x-1)/log(10)
* abs(log10(x)) >= abs(x-1)/10
*
* 1 < x < 10:
*
* We use: (x-1)/(x*log(10)) < log10(x)
* abs((x-1)/100) < abs(log10(x))
*
* XXX: abs((x-1)/10) would work, need ACL2 proof.
*
*
* Let (0 < x < 1 and y < 0) or (x > 1 and y > 0). (H1)
* Let ub_omega(exp_inf) < lb_zeta(x) + lb_theta(y) (H2)
*
* Then:
* log10(abs(exp_inf)) < log10(abs(log10(x))) + log10(abs(y)). (1)
* exp_inf < log10(x) * y (2)
* 10**exp_inf < x**y (3)
*
* Let (0 < x < 1 and y > 0) or (x > 1 and y < 0). (H3)
* Let ub_omega(exp_clamp) < lb_zeta(x) + lb_theta(y) (H4)
*
* Then:
* log10(abs(exp_clamp)) < log10(abs(log10(x))) + log10(abs(y)). (4)
* log10(x) * y < exp_clamp (5)
* x**y < 10**exp_clamp (6)
*
*/
static mpd_ssize_t
_lower_bound_zeta(const mpd_t *x, uint32_t *status)
{
mpd_context_t maxctx;
MPD_NEW_STATIC(scratch,0,0,0,0);
mpd_ssize_t t, u;
t = mpd_adjexp(x);
if (t > 0) {
/* x >= 10 -> floor(log10(floor(abs(log10(x))))) */
return mpd_exp_digits(t) - 1;
}
else if (t < -1) {
/* x < 1/10 -> floor(log10(floor(abs(log10(x))))) */
return mpd_exp_digits(t+1) - 1;
}
else {
mpd_maxcontext(&maxctx);
mpd_qsub(&scratch, x, &one, &maxctx, status);
if (mpd_isspecial(&scratch)) {
mpd_del(&scratch);
return MPD_SSIZE_MAX;
}
u = mpd_adjexp(&scratch);
mpd_del(&scratch);
/* t == -1, 1/10 <= x < 1 -> floor(log10(abs(x-1)/10))
* t == 0, 1 < x < 10 -> floor(log10(abs(x-1)/100)) */
return (t == 0) ? u-2 : u-1;
}
}
/*
* Detect cases of certain overflow/underflow in the power function.
* Assumptions: x != 1, y != 0. The proof above is for positive x.
* If x is negative and y is an odd integer, x**y == -(abs(x)**y),
* so the analysis does not change.
*/
static int
_qcheck_pow_bounds(mpd_t *result, const mpd_t *x, const mpd_t *y,
uint8_t resultsign,
const mpd_context_t *ctx, uint32_t *status)
{
MPD_NEW_SHARED(abs_x, x);
mpd_ssize_t ub_omega, lb_zeta, lb_theta;
uint8_t sign;
mpd_set_positive(&abs_x);
lb_theta = mpd_adjexp(y);
lb_zeta = _lower_bound_zeta(&abs_x, status);
if (lb_zeta == MPD_SSIZE_MAX) {
mpd_seterror(result, MPD_Malloc_error, status);
return 1;
}
sign = (mpd_adjexp(&abs_x) < 0) ^ mpd_sign(y);
if (sign == 0) {
/* (0 < |x| < 1 and y < 0) or (|x| > 1 and y > 0) */
ub_omega = mpd_exp_digits(ctx->emax);
if (ub_omega < lb_zeta + lb_theta) {
_settriple(result, resultsign, 1, MPD_EXP_INF);
mpd_qfinalize(result, ctx, status);
return 1;
}
}
else {
/* (0 < |x| < 1 and y > 0) or (|x| > 1 and y < 0). */
ub_omega = mpd_exp_digits(mpd_etiny(ctx));
if (ub_omega < lb_zeta + lb_theta) {
_settriple(result, resultsign, 1, mpd_etiny(ctx)-1);
mpd_qfinalize(result, ctx, status);
return 1;
}
}
return 0;
}
/*
* TODO: Implement algorithm for computing exact powers from decimal.py.
* In order to prevent infinite loops, this has to be called before
* using Ziv's strategy for correct rounding.
*/
/*
static int
_mpd_qpow_exact(mpd_t *result, const mpd_t *base, const mpd_t *exp,
const mpd_context_t *ctx, uint32_t *status)
{
return 0;
}
*/
/*
* The power function for real exponents.
* Relative error: abs(result - e**y) < e**y * 1/5 * 10**(-prec - 1)
*/
static void
_mpd_qpow_real(mpd_t *result, const mpd_t *base, const mpd_t *exp,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_context_t workctx;
MPD_NEW_STATIC(texp,0,0,0,0);
if (!mpd_qcopy(&texp, exp, status)) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
mpd_maxcontext(&workctx);
workctx.prec = (base->digits > ctx->prec) ? base->digits : ctx->prec;
workctx.prec += (4 + MPD_EXPDIGITS);
workctx.round = MPD_ROUND_HALF_EVEN;
workctx.allcr = ctx->allcr;
/*
* extra := MPD_EXPDIGITS = MPD_EXP_MAX_T
* wp := prec + 4 + extra
* abs(err) < 5 * 10**-wp
* y := log(base) * exp
* Calculate:
* 1) e**(y * (1 + err)**2) * (1 + err)
* = e**y * e**(y * (2*err + err**2)) * (1 + err)
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Relative error of the underlined term:
* 2) abs(e**(y * (2*err + err**2)) - 1)
* Case abs(y) >= 10**extra:
* 3) adjexp(y)+1 > log10(abs(y)) >= extra
* This triggers the Overflow/Underflow shortcut in _mpd_qexp(),
* so no further analysis is necessary.
* Case abs(y) < 10**extra:
* 4) abs(y * (2*err + err**2)) < 1/5 * 10**(-prec - 2)
* Use (see _mpd_qexp):
* 5) abs(x) <= 9/10 * 10**-p ==> abs(e**x - 1) < 10**-p
* With 2), 4) and 5):
* 6) abs(e**(y * (2*err + err**2)) - 1) < 10**(-prec - 2)
* The complete relative error of 1) is:
* 7) abs(result - e**y) < e**y * 1/5 * 10**(-prec - 1)
*/
mpd_qln(result, base, &workctx, &workctx.status);
mpd_qmul(result, result, &texp, &workctx, &workctx.status);
mpd_qexp(result, result, &workctx, status);
mpd_del(&texp);
*status |= (workctx.status&MPD_Errors);
*status |= (MPD_Inexact|MPD_Rounded);
}
/* The power function: base**exp */
void
mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp,
const mpd_context_t *ctx, uint32_t *status)
{
uint8_t resultsign = 0;
int intexp = 0;
int cmp;
if (mpd_isspecial(base) || mpd_isspecial(exp)) {
if (mpd_qcheck_nans(result, base, exp, ctx, status)) {
return;
}
}
if (mpd_isinteger(exp)) {
intexp = 1;
resultsign = mpd_isnegative(base) && mpd_isodd(exp);
}
if (mpd_iszero(base)) {
if (mpd_iszero(exp)) {
mpd_seterror(result, MPD_Invalid_operation, status);
}
else if (mpd_isnegative(exp)) {
mpd_setspecial(result, resultsign, MPD_INF);
}
else {
_settriple(result, resultsign, 0, 0);
}
return;
}
if (mpd_isnegative(base)) {
if (!intexp || mpd_isinfinite(exp)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
}
if (mpd_isinfinite(exp)) {
/* power of one */
cmp = _qcheck_pow_one_inf(result, base, resultsign, ctx, status);
if (cmp == 0) {
return;
}
else {
cmp *= mpd_arith_sign(exp);
if (cmp < 0) {
_settriple(result, resultsign, 0, 0);
}
else {
mpd_setspecial(result, resultsign, MPD_INF);
}
}
return;
}
if (mpd_isinfinite(base)) {
if (mpd_iszero(exp)) {
_settriple(result, resultsign, 1, 0);
}
else if (mpd_isnegative(exp)) {
_settriple(result, resultsign, 0, 0);
}
else {
mpd_setspecial(result, resultsign, MPD_INF);
}
return;
}
if (mpd_iszero(exp)) {
_settriple(result, resultsign, 1, 0);
return;
}
if (_qcheck_pow_one(result, base, exp, resultsign, ctx, status) == 0) {
return;
}
if (_qcheck_pow_bounds(result, base, exp, resultsign, ctx, status)) {
return;
}
if (intexp) {
_mpd_qpow_int(result, base, exp, resultsign, ctx, status);
}
else {
_mpd_qpow_real(result, base, exp, ctx, status);
if (!mpd_isspecial(result) && _mpd_cmp(result, &one) == 0) {
mpd_ssize_t shift = ctx->prec-1;
mpd_qshiftl(result, &one, shift, status);
result->exp = -shift;
}
if (mpd_isinfinite(result)) {
/* for ROUND_DOWN, ROUND_FLOOR, etc. */
_settriple(result, MPD_POS, 1, MPD_EXP_INF);
}
mpd_qfinalize(result, ctx, status);
}
}
/*
* Internal function: Integer powmod with mpd_uint_t exponent, base is modified!
* Function can fail with MPD_Malloc_error.
*/
static inline void
_mpd_qpowmod_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp,
const mpd_t *mod, uint32_t *status)
{
mpd_context_t maxcontext;
mpd_maxcontext(&maxcontext);
/* resize to smaller cannot fail */
mpd_qcopy(result, &one, status);
while (exp > 0) {
if (exp & 1) {
_mpd_qmul_exact(result, result, base, &maxcontext, status);
mpd_qrem(result, result, mod, &maxcontext, status);
}
_mpd_qmul_exact(base, base, base, &maxcontext, status);
mpd_qrem(base, base, mod, &maxcontext, status);
exp >>= 1;
}
}
/* The powmod function: (base**exp) % mod */
void
mpd_qpowmod(mpd_t *result, const mpd_t *base, const mpd_t *exp,
const mpd_t *mod,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_context_t maxcontext;
MPD_NEW_STATIC(tbase,0,0,0,0);
MPD_NEW_STATIC(texp,0,0,0,0);
MPD_NEW_STATIC(tmod,0,0,0,0);
MPD_NEW_STATIC(tmp,0,0,0,0);
MPD_NEW_CONST(two,0,0,1,1,1,2);
mpd_ssize_t tbase_exp, texp_exp;
mpd_ssize_t i;
mpd_t t;
mpd_uint_t r;
uint8_t sign;
if (mpd_isspecial(base) || mpd_isspecial(exp) || mpd_isspecial(mod)) {
if (mpd_qcheck_3nans(result, base, exp, mod, ctx, status)) {
return;
}
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (!_mpd_isint(base) || !_mpd_isint(exp) || !_mpd_isint(mod)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (mpd_iszerocoeff(mod)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (mod->digits+mod->exp > ctx->prec) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
sign = (mpd_isnegative(base)) && (mpd_isodd(exp));
if (mpd_iszerocoeff(exp)) {
if (mpd_iszerocoeff(base)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
r = (_mpd_cmp_abs(mod, &one)==0) ? 0 : 1;
_settriple(result, sign, r, 0);
return;
}
if (mpd_isnegative(exp)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (mpd_iszerocoeff(base)) {
_settriple(result, sign, 0, 0);
return;
}
mpd_maxcontext(&maxcontext);
mpd_qrescale(&tmod, mod, 0, &maxcontext, &maxcontext.status);
if (maxcontext.status&MPD_Errors) {
mpd_seterror(result, maxcontext.status&MPD_Errors, status);
goto out;
}
maxcontext.status = 0;
mpd_set_positive(&tmod);
mpd_qround_to_int(&tbase, base, &maxcontext, status);
mpd_set_positive(&tbase);
tbase_exp = tbase.exp;
tbase.exp = 0;
mpd_qround_to_int(&texp, exp, &maxcontext, status);
texp_exp = texp.exp;
texp.exp = 0;
/* base = (base.int % modulo * pow(10, base.exp, modulo)) % modulo */
mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
mpd_qshiftl(result, &one, tbase_exp, status);
mpd_qrem(result, result, &tmod, &maxcontext, status);
_mpd_qmul_exact(&tbase, &tbase, result, &maxcontext, status);
mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
if (mpd_isspecial(&tbase) ||
mpd_isspecial(&texp) ||
mpd_isspecial(&tmod)) {
goto mpd_errors;
}
for (i = 0; i < texp_exp; i++) {
_mpd_qpowmod_uint(&tmp, &tbase, 10, &tmod, status);
t = tmp;
tmp = tbase;
tbase = t;
}
if (mpd_isspecial(&tbase)) {
goto mpd_errors; /* GCOV_UNLIKELY */
}
/* resize to smaller cannot fail */
mpd_qcopy(result, &one, status);
while (mpd_isfinite(&texp) && !mpd_iszero(&texp)) {
if (mpd_isodd(&texp)) {
_mpd_qmul_exact(result, result, &tbase, &maxcontext, status);
mpd_qrem(result, result, &tmod, &maxcontext, status);
}
_mpd_qmul_exact(&tbase, &tbase, &tbase, &maxcontext, status);
mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
mpd_qdivint(&texp, &texp, &two, &maxcontext, status);
}
if (mpd_isspecial(&texp) || mpd_isspecial(&tbase) ||
mpd_isspecial(&tmod) || mpd_isspecial(result)) {
/* MPD_Malloc_error */
goto mpd_errors;
}
else {
mpd_set_sign(result, sign);
}
out:
mpd_del(&tbase);
mpd_del(&texp);
mpd_del(&tmod);
mpd_del(&tmp);
return;
mpd_errors:
mpd_setspecial(result, MPD_POS, MPD_NAN);
goto out;
}
void
mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
uint32_t workstatus = 0;
mpd_ssize_t b_exp = b->exp;
mpd_ssize_t expdiff, shift;
mpd_uint_t rnd;
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(result, a, b, ctx, status)) {
return;
}
if (mpd_isinfinite(a) && mpd_isinfinite(b)) {
mpd_qcopy(result, a, status);
return;
}
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (b->exp > ctx->emax || b->exp < mpd_etiny(ctx)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (mpd_iszero(a)) {
_settriple(result, mpd_sign(a), 0, b->exp);
mpd_qfinalize(result, ctx, status);
return;
}
expdiff = a->exp - b->exp;
if (a->digits + expdiff > ctx->prec) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (expdiff >= 0) {
shift = expdiff;
if (!mpd_qshiftl(result, a, shift, status)) {
return;
}
result->exp = b_exp;
}
else {
/* At this point expdiff < 0 and a->digits+expdiff <= prec,
* so the shift before an increment will fit in prec. */
shift = -expdiff;
rnd = mpd_qshiftr(result, a, shift, status);
if (rnd == MPD_UINT_MAX) {
return;
}
result->exp = b_exp;
if (!_mpd_apply_round_fit(result, rnd, ctx, status)) {
return;
}
workstatus |= MPD_Rounded;
if (rnd) {
workstatus |= MPD_Inexact;
}
}
if (mpd_adjexp(result) > ctx->emax ||
mpd_adjexp(result) < mpd_etiny(ctx)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
*status |= workstatus;
mpd_qfinalize(result, ctx, status);
}
void
mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_ssize_t shift, maxexp, maxshift;
uint8_t sign_a = mpd_sign(a);
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
mpd_qcopy(result, a, status);
return;
}
if (!mpd_qcopy(result, a, status)) {
return;
}
mpd_qfinalize(result, ctx, status);
if (mpd_isspecial(result)) {
return;
}
if (mpd_iszero(result)) {
_settriple(result, sign_a, 0, 0);
return;
}
shift = mpd_trail_zeros(result);
maxexp = (ctx->clamp) ? mpd_etop(ctx) : ctx->emax;
/* After the finalizing above result->exp <= maxexp. */
maxshift = maxexp - result->exp;
shift = (shift > maxshift) ? maxshift : shift;
mpd_qshiftr_inplace(result, shift);
result->exp += shift;
}
void
mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx,
uint32_t *status)
{
MPD_NEW_STATIC(q,0,0,0,0);
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(r, a, b, ctx, status)) {
return;
}
if (mpd_isinfinite(a)) {
mpd_seterror(r, MPD_Invalid_operation, status);
return;
}
if (mpd_isinfinite(b)) {
mpd_qcopy(r, a, status);
mpd_qfinalize(r, ctx, status);
return;
}
/* debug */
abort(); /* GCOV_NOT_REACHED */
}
if (mpd_iszerocoeff(b)) {
if (mpd_iszerocoeff(a)) {
mpd_seterror(r, MPD_Division_undefined, status);
}
else {
mpd_seterror(r, MPD_Invalid_operation, status);
}
return;
}
_mpd_qdivmod(&q, r, a, b, ctx, status);
mpd_del(&q);
mpd_qfinalize(r, ctx, status);
}
void
mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_context_t workctx;
MPD_NEW_STATIC(btmp,0,0,0,0);
MPD_NEW_STATIC(q,0,0,0,0);
mpd_ssize_t expdiff, qdigits;
int cmp, isodd, allnine;
if (mpd_isspecial(a) || mpd_isspecial(b)) {
if (mpd_qcheck_nans(r, a, b, ctx, status)) {
return;
}
if (mpd_isinfinite(a)) {
mpd_seterror(r, MPD_Invalid_operation, status);
return;
}
if (mpd_isinfinite(b)) {
mpd_qcopy(r, a, status);
mpd_qfinalize(r, ctx, status);
return;
}
/* debug */
abort(); /* GCOV_NOT_REACHED */
}
if (mpd_iszerocoeff(b)) {
if (mpd_iszerocoeff(a)) {
mpd_seterror(r, MPD_Division_undefined, status);
}
else {
mpd_seterror(r, MPD_Invalid_operation, status);
}
return;
}
if (r == b) {
if (!mpd_qcopy(&btmp, b, status)) {
mpd_seterror(r, MPD_Malloc_error, status);
return;
}
b = &btmp;
}
_mpd_qdivmod(&q, r, a, b, ctx, status);
if (mpd_isnan(&q) || mpd_isnan(r)) {
goto finish;
}
if (mpd_iszerocoeff(r)) {
goto finish;
}
expdiff = mpd_adjexp(b) - mpd_adjexp(r);
if (-1 <= expdiff && expdiff <= 1) {
allnine = mpd_coeff_isallnine(&q);
qdigits = q.digits;
isodd = mpd_isodd(&q);
mpd_maxcontext(&workctx);
if (mpd_sign(a) == mpd_sign(b)) {
/* sign(r) == sign(b) */
_mpd_qsub(&q, r, b, &workctx, &workctx.status);
}
else {
/* sign(r) != sign(b) */
_mpd_qadd(&q, r, b, &workctx, &workctx.status);
}
if (workctx.status&MPD_Errors) {
mpd_seterror(r, workctx.status&MPD_Errors, status);
goto finish;
}
cmp = _mpd_cmp_abs(&q, r);
if (cmp < 0 || (cmp == 0 && isodd)) {
/* abs(r) > abs(b)/2 or abs(r) == abs(b)/2 and isodd(quotient) */
if (allnine && qdigits == ctx->prec) {
/* abs(quotient) + 1 == 10**prec */
mpd_seterror(r, MPD_Division_impossible, status);
goto finish;
}
mpd_qcopy(r, &q, status);
}
}
finish:
mpd_del(&btmp);
mpd_del(&q);
mpd_qfinalize(r, ctx, status);
}
static void
_mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_ssize_t expdiff, shift;
mpd_uint_t rnd;
if (mpd_isspecial(a)) {
mpd_qcopy(result, a, status);
return;
}
if (mpd_iszero(a)) {
_settriple(result, mpd_sign(a), 0, exp);
return;
}
expdiff = a->exp - exp;
if (expdiff >= 0) {
shift = expdiff;
if (a->digits + shift > MPD_MAX_PREC+1) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (!mpd_qshiftl(result, a, shift, status)) {
return;
}
result->exp = exp;
}
else {
shift = -expdiff;
rnd = mpd_qshiftr(result, a, shift, status);
if (rnd == MPD_UINT_MAX) {
return;
}
result->exp = exp;
_mpd_apply_round_excess(result, rnd, ctx, status);
*status |= MPD_Rounded;
if (rnd) {
*status |= MPD_Inexact;
}
}
if (mpd_issubnormal(result, ctx)) {
*status |= MPD_Subnormal;
}
}
/*
* Rescale a number so that it has exponent 'exp'. Does not regard context
* precision, emax, emin, but uses the rounding mode. Special numbers are
* quietly copied. Restrictions:
*
* MPD_MIN_ETINY <= exp <= MPD_MAX_EMAX+1
* result->digits <= MPD_MAX_PREC+1
*/
void
mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
const mpd_context_t *ctx, uint32_t *status)
{
if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
_mpd_qrescale(result, a, exp, ctx, status);
}
/*
* Same as mpd_qrescale, but with relaxed restrictions. The result of this
* function should only be used for formatting a number and never as input
* for other operations.
*
* MPD_MIN_ETINY-MPD_MAX_PREC <= exp <= MPD_MAX_EMAX+1
* result->digits <= MPD_MAX_PREC+1
*/
void
mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
const mpd_context_t *ctx, uint32_t *status)
{
if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY-MPD_MAX_PREC) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
_mpd_qrescale(result, a, exp, ctx, status);
}
/* Round to an integer according to 'action' and ctx->round. */
enum {TO_INT_EXACT, TO_INT_SILENT, TO_INT_TRUNC};
static void
_mpd_qround_to_integral(int action, mpd_t *result, const mpd_t *a,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_uint_t rnd;
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
mpd_qcopy(result, a, status);
return;
}
if (a->exp >= 0) {
mpd_qcopy(result, a, status);
return;
}
if (mpd_iszerocoeff(a)) {
_settriple(result, mpd_sign(a), 0, 0);
return;
}
rnd = mpd_qshiftr(result, a, -a->exp, status);
if (rnd == MPD_UINT_MAX) {
return;
}
result->exp = 0;
if (action == TO_INT_EXACT || action == TO_INT_SILENT) {
_mpd_apply_round_excess(result, rnd, ctx, status);
if (action == TO_INT_EXACT) {
*status |= MPD_Rounded;
if (rnd) {
*status |= MPD_Inexact;
}
}
}
}
void
mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
(void)_mpd_qround_to_integral(TO_INT_EXACT, result, a, ctx, status);
}
void
mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
(void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, ctx, status);
}
void
mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
(void)_mpd_qround_to_integral(TO_INT_TRUNC, result, a, ctx, status);
}
void
mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx = *ctx;
workctx.round = MPD_ROUND_FLOOR;
(void)_mpd_qround_to_integral(TO_INT_SILENT, result, a,
&workctx, status);
}
void
mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx = *ctx;
workctx.round = MPD_ROUND_CEILING;
(void)_mpd_qround_to_integral(TO_INT_SILENT, result, a,
&workctx, status);
}
int
mpd_same_quantum(const mpd_t *a, const mpd_t *b)
{
if (mpd_isspecial(a) || mpd_isspecial(b)) {
return ((mpd_isnan(a) && mpd_isnan(b)) ||
(mpd_isinfinite(a) && mpd_isinfinite(b)));
}
return a->exp == b->exp;
}
/* Schedule the increase in precision for the Newton iteration. */
static inline int
recpr_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2],
mpd_ssize_t maxprec, mpd_ssize_t initprec)
{
mpd_ssize_t k;
int i;
assert(maxprec > 0 && initprec > 0);
if (maxprec <= initprec) return -1;
i = 0; k = maxprec;
do {
k = (k+1) / 2;
klist[i++] = k;
} while (k > initprec);
return i-1;
}
/*
* Initial approximation for the reciprocal:
* k_0 := MPD_RDIGITS-2
* z_0 := 10**(-k_0) * floor(10**(2*k_0 + 2) / floor(v * 10**(k_0 + 2)))
* Absolute error:
* |1/v - z_0| < 10**(-k_0)
* ACL2 proof: maxerror-inverse-approx
*/
static void
_mpd_qreciprocal_approx(mpd_t *z, const mpd_t *v, uint32_t *status)
{
mpd_uint_t p10data[2] = {0, mpd_pow10[MPD_RDIGITS-2]};
mpd_uint_t dummy, word;
int n;
assert(v->exp == -v->digits);
_mpd_get_msdigits(&dummy, &word, v, MPD_RDIGITS);
n = mpd_word_digits(word);
word *= mpd_pow10[MPD_RDIGITS-n];
mpd_qresize(z, 2, status);
(void)_mpd_shortdiv(z->data, p10data, 2, word);
mpd_clear_flags(z);
z->exp = -(MPD_RDIGITS-2);
z->len = (z->data[1] == 0) ? 1 : 2;
mpd_setdigits(z);
}
/*
* Reciprocal, calculated with Newton's Method. Assumption: result != a.
* NOTE: The comments in the function show that certain operations are
* exact. The proof for the maximum error is too long to fit in here.
* ACL2 proof: maxerror-inverse-complete
*/
static void
_mpd_qreciprocal(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t varcontext, maxcontext;
mpd_t *z = result; /* current approximation */
mpd_t *v; /* a, normalized to a number between 0.1 and 1 */
MPD_NEW_SHARED(vtmp, a); /* v shares data with a */
MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */
MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */
MPD_NEW_CONST(two,0,0,1,1,1,2); /* const 2 */
mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
mpd_ssize_t adj, maxprec, initprec;
uint8_t sign = mpd_sign(a);
int i;
assert(result != a);
v = &vtmp;
mpd_clear_flags(v);
adj = v->digits + v->exp;
v->exp = -v->digits;
/* Initial approximation */
_mpd_qreciprocal_approx(z, v, status);
mpd_maxcontext(&varcontext);
mpd_maxcontext(&maxcontext);
varcontext.round = maxcontext.round = MPD_ROUND_TRUNC;
varcontext.emax = maxcontext.emax = MPD_MAX_EMAX + 100;
varcontext.emin = maxcontext.emin = MPD_MIN_EMIN - 100;
maxcontext.prec = MPD_MAX_PREC + 100;
maxprec = ctx->prec;
maxprec += 2;
initprec = MPD_RDIGITS-3;
i = recpr_schedule_prec(klist, maxprec, initprec);
for (; i >= 0; i--) {
/* Loop invariant: z->digits <= klist[i]+7 */
/* Let s := z**2, exact result */
_mpd_qmul_exact(&s, z, z, &maxcontext, status);
varcontext.prec = 2*klist[i] + 5;
if (v->digits > varcontext.prec) {
/* Let t := v, truncated to n >= 2*k+5 fraction digits */
mpd_qshiftr(&t, v, v->digits-varcontext.prec, status);
t.exp = -varcontext.prec;
/* Let t := trunc(v)*s, truncated to n >= 2*k+1 fraction digits */
mpd_qmul(&t, &t, &s, &varcontext, status);
}
else { /* v->digits <= 2*k+5 */
/* Let t := v*s, truncated to n >= 2*k+1 fraction digits */
mpd_qmul(&t, v, &s, &varcontext, status);
}
/* Let s := 2*z, exact result */
_mpd_qmul_exact(&s, z, &two, &maxcontext, status);
/* s.digits < t.digits <= 2*k+5, |adjexp(s)-adjexp(t)| <= 1,
* so the subtraction generates at most 2*k+6 <= klist[i+1]+7
* digits. The loop invariant is preserved. */
_mpd_qsub_exact(z, &s, &t, &maxcontext, status);
}
if (!mpd_isspecial(z)) {
z->exp -= adj;
mpd_set_flags(z, sign);
}
mpd_del(&s);
mpd_del(&t);
mpd_qfinalize(z, ctx, status);
}
/*
* Internal function for large numbers:
*
* q, r = divmod(coeff(a), coeff(b))
*
* Strategy: Multiply the dividend by the reciprocal of the divisor. The
* inexact result is fixed by a small loop, using at most one iteration.
*
* ACL2 proofs:
* ------------
* 1) q is a natural number. (ndivmod-quotient-natp)
* 2) r is a natural number. (ndivmod-remainder-natp)
* 3) a = q * b + r (ndivmod-q*b+r==a)
* 4) r < b (ndivmod-remainder-<-b)
*/
static void
_mpd_base_ndivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
uint32_t *status)
{
mpd_context_t workctx;
mpd_t *qq = q, *rr = r;
mpd_t aa, bb;
int k;
_mpd_copy_shared(&aa, a);
_mpd_copy_shared(&bb, b);
mpd_set_positive(&aa);
mpd_set_positive(&bb);
aa.exp = 0;
bb.exp = 0;
if (q == a || q == b) {
if ((qq = mpd_qnew()) == NULL) {
*status |= MPD_Malloc_error;
goto nanresult;
}
}
if (r == a || r == b) {
if ((rr = mpd_qnew()) == NULL) {
*status |= MPD_Malloc_error;
goto nanresult;
}
}
mpd_maxcontext(&workctx);
/* Let prec := adigits - bdigits + 4 */
workctx.prec = a->digits - b->digits + 1 + 3;
if (a->digits > MPD_MAX_PREC || workctx.prec > MPD_MAX_PREC) {
*status |= MPD_Division_impossible;
goto nanresult;
}
/* Let x := _mpd_qreciprocal(b, prec)
* Then x is bounded by:
* 1) 1/b - 10**(-prec - bdigits) < x < 1/b + 10**(-prec - bdigits)
* 2) 1/b - 10**(-adigits - 4) < x < 1/b + 10**(-adigits - 4)
*/
_mpd_qreciprocal(rr, &bb, &workctx, &workctx.status);
/* Get an estimate for the quotient. Let q := a * x
* Then q is bounded by:
* 3) a/b - 10**-4 < q < a/b + 10**-4
*/
_mpd_qmul(qq, &aa, rr, &workctx, &workctx.status);
/* Truncate q to an integer:
* 4) a/b - 2 < trunc(q) < a/b + 1
*/
mpd_qtrunc(qq, qq, &workctx, &workctx.status);
workctx.prec = aa.digits + 3;
workctx.emax = MPD_MAX_EMAX + 3;
workctx.emin = MPD_MIN_EMIN - 3;
/* Multiply the estimate for q by b:
* 5) a - 2 * b < trunc(q) * b < a + b
*/
_mpd_qmul(rr, &bb, qq, &workctx, &workctx.status);
/* Get the estimate for r such that a = q * b + r. */
_mpd_qsub_exact(rr, &aa, rr, &workctx, &workctx.status);
/* Fix the result. At this point -b < r < 2*b, so the correction loop
takes at most one iteration. */
for (k = 0;; k++) {
if (mpd_isspecial(qq) || mpd_isspecial(rr)) {
*status |= (workctx.status&MPD_Errors);
goto nanresult;
}
if (k > 2) { /* Allow two iterations despite the proof. */
mpd_err_warn("libmpdec: internal error in " /* GCOV_NOT_REACHED */
"_mpd_base_ndivmod: please report"); /* GCOV_NOT_REACHED */
*status |= MPD_Invalid_operation; /* GCOV_NOT_REACHED */
goto nanresult; /* GCOV_NOT_REACHED */
}
/* r < 0 */
else if (_mpd_cmp(&zero, rr) == 1) {
_mpd_qadd_exact(rr, rr, &bb, &workctx, &workctx.status);
_mpd_qadd_exact(qq, qq, &minus_one, &workctx, &workctx.status);
}
/* 0 <= r < b */
else if (_mpd_cmp(rr, &bb) == -1) {
break;
}
/* r >= b */
else {
_mpd_qsub_exact(rr, rr, &bb, &workctx, &workctx.status);
_mpd_qadd_exact(qq, qq, &one, &workctx, &workctx.status);
}
}
if (qq != q) {
if (!mpd_qcopy(q, qq, status)) {
goto nanresult; /* GCOV_UNLIKELY */
}
mpd_del(qq);
}
if (rr != r) {
if (!mpd_qcopy(r, rr, status)) {
goto nanresult; /* GCOV_UNLIKELY */
}
mpd_del(rr);
}
*status |= (workctx.status&MPD_Errors);
return;
nanresult:
if (qq && qq != q) mpd_del(qq);
if (rr && rr != r) mpd_del(rr);
mpd_setspecial(q, MPD_POS, MPD_NAN);
mpd_setspecial(r, MPD_POS, MPD_NAN);
}
/* LIBMPDEC_ONLY */
/*
* Schedule the optimal precision increase for the Newton iteration.
* v := input operand
* z_0 := initial approximation
* initprec := natural number such that abs(sqrt(v) - z_0) < 10**-initprec
* maxprec := target precision
*
* For convenience the output klist contains the elements in reverse order:
* klist := [k_n-1, ..., k_0], where
* 1) k_0 <= initprec and
* 2) abs(sqrt(v) - result) < 10**(-2*k_n-1 + 2) <= 10**-maxprec.
*/
static inline int
invroot_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2],
mpd_ssize_t maxprec, mpd_ssize_t initprec)
{
mpd_ssize_t k;
int i;
assert(maxprec >= 3 && initprec >= 3);
if (maxprec <= initprec) return -1;
i = 0; k = maxprec;
do {
k = (k+3) / 2;
klist[i++] = k;
} while (k > initprec);
return i-1;
}
/*
* Initial approximation for the inverse square root function.
* Input:
* v := rational number, with 1 <= v < 100
* vhat := floor(v * 10**6)
* Output:
* z := approximation to 1/sqrt(v), such that abs(z - 1/sqrt(v)) < 10**-3.
*/
static inline void
_invroot_init_approx(mpd_t *z, mpd_uint_t vhat)
{
mpd_uint_t lo = 1000;
mpd_uint_t hi = 10000;
mpd_uint_t a, sq;
assert(lo*lo <= vhat && vhat < (hi+1)*(hi+1));
for(;;) {
a = (lo + hi) / 2;
sq = a * a;
if (vhat >= sq) {
if (vhat < sq + 2*a + 1) {
break;
}
lo = a + 1;
}
else {
hi = a - 1;
}
}
/*
* After the binary search we have:
* 1) a**2 <= floor(v * 10**6) < (a + 1)**2
* This implies:
* 2) a**2 <= v * 10**6 < (a + 1)**2
* 3) a <= sqrt(v) * 10**3 < a + 1
* Since 10**3 <= a:
* 4) 0 <= 10**prec/a - 1/sqrt(v) < 10**-prec
* We have:
* 5) 10**3/a - 10**-3 < floor(10**9/a) * 10**-6 <= 10**3/a
* Merging 4) and 5):
* 6) abs(floor(10**9/a) * 10**-6 - 1/sqrt(v)) < 10**-3
*/
mpd_minalloc(z);
mpd_clear_flags(z);
z->data[0] = 1000000000UL / a;
z->len = 1;
z->exp = -6;
mpd_setdigits(z);
}
/*
* Set 'result' to 1/sqrt(a).
* Relative error: abs(result - 1/sqrt(a)) < 10**-prec * 1/sqrt(a)
*/
static void
_mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
uint32_t workstatus = 0;
mpd_context_t varcontext, maxcontext;
mpd_t *z = result; /* current approximation */
mpd_t *v; /* a, normalized to a number between 1 and 100 */
MPD_NEW_SHARED(vtmp, a); /* by default v will share data with a */
MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */
MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */
MPD_NEW_CONST(one_half,0,-1,1,1,1,5);
MPD_NEW_CONST(three,0,0,1,1,1,3);
mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
mpd_ssize_t ideal_exp, shift;
mpd_ssize_t adj, tz;
mpd_ssize_t maxprec, fracdigits;
mpd_uint_t vhat, dummy;
int i, n;
ideal_exp = -(a->exp - (a->exp & 1)) / 2;
v = &vtmp;
if (result == a) {
if ((v = mpd_qncopy(a)) == NULL) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
}
/* normalize a to 1 <= v < 100 */
if ((v->digits+v->exp) & 1) {
fracdigits = v->digits - 1;
v->exp = -fracdigits;
n = (v->digits > 7) ? 7 : (int)v->digits;
/* Let vhat := floor(v * 10**(2*initprec)) */
_mpd_get_msdigits(&dummy, &vhat, v, n);
if (n < 7) {
vhat *= mpd_pow10[7-n];
}
}
else {
fracdigits = v->digits - 2;
v->exp = -fracdigits;
n = (v->digits > 8) ? 8 : (int)v->digits;
/* Let vhat := floor(v * 10**(2*initprec)) */
_mpd_get_msdigits(&dummy, &vhat, v, n);
if (n < 8) {
vhat *= mpd_pow10[8-n];
}
}
adj = (a->exp-v->exp) / 2;
/* initial approximation */
_invroot_init_approx(z, vhat);
mpd_maxcontext(&maxcontext);
mpd_maxcontext(&varcontext);
varcontext.round = MPD_ROUND_TRUNC;
maxprec = ctx->prec + 1;
/* initprec == 3 */
i = invroot_schedule_prec(klist, maxprec, 3);
for (; i >= 0; i--) {
varcontext.prec = 2*klist[i]+2;
mpd_qmul(&s, z, z, &maxcontext, &workstatus);
if (v->digits > varcontext.prec) {
shift = v->digits - varcontext.prec;
mpd_qshiftr(&t, v, shift, &workstatus);
t.exp += shift;
mpd_qmul(&t, &t, &s, &varcontext, &workstatus);
}
else {
mpd_qmul(&t, v, &s, &varcontext, &workstatus);
}
mpd_qsub(&t, &three, &t, &maxcontext, &workstatus);
mpd_qmul(z, z, &t, &varcontext, &workstatus);
mpd_qmul(z, z, &one_half, &maxcontext, &workstatus);
}
z->exp -= adj;
tz = mpd_trail_zeros(result);
shift = ideal_exp - result->exp;
shift = (tz > shift) ? shift : tz;
if (shift > 0) {
mpd_qshiftr_inplace(result, shift);
result->exp += shift;
}
mpd_del(&s);
mpd_del(&t);
if (v != &vtmp) mpd_del(v);
*status |= (workstatus&MPD_Errors);
*status |= (MPD_Rounded|MPD_Inexact);
}
void
mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t workctx;
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
if (mpd_isnegative(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
/* positive infinity */
_settriple(result, MPD_POS, 0, mpd_etiny(ctx));
*status |= MPD_Clamped;
return;
}
if (mpd_iszero(a)) {
mpd_setspecial(result, mpd_sign(a), MPD_INF);
*status |= MPD_Division_by_zero;
return;
}
if (mpd_isnegative(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
workctx = *ctx;
workctx.prec += 2;
workctx.round = MPD_ROUND_HALF_EVEN;
_mpd_qinvroot(result, a, &workctx, status);
mpd_qfinalize(result, ctx, status);
}
/* END LIBMPDEC_ONLY */
/* Algorithm from decimal.py */
void
mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
uint32_t *status)
{
mpd_context_t maxcontext;
MPD_NEW_STATIC(c,0,0,0,0);
MPD_NEW_STATIC(q,0,0,0,0);
MPD_NEW_STATIC(r,0,0,0,0);
MPD_NEW_CONST(two,0,0,1,1,1,2);
mpd_ssize_t prec, ideal_exp;
mpd_ssize_t l, shift;
int exact = 0;
ideal_exp = (a->exp - (a->exp & 1)) / 2;
if (mpd_isspecial(a)) {
if (mpd_qcheck_nan(result, a, ctx, status)) {
return;
}
if (mpd_isnegative(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
mpd_setspecial(result, MPD_POS, MPD_INF);
return;
}
if (mpd_iszero(a)) {
_settriple(result, mpd_sign(a), 0, ideal_exp);
mpd_qfinalize(result, ctx, status);
return;
}
if (mpd_isnegative(a)) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
mpd_maxcontext(&maxcontext);
prec = ctx->prec + 1;
if (!mpd_qcopy(&c, a, status)) {
goto malloc_error;
}
c.exp = 0;
if (a->exp & 1) {
if (!mpd_qshiftl(&c, &c, 1, status)) {
goto malloc_error;
}
l = (a->digits >> 1) + 1;
}
else {
l = (a->digits + 1) >> 1;
}
shift = prec - l;
if (shift >= 0) {
if (!mpd_qshiftl(&c, &c, 2*shift, status)) {
goto malloc_error;
}
exact = 1;
}
else {
exact = !mpd_qshiftr_inplace(&c, -2*shift);
}
ideal_exp -= shift;
/* find result = floor(sqrt(c)) using Newton's method */
if (!mpd_qshiftl(result, &one, prec, status)) {
goto malloc_error;
}
while (1) {
_mpd_qdivmod(&q, &r, &c, result, &maxcontext, &maxcontext.status);
if (mpd_isspecial(result) || mpd_isspecial(&q)) {
mpd_seterror(result, maxcontext.status&MPD_Errors, status);
goto out;
}
if (_mpd_cmp(result, &q) <= 0) {
break;
}
_mpd_qadd_exact(result, result, &q, &maxcontext, &maxcontext.status);
if (mpd_isspecial(result)) {
mpd_seterror(result, maxcontext.status&MPD_Errors, status);
goto out;
}
_mpd_qdivmod(result, &r, result, &two, &maxcontext, &maxcontext.status);
}
if (exact) {
_mpd_qmul_exact(&r, result, result, &maxcontext, &maxcontext.status);
if (mpd_isspecial(&r)) {
mpd_seterror(result, maxcontext.status&MPD_Errors, status);
goto out;
}
exact = (_mpd_cmp(&r, &c) == 0);
}
if (exact) {
if (shift >= 0) {
mpd_qshiftr_inplace(result, shift);
}
else {
if (!mpd_qshiftl(result, result, -shift, status)) {
goto malloc_error;
}
}
ideal_exp += shift;
}
else {
int lsd = (int)mpd_lsd(result->data[0]);
if (lsd == 0 || lsd == 5) {
result->data[0] += 1;
}
}
result->exp = ideal_exp;
out:
mpd_del(&c);
mpd_del(&q);
mpd_del(&r);
maxcontext = *ctx;
maxcontext.round = MPD_ROUND_HALF_EVEN;
mpd_qfinalize(result, &maxcontext, status);
return;
malloc_error:
mpd_seterror(result, MPD_Malloc_error, status);
goto out;
}
/******************************************************************************/
/* Base conversions */
/******************************************************************************/
/* Space needed to represent an integer mpd_t in base 'base'. */
size_t
mpd_sizeinbase(const mpd_t *a, uint32_t base)
{
double x;
size_t digits;
assert(mpd_isinteger(a));
assert(base >= 2);
if (mpd_iszero(a)) {
return 1;
}
digits = a->digits+a->exp;
assert(digits > 0);
/* ceil(2711437152599294 / log10(2)) + 4 == 2**53 */
if (digits > 2711437152599294ULL) {
return SIZE_MAX;
}
x = (double)digits / log10(base);
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
return (x > (SIZE_MAX>>1)+1) ? SIZE_MAX : (size_t)x + 1;
}
/* Space needed to import a base 'base' integer of length 'srclen'. */
static mpd_ssize_t
_mpd_importsize(size_t srclen, uint32_t base)
{
double x;
assert(srclen > 0);
assert(base >= 2);
#if SIZE_MAX == UINT64_MAX
if (srclen > (1ULL<<53)) {
return MPD_SSIZE_MAX;
}
#endif
x = (double)srclen * (log10(base)/MPD_RDIGITS);
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
return (x >= (double)(MPD_MAXIMPORT/2)) ? MPD_SSIZE_MAX : (mpd_ssize_t)x + 1;
}
static uint8_t
mpd_resize_u16(uint16_t **w, size_t nmemb)
{
uint8_t err = 0;
*w = mpd_realloc(*w, nmemb, sizeof **w, &err);
return !err;
}
static uint8_t
mpd_resize_u32(uint32_t **w, size_t nmemb)
{
uint8_t err = 0;
*w = mpd_realloc(*w, nmemb, sizeof **w, &err);
return !err;
}
static size_t
_baseconv_to_u16(uint16_t **w, size_t wlen, mpd_uint_t wbase,
mpd_uint_t *u, mpd_ssize_t ulen)
{
size_t n = 0;
assert(wlen > 0 && ulen > 0);
assert(wbase <= (1U<<16));
do {
if (n >= wlen) {
if (!mpd_resize_u16(w, n+1)) {
return SIZE_MAX;
}
wlen = n+1;
}
(*w)[n++] = (uint16_t)_mpd_shortdiv(u, u, ulen, wbase);
/* ulen is at least 1. u[ulen-1] can only be zero if ulen == 1. */
ulen = _mpd_real_size(u, ulen);
} while (u[ulen-1] != 0);
return n;
}
static size_t
_coeff_from_u16(mpd_t *w, mpd_ssize_t wlen,
const mpd_uint_t *u, size_t ulen, uint32_t ubase,
uint32_t *status)
{
mpd_ssize_t n = 0;
mpd_uint_t carry;
assert(wlen > 0 && ulen > 0);
assert(ubase <= (1U<<16));
w->data[n++] = u[--ulen];
while (--ulen != SIZE_MAX) {
carry = _mpd_shortmul_c(w->data, w->data, n, ubase);
if (carry) {
if (n >= wlen) {
if (!mpd_qresize(w, n+1, status)) {
return SIZE_MAX;
}
wlen = n+1;
}
w->data[n++] = carry;
}
carry = _mpd_shortadd(w->data, n, u[ulen]);
if (carry) {
if (n >= wlen) {
if (!mpd_qresize(w, n+1, status)) {
return SIZE_MAX;
}
wlen = n+1;
}
w->data[n++] = carry;
}
}
return n;
}
/* target base wbase < source base ubase */
static size_t
_baseconv_to_smaller(uint32_t **w, size_t wlen, uint32_t wbase,
mpd_uint_t *u, mpd_ssize_t ulen, mpd_uint_t ubase)
{
size_t n = 0;
assert(wlen > 0 && ulen > 0);
assert(wbase < ubase);
do {
if (n >= wlen) {
if (!mpd_resize_u32(w, n+1)) {
return SIZE_MAX;
}
wlen = n+1;
}
(*w)[n++] = (uint32_t)_mpd_shortdiv_b(u, u, ulen, wbase, ubase);
/* ulen is at least 1. u[ulen-1] can only be zero if ulen == 1. */
ulen = _mpd_real_size(u, ulen);
} while (u[ulen-1] != 0);
return n;
}
/* target base 'wbase' > source base 'ubase' */
static size_t
_coeff_from_smaller_base(mpd_t *w, mpd_ssize_t wlen, mpd_uint_t wbase,
const uint32_t *u, size_t ulen, mpd_uint_t ubase,
uint32_t *status)
{
mpd_ssize_t n = 0;
mpd_uint_t carry;
assert(wlen > 0 && ulen > 0);
assert(wbase > ubase);
w->data[n++] = u[--ulen];
while (--ulen != SIZE_MAX) {
carry = _mpd_shortmul_b(w->data, w->data, n, ubase, wbase);
if (carry) {
if (n >= wlen) {
if (!mpd_qresize(w, n+1, status)) {
return SIZE_MAX;
}
wlen = n+1;
}
w->data[n++] = carry;
}
carry = _mpd_shortadd_b(w->data, n, u[ulen], wbase);
if (carry) {
if (n >= wlen) {
if (!mpd_qresize(w, n+1, status)) {
return SIZE_MAX;
}
wlen = n+1;
}
w->data[n++] = carry;
}
}
return n;
}
/*
* Convert an integer mpd_t to a multiprecision integer with base <= 2**16.
* The least significant word of the result is (*rdata)[0].
*
* If rdata is NULL, space is allocated by the function and rlen is irrelevant.
* In case of an error any allocated storage is freed and rdata is set back to
* NULL.
*
* If rdata is non-NULL, it MUST be allocated by one of libmpdec's allocation
* functions and rlen MUST be correct. If necessary, the function will resize
* rdata. In case of an error the caller must free rdata.
*
* Return value: In case of success, the exact length of rdata, SIZE_MAX
* otherwise.
*/
size_t
mpd_qexport_u16(uint16_t **rdata, size_t rlen, uint32_t rbase,
const mpd_t *src, uint32_t *status)
{
MPD_NEW_STATIC(tsrc,0,0,0,0);
int alloc = 0; /* rdata == NULL */
size_t n;
assert(rbase <= (1U<<16));
if (mpd_isspecial(src) || !_mpd_isint(src)) {
*status |= MPD_Invalid_operation;
return SIZE_MAX;
}
if (*rdata == NULL) {
rlen = mpd_sizeinbase(src, rbase);
if (rlen == SIZE_MAX) {
*status |= MPD_Invalid_operation;
return SIZE_MAX;
}
*rdata = mpd_alloc(rlen, sizeof **rdata);
if (*rdata == NULL) {
goto malloc_error;
}
alloc = 1;
}
if (mpd_iszero(src)) {
**rdata = 0;
return 1;
}
if (src->exp >= 0) {
if (!mpd_qshiftl(&tsrc, src, src->exp, status)) {
goto malloc_error;
}
}
else {
if (mpd_qshiftr(&tsrc, src, -src->exp, status) == MPD_UINT_MAX) {
goto malloc_error;
}
}
n = _baseconv_to_u16(rdata, rlen, rbase, tsrc.data, tsrc.len);
if (n == SIZE_MAX) {
goto malloc_error;
}
out:
mpd_del(&tsrc);
return n;
malloc_error:
if (alloc) {
mpd_free(*rdata);
*rdata = NULL;
}
n = SIZE_MAX;
*status |= MPD_Malloc_error;
goto out;
}
/*
* Convert an integer mpd_t to a multiprecision integer with base<=UINT32_MAX.
* The least significant word of the result is (*rdata)[0].
*
* If rdata is NULL, space is allocated by the function and rlen is irrelevant.
* In case of an error any allocated storage is freed and rdata is set back to
* NULL.
*
* If rdata is non-NULL, it MUST be allocated by one of libmpdec's allocation
* functions and rlen MUST be correct. If necessary, the function will resize
* rdata. In case of an error the caller must free rdata.
*
* Return value: In case of success, the exact length of rdata, SIZE_MAX
* otherwise.
*/
size_t
mpd_qexport_u32(uint32_t **rdata, size_t rlen, uint32_t rbase,
const mpd_t *src, uint32_t *status)
{
MPD_NEW_STATIC(tsrc,0,0,0,0);
int alloc = 0; /* rdata == NULL */
size_t n;
if (mpd_isspecial(src) || !_mpd_isint(src)) {
*status |= MPD_Invalid_operation;
return SIZE_MAX;
}
if (*rdata == NULL) {
rlen = mpd_sizeinbase(src, rbase);
if (rlen == SIZE_MAX) {
*status |= MPD_Invalid_operation;
return SIZE_MAX;
}
*rdata = mpd_alloc(rlen, sizeof **rdata);
if (*rdata == NULL) {
goto malloc_error;
}
alloc = 1;
}
if (mpd_iszero(src)) {
**rdata = 0;
return 1;
}
if (src->exp >= 0) {
if (!mpd_qshiftl(&tsrc, src, src->exp, status)) {
goto malloc_error;
}
}
else {
if (mpd_qshiftr(&tsrc, src, -src->exp, status) == MPD_UINT_MAX) {
goto malloc_error;
}
}
n = _baseconv_to_smaller(rdata, rlen, rbase,
tsrc.data, tsrc.len, MPD_RADIX);
if (n == SIZE_MAX) {
goto malloc_error;
}
out:
mpd_del(&tsrc);
return n;
malloc_error:
if (alloc) {
mpd_free(*rdata);
*rdata = NULL;
}
n = SIZE_MAX;
*status |= MPD_Malloc_error;
goto out;
}
/*
* Converts a multiprecision integer with base <= UINT16_MAX+1 to an mpd_t.
* The least significant word of the source is srcdata[0].
*/
void
mpd_qimport_u16(mpd_t *result,
const uint16_t *srcdata, size_t srclen,
uint8_t srcsign, uint32_t srcbase,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_uint_t *usrc; /* uint16_t src copied to an mpd_uint_t array */
mpd_ssize_t rlen; /* length of the result */
size_t n;
assert(srclen > 0);
assert(srcbase <= (1U<<16));
rlen = _mpd_importsize(srclen, srcbase);
if (rlen == MPD_SSIZE_MAX) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc);
if (usrc == NULL) {
mpd_seterror(result, MPD_Malloc_error, status);
return;
}
for (n = 0; n < srclen; n++) {
usrc[n] = srcdata[n];
}
if (!mpd_qresize(result, rlen, status)) {
goto finish;
}
n = _coeff_from_u16(result, rlen, usrc, srclen, srcbase, status);
if (n == SIZE_MAX) {
goto finish;
}
mpd_set_flags(result, srcsign);
result->exp = 0;
result->len = n;
mpd_setdigits(result);
mpd_qresize(result, result->len, status);
mpd_qfinalize(result, ctx, status);
finish:
mpd_free(usrc);
}
/*
* Converts a multiprecision integer with base <= UINT32_MAX to an mpd_t.
* The least significant word of the source is srcdata[0].
*/
void
mpd_qimport_u32(mpd_t *result,
const uint32_t *srcdata, size_t srclen,
uint8_t srcsign, uint32_t srcbase,
const mpd_context_t *ctx, uint32_t *status)
{
mpd_ssize_t rlen; /* length of the result */
size_t n;
assert(srclen > 0);
rlen = _mpd_importsize(srclen, srcbase);
if (rlen == MPD_SSIZE_MAX) {
mpd_seterror(result, MPD_Invalid_operation, status);
return;
}
if (!mpd_qresize(result, rlen, status)) {
return;
}
n = _coeff_from_smaller_base(result, rlen, MPD_RADIX,
srcdata, srclen, srcbase,
status);
if (n == SIZE_MAX) {
return;
}
mpd_set_flags(result, srcsign);
result->exp = 0;
result->len = n;
mpd_setdigits(result);
mpd_qresize(result, result->len, status);
mpd_qfinalize(result, ctx, status);
}