mpdecimal-4.0.1/0000755000000000000000000000000015005764474010411 5ustar00mpdecimal-4.0.1/CHANGELOG.txt0000644000000000000000000003605615006211506012433 0ustar00 Changelog ========= Version 4.0.1 ------------- build/install ~~~~~~~~~~~~~ **features** - Add Cygwin support. - Update config.guess and config.sub to the latest versions. **build fixes** - Fix pkg-config files for custom paths. - Set LD/LDXX unconditionally to CC/CXX, since LDFLAGS/LDXXFLAGS from ./configure rely on it. - macOS: use libdir instead of RPATH for the install_name. Version 4.0.0 ------------- general ~~~~~~~ **sync soversion and major_version** - The added number formatting feature requires an ABI change, hence the increase to SOVERSION=4. - Packagers outside of the Linux distributions sometimes use the major version number as the equivalent of SOVERSION on their platforms and have an incorrect SOVERSION for 2.5.1, which requires SOVERSION=3. - While SOVERSION is not required to match the major version number (example: glibc), mpdecimal will from now on take the path of least resistance and always use SOVERSION=MPD_MAJOR_VERSION. - The jump to 4.0.0 should also remind users that a C++ library is available. build/install ~~~~~~~~~~~~~ **features** - Support for out-of-tree build. - Support for pkg-config. - Unix: support for Loongson. - Unix: support for CheriBSD. - Compilers: support for icx, icpx, ibm-clang_r, ibm-clang++_r, CompCert, clang-cl and emscripten. - Windows: support for MSYS2/MinGW. - MSVC: the build now uses /O2 /DNDEBUG. - MSVC: new arm64/arm32 cross build scripts. - AIX: the shared libraries are now installed as versioned objects, e.g., shr4.o, shr4_64.o. - New ``./configure`` switches: ``--enable-static``: enable/disable the build of the static libraries (default: enabled). ``--enable-pc``: enable/disable the install of the pkgconfig files (default: enabled). ``--enable-doc``: enable/disable the install of the documentation (default: enabled). - New ``./configure`` behavior: On multilib platforms like AIX that default to 32-bit the 64-bit build can be forced with a single ``./configure MACHINE=uint128`` (ibm-clang, gcc) or ``./configure MACHINE=ansi64`` (xlc) rather than explicitly setting ``CFLAGS``, ``LDFLAGS``, ``CXXFLAGS`` and ``LDXXFLAGS``. Note that on most other (multilib) platforms the default is 64-bit and the optimal configuration is chosen by just using ``./configure``. - New man pages direct users to the mpdecimal-doc package or the online HTML documentation. **tests** - The C++ tests now automatically skip a small number of bignum tests if the std::thread stack size (which cannot be altered) is less than 512K. For all other tests a thread stack size of roughly 50K is sufficient. - Files in the tests/testdata_dist directory have been significantly abbreviated in order to facilitate testing on slower platforms. The tests take 5s on a modern x86_64 platform. The previous tests have been moved to the separate mpdecimal-testdata package (replace tests/testdata_dist with the renamed mpdecimal-testdata directory). **toolchain issues** - AIX: The preferred C/C++ compilers are ibm-clang_r and ibm-clang_r++. g++ has sporadic C++11 threading issues that only show up in long running programs (or short ones with a sufficient number of repetitions): https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98390 If you only use libmpdec (``--disable-cxx``), gcc and xlc are very stable. **changed** - The ``--enable-profile`` configure option has been removed due to fragile integration with a sequence like ``make && make install``. The new method is ``make profile && make install``. **removed** - The prebuilt HTML documentation is now in the separate mpdecimal-doc package, which gives distributions that reject prebuilt documentation the option to disregard it and use the new man pages. libmpdec ~~~~~~~~ **features** - Add the "z" format specifier (coerce negative zeros to positive). - In extremely rare cases the transcendental functions (exp, ln, log10) did not set the Subnormal/Underflow flags. The reason is that in the case of an exponent boundary the Ziv correction loop for correct rounding requires very few iterations to arrive at the correctly rounded result, but may need many more iterations to arrive at the correct flags. In these cases, Subnormal/Underflow is not very informative, so the status quo was to skip the extra iterations. Version 4.0.0 now specializes exponent boundary cases and uses up to five additional iterations to set Subnormal/Underflow. The refactored code has no speed penalty on average; in fact, in the deccheck tests (random tests with a bias towards corner cases) it is slightly faster. No cases have been found where more than two additional iterations are required, but they may exist. **reliability fixes** - mpd_qset_string_exact(), mpd_qset_i64_exact() and mpd_qset_u64_exact() can now be called with a nonzero status. Previously, the functions could return NaN/Invalid_operation in that case. This is listed under "reliability fixes" since there is no possible scenario under which these functions would legitimately be called with a nonzero status. libmpdec++ ~~~~~~~~~~ **features** - Add input validation for Decimal.shiftl(), Decimal.shiftr() and Decimal::ln10(). Version 2.5.1 ------------- libmpdec ~~~~~~~~ **features** - New functions for conversion between mpd_t and a decimal triple with a split uint128_t coefficient. - All symbols in the header files now have an MPD_* or mpd_* prefix. - libmpdec/.objs/symbols64.exp and libmpdec/.objs/symbols32.exp contain all symbols of the exported API. The files are almost identical, but mpd_qsset_i64, mpd_sset_i64, mpd_qsset_u64 and mpd_sset_u64 are only available in the 64-bit build. libmpdec/.objs/libmpdec.imp is the unified 64/32-bit import file for AIX. - The new test target *make check_local* does not attempt to download dectest.zip. This is useful for packagers whose infrastructure does not allow downloading during the testing phase. *make check* is still preferable because it runs all tests. **style fixes** - Apply several clang-tidy suggestions (high diagnostic level). **build features** - AIX: full support for xlc/gcc builds in ./configure. - full support for AIX-style shared libraries. - full support for AIX multilib header. **build fixes** - Update config.guess and config.sub in order to support IBM Power architectures. - Fix false positive _FORTIFY_SOURCE warning on Fedora. libmpdec++ ~~~~~~~~~~ **features** - New methods for conversion between Decimal and a decimal triple with a split uint128_t coefficient. - decimal::Context now uses default constructors wherever possible. - AIX: The tests now have a --pthread option. The default thread stack size on AIX (96K) makes std::thread unusable for runtest.cc, which needs around 300K. - Windows: The DLL can now be built. Since DLLs do not support the C++11 extern thread_local context, each translation unit gets its own static reference to the thread_local context. This should preserve the semantics at the expense of clarity. Note that this scheme is specific to the DLL build; the static library build on Windows as well as all other operating systems (except for OpenBSD and Solaris) use the C++11 extern thread_local context. - OpenBSD, Solaris: The shared library now works using the above scheme. For simplicity, both the shared and static libraries use the workaround. **style fixes** - Apply several clang-tidy suggestions (high diagnostic level). **bug fixes** - DecimalException now inherits from std::runtime_error instead of std::exception. This automatically provides a nothrow copy constructor. - Use mpd_free() instead of free(). This only affects applications using the libmpdec custom allocators. **build fixes** - Undefine some additional math.h macros for non-compliant C++11 implementations. - libmpdec++ is now linked against libmpdec. Version 2.5.0 ------------- **New: libmpdec++** libmpdec++ is a new C++ library around libmpdec. It frees users from manual memory management and allows cleaner code using inline operators. libmpdec++ has a thread local context, so inline operators work seamlessly with threaded code. **features** 1) New functions *mpd_qset_string_exact*, *mpd_qset_i64_exact* and *mpd_qset_u64_exact*. 2) For very large precisions like *MPD_MAX_PREC* libmpdec failed with *MPD_Malloc_error* even when the result was exact and required far fewer digits. Now libmpdec retries the operation with the smallest possible precision for exact results. 3) ./configure now has the *--enable-profile* option for easier profile guided optimization builds. Using PGO, recent compilers produce better optimized libraries with speedups in the order of 20%. 4) C++ use: All headers now assume at least C++11, so a couple of hacks have been removed from the headers. C++ compatibility is fully tested in libmpdec++. **behavior changes** 1) The functions *mpd_ceil*, *mpd_floor* and *mpd_trunc* now set *MPD_Invalid_operation* when the input is *NaN* or *Infinity*. Previously they returned special values unchanged. That behavior was inspired by the similar *to_integral* function from the specification, but does not seem useful for the above functions. **build fixes** 1) OS X: Linking has been completely reworked and now uses .dylib. 2) Windows: vcstdint.h has been removed, Windows now supports stdint.h. **bug fixes** 1) A couple of quiet functions have been made resilient against being called with a "dirty" status. Note that it is not recommended in general to call quiet functions with any status other than 0. 2) In runtest.c, fma_eq.decTest and powmod_eq.decTest operands were accidentally reversed for the *op_eq_eq* tests. Since both the code and the tests assumed reversed operands, the tests were correct. However, for readability this situation has been fixed. Version 2.4.2 ------------- **build fixes** 1) ICC/Windows: the optimized x86 build requires -fp-model=precise. 2) OS X: the linker requires -dynamiclib and -install_name for building a shared library. Version 2.4.1 ------------- **build fixes** 1) The __uint128_t detection in ./configure has been fixed . Failure to detect the option resulted in building the significantly slower ANSI target on non-x86/amd64 platforms. 2) Use -fPIC instead of -fpic to fix a build failure on SPARC platforms. 3) Split the tests into a faster "make check" and a slower "make check_alloc". The latter tests allocation failures but is too slow on older machines. 4) Generate detailed test output for better feedback on slower machines. 5) The static library is now built without -fPIC, which is significantly faster at least on x86. Both the static and the shared library are now tested separately. **bug fixes** 1) PEP 3101 formatting: With the '%' format type, a trailing percent sign is now also added for infinities and NaNs. Version 2.4.0 ------------- **features** 1) Faster integer to string conversion. 2) mpd_qln(), mpd_qlog10() and mpd_pow() are now thread-safe. 3) All functions that take or return C integers are now available in both the 64-bit and the 32-bit builds. 4) Support for cross-compiling. 5) Scripts for Visual Studio builds. **code improvements** 1) This version is exactly the same as the version shipped with Python-3.3+. Large portions of the code have been refactored in order to facilitate proofs. Many ACL2 proofs have been added. **removed** 1) The Python module has been removed from mpdecimal, since both libmpdec and cdecimal are included in Python-3.3+. 2) The large test suite against decNumber as well as the multi-precision tests against gmp have been removed, but will be available in a separate package. Naturally these tests are still run as part of the release process. Version 2.3 ----------- **features** 1) New test suite with comprehensive tests against decNumber. 2) Full support for compilers without uint64_t (tested with CompCert). **bug fixes** 1) If ROUND_FLOOR is set and the operand is zero, the functions mpd_plus() and mpd_minus() have special cases for the sign of the result. Version 2.2 ----------- **build process** 1) configure: append CFLAGS to CONFIG flags. 2) Makefile: use includedir, libdir, datarootdir, datadir, docdir, DESTDIR. **workarounds for toolchain bugs** 1) Enable workaround for a gcc miscompilation. See: `http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 `_ 2) Enable workaround for the glibc _FORTIFY_SOURCE/memmove bug, which is exposed by gcc-4.6. See: `http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html `_ **features** 1) Make PPRO inline assembly PIC-compliant (for the dynamic library). Version 2.1 ----------- Version 2.1 was never released, but escaped into the wild via the Makefile and setup.py in cdecimal-1.97-rc2.tar.gz. Both files already had that version number. **features** 1) Code coverage increased to 100%. This includes every possible allocation failure. 2) Switch build process to ./configure. 3) Makefile targets for creating coverage reports. **bug fixes** 1) mpd_qget_uint, mpd_qget_u64, mpd_qget_u32 did not raise for negative input. 2) Handle allocation failures in _mpd_fntmul under extreme conditions. Version 1.2.1 ------------- **bug fixes** 1) With MACHINE=ansi64, the macros BSR and BSF used x86 assembly. This caused compilation to fail on non-x64 platforms. Version 1.2 ----------- **features** 1) Support for compilers with __uint128_t (option MACHINE=ansi64). 2) Support for other 64-bit compilers (option MACHINE=ansi64c32). 3) Support for legacy compilers without uint64_t (option MACHINE=ansi-legacy). 4) Slightly different build process (please read INSTALL.txt). 5) If clamp=1, the maximum payload length of a NaN is prec-1. **bug fixes** 1) Fix for mpd_qround_to_int, which did not handle digits exceeding the context precision correctly in all cases. 2) In rare corner cases Underflow was not set in transcendental functions. mpdecimal-4.0.1/COPYRIGHT.txt0000644000000000000000000000240515005764474012523 0ustar00Copyright (c) 2008-2025 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. mpdecimal-4.0.1/INSTALL.txt0000644000000000000000000000563215005764474012266 0ustar00 # ============================================================================== # Unix: library install instructions # ============================================================================== # NONGNU: gmake required! # This automatically selects the optimal build on all architectures except # for multilib systems that default to 32-bit builds (AIX, Solaris): ./configure make # The default tests suite attempts to download the official tests cases: make check # Alternatively, if wget is not installed or no network is available, run: make check_local # Install: make install # On some systems it is necessary to run ``ldconfig'', so the newly installed # library is found by the system linker. The Makefile does not run `ldconfig'' # because it is not portable: ldconfig # ============================================================================== # Custom build # ============================================================================== # # MACHINE variable: # # If ./configure fails to detect the optimal configuration, a specific # configuration can be enforced by providing the MACHINE variable. This # should only be necessary on AIX, Solaris or for a MacOS universal build. # # Example: # # ./configure MACHINE=x64 # # Possible values (in decreasing order of preference): # # 1. x64 - 64-bit OS with x86_64 processor (AMD, Intel) # # 2. uint128 - 64-bit OS, compiler provides __uint128_t (gcc) # # 3. ansi64 - 64-bit OS, ANSI C # # 4. ppro - 32-bit OS, x86 CPU, PentiumPro or later # # 5. ansi32 - 32-bit OS, ANSI C # # 6. ansi-legacy - 32-bit OS, compiler without uint64_t # # Multilib builds (Darwin and AIX): # # 7. universal - builds a 64-bit or a 32-bit library according to the # compiler ABI settings: # # Darwin: -m64 or -m32 # AIX (gcc): -maix64 or -maix32 # AIX (xlc): -q64 or -q32 # # The generated header file is suitable for both 64-bit # and 32-bit installs. # # # CFLAGS, LDFLAGS, CXXFLAGS, LDXXFLAGS: # # If CFLAGS or LDFLAGS (or the C++ counterparts) are passed to ./configure, # they are appended to the minimal libmpdec (or libmpdec++) configuration: # # ./configure CFLAGS="-m32 -march=i586 -O3" LDFLAGS="-m32" # # ==> -DCONFIG_32 -DPPRO -DASM -O2 -fpic -m32 -march=i586 -O3 # # Both MACHINE and CFLAGS can be specified, making it possible to have a # complete custom configuration: # # ./configure MACHINE=ansi32 CFLAGS="-Wall -W -O3 -g" # # ==> -DCONFIG_32 -DANSI -Wall -W -O3 -g # # ====================================================================== # Windows: library install instructions # ====================================================================== Build scripts for Visual Studio are in the vcbuild directory. mpdecimal-4.0.1/Makefile.in0000644000000000000000000001044115005764474012456 0ustar00 # ============================================================================== # Unix Makefile for libmpdec/libmpdec++ # ============================================================================== PACKAGE_TARNAME = @PACKAGE_TARNAME@ INSTALL = @INSTALL@ ENABLE_CXX = @ENABLE_CXX@ ENABLE_STATIC = @ENABLE_STATIC@ ENABLE_SHARED = @ENABLE_SHARED@ ENABLE_PC = @ENABLE_PC@ ENABLE_DOC = @ENABLE_DOC@ ENABLE_MINGW = @ENABLE_MINGW@ PROFILE = LIBSTATIC = @LIBSTATIC@ LIBNAME = @LIBNAME@ LIBSONAME = @LIBSONAME@ LIBSHARED = @LIBSHARED@ LIBIMPORT = @LIBIMPORT@ LIBSTATIC_CXX = @LIBSTATIC_CXX@ LIBNAME_CXX = @LIBNAME_CXX@ LIBSONAME_CXX = @LIBSONAME_CXX@ LIBSHARED_CXX = @LIBSHARED_CXX@ LIBIMPORT_CXX = @LIBIMPORT_CXX@ LIBSHARED_USE_AR = @LIBSHARED_USE_AR@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ includedir = @includedir@ libdir = @libdir@ datarootdir = @datarootdir@ docdir = @docdir@ mandir = @mandir@ ifeq ($(ENABLE_CXX), yes) default: libcxx check: cd libmpdec && $(MAKE) check cd libmpdec++ && $(MAKE) check check_local: cd libmpdec && $(MAKE) check_local cd libmpdec++ && $(MAKE) check_local check_alloc: cd libmpdec && $(MAKE) check_alloc cd libmpdec++ && $(MAKE) check_alloc else default: lib check: cd libmpdec && $(MAKE) check check_local: cd libmpdec && $(MAKE) check_local check_alloc: cd libmpdec && $(MAKE) check_alloc endif lib: cd libmpdec && $(MAKE) $(PROFILE) libcxx: lib cd libmpdec++ && $(MAKE) $(PROFILE) install: install_dirs install_files install_dirs: default ifeq ($(ENABLE_MINGW), yes) $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) endif $(INSTALL) -d -m 755 $(DESTDIR)$(includedir) $(INSTALL) -d -m 755 $(DESTDIR)$(libdir) $(INSTALL) -d -m 755 $(DESTDIR)$(docdir) ifeq ($(ENABLE_PC), yes) $(INSTALL) -d -m 755 $(DESTDIR)$(libdir)/pkgconfig endif ifeq ($(ENABLE_DOC), yes) $(INSTALL) -d -m 755 $(DESTDIR)$(mandir)/man3 endif install_files: install_dirs $(INSTALL) -m 644 libmpdec/mpdecimal.h $(DESTDIR)$(includedir) ifeq ($(ENABLE_STATIC), yes) $(INSTALL) -m 644 libmpdec/$(LIBSTATIC) $(DESTDIR)$(libdir) endif ifeq ($(ENABLE_SHARED), yes) ifeq ($(ENABLE_MINGW), yes) $(INSTALL) -m 644 libmpdec/$(LIBIMPORT) $(DESTDIR)$(libdir) $(INSTALL) -m 755 libmpdec/$(LIBSHARED) $(DESTDIR)$(bindir) else ifeq ($(LIBSHARED_USE_AR), no) $(INSTALL) -m 755 libmpdec/$(LIBSHARED) $(DESTDIR)$(libdir) cd $(DESTDIR)$(libdir) && ln -sf $(LIBSHARED) $(LIBSONAME) && ln -sf $(LIBSHARED) $(LIBNAME) endif endif endif ifeq ($(ENABLE_CXX), yes) $(INSTALL) -m 644 libmpdec++/decimal.hh $(DESTDIR)$(includedir) ifeq ($(ENABLE_STATIC), yes) $(INSTALL) -m 644 libmpdec++/$(LIBSTATIC_CXX) $(DESTDIR)$(libdir) endif ifeq ($(ENABLE_SHARED), yes) ifeq ($(ENABLE_MINGW), yes) $(INSTALL) -m 644 libmpdec++/$(LIBIMPORT_CXX) $(DESTDIR)$(libdir) $(INSTALL) -m 755 libmpdec++/$(LIBSHARED_CXX) $(DESTDIR)$(bindir) else ifeq ($(LIBSHARED_USE_AR), no) $(INSTALL) -m 755 libmpdec++/$(LIBSHARED_CXX) $(DESTDIR)$(libdir) cd $(DESTDIR)$(libdir) && ln -sf $(LIBSHARED_CXX) $(LIBSONAME_CXX) && ln -sf $(LIBSHARED_CXX) $(LIBNAME_CXX) endif endif endif endif ifeq ($(ENABLE_PC), yes) $(INSTALL) -m 644 libmpdec/.pc/libmpdec.pc $(DESTDIR)$(libdir)/pkgconfig ifeq ($(ENABLE_CXX), yes) $(INSTALL) -m 644 libmpdec++/.pc/libmpdec++.pc $(DESTDIR)$(libdir)/pkgconfig endif endif $(INSTALL) -m 644 doc/COPYRIGHT.txt $(DESTDIR)$(docdir) ifeq ($(ENABLE_DOC), yes) $(INSTALL) -m 644 doc/mpdecimal.3 $(DESTDIR)$(mandir)/man3 $(INSTALL) -m 644 doc/libmpdec.3 $(DESTDIR)$(mandir)/man3 ifeq ($(ENABLE_CXX), yes) $(INSTALL) -m 644 doc/libmpdec++.3 $(DESTDIR)$(mandir)/man3 endif endif profile: PROFILE := profile profile: default clean: cd libmpdec && if [ -f Makefile ]; then $(MAKE) clean; else exit 0; fi cd libmpdec++ && if [ -f Makefile ]; then $(MAKE) clean; else exit 0; fi cd tests && if [ -f Makefile ]; then $(MAKE) clean; else exit 0; fi cd tests++ && if [ -f Makefile ]; then $(MAKE) clean; else exit 0; fi distclean: cd libmpdec && if [ -f Makefile ]; then $(MAKE) distclean; else exit 0; fi cd libmpdec++ && if [ -f Makefile ]; then $(MAKE) distclean; else exit 0; fi cd tests && if [ -f Makefile ]; then $(MAKE) distclean; else exit 0; fi cd tests++ && if [ -f Makefile ]; then $(MAKE) distclean; else exit 0; fi rm -f config.h config.log config.status Makefile rm -rf autom4te.cache mpdecimal-4.0.1/README.txt0000644000000000000000000000273415005764474012115 0ustar00 libmpdec ======== libmpdec is a fast C/C++ library for correctly-rounded arbitrary precision decimal floating point arithmetic. It is a complete implementation of Mike Cowlishaw/IBM's General Decimal Arithmetic Specification. The full specification is available here: http://speleotrove.com/decimal/ libmpdec will - with minor restrictions - also conform to the IEEE 754-2008 Standard for Floating-Point Arithmetic, provided that the appropriate context parameters are set. libmpdec is the basis for the decimal module in Python-3.3. The library has been tested on the following platforms: amd64: Linux, FreeBSD, OpenBSD, OpenSolaris, Windows ppc64: AIX x86: Linux, FreeBSD, OpenBSD, OpenSolaris, Windows mips32: Debian libmpdec++ ========== libmpdec++ is a complete implementation of the General Decimal Arithmetic Specification. libmpdec++ is mostly a header library around libmpdec's C functions. The library frees users from manual memory management and has an easy API with inline operators similar to the one in Python's decimal module. Like Python's decimal module, libmpdec++ has a thread local context for inline operators and other functions that use the implicit context. In benchmarks the speed is close to libmpdec (about 4% slower due to the copying, destructor overhead and the thread local context). libmpdec++ has been tested on 64/32-bit Linux, 64/32-bit FreeBSD and OpenBSD and 64/32-bit Windows. Contact: Stefan Krah mpdecimal-4.0.1/config.guess0000755000000000000000000014306715005764474012744 0ustar00#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2024-07-27' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still # use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c17 c99 c89 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #if defined(__ANDROID__) LIBC=android #else #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #elif defined(__LLVM_LIBC__) LIBC=llvm #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like '4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-pc-managarm-mlibc" ;; *:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __ARM_EABI__ #ifdef __ARM_PCS_VFP ABI=eabihf #else ABI=eabi #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; esac fi GUESS=$CPU-unknown-linux-$LIBCABI ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:cos:*:*) GUESS=$UNAME_MACHINE-unknown-cos ;; kvx:mbr:*:*) GUESS=$UNAME_MACHINE-unknown-mbr ;; loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; *:Ironclad:*:*) GUESS=$UNAME_MACHINE-unknown-ironclad ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif int main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mpdecimal-4.0.1/config.h.in0000644000000000000000000000645315005764474012444 0ustar00/* config.h.in. Generated from configure.ac by autoheader. */ /* * The generated config.h is only included in runtest.cc, and there are * no plans to use it elsewhere. All defines apart from HAVE_PTHREAD_H * are purely informational. */ /* Define if we can use x64 gcc inline assembler. */ #undef HAVE_GCC_ASM_FOR_X64 /* Define if we can use x87 gcc inline assembler. */ #undef HAVE_GCC_ASM_FOR_X87 /* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and bcopy. */ #undef HAVE_GLIBC_MEMMOVE_BUG /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define if gcc has the ipa-pure-const bug. */ #undef HAVE_IPA_PURE_CONST_BUG /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define if your compiler provides __uint128_t. */ #undef HAVE_UINT128_T /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* The size of `size_t', as computed by sizeof. */ #undef SIZEOF_SIZE_T /* The size of `__uint128_t', as computed by sizeof. */ #undef SIZEOF___UINT128_T /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef int64_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t mpdecimal-4.0.1/config.sub0000755000000000000000000011544115005764474012402 0ustar00#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale timestamp='2024-05-27' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in cloudabi*-eabi* \ | kfreebsd*-gnu* \ | knetbsd*-gnu* \ | kopensolaris*-gnu* \ | linux-* \ | managarm-* \ | netbsd*-eabi* \ | netbsd*-gnu* \ | nto-qnx* \ | os2-emx* \ | rtmk-nova* \ | storm-chaos* \ | uclinux-gnu* \ | uclinux-uclibc* \ | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) case $field1-$field2 in # Shorthands that happen to contain a single dash convex-c[12] | convex-c3[248]) basic_machine=$field2-convex basic_os= ;; decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Do not treat sunos as a manufacturer sun*os*) basic_machine=$field1 basic_os=$field2 ;; # Manufacturers 3100* \ | 32* \ | 3300* \ | 3600* \ | 7300* \ | acorn \ | altos* \ | apollo \ | apple \ | atari \ | att* \ | axis \ | be \ | bull \ | cbm \ | ccur \ | cisco \ | commodore \ | convergent* \ | convex* \ | cray \ | crds \ | dec* \ | delta* \ | dg \ | digital \ | dolphin \ | encore* \ | gould \ | harris \ | highlevel \ | hitachi* \ | hp \ | ibm* \ | intergraph \ | isi* \ | knuth \ | masscomp \ | microblaze* \ | mips* \ | motorola* \ | ncr* \ | news \ | next \ | ns \ | oki \ | omron* \ | pc533* \ | rebel \ | rom68k \ | rombug \ | semi \ | sequent* \ | siemens \ | sgi* \ | siemens \ | sim \ | sni \ | sony* \ | stratus \ | sun \ | sun[234]* \ | tektronix \ | tti* \ | ultra \ | unicom* \ | wec \ | winbond \ | wrs) basic_machine=$field1-$field2 basic_os= ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300) cpu=m68k vendor=motorola ;; # This used to be dpx2*, but that gets the RS6000-based # DPX/20 and the x86-based DPX/2-100 wrong. See # https://oldskool.silicium.org/stations/bull_dpx20.htm # https://www.feb-patrimoine.com/english/bull_dpx2.htm # https://www.feb-patrimoine.com/english/unix_and_bull.htm dpx2 | dpx2[23]00 | dpx2[23]xx) cpu=m68k vendor=bull ;; dpx2100 | dpx21xx) cpu=i386 vendor=bull ;; dpx20) cpu=rs6000 vendor=bull ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x"$basic_os" != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. obj= case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) saved_IFS=$IFS IFS="-" read kernel os <&2 fi ;; *) echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 exit 1 ;; esac case $obj in aout* | coff* | elf* | pe*) ;; '') # empty is fine ;; *) echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 exit 1 ;; esac # Here we handle the constraint that a (synthetic) cpu and os are # valid only in combination with each other and nowhere else. case $cpu-$os in # The "javascript-unknown-ghcjs" triple is used by GHC; we # accept it here in order to tolerate that, but reject any # variations. javascript-ghcjs) ;; javascript-* | *-ghcjs) echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os-$obj in linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ | linux-mlibc*- | linux-musl*- | linux-newlib*- \ | linux-relibc*- | linux-uclibc*- | linux-ohos*- ) ;; uclinux-uclibc*- | uclinux-gnu*- ) ;; managarm-mlibc*- | managarm-kernel*- ) ;; windows*-msvc*-) ;; -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ | -uclibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; -kernel*- ) echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 exit 1 ;; *-kernel*- ) echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 exit 1 ;; *-msvc*- ) echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 exit 1 ;; kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-) ;; vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) ;; nto-qnx*-) ;; os2-emx-) ;; rtmk-nova-) ;; *-eabi*- | *-gnueabi*-) ;; none--*) # None (no kernel, i.e. freestanding / bare metal), # can be paired with an machine code file format ;; -*-) # Blank kernel with real OS is always fine. ;; --*) # Blank kernel and OS with real machine code file format is always fine. ;; *-*-*) echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos* | *-solaris*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mpdecimal-4.0.1/configure0000755000000000000000000063021615005764474012330 0ustar00#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for mpdecimal 4.0.1. # # Report bugs to . # # # Copyright (c) 2008-2025 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. # # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: mpdecimal-bugs@bytereef.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mpdecimal' PACKAGE_TARNAME='mpdecimal' PACKAGE_VERSION='4.0.1' PACKAGE_STRING='mpdecimal 4.0.1' PACKAGE_BUGREPORT='mpdecimal-bugs@bytereef.org' PACKAGE_URL='https://www.bytereef.org/mpdecimal/index.html' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS CONFIGURE_LDXXFLAGS CONFIGURE_CXXFLAGS CONFIGURE_LDFLAGS CONFIGURE_CFLAGS CONFIGURE_LIBMPDEC_CFLAGS MPD_PREC MPD_GNU99 MPD_HEADER_CONFIG OBJECT_SUFFIX EXPORTSYMS INSTALL INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM EGREP GREP CPP MPD_PUSE MPD_PGEN MPD_PTHREAD FILTER_FOR_STATIC LDXX LD LDXXFLAGS MACHINE RANLIB AR ac_ct_CXX CXXFLAGS CXX OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC ENABLE_PC ENABLE_DOC ENABLE_SHARED ENABLE_STATIC ENABLE_CXX ENABLE_MINGW LIBIMPORT_CXX LIBSHARED_CXX LIBSONAME_CXX LIBNAME_CXX LIBSTATIC_CXX LINK_DYNAMIC LINK_STATIC LIBSHARED_USE_AR LIBIMPORT LIBSHARED LIBSONAME LIBNAME LIBSTATIC FPIC host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_cxx enable_static enable_shared enable_doc enable_pc ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC MACHINE LDXXFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures mpdecimal 4.0.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/mpdecimal] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of mpdecimal 4.0.1:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-cxx enable building libmpdec++ (default is yes) --enable-static enable building static libraries (default is yes) --enable-shared enable building shared libraries (default is yes) --enable-doc enable installing the documentation (default is yes) --enable-pc enable installing the pkg-config files (default is yes) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags MACHINE force configuration: x64, uint128, ansi64, ppro, ansi32, ansi-legacy, universal LDXXFLAGS C++ linker flags CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . mpdecimal home page: . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF mpdecimal configure 4.0.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Copyright (c) 2008-2025 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. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------------ ## ## Report this to mpdecimal-bugs@bytereef.org ## ## ------------------------------------------ ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_find_intX_t LINENO BITS VAR # ----------------------------------- # Finds a signed integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_intX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in int$2_t 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else case $ac_type in #( int$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by mpdecimal $as_me 4.0.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" ac_config_files="$ac_config_files Makefile libmpdec/Makefile libmpdec/mpdecimal.h libmpdec/.pc/libmpdec.pc libmpdec++/Makefile libmpdec++/.pc/libmpdec++.pc tests/Makefile tests++/Makefile" # Link files for out-of-tree builds: ac_config_links="$ac_config_links CHANGELOG.txt:CHANGELOG.txt COPYRIGHT.txt:COPYRIGHT.txt INSTALL.txt:INSTALL.txt Makefile.in:Makefile.in README.txt:README.txt config.guess:config.guess config.h.in:config.h.in config.sub:config.sub configure:configure configure.ac:configure.ac install-sh:install-sh doc/COPYRIGHT.txt:doc/COPYRIGHT.txt doc/libmpdec.3:doc/libmpdec.3 doc/libmpdec++.3:doc/libmpdec++.3 doc/mpdecimal.3:doc/mpdecimal.3 libmpdec/Makefile.in:libmpdec/Makefile.in libmpdec/Makefile.vc:libmpdec/Makefile.vc libmpdec/README.txt:libmpdec/README.txt libmpdec/basearith.c:libmpdec/basearith.c libmpdec/basearith.h:libmpdec/basearith.h libmpdec/bench.c:libmpdec/bench.c libmpdec/bench_full.c:libmpdec/bench_full.c libmpdec/bits.h:libmpdec/bits.h libmpdec/constants.c:libmpdec/constants.c libmpdec/constants.h:libmpdec/constants.h libmpdec/context.c:libmpdec/context.c libmpdec/convolute.c:libmpdec/convolute.c libmpdec/convolute.h:libmpdec/convolute.h libmpdec/crt.c:libmpdec/crt.c libmpdec/crt.h:libmpdec/crt.h libmpdec/difradix2.c:libmpdec/difradix2.c libmpdec/difradix2.h:libmpdec/difradix2.h libmpdec/fnt.c:libmpdec/fnt.c libmpdec/fnt.h:libmpdec/fnt.h libmpdec/fourstep.c:libmpdec/fourstep.c libmpdec/fourstep.h:libmpdec/fourstep.h libmpdec/io.c:libmpdec/io.c libmpdec/io.h:libmpdec/io.h libmpdec/mpalloc.c:libmpdec/mpalloc.c libmpdec/mpalloc.h:libmpdec/mpalloc.h libmpdec/mpdecimal.c:libmpdec/mpdecimal.c libmpdec/mpdecimal32vc.h:libmpdec/mpdecimal32vc.h libmpdec/mpdecimal64vc.h:libmpdec/mpdecimal64vc.h libmpdec/mpdecimal.h.in:libmpdec/mpdecimal.h.in libmpdec/mpsignal.c:libmpdec/mpsignal.c libmpdec/numbertheory.c:libmpdec/numbertheory.c libmpdec/numbertheory.h:libmpdec/numbertheory.h libmpdec/sixstep.c:libmpdec/sixstep.c libmpdec/sixstep.h:libmpdec/sixstep.h libmpdec/transpose.c:libmpdec/transpose.c libmpdec/transpose.h:libmpdec/transpose.h libmpdec/typearith.h:libmpdec/typearith.h libmpdec/umodarith.h:libmpdec/umodarith.h libmpdec/vcdiv64.asm:libmpdec/vcdiv64.asm libmpdec/examples/README.txt:libmpdec/examples/README.txt libmpdec/examples/compare.c:libmpdec/examples/compare.c libmpdec/examples/div.c:libmpdec/examples/div.c libmpdec/examples/divmod.c:libmpdec/examples/divmod.c libmpdec/examples/multiply.c:libmpdec/examples/multiply.c libmpdec/examples/pow.c:libmpdec/examples/pow.c libmpdec/examples/powmod.c:libmpdec/examples/powmod.c libmpdec/examples/shift.c:libmpdec/examples/shift.c libmpdec/examples/sqrt.c:libmpdec/examples/sqrt.c libmpdec/.objs/README.txt:libmpdec/.objs/README.txt libmpdec/.objs/symbols32.exp:libmpdec/.objs/symbols32.exp libmpdec/.objs/symbols64.exp:libmpdec/.objs/symbols64.exp libmpdec/.pc/libmpdec.pc.in:libmpdec/.pc/libmpdec.pc.in libmpdec/.profile/train.sh:libmpdec/.profile/train.sh libmpdec++/Makefile.in:libmpdec++/Makefile.in libmpdec++/Makefile.vc:libmpdec++/Makefile.vc libmpdec++/bench.cc:libmpdec++/bench.cc libmpdec++/bench_full.cc:libmpdec++/bench_full.cc libmpdec++/decimal.cc:libmpdec++/decimal.cc libmpdec++/decimal.hh:libmpdec++/decimal.hh libmpdec++/examples/factorial.cc:libmpdec++/examples/factorial.cc libmpdec++/examples/pi.cc:libmpdec++/examples/pi.cc libmpdec++/.objs/README.txt:libmpdec++/.objs/README.txt libmpdec++/.pc/libmpdec++.pc.in:libmpdec++/.pc/libmpdec++.pc.in libmpdec++/.profile/train.sh:libmpdec++/.profile/train.sh tests/Makefile.in:tests/Makefile.in tests/Makefile.vc:tests/Makefile.vc tests/README.txt:tests/README.txt tests/additional.decTest:tests/additional.decTest tests/gettests.bat:tests/gettests.bat tests/gettests.sh:tests/gettests.sh tests/official.decTest:tests/official.decTest tests/runshort.sh:tests/runshort.sh tests/runshort_alloc.sh:tests/runshort_alloc.sh tests/runtest.c:tests/runtest.c tests/test.c:tests/test.c tests/test.h:tests/test.h tests/vctest.h:tests/vctest.h tests/testdata_dist/baseconv.decTest:tests/testdata_dist/baseconv.decTest tests/testdata_dist/binop_eq.decTest:tests/testdata_dist/binop_eq.decTest tests/testdata_dist/cov.decTest:tests/testdata_dist/cov.decTest tests/testdata_dist/divmod.decTest:tests/testdata_dist/divmod.decTest tests/testdata_dist/divmod_eq.decTest:tests/testdata_dist/divmod_eq.decTest tests/testdata_dist/extra.decTest:tests/testdata_dist/extra.decTest tests/testdata_dist/fma_eq.decTest:tests/testdata_dist/fma_eq.decTest tests/testdata_dist/format.decTest:tests/testdata_dist/format.decTest tests/testdata_dist/getint.decTest:tests/testdata_dist/getint.decTest tests/testdata_dist/invroot.decTest:tests/testdata_dist/invroot.decTest tests/testdata_dist/largeint.decTest:tests/testdata_dist/largeint.decTest tests/testdata_dist/maxprec.decTest:tests/testdata_dist/maxprec.decTest tests/testdata_dist/powmod.decTest:tests/testdata_dist/powmod.decTest tests/testdata_dist/powmod_eq.decTest:tests/testdata_dist/powmod_eq.decTest tests/testdata_dist/shiftlr.decTest:tests/testdata_dist/shiftlr.decTest tests/testdata_dist/testruntest.decTest:tests/testdata_dist/testruntest.decTest tests++/Makefile.in:tests++/Makefile.in tests++/Makefile.vc:tests++/Makefile.vc tests++/README.txt:tests++/README.txt tests++/additional.topTest:tests++/additional.topTest tests++/apitest.cc:tests++/apitest.cc tests++/gettests.bat:tests++/gettests.bat tests++/gettests.sh:tests++/gettests.sh tests++/official.topTest:tests++/official.topTest tests++/runshort.sh:tests++/runshort.sh tests++/runshort_alloc.sh:tests++/runshort_alloc.sh tests++/runtest.cc:tests++/runtest.cc tests++/test.cc:tests++/test.cc tests++/test.hh:tests++/test.hh tests++/vctest.hh:tests++/vctest.hh" # ============================================================================== # MPD_HEADER_CONFIG # ============================================================================== CONFIG_64=" /* ABI: 64-bit */ #define MPD_CONFIG_64 1 #ifdef MPD_CONFIG_32 #error \"cannot use MPD_CONFIG_32 with 64-bit header.\" #endif #ifdef CONFIG_32 #error \"cannot use CONFIG_32 with 64-bit header.\" #endif" CONFIG_32=" /* ABI: 32-bit */ #define MPD_CONFIG_32 1 #ifdef MPD_CONFIG_64 #error \"cannot use MPD_CONFIG_64 with 32-bit header.\" #endif #ifdef CONFIG_64 #error \"cannot use CONFIG_64 with 32-bit header.\" #endif" CONFIG_32_LEGACY=" /* ABI: 32-bit */ #define MPD_CONFIG_32 1 /* libmpdec was compiled without support for int64_t */ #define MPD_LEGACY_COMPILER 1 #ifdef MPD_CONFIG_64 #error \"cannot use MPD_CONFIG_64 with 32-bit header.\" #endif #ifdef CONFIG_64 #error \"cannot use CONFIG_64 with 32-bit header.\" #endif" CONFIG_UNIVERSAL=" /* Mac OS X: support for building universal binaries */ #if defined(MPD_CONFIG_64) || defined(MPD_CONFIG_32) #error \"cannot use MPD_CONFIG_64 or MPD_CONFIG_32 with universal header.\" #endif #if defined(CONFIG_64) || defined(CONFIG_32) #error \"cannot use CONFIG_64 or CONFIG_32 with universal header.\" #endif #if defined(__ppc__) #define MPD_CONFIG_32 1 #ifdef UNIVERSAL #define CONFIG_32 #define ANSI #endif #elif defined(__ppc64__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ANSI #endif #elif defined(__i386__) #define MPD_CONFIG_32 1 #ifdef UNIVERSAL #define CONFIG_32 #define ANSI #endif #elif defined(__x86_64__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ASM #endif #elif defined(__arm64__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ANSI #endif #else #error \"unknown architecture for universal build.\" #endif" CONFIG_UNIVERSAL_AIX_UINT128=" /* AIX: support for multilib */ #if defined(MPD_CONFIG_64) || defined(MPD_CONFIG_32) #error \"cannot use MPD_CONFIG_64 or MPD_CONFIG_32 with multilib header.\" #endif #if defined(CONFIG_64) || defined(CONFIG_32) #error \"cannot use CONFIG_64 or CONFIG_32 with multilib header.\" #endif #if defined(__64BIT__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ANSI #define HAVE_UINT128_T #endif #else #define MPD_CONFIG_32 1 #ifdef UNIVERSAL #define CONFIG_32 #define ANSI #endif #endif" CONFIG_UNIVERSAL_AIX_ANSI64=" /* AIX: support for multilib */ #if defined(MPD_CONFIG_64) || defined(MPD_CONFIG_32) #error \"cannot use MPD_CONFIG_64 or MPD_CONFIG_32 with multilib header.\" #endif #if defined(CONFIG_64) || defined(CONFIG_32) #error \"cannot use CONFIG_64 or CONFIG_32 with multilib header.\" #endif #if defined(__64BIT__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ANSI #endif #else #define MPD_CONFIG_32 1 #ifdef UNIVERSAL #define CONFIG_32 #define ANSI #endif #endif" # ============================================================================== # Detect build and host systems # ============================================================================== ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # ============================================================================== # Select library names # ============================================================================== # MinGW/Cygwin/MSYS2 support: ENABLE_MINGW="no" # Set library names and linker flags: FPIC="-fPIC" LIBSTATIC=libmpdec.a LIBSHARED_USE_AR="no" LIBIMPORT= LINK_STATIC= LINK_DYNAMIC= case $host in *-*-darwin*) LIBNAME="libmpdec.dylib" LIBSONAME="libmpdec.4.dylib" LIBSHARED="libmpdec.4.0.1.dylib" CONFIGURE_LDFLAGS="-dynamiclib $FPIC -install_name \$(libdir)/$LIBSONAME -compatibility_version 4.0 -current_version 4.0.1" ;; *-*-aix*) LIBNAME= LIBSONAME= LIBSHARED="shr.o" LIBSHARED_USE_AR="yes" CONFIGURE_LDFLAGS="-shared $FPIC -Wl,-bnoentry -Wl,-bE:.objs/symbols.exp" LINK_STATIC="-Wl,-bstatic" LINK_DYNAMIC="-Wl,-bshared" ;; *-*-mingw*) FPIC= LIBNAME= LIBIMPORT="libmpdec.dll.a" LIBSONAME= LIBSHARED="libmpdec-4.dll" CONFIGURE_LDFLAGS="-shared -Wl,--out-implib,$LIBIMPORT" ENABLE_MINGW="yes" ;; *-*-cygwin*) FPIC= LIBNAME= LIBIMPORT="libmpdec.dll.a" LIBSONAME= LIBSHARED="cygmpdec-4.dll" CONFIGURE_LDFLAGS="-shared -Wl,--out-implib,$LIBIMPORT" ENABLE_MINGW="yes" ;; *-*-msys) FPIC= LIBNAME= LIBIMPORT="libmpdec.dll.a" LIBSONAME= LIBSHARED="msys-mpdec-4.dll" CONFIGURE_LDFLAGS="-shared -Wl,--out-implib,$LIBIMPORT" ENABLE_MINGW="yes" ;; *) LIBNAME="libmpdec.so" LIBSONAME="libmpdec.so.4" LIBSHARED="libmpdec.so.4.0.1" CONFIGURE_LDFLAGS="-shared $FPIC -Wl,-soname,$LIBSONAME" ;; esac LIBSTATIC_CXX=libmpdec++.a LIBIMPORT_CXX= case $host in *-*-darwin*) LIBNAME_CXX="libmpdec++.dylib" LIBSONAME_CXX="libmpdec++.4.dylib" LIBSHARED_CXX="libmpdec++.4.0.1.dylib" CONFIGURE_LDXXFLAGS="-dynamiclib $FPIC -install_name \$(libdir)/$LIBSONAME_CXX -compatibility_version 4.0 -current_version 4.0.1" ;; *-*-aix*) LIBNAME_CXX= LIBSONAME_CXX= LIBSHARED_CXX="shr.o" CONFIGURE_LDXXFLAGS="-shared $FPIC -Wl,-bnoentry -Wl,-bE:.objs/symbols.exp" ;; *-*-mingw*) LIBNAME_CXX= LIBIMPORT_CXX="libmpdec++.dll.a" LIBSONAME_CXX= LIBSHARED_CXX="libmpdec++-4.dll" CONFIGURE_LDXXFLAGS="-shared -Wl,--out-implib,$LIBIMPORT_CXX" ;; *-*-cygwin*) LIBNAME_CXX= LIBIMPORT_CXX="libmpdec++.dll.a" LIBSONAME_CXX= LIBSHARED_CXX="cygmpdec++-4.dll" CONFIGURE_LDXXFLAGS="-shared -Wl,--out-implib,$LIBIMPORT_CXX" ;; *-*-msys) LIBNAME_CXX= LIBIMPORT_CXX="libmpdec++.dll.a" LIBSONAME_CXX= LIBSHARED_CXX="msys-mpdec++-4.dll" CONFIGURE_LDXXFLAGS="-shared -Wl,--out-implib,$LIBIMPORT_CXX" ;; *) LIBNAME_CXX="libmpdec++.so" LIBSONAME_CXX="libmpdec++.so.4" LIBSHARED_CXX="libmpdec++.so.4.0.1" CONFIGURE_LDXXFLAGS="-shared $FPIC -Wl,-soname,$LIBSONAME_CXX" ;; esac # ============================================================================== # User options # ============================================================================== # Check whether to build libmpdec++: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-cxx" >&5 $as_echo_n "checking for --enable-cxx... " >&6; } # Check whether --enable-cxx was given. if test "${enable_cxx+set}" = set; then : enableval=$enable_cxx; fi ENABLE_CXX="$enable_cxx" if test -z "$ENABLE_CXX" then if test x"$MACHINE" = x"ansi-legacy"; then ENABLE_CXX="no" else ENABLE_CXX="yes" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_CXX" >&5 $as_echo "$ENABLE_CXX" >&6; } # Check whether to build the static libraries: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-static" >&5 $as_echo_n "checking for --enable-static... " >&6; } # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; fi ENABLE_STATIC="$enable_static" if test -z "$ENABLE_STATIC" then ENABLE_STATIC="yes" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_STATIC" >&5 $as_echo "$ENABLE_STATIC" >&6; } # Check whether to build the shared libraries: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-shared" >&5 $as_echo_n "checking for --enable-shared... " >&6; } # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; fi ENABLE_SHARED="$enable_shared" if test -z "$ENABLE_SHARED" then ENABLE_SHARED="yes" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_SHARED" >&5 $as_echo "$ENABLE_SHARED" >&6; } # Check whether at least one library is enabled: if test x"$ENABLE_STATIC" = x"no" -a x"$ENABLE_SHARED" = x"no" then as_fn_error $? "at least one of --enable-static or --enable-shared must be set" "$LINENO" 5 fi # AIX: both static and shared libraries must be enabled: case $host in *-*-aix*) if test x"$ENABLE_STATIC" = x"no" -o x"$ENABLE_SHARED" = x"no" then as_fn_error $? "the AIX build requires --enable-static and --enable-shared" "$LINENO" 5 fi ;; esac # Check whether to install the documentation: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-doc" >&5 $as_echo_n "checking for --enable-doc... " >&6; } # Check whether --enable-doc was given. if test "${enable_doc+set}" = set; then : enableval=$enable_doc; fi ENABLE_DOC="$enable_doc" if test -z "$ENABLE_DOC" then ENABLE_DOC="yes" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_DOC" >&5 $as_echo "$ENABLE_DOC" >&6; } # Check whether to install the pkg-config files: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-pc" >&5 $as_echo_n "checking for --enable-pc... " >&6; } # Check whether --enable-pc was given. if test "${enable_pc+set}" = set; then : enableval=$enable_pc; fi ENABLE_PC="$enable_pc" if test -z "$ENABLE_PC" then ENABLE_PC="yes" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_PC" >&5 $as_echo "$ENABLE_PC" >&6; } # ============================================================================== # Compilers and flags # ============================================================================== # Save initial compiler flags: INITIAL_CFLAGS="$CFLAGS" INITIAL_CXXFLAGS="$CXXFLAGS" INITIAL_LDFLAGS="$LDFLAGS" INITIAL_LDXXFLAGS="$LDXXFLAGS" # Rename compiler in case $CC=cc: case $CC in cc) case $build in *-*-freebsd* | *-*-openbsd* | *-*-darwin*) CC=clang ;; *-*-netbsd*) CC=gcc ;; *-*-solaris* | *-*-sunos*) CC=suncc ;; esac ;; esac case $CXX in c++) case $build in *-*-freebsd* | *-*-openbsd* | *-*-darwin*) CXX=clang++ ;; *-*-netbsd*) CXX=g++ ;; esac ;; esac # Language and compiler: ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Preference of tested compilers: case $host in *-*-aix*) PREFERRED_CC="ibm-clang_r ibm-clang gcc xlc_r xlc cc" PREFERRED_CXX="ibm-clang++_r g++ c++" ;; *-*-freebsd* | *-*-openbsd*) PREFERRED_CC="clang gcc cc" PREFERRED_CXX="clang++ g++ c++" ;; *) PREFERRED_CC="gcc icc clang icx suncc ccomp cc" PREFERRED_CXX="g++ icpc clang++ icpx c++" ;; esac # Find CC: saved_cflags="$CFLAGS" saved_ldflags="$LDFLAGS" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in $PREFERRED_CC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in $PREFERRED_CC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" # These compilers do not fully support C++11. Disable CXX to avoid mixing # different C and C++ compilers: case $CC in *xlc* | suncc | ccomp) ENABLE_CXX="no" ;; esac # Find CXX: if test x"$ENABLE_CXX" = x"yes"; then saved_cxxflags="$CXXFLAGS" saved_ldxxflags="$LDXXFLAGS" ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in $PREFERRED_CXX do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in $PREFERRED_CXX do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CXXFLAGS="$saved_cxxflags" LDXXFLAGS="$saved_ldxxflags" fi # Check availability of -O2: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -O2" >&5 $as_echo_n "checking for -O2... " >&6; } saved_cflags="$CFLAGS" saved_ldflags="$LDFLAGS" CFLAGS="-O2" LDFLAGS= cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : have_O2=yes else have_O2=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_O2" >&5 $as_echo "$have_O2" >&6; } CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" # Find ar and ranlib: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="ar" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Force explicit configuration. This section must be here because the size # checks in the next section require the correct CFLAGS. M64= M32= if test -n "$MACHINE"; then case $host in *-*-aix*) case $CC in *xlc*) M64="-q64" M32="-q32" ;; *gcc*) M64="-maix64" M32="-maix32" ;; *) M64="-m64" M32="-m32" ;; esac ;; *) M64="-m64" M32="-m32" ;; esac case "$MACHINE" in x64 | uint128 | ansi64) CFLAGS="$CFLAGS $M64" CXXFLAGS="$CXXFLAGS $M64" LDFLAGS="$LDFLAGS $M64" LDXXFLAGS="$LDXXFLAGS $M64" ;; ppro | ansi32 | ansi-legacy) CFLAGS="$CFLAGS $M32" CXXFLAGS="$CXXFLAGS $M32" LDFLAGS="$LDFLAGS $M32" LDXXFLAGS="$LDXXFLAGS $M64" ;; universal) : ;; *) as_fn_error $? "invalid MACHINE variable: $MACHINE" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the toolchain supports the chosen ABI" >&5 $as_echo_n "checking whether the toolchain supports the chosen ABI... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : machine_supported=yes else machine_supported=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $machine_supported" >&5 $as_echo "$machine_supported" >&6; } if test "$machine_supported" = no; then as_fn_error $? "toolchain cannot handle MACHINE=$MACHINE" "$LINENO" 5 fi fi # Compiler dependent settings: MPD_PTHREAD= MPD_WARN= MPD_WARNXX= MPD_OPT="-O2" MPD_PGEN= MPD_PUSE= CONFIG_UNIVERSAL_AIX= FILTER_FOR_STATIC= case $CC in *gcc*) CONFIG_UNIVERSAL_AIX=$CONFIG_UNIVERSAL_AIX_UINT128 MPD_PTHREAD="-pthread" MPD_WARN="-Wall -Wextra -Wno-unknown-pragmas -std=c99 -pedantic" MPD_WARNXX="-Wall -Wextra -std=c++11 -pedantic" MPD_OPT="-DNDEBUG -O2" MPD_PGEN="-fprofile-generate -fprofile-values" MPD_PUSE="-fprofile-use -freorder-blocks" FILTER_FOR_STATIC="-flto% -ffat-lto-objects" ;; *icc*) AR=xiar CXX=icpc MPD_PTHREAD="-pthread" MPD_WARN="-Wall -Wextra -Wno-unknown-pragmas -std=c99 -pedantic -diag-disable=11074,11076" MPD_WARNXX="-Wall -Wextra -std=c++11 -pedantic -diag-disable=11074,11076" MPD_OPT="-DNDEBUG -O2" MPD_PGEN="-wd11505 -prof-gen" MPD_PUSE="-wd11505 -prof-use" ;; *clang* | *icx* | *emcc*) CONFIG_UNIVERSAL_AIX=$CONFIG_UNIVERSAL_AIX_UINT128 MPD_PTHREAD="-pthread" MPD_WARN="-Wall -Wextra -Wno-unknown-pragmas -std=c99 -pedantic" MPD_WARNXX="-Wall -Wextra -Wexit-time-destructors -std=c++11 -pedantic" MPD_OPT="-DNDEBUG -O2" ;; *xlc*) CONFIG_UNIVERSAL_AIX=$CONFIG_UNIVERSAL_AIX_ANSI64 CONFIGURE_LDFLAGS="-qmkshrobj -bnoentry -bE:.objs/symbols.exp" LINK_STATIC="-bstatic" LINK_DYNAMIC="-bshared" MPD_PTHREAD="-qthreaded -D_THREAD_SAFE" MPD_WARN="-qlanglvl=stdc99" MPD_OPT="-DNDEBUG -O2 -qalias=ansi -qmaxmem=-1" ;; *suncc*) MPD_WARN="-xc99" MPD_OPT="-DNDEBUG -O2" ;; *ccomp*) ENABLE_SHARED=no LINK_STATIC="-Wl,-znoexecstack" MPD_WARN="-Wall -Wno-unknown-pragmas -std=c99 -fstruct-passing" MPD_OPT="-DNDEBUG -O2" ;; *) ;; esac # These variables are set unconditionally because CONFIGURE_LDFLAGS etc. # require the compiler frontends. We leave them in the Makefiles in case # someone needs to edit the Makefiles manually. LD="$CC" LDXX="$CXX" # ============================================================================== # Headers, types, assembly, install program # ============================================================================== # Check for header files: ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in pthread.h do : ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_H 1 _ACEOF fi done # Type availability checks: ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" case $ac_cv_c_int32_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int32_t $ac_cv_c_int32_t _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" case $ac_cv_c_int64_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int64_t $ac_cv_c_int64_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) $as_echo "#define _UINT32_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint32_t $ac_cv_c_uint32_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) $as_echo "#define _UINT64_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint64_t $ac_cv_c_uint64_t _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default" if test "x$ac_cv_type___uint128_t" = xyes; then : $as_echo "#define HAVE_UINT128_T 1" >>confdefs.h fi # Sizes of various types: # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 $as_echo_n "checking size of size_t... " >&6; } if ${ac_cv_sizeof_size_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : else if test "$ac_cv_type_size_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (size_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_size_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 $as_echo "$ac_cv_sizeof_size_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_SIZE_T $ac_cv_sizeof_size_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of __uint128_t" >&5 $as_echo_n "checking size of __uint128_t... " >&6; } if ${ac_cv_sizeof___uint128_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (__uint128_t))" "ac_cv_sizeof___uint128_t" "$ac_includes_default"; then : else if test "$ac_cv_type___uint128_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (__uint128_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof___uint128_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof___uint128_t" >&5 $as_echo "$ac_cv_sizeof___uint128_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF___UINT128_T $ac_cv_sizeof___uint128_t _ACEOF # x64 with gcc asm: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for x64 gcc inline assembler" >&5 $as_echo_n "checking for x64 gcc inline assembler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { __asm__ __volatile__ ("movq %rcx, %rax"); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_x64=yes else have_gcc_asm_for_x64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x64" >&5 $as_echo "$have_gcc_asm_for_x64" >&6; } if test "$have_gcc_asm_for_x64" = yes; then $as_echo "#define HAVE_GCC_ASM_FOR_X64 1" >>confdefs.h fi # x87 with gcc asm: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for x87 gcc inline assembler" >&5 $as_echo_n "checking for x87 gcc inline assembler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { unsigned short cw; __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_gcc_asm_for_x87=yes else have_gcc_asm_for_x87=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x87" >&5 $as_echo "$have_gcc_asm_for_x87" >&6; } if test "$have_gcc_asm_for_x87" = yes; then $as_echo "#define HAVE_GCC_ASM_FOR_X87 1" >>confdefs.h fi # Install program: # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # ============================================================================== # Detect toolchain bugs # ============================================================================== # _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: # http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html { $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc _FORTIFY_SOURCE/memmove bug" >&5 $as_echo_n "checking for glibc _FORTIFY_SOURCE/memmove bug... " >&6; } saved_cflags="$CFLAGS" saved_ldflags="$LDFLAGS" CFLAGS="-O2 -D_FORTIFY_SOURCE=2" if test "$have_O2" = no; then CFLAGS= fi LDFLAGS= if test "$cross_compiling" = yes; then : have_glibc_memmove_bug=undefined else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include void foo(void *p, void *q) { memmove(p, q, 19); } int main() { char a[32] = "123456789000000000"; foo(&a[9], a); if (strcmp(a, "123456789123456789000000000") != 0) return 1; foo(a, &a[9]); if (strcmp(a, "123456789000000000") != 0) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : have_glibc_memmove_bug=no else have_glibc_memmove_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_glibc_memmove_bug" >&5 $as_echo "$have_glibc_memmove_bug" >&6; } if test "$have_glibc_memmove_bug" = yes; then $as_echo "#define HAVE_GLIBC_MEMMOVE_BUG 1" >>confdefs.h fi # ============================================================================== # Optimized configurations # ============================================================================== # Auto-detect machine dependent settings: AIX_AR= AIX_RANLIB= EXPORTSYMS= OBJECT_SUFFIX= DETECTED_MACHINE= if test $ac_cv_sizeof_size_t -eq 8; then AIX_AR="ar -X64" AIX_RANLIB="ranlib -X64" EXPORTSYMS="symbols64.exp" OBJECT_SUFFIX="4_64.o" if test $have_gcc_asm_for_x64 = yes; then DETECTED_MACHINE="x64" elif test $ac_cv_type___uint128_t = yes; then DETECTED_MACHINE="uint128" else DETECTED_MACHINE="ansi64" fi else AIX_AR="ar -X32" AIX_RANLIB="ranlib -X32" EXPORTSYMS="symbols32.exp" OBJECT_SUFFIX="4.o" DETECTED_MACHINE="ansi32" if test $have_gcc_asm_for_x87 = yes; then case $CC in *gcc* | *clang*) # icc >= 11.0 works as well case $host in *-*-darwin*) ;; *) DETECTED_MACHINE="ppro" ;; esac ;; esac fi fi if test -z "$MACHINE"; then MACHINE="$DETECTED_MACHINE" fi # Set configuration variables: MPD_ABI= MPD_PREC=9 case "$MACHINE" in x64) MPD_HEADER_CONFIG=$CONFIG_64 MPD_ABI=$M64 MPD_CONFIG="-DCONFIG_64 -DASM" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M64" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M64" MPD_PREC=19 ;; uint128) MPD_HEADER_CONFIG=$CONFIG_64 MPD_ABI=$M64 MPD_CONFIG="-DCONFIG_64 -DANSI -DHAVE_UINT128_T" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M64" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M64" MPD_PREC=19 ;; ansi64) MPD_HEADER_CONFIG=$CONFIG_64 MPD_ABI=$M64 MPD_CONFIG="-DCONFIG_64 -DANSI" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M64" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M64" MPD_PREC=19 ;; ppro) MPD_HEADER_CONFIG=$CONFIG_32 MPD_ABI=$M32 MPD_CONFIG="-DCONFIG_32 -DPPRO -DASM" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M32" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M32" # Some versions of gcc miscompile inline asm: # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html case $CC in *gcc*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc ipa-pure-const bug" >&5 $as_echo_n "checking for gcc ipa-pure-const bug... " >&6; } saved_cflags="$CFLAGS" saved_ldflags="$LDFLAGS" CFLAGS="-O2" LDFLAGS= if test "$cross_compiling" = yes; then : have_ipa_pure_const_bug=undefined else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ __attribute__((noinline)) int foo(int *p) { int r; asm ( "movl \$6, (%1)\n\t" "xorl %0, %0\n\t" : "=r" (r) : "r" (p) : "memory" ); return r; } int main() { int p = 8; if ((foo(&p) ? : p) != 6) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : have_ipa_pure_const_bug=no else have_ipa_pure_const_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ipa_pure_const_bug" >&5 $as_echo "$have_ipa_pure_const_bug" >&6; } if test "$have_ipa_pure_const_bug" = yes; then MPD_CONFIG="$MPD_CONFIG -fno-ipa-pure-const" $as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h fi ;; esac ;; ansi32) MPD_HEADER_CONFIG=$CONFIG_32 MPD_ABI=$M32 MPD_CONFIG="-DCONFIG_32 -DANSI" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M32" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M32" ;; ansi-legacy) MPD_HEADER_CONFIG=$CONFIG_32_LEGACY MPD_ABI=$M32 MPD_CONFIG="-DCONFIG_32 -DANSI -DLEGACY_COMPILER" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M32" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M32" ;; universal) MPD_HEADER_CONFIG=$CONFIG_UNIVERSAL MPD_CONFIG="-DUNIVERSAL" ;; *) as_fn_error $? "cannot detect MACHINE" "$LINENO" 5 ;; esac # Special cases: MPD_CXXOPT= MPD_GNU99= case $host in *-*-aix*) AR=$AIX_AR RANLIB=$AIX_RANLIB MPD_OPT="-D_THREAD_SAFE $MPD_OPT" MPD_CXXOPT="-D_THREAD_SAFE" case "$MACHINE" in universal) MPD_HEADER_CONFIG=$CONFIG_UNIVERSAL_AIX AR="ar -X32_64" RANLIB="ranlib -X32_64" ;; esac ;; *-*-netbsd*) MPD_OPT="-D_REENTRANT $MPD_OPT" MPD_CXXOPT="-D_REENTRANT" ;; *-*-solaris* | *-*-sunos*) MPD_OPT="-D_REENTRANT $MPD_OPT" MPD_CXXOPT="-D_REENTRANT" case $CC in *gcc*) MPD_GNU99=-std=gnu99 ;; esac ;; esac # ============================================================================== # Substitute remaining variables # ============================================================================== if test -z "$INITIAL_CFLAGS"; then CONFIGURE_LIBMPDEC_CFLAGS="$MPD_WARN $MPD_CONFIG $MPD_OPT $MPD_ABI" CONFIGURE_CFLAGS="$MPD_WARN $MPD_OPT $MPD_ABI" else CONFIGURE_LIBMPDEC_CFLAGS="$MPD_WARN $MPD_CONFIG $MPD_OPT $MPD_ABI $INITIAL_CFLAGS" CONFIGURE_CFLAGS="$MPD_WARN $MPD_OPT $MPD_ABI $INITIAL_CFLAGS" fi if test "$have_glibc_memmove_bug" = yes; then CONFIGURE_LIBMPDEC_CFLAGS="$CONFIGURE_LIBMPDEC_CFLAGS -U_FORTIFY_SOURCE" CONFIGURE_CFLAGS="$CONFIGURE_CFLAGS -U_FORTIFY_SOURCE" fi if test -z "$INITIAL_CXXFLAGS"; then CONFIGURE_CXXFLAGS="$MPD_WARNXX $MPD_CXXOPT -DNDEBUG -O3 $MPD_ABI" else CONFIGURE_CXXFLAGS="$MPD_WARNXX $MPD_CXXOPT -DNDEBUG -O3 $MPD_ABI $INITIAL_CXXFLAGS" fi if test -n "$INITIAL_LDFLAGS"; then CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $INITIAL_LDFLAGS" fi if test -n "$INITIAL_LDXXFLAGS"; then CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $INITIAL_LDXXFLAGS" fi # ============================================================================== # Write output # ============================================================================== cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by mpdecimal $as_me 4.0.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_links="$ac_config_links" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration links: $config_links Report bugs to . mpdecimal home page: ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ mpdecimal config.status 4.0.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "libmpdec/Makefile") CONFIG_FILES="$CONFIG_FILES libmpdec/Makefile" ;; "libmpdec/mpdecimal.h") CONFIG_FILES="$CONFIG_FILES libmpdec/mpdecimal.h" ;; "libmpdec/.pc/libmpdec.pc") CONFIG_FILES="$CONFIG_FILES libmpdec/.pc/libmpdec.pc" ;; "libmpdec++/Makefile") CONFIG_FILES="$CONFIG_FILES libmpdec++/Makefile" ;; "libmpdec++/.pc/libmpdec++.pc") CONFIG_FILES="$CONFIG_FILES libmpdec++/.pc/libmpdec++.pc" ;; "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; "tests++/Makefile") CONFIG_FILES="$CONFIG_FILES tests++/Makefile" ;; "CHANGELOG.txt") CONFIG_LINKS="$CONFIG_LINKS CHANGELOG.txt:CHANGELOG.txt" ;; "COPYRIGHT.txt") CONFIG_LINKS="$CONFIG_LINKS COPYRIGHT.txt:COPYRIGHT.txt" ;; "INSTALL.txt") CONFIG_LINKS="$CONFIG_LINKS INSTALL.txt:INSTALL.txt" ;; "Makefile.in") CONFIG_LINKS="$CONFIG_LINKS Makefile.in:Makefile.in" ;; "README.txt") CONFIG_LINKS="$CONFIG_LINKS README.txt:README.txt" ;; "config.guess") CONFIG_LINKS="$CONFIG_LINKS config.guess:config.guess" ;; "config.h.in") CONFIG_LINKS="$CONFIG_LINKS config.h.in:config.h.in" ;; "config.sub") CONFIG_LINKS="$CONFIG_LINKS config.sub:config.sub" ;; "configure") CONFIG_LINKS="$CONFIG_LINKS configure:configure" ;; "configure.ac") CONFIG_LINKS="$CONFIG_LINKS configure.ac:configure.ac" ;; "install-sh") CONFIG_LINKS="$CONFIG_LINKS install-sh:install-sh" ;; "doc/COPYRIGHT.txt") CONFIG_LINKS="$CONFIG_LINKS doc/COPYRIGHT.txt:doc/COPYRIGHT.txt" ;; "doc/libmpdec.3") CONFIG_LINKS="$CONFIG_LINKS doc/libmpdec.3:doc/libmpdec.3" ;; "doc/libmpdec++.3") CONFIG_LINKS="$CONFIG_LINKS doc/libmpdec++.3:doc/libmpdec++.3" ;; "doc/mpdecimal.3") CONFIG_LINKS="$CONFIG_LINKS doc/mpdecimal.3:doc/mpdecimal.3" ;; "libmpdec/Makefile.in") CONFIG_LINKS="$CONFIG_LINKS libmpdec/Makefile.in:libmpdec/Makefile.in" ;; "libmpdec/Makefile.vc") CONFIG_LINKS="$CONFIG_LINKS libmpdec/Makefile.vc:libmpdec/Makefile.vc" ;; "libmpdec/README.txt") CONFIG_LINKS="$CONFIG_LINKS libmpdec/README.txt:libmpdec/README.txt" ;; "libmpdec/basearith.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/basearith.c:libmpdec/basearith.c" ;; "libmpdec/basearith.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/basearith.h:libmpdec/basearith.h" ;; "libmpdec/bench.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/bench.c:libmpdec/bench.c" ;; "libmpdec/bench_full.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/bench_full.c:libmpdec/bench_full.c" ;; "libmpdec/bits.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/bits.h:libmpdec/bits.h" ;; "libmpdec/constants.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/constants.c:libmpdec/constants.c" ;; "libmpdec/constants.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/constants.h:libmpdec/constants.h" ;; "libmpdec/context.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/context.c:libmpdec/context.c" ;; "libmpdec/convolute.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/convolute.c:libmpdec/convolute.c" ;; "libmpdec/convolute.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/convolute.h:libmpdec/convolute.h" ;; "libmpdec/crt.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/crt.c:libmpdec/crt.c" ;; "libmpdec/crt.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/crt.h:libmpdec/crt.h" ;; "libmpdec/difradix2.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/difradix2.c:libmpdec/difradix2.c" ;; "libmpdec/difradix2.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/difradix2.h:libmpdec/difradix2.h" ;; "libmpdec/fnt.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/fnt.c:libmpdec/fnt.c" ;; "libmpdec/fnt.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/fnt.h:libmpdec/fnt.h" ;; "libmpdec/fourstep.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/fourstep.c:libmpdec/fourstep.c" ;; "libmpdec/fourstep.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/fourstep.h:libmpdec/fourstep.h" ;; "libmpdec/io.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/io.c:libmpdec/io.c" ;; "libmpdec/io.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/io.h:libmpdec/io.h" ;; "libmpdec/mpalloc.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/mpalloc.c:libmpdec/mpalloc.c" ;; "libmpdec/mpalloc.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/mpalloc.h:libmpdec/mpalloc.h" ;; "libmpdec/mpdecimal.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/mpdecimal.c:libmpdec/mpdecimal.c" ;; "libmpdec/mpdecimal32vc.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/mpdecimal32vc.h:libmpdec/mpdecimal32vc.h" ;; "libmpdec/mpdecimal64vc.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/mpdecimal64vc.h:libmpdec/mpdecimal64vc.h" ;; "libmpdec/mpdecimal.h.in") CONFIG_LINKS="$CONFIG_LINKS libmpdec/mpdecimal.h.in:libmpdec/mpdecimal.h.in" ;; "libmpdec/mpsignal.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/mpsignal.c:libmpdec/mpsignal.c" ;; "libmpdec/numbertheory.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/numbertheory.c:libmpdec/numbertheory.c" ;; "libmpdec/numbertheory.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/numbertheory.h:libmpdec/numbertheory.h" ;; "libmpdec/sixstep.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/sixstep.c:libmpdec/sixstep.c" ;; "libmpdec/sixstep.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/sixstep.h:libmpdec/sixstep.h" ;; "libmpdec/transpose.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/transpose.c:libmpdec/transpose.c" ;; "libmpdec/transpose.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/transpose.h:libmpdec/transpose.h" ;; "libmpdec/typearith.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/typearith.h:libmpdec/typearith.h" ;; "libmpdec/umodarith.h") CONFIG_LINKS="$CONFIG_LINKS libmpdec/umodarith.h:libmpdec/umodarith.h" ;; "libmpdec/vcdiv64.asm") CONFIG_LINKS="$CONFIG_LINKS libmpdec/vcdiv64.asm:libmpdec/vcdiv64.asm" ;; "libmpdec/examples/README.txt") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/README.txt:libmpdec/examples/README.txt" ;; "libmpdec/examples/compare.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/compare.c:libmpdec/examples/compare.c" ;; "libmpdec/examples/div.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/div.c:libmpdec/examples/div.c" ;; "libmpdec/examples/divmod.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/divmod.c:libmpdec/examples/divmod.c" ;; "libmpdec/examples/multiply.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/multiply.c:libmpdec/examples/multiply.c" ;; "libmpdec/examples/pow.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/pow.c:libmpdec/examples/pow.c" ;; "libmpdec/examples/powmod.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/powmod.c:libmpdec/examples/powmod.c" ;; "libmpdec/examples/shift.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/shift.c:libmpdec/examples/shift.c" ;; "libmpdec/examples/sqrt.c") CONFIG_LINKS="$CONFIG_LINKS libmpdec/examples/sqrt.c:libmpdec/examples/sqrt.c" ;; "libmpdec/.objs/README.txt") CONFIG_LINKS="$CONFIG_LINKS libmpdec/.objs/README.txt:libmpdec/.objs/README.txt" ;; "libmpdec/.objs/symbols32.exp") CONFIG_LINKS="$CONFIG_LINKS libmpdec/.objs/symbols32.exp:libmpdec/.objs/symbols32.exp" ;; "libmpdec/.objs/symbols64.exp") CONFIG_LINKS="$CONFIG_LINKS libmpdec/.objs/symbols64.exp:libmpdec/.objs/symbols64.exp" ;; "libmpdec/.pc/libmpdec.pc.in") CONFIG_LINKS="$CONFIG_LINKS libmpdec/.pc/libmpdec.pc.in:libmpdec/.pc/libmpdec.pc.in" ;; "libmpdec/.profile/train.sh") CONFIG_LINKS="$CONFIG_LINKS libmpdec/.profile/train.sh:libmpdec/.profile/train.sh" ;; "libmpdec++/Makefile.in") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/Makefile.in:libmpdec++/Makefile.in" ;; "libmpdec++/Makefile.vc") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/Makefile.vc:libmpdec++/Makefile.vc" ;; "libmpdec++/bench.cc") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/bench.cc:libmpdec++/bench.cc" ;; "libmpdec++/bench_full.cc") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/bench_full.cc:libmpdec++/bench_full.cc" ;; "libmpdec++/decimal.cc") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/decimal.cc:libmpdec++/decimal.cc" ;; "libmpdec++/decimal.hh") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/decimal.hh:libmpdec++/decimal.hh" ;; "libmpdec++/examples/factorial.cc") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/examples/factorial.cc:libmpdec++/examples/factorial.cc" ;; "libmpdec++/examples/pi.cc") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/examples/pi.cc:libmpdec++/examples/pi.cc" ;; "libmpdec++/.objs/README.txt") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/.objs/README.txt:libmpdec++/.objs/README.txt" ;; "libmpdec++/.pc/libmpdec++.pc.in") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/.pc/libmpdec++.pc.in:libmpdec++/.pc/libmpdec++.pc.in" ;; "libmpdec++/.profile/train.sh") CONFIG_LINKS="$CONFIG_LINKS libmpdec++/.profile/train.sh:libmpdec++/.profile/train.sh" ;; "tests/Makefile.in") CONFIG_LINKS="$CONFIG_LINKS tests/Makefile.in:tests/Makefile.in" ;; "tests/Makefile.vc") CONFIG_LINKS="$CONFIG_LINKS tests/Makefile.vc:tests/Makefile.vc" ;; "tests/README.txt") CONFIG_LINKS="$CONFIG_LINKS tests/README.txt:tests/README.txt" ;; "tests/additional.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/additional.decTest:tests/additional.decTest" ;; "tests/gettests.bat") CONFIG_LINKS="$CONFIG_LINKS tests/gettests.bat:tests/gettests.bat" ;; "tests/gettests.sh") CONFIG_LINKS="$CONFIG_LINKS tests/gettests.sh:tests/gettests.sh" ;; "tests/official.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/official.decTest:tests/official.decTest" ;; "tests/runshort.sh") CONFIG_LINKS="$CONFIG_LINKS tests/runshort.sh:tests/runshort.sh" ;; "tests/runshort_alloc.sh") CONFIG_LINKS="$CONFIG_LINKS tests/runshort_alloc.sh:tests/runshort_alloc.sh" ;; "tests/runtest.c") CONFIG_LINKS="$CONFIG_LINKS tests/runtest.c:tests/runtest.c" ;; "tests/test.c") CONFIG_LINKS="$CONFIG_LINKS tests/test.c:tests/test.c" ;; "tests/test.h") CONFIG_LINKS="$CONFIG_LINKS tests/test.h:tests/test.h" ;; "tests/vctest.h") CONFIG_LINKS="$CONFIG_LINKS tests/vctest.h:tests/vctest.h" ;; "tests/testdata_dist/baseconv.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/baseconv.decTest:tests/testdata_dist/baseconv.decTest" ;; "tests/testdata_dist/binop_eq.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/binop_eq.decTest:tests/testdata_dist/binop_eq.decTest" ;; "tests/testdata_dist/cov.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/cov.decTest:tests/testdata_dist/cov.decTest" ;; "tests/testdata_dist/divmod.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/divmod.decTest:tests/testdata_dist/divmod.decTest" ;; "tests/testdata_dist/divmod_eq.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/divmod_eq.decTest:tests/testdata_dist/divmod_eq.decTest" ;; "tests/testdata_dist/extra.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/extra.decTest:tests/testdata_dist/extra.decTest" ;; "tests/testdata_dist/fma_eq.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/fma_eq.decTest:tests/testdata_dist/fma_eq.decTest" ;; "tests/testdata_dist/format.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/format.decTest:tests/testdata_dist/format.decTest" ;; "tests/testdata_dist/getint.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/getint.decTest:tests/testdata_dist/getint.decTest" ;; "tests/testdata_dist/invroot.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/invroot.decTest:tests/testdata_dist/invroot.decTest" ;; "tests/testdata_dist/largeint.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/largeint.decTest:tests/testdata_dist/largeint.decTest" ;; "tests/testdata_dist/maxprec.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/maxprec.decTest:tests/testdata_dist/maxprec.decTest" ;; "tests/testdata_dist/powmod.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/powmod.decTest:tests/testdata_dist/powmod.decTest" ;; "tests/testdata_dist/powmod_eq.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/powmod_eq.decTest:tests/testdata_dist/powmod_eq.decTest" ;; "tests/testdata_dist/shiftlr.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/shiftlr.decTest:tests/testdata_dist/shiftlr.decTest" ;; "tests/testdata_dist/testruntest.decTest") CONFIG_LINKS="$CONFIG_LINKS tests/testdata_dist/testruntest.decTest:tests/testdata_dist/testruntest.decTest" ;; "tests++/Makefile.in") CONFIG_LINKS="$CONFIG_LINKS tests++/Makefile.in:tests++/Makefile.in" ;; "tests++/Makefile.vc") CONFIG_LINKS="$CONFIG_LINKS tests++/Makefile.vc:tests++/Makefile.vc" ;; "tests++/README.txt") CONFIG_LINKS="$CONFIG_LINKS tests++/README.txt:tests++/README.txt" ;; "tests++/additional.topTest") CONFIG_LINKS="$CONFIG_LINKS tests++/additional.topTest:tests++/additional.topTest" ;; "tests++/apitest.cc") CONFIG_LINKS="$CONFIG_LINKS tests++/apitest.cc:tests++/apitest.cc" ;; "tests++/gettests.bat") CONFIG_LINKS="$CONFIG_LINKS tests++/gettests.bat:tests++/gettests.bat" ;; "tests++/gettests.sh") CONFIG_LINKS="$CONFIG_LINKS tests++/gettests.sh:tests++/gettests.sh" ;; "tests++/official.topTest") CONFIG_LINKS="$CONFIG_LINKS tests++/official.topTest:tests++/official.topTest" ;; "tests++/runshort.sh") CONFIG_LINKS="$CONFIG_LINKS tests++/runshort.sh:tests++/runshort.sh" ;; "tests++/runshort_alloc.sh") CONFIG_LINKS="$CONFIG_LINKS tests++/runshort_alloc.sh:tests++/runshort_alloc.sh" ;; "tests++/runtest.cc") CONFIG_LINKS="$CONFIG_LINKS tests++/runtest.cc:tests++/runtest.cc" ;; "tests++/test.cc") CONFIG_LINKS="$CONFIG_LINKS tests++/test.cc:tests++/test.cc" ;; "tests++/test.hh") CONFIG_LINKS="$CONFIG_LINKS tests++/test.hh:tests++/test.hh" ;; "tests++/vctest.hh") CONFIG_LINKS="$CONFIG_LINKS tests++/vctest.hh:tests++/vctest.hh" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_LINKS+set}" = set || CONFIG_LINKS=$config_links fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :L $CONFIG_LINKS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; :L) # # CONFIG_LINK # if test "$ac_source" = "$ac_file" && test "$srcdir" = '.'; then : else # Prefer the file from the source tree if names are identical. if test "$ac_source" = "$ac_file" || test ! -r "$ac_source"; then ac_source=$srcdir/$ac_source fi { $as_echo "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5 $as_echo "$as_me: linking $ac_source to $ac_file" >&6;} if test ! -r "$ac_source"; then as_fn_error $? "$ac_source: file not found" "$LINENO" 5 fi rm -f "$ac_file" # Try a relative symlink, then a hard link, then a copy. case $ac_source in [\\/$]* | ?:[\\/]* ) ac_rel_source=$ac_source ;; *) ac_rel_source=$ac_top_build_prefix$ac_source ;; esac ln -s "$ac_rel_source" "$ac_file" 2>/dev/null || ln "$ac_source" "$ac_file" 2>/dev/null || cp -p "$ac_source" "$ac_file" || as_fn_error $? "cannot link or copy $ac_source to $ac_file" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi GLIBC_MEMMOVE_BUG_WARN=" ***************************** WARNING ********************************* Detected glibc _FORTIFY_SOURCE/memmove bug. See: http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html Enabling -U_FORTIFY_SOURCE workaround. If -D_FORTIFY_SOURCE is also present in the command line, make sure that the order of the two options is: ... -D_FORTIFY_SOURCE=2 ... -U_FORTIFY_SOURCE ... A better solution is to upgrade glibc or to report the bug to your OS vendor. ***************************** WARNING ********************************* " if test "$have_glibc_memmove_bug" = yes; then echo "$GLIBC_MEMMOVE_BUG_WARN" fi mpdecimal-4.0.1/configure.ac0000644000000000000000000010243515005764474012704 0ustar00AC_COPYRIGHT([ Copyright (c) 2008-2025 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. ]) AH_TOP([ /* * The generated config.h is only included in runtest.cc, and there are * no plans to use it elsewhere. All defines apart from HAVE_PTHREAD_H * are purely informational. */ ]) AC_PREREQ([2.69]) AC_INIT([mpdecimal], [4.0.1], [mpdecimal-bugs@bytereef.org], [mpdecimal], [https://www.bytereef.org/mpdecimal/index.html]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile libmpdec/Makefile libmpdec/mpdecimal.h libmpdec/.pc/libmpdec.pc libmpdec++/Makefile libmpdec++/.pc/libmpdec++.pc tests/Makefile tests++/Makefile]) # Link files for out-of-tree builds: AC_CONFIG_LINKS([CHANGELOG.txt:CHANGELOG.txt COPYRIGHT.txt:COPYRIGHT.txt INSTALL.txt:INSTALL.txt Makefile.in:Makefile.in README.txt:README.txt config.guess:config.guess config.h.in:config.h.in config.sub:config.sub configure:configure configure.ac:configure.ac install-sh:install-sh doc/COPYRIGHT.txt:doc/COPYRIGHT.txt doc/libmpdec.3:doc/libmpdec.3 doc/libmpdec++.3:doc/libmpdec++.3 doc/mpdecimal.3:doc/mpdecimal.3 libmpdec/Makefile.in:libmpdec/Makefile.in libmpdec/Makefile.vc:libmpdec/Makefile.vc libmpdec/README.txt:libmpdec/README.txt libmpdec/basearith.c:libmpdec/basearith.c libmpdec/basearith.h:libmpdec/basearith.h libmpdec/bench.c:libmpdec/bench.c libmpdec/bench_full.c:libmpdec/bench_full.c libmpdec/bits.h:libmpdec/bits.h libmpdec/constants.c:libmpdec/constants.c libmpdec/constants.h:libmpdec/constants.h libmpdec/context.c:libmpdec/context.c libmpdec/convolute.c:libmpdec/convolute.c libmpdec/convolute.h:libmpdec/convolute.h libmpdec/crt.c:libmpdec/crt.c libmpdec/crt.h:libmpdec/crt.h libmpdec/difradix2.c:libmpdec/difradix2.c libmpdec/difradix2.h:libmpdec/difradix2.h libmpdec/fnt.c:libmpdec/fnt.c libmpdec/fnt.h:libmpdec/fnt.h libmpdec/fourstep.c:libmpdec/fourstep.c libmpdec/fourstep.h:libmpdec/fourstep.h libmpdec/io.c:libmpdec/io.c libmpdec/io.h:libmpdec/io.h libmpdec/mpalloc.c:libmpdec/mpalloc.c libmpdec/mpalloc.h:libmpdec/mpalloc.h libmpdec/mpdecimal.c:libmpdec/mpdecimal.c libmpdec/mpdecimal32vc.h:libmpdec/mpdecimal32vc.h libmpdec/mpdecimal64vc.h:libmpdec/mpdecimal64vc.h libmpdec/mpdecimal.h.in:libmpdec/mpdecimal.h.in libmpdec/mpsignal.c:libmpdec/mpsignal.c libmpdec/numbertheory.c:libmpdec/numbertheory.c libmpdec/numbertheory.h:libmpdec/numbertheory.h libmpdec/sixstep.c:libmpdec/sixstep.c libmpdec/sixstep.h:libmpdec/sixstep.h libmpdec/transpose.c:libmpdec/transpose.c libmpdec/transpose.h:libmpdec/transpose.h libmpdec/typearith.h:libmpdec/typearith.h libmpdec/umodarith.h:libmpdec/umodarith.h libmpdec/vcdiv64.asm:libmpdec/vcdiv64.asm libmpdec/examples/README.txt:libmpdec/examples/README.txt libmpdec/examples/compare.c:libmpdec/examples/compare.c libmpdec/examples/div.c:libmpdec/examples/div.c libmpdec/examples/divmod.c:libmpdec/examples/divmod.c libmpdec/examples/multiply.c:libmpdec/examples/multiply.c libmpdec/examples/pow.c:libmpdec/examples/pow.c libmpdec/examples/powmod.c:libmpdec/examples/powmod.c libmpdec/examples/shift.c:libmpdec/examples/shift.c libmpdec/examples/sqrt.c:libmpdec/examples/sqrt.c libmpdec/.objs/README.txt:libmpdec/.objs/README.txt libmpdec/.objs/symbols32.exp:libmpdec/.objs/symbols32.exp libmpdec/.objs/symbols64.exp:libmpdec/.objs/symbols64.exp libmpdec/.pc/libmpdec.pc.in:libmpdec/.pc/libmpdec.pc.in libmpdec/.profile/train.sh:libmpdec/.profile/train.sh libmpdec++/Makefile.in:libmpdec++/Makefile.in libmpdec++/Makefile.vc:libmpdec++/Makefile.vc libmpdec++/bench.cc:libmpdec++/bench.cc libmpdec++/bench_full.cc:libmpdec++/bench_full.cc libmpdec++/decimal.cc:libmpdec++/decimal.cc libmpdec++/decimal.hh:libmpdec++/decimal.hh libmpdec++/examples/factorial.cc:libmpdec++/examples/factorial.cc libmpdec++/examples/pi.cc:libmpdec++/examples/pi.cc libmpdec++/.objs/README.txt:libmpdec++/.objs/README.txt libmpdec++/.pc/libmpdec++.pc.in:libmpdec++/.pc/libmpdec++.pc.in libmpdec++/.profile/train.sh:libmpdec++/.profile/train.sh tests/Makefile.in:tests/Makefile.in tests/Makefile.vc:tests/Makefile.vc tests/README.txt:tests/README.txt tests/additional.decTest:tests/additional.decTest tests/gettests.bat:tests/gettests.bat tests/gettests.sh:tests/gettests.sh tests/official.decTest:tests/official.decTest tests/runshort.sh:tests/runshort.sh tests/runshort_alloc.sh:tests/runshort_alloc.sh tests/runtest.c:tests/runtest.c tests/test.c:tests/test.c tests/test.h:tests/test.h tests/vctest.h:tests/vctest.h tests/testdata_dist/baseconv.decTest:tests/testdata_dist/baseconv.decTest tests/testdata_dist/binop_eq.decTest:tests/testdata_dist/binop_eq.decTest tests/testdata_dist/cov.decTest:tests/testdata_dist/cov.decTest tests/testdata_dist/divmod.decTest:tests/testdata_dist/divmod.decTest tests/testdata_dist/divmod_eq.decTest:tests/testdata_dist/divmod_eq.decTest tests/testdata_dist/extra.decTest:tests/testdata_dist/extra.decTest tests/testdata_dist/fma_eq.decTest:tests/testdata_dist/fma_eq.decTest tests/testdata_dist/format.decTest:tests/testdata_dist/format.decTest tests/testdata_dist/getint.decTest:tests/testdata_dist/getint.decTest tests/testdata_dist/invroot.decTest:tests/testdata_dist/invroot.decTest tests/testdata_dist/largeint.decTest:tests/testdata_dist/largeint.decTest tests/testdata_dist/maxprec.decTest:tests/testdata_dist/maxprec.decTest tests/testdata_dist/powmod.decTest:tests/testdata_dist/powmod.decTest tests/testdata_dist/powmod_eq.decTest:tests/testdata_dist/powmod_eq.decTest tests/testdata_dist/shiftlr.decTest:tests/testdata_dist/shiftlr.decTest tests/testdata_dist/testruntest.decTest:tests/testdata_dist/testruntest.decTest tests++/Makefile.in:tests++/Makefile.in tests++/Makefile.vc:tests++/Makefile.vc tests++/README.txt:tests++/README.txt tests++/additional.topTest:tests++/additional.topTest tests++/apitest.cc:tests++/apitest.cc tests++/gettests.bat:tests++/gettests.bat tests++/gettests.sh:tests++/gettests.sh tests++/official.topTest:tests++/official.topTest tests++/runshort.sh:tests++/runshort.sh tests++/runshort_alloc.sh:tests++/runshort_alloc.sh tests++/runtest.cc:tests++/runtest.cc tests++/test.cc:tests++/test.cc tests++/test.hh:tests++/test.hh tests++/vctest.hh:tests++/vctest.hh]) # ============================================================================== # MPD_HEADER_CONFIG # ============================================================================== CONFIG_64=" /* ABI: 64-bit */ #define MPD_CONFIG_64 1 #ifdef MPD_CONFIG_32 #error \"cannot use MPD_CONFIG_32 with 64-bit header.\" #endif #ifdef CONFIG_32 #error \"cannot use CONFIG_32 with 64-bit header.\" #endif" CONFIG_32=" /* ABI: 32-bit */ #define MPD_CONFIG_32 1 #ifdef MPD_CONFIG_64 #error \"cannot use MPD_CONFIG_64 with 32-bit header.\" #endif #ifdef CONFIG_64 #error \"cannot use CONFIG_64 with 32-bit header.\" #endif" CONFIG_32_LEGACY=" /* ABI: 32-bit */ #define MPD_CONFIG_32 1 /* libmpdec was compiled without support for int64_t */ #define MPD_LEGACY_COMPILER 1 #ifdef MPD_CONFIG_64 #error \"cannot use MPD_CONFIG_64 with 32-bit header.\" #endif #ifdef CONFIG_64 #error \"cannot use CONFIG_64 with 32-bit header.\" #endif" CONFIG_UNIVERSAL=" /* Mac OS X: support for building universal binaries */ #if defined(MPD_CONFIG_64) || defined(MPD_CONFIG_32) #error \"cannot use MPD_CONFIG_64 or MPD_CONFIG_32 with universal header.\" #endif #if defined(CONFIG_64) || defined(CONFIG_32) #error \"cannot use CONFIG_64 or CONFIG_32 with universal header.\" #endif #if defined(__ppc__) #define MPD_CONFIG_32 1 #ifdef UNIVERSAL #define CONFIG_32 #define ANSI #endif #elif defined(__ppc64__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ANSI #endif #elif defined(__i386__) #define MPD_CONFIG_32 1 #ifdef UNIVERSAL #define CONFIG_32 #define ANSI #endif #elif defined(__x86_64__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ASM #endif #elif defined(__arm64__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ANSI #endif #else #error \"unknown architecture for universal build.\" #endif" CONFIG_UNIVERSAL_AIX_UINT128=" /* AIX: support for multilib */ #if defined(MPD_CONFIG_64) || defined(MPD_CONFIG_32) #error \"cannot use MPD_CONFIG_64 or MPD_CONFIG_32 with multilib header.\" #endif #if defined(CONFIG_64) || defined(CONFIG_32) #error \"cannot use CONFIG_64 or CONFIG_32 with multilib header.\" #endif #if defined(__64BIT__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ANSI #define HAVE_UINT128_T #endif #else #define MPD_CONFIG_32 1 #ifdef UNIVERSAL #define CONFIG_32 #define ANSI #endif #endif" CONFIG_UNIVERSAL_AIX_ANSI64=" /* AIX: support for multilib */ #if defined(MPD_CONFIG_64) || defined(MPD_CONFIG_32) #error \"cannot use MPD_CONFIG_64 or MPD_CONFIG_32 with multilib header.\" #endif #if defined(CONFIG_64) || defined(CONFIG_32) #error \"cannot use CONFIG_64 or CONFIG_32 with multilib header.\" #endif #if defined(__64BIT__) #define MPD_CONFIG_64 1 #ifdef UNIVERSAL #define CONFIG_64 #define ANSI #endif #else #define MPD_CONFIG_32 1 #ifdef UNIVERSAL #define CONFIG_32 #define ANSI #endif #endif" # ============================================================================== # Detect build and host systems # ============================================================================== AC_CANONICAL_HOST # ============================================================================== # Select library names # ============================================================================== # MinGW/Cygwin/MSYS2 support: ENABLE_MINGW="no" # Set library names and linker flags: FPIC="-fPIC" LIBSTATIC=libmpdec.a LIBSHARED_USE_AR="no" LIBIMPORT= LINK_STATIC= LINK_DYNAMIC= case $host in *-*-darwin*) LIBNAME="libmpdec.dylib" LIBSONAME="libmpdec.4.dylib" LIBSHARED="libmpdec.4.0.1.dylib" CONFIGURE_LDFLAGS="-dynamiclib $FPIC -install_name \$(libdir)/$LIBSONAME -compatibility_version 4.0 -current_version 4.0.1" ;; *-*-aix*) LIBNAME= LIBSONAME= LIBSHARED="shr.o" LIBSHARED_USE_AR="yes" CONFIGURE_LDFLAGS="-shared $FPIC -Wl,-bnoentry -Wl,-bE:.objs/symbols.exp" LINK_STATIC="-Wl,-bstatic" LINK_DYNAMIC="-Wl,-bshared" ;; *-*-mingw*) FPIC= LIBNAME= LIBIMPORT="libmpdec.dll.a" LIBSONAME= LIBSHARED="libmpdec-4.dll" CONFIGURE_LDFLAGS="-shared -Wl,--out-implib,$LIBIMPORT" ENABLE_MINGW="yes" ;; *-*-cygwin*) FPIC= LIBNAME= LIBIMPORT="libmpdec.dll.a" LIBSONAME= LIBSHARED="cygmpdec-4.dll" CONFIGURE_LDFLAGS="-shared -Wl,--out-implib,$LIBIMPORT" ENABLE_MINGW="yes" ;; *-*-msys) FPIC= LIBNAME= LIBIMPORT="libmpdec.dll.a" LIBSONAME= LIBSHARED="msys-mpdec-4.dll" CONFIGURE_LDFLAGS="-shared -Wl,--out-implib,$LIBIMPORT" ENABLE_MINGW="yes" ;; *) LIBNAME="libmpdec.so" LIBSONAME="libmpdec.so.4" LIBSHARED="libmpdec.so.4.0.1" CONFIGURE_LDFLAGS="-shared $FPIC -Wl,-soname,$LIBSONAME" ;; esac LIBSTATIC_CXX=libmpdec++.a LIBIMPORT_CXX= case $host in *-*-darwin*) LIBNAME_CXX="libmpdec++.dylib" LIBSONAME_CXX="libmpdec++.4.dylib" LIBSHARED_CXX="libmpdec++.4.0.1.dylib" CONFIGURE_LDXXFLAGS="-dynamiclib $FPIC -install_name \$(libdir)/$LIBSONAME_CXX -compatibility_version 4.0 -current_version 4.0.1" ;; *-*-aix*) LIBNAME_CXX= LIBSONAME_CXX= LIBSHARED_CXX="shr.o" CONFIGURE_LDXXFLAGS="-shared $FPIC -Wl,-bnoentry -Wl,-bE:.objs/symbols.exp" ;; *-*-mingw*) LIBNAME_CXX= LIBIMPORT_CXX="libmpdec++.dll.a" LIBSONAME_CXX= LIBSHARED_CXX="libmpdec++-4.dll" CONFIGURE_LDXXFLAGS="-shared -Wl,--out-implib,$LIBIMPORT_CXX" ;; *-*-cygwin*) LIBNAME_CXX= LIBIMPORT_CXX="libmpdec++.dll.a" LIBSONAME_CXX= LIBSHARED_CXX="cygmpdec++-4.dll" CONFIGURE_LDXXFLAGS="-shared -Wl,--out-implib,$LIBIMPORT_CXX" ;; *-*-msys) LIBNAME_CXX= LIBIMPORT_CXX="libmpdec++.dll.a" LIBSONAME_CXX= LIBSHARED_CXX="msys-mpdec++-4.dll" CONFIGURE_LDXXFLAGS="-shared -Wl,--out-implib,$LIBIMPORT_CXX" ;; *) LIBNAME_CXX="libmpdec++.so" LIBSONAME_CXX="libmpdec++.so.4" LIBSHARED_CXX="libmpdec++.so.4.0.1" CONFIGURE_LDXXFLAGS="-shared $FPIC -Wl,-soname,$LIBSONAME_CXX" ;; esac AC_SUBST(FPIC) AC_SUBST(LIBSTATIC) AC_SUBST(LIBNAME) AC_SUBST(LIBSONAME) AC_SUBST(LIBSHARED) AC_SUBST(LIBIMPORT) AC_SUBST(LIBSHARED_USE_AR) AC_SUBST(LINK_STATIC) AC_SUBST(LINK_DYNAMIC) AC_SUBST(LIBSTATIC_CXX) AC_SUBST(LIBNAME_CXX) AC_SUBST(LIBSONAME_CXX) AC_SUBST(LIBSHARED_CXX) AC_SUBST(LIBIMPORT_CXX) AC_SUBST(ENABLE_MINGW) # ============================================================================== # User options # ============================================================================== # Check whether to build libmpdec++: AC_MSG_CHECKING(for --enable-cxx) AC_ARG_ENABLE(cxx, AS_HELP_STRING([--enable-cxx], [enable building libmpdec++ (default is yes)])) ENABLE_CXX="$enable_cxx" if test -z "$ENABLE_CXX" then if test x"$MACHINE" = x"ansi-legacy"; then ENABLE_CXX="no" else ENABLE_CXX="yes" fi fi AC_MSG_RESULT($ENABLE_CXX) # Check whether to build the static libraries: AC_MSG_CHECKING(for --enable-static) AC_ARG_ENABLE(static, AS_HELP_STRING([--enable-static], [enable building static libraries (default is yes)])) ENABLE_STATIC="$enable_static" if test -z "$ENABLE_STATIC" then ENABLE_STATIC="yes" fi AC_MSG_RESULT($ENABLE_STATIC) # Check whether to build the shared libraries: AC_MSG_CHECKING(for --enable-shared) AC_ARG_ENABLE(shared, AS_HELP_STRING([--enable-shared], [enable building shared libraries (default is yes)])) ENABLE_SHARED="$enable_shared" if test -z "$ENABLE_SHARED" then ENABLE_SHARED="yes" fi AC_MSG_RESULT($ENABLE_SHARED) # Check whether at least one library is enabled: if test x"$ENABLE_STATIC" = x"no" -a x"$ENABLE_SHARED" = x"no" then AC_MSG_ERROR([at least one of --enable-static or --enable-shared must be set]) fi # AIX: both static and shared libraries must be enabled: case $host in *-*-aix*) if test x"$ENABLE_STATIC" = x"no" -o x"$ENABLE_SHARED" = x"no" then AC_MSG_ERROR([the AIX build requires --enable-static and --enable-shared]) fi ;; esac # Check whether to install the documentation: AC_MSG_CHECKING(for --enable-doc) AC_ARG_ENABLE(doc, AS_HELP_STRING([--enable-doc], [enable installing the documentation (default is yes)])) ENABLE_DOC="$enable_doc" if test -z "$ENABLE_DOC" then ENABLE_DOC="yes" fi AC_MSG_RESULT($ENABLE_DOC) # Check whether to install the pkg-config files: AC_MSG_CHECKING(for --enable-pc) AC_ARG_ENABLE(pc, AS_HELP_STRING([--enable-pc], [enable installing the pkg-config files (default is yes)])) ENABLE_PC="$enable_pc" if test -z "$ENABLE_PC" then ENABLE_PC="yes" fi AC_MSG_RESULT($ENABLE_PC) AC_SUBST(ENABLE_CXX) AC_SUBST(ENABLE_STATIC) AC_SUBST(ENABLE_SHARED) AC_SUBST(ENABLE_DOC) AC_SUBST(ENABLE_PC) # ============================================================================== # Compilers and flags # ============================================================================== # Save initial compiler flags: INITIAL_CFLAGS="$CFLAGS" INITIAL_CXXFLAGS="$CXXFLAGS" INITIAL_LDFLAGS="$LDFLAGS" INITIAL_LDXXFLAGS="$LDXXFLAGS" # Rename compiler in case $CC=cc: case $CC in cc) case $build in *-*-freebsd* | *-*-openbsd* | *-*-darwin*) CC=clang ;; *-*-netbsd*) CC=gcc ;; *-*-solaris* | *-*-sunos*) CC=suncc ;; esac ;; esac case $CXX in c++) case $build in *-*-freebsd* | *-*-openbsd* | *-*-darwin*) CXX=clang++ ;; *-*-netbsd*) CXX=g++ ;; esac ;; esac # Language and compiler: AC_LANG([C]) # Preference of tested compilers: case $host in *-*-aix*) PREFERRED_CC="ibm-clang_r ibm-clang gcc xlc_r xlc cc" PREFERRED_CXX="ibm-clang++_r g++ c++" ;; *-*-freebsd* | *-*-openbsd*) PREFERRED_CC="clang gcc cc" PREFERRED_CXX="clang++ g++ c++" ;; *) PREFERRED_CC="gcc icc clang icx suncc ccomp cc" PREFERRED_CXX="g++ icpc clang++ icpx c++" ;; esac # Find CC: saved_cflags="$CFLAGS" saved_ldflags="$LDFLAGS" AC_PROG_CC([$PREFERRED_CC]) CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" # These compilers do not fully support C++11. Disable CXX to avoid mixing # different C and C++ compilers: case $CC in *xlc* | suncc | ccomp) ENABLE_CXX="no" ;; esac # Find CXX: if test x"$ENABLE_CXX" = x"yes"; then saved_cxxflags="$CXXFLAGS" saved_ldxxflags="$LDXXFLAGS" AC_PROG_CXX([$PREFERRED_CXX]) CXXFLAGS="$saved_cxxflags" LDXXFLAGS="$saved_ldxxflags" fi # Check availability of -O2: AC_MSG_CHECKING(for -O2) saved_cflags="$CFLAGS" saved_ldflags="$LDFLAGS" CFLAGS="-O2" LDFLAGS= AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[have_O2=yes],[have_O2=no]) AC_MSG_RESULT($have_O2) CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" # Find ar and ranlib: AC_CHECK_TOOL(AR, ar, ar) AC_PROG_RANLIB # Force explicit configuration. This section must be here because the size # checks in the next section require the correct CFLAGS. AC_ARG_VAR(MACHINE, [ force configuration: x64, uint128, ansi64, ppro, ansi32, ansi-legacy, universal]) M64= M32= if test -n "$MACHINE"; then case $host in *-*-aix*) case $CC in *xlc*) M64="-q64" M32="-q32" ;; *gcc*) M64="-maix64" M32="-maix32" ;; *) M64="-m64" M32="-m32" ;; esac ;; *) M64="-m64" M32="-m32" ;; esac case "$MACHINE" in x64 | uint128 | ansi64) CFLAGS="$CFLAGS $M64" CXXFLAGS="$CXXFLAGS $M64" LDFLAGS="$LDFLAGS $M64" LDXXFLAGS="$LDXXFLAGS $M64" ;; ppro | ansi32 | ansi-legacy) CFLAGS="$CFLAGS $M32" CXXFLAGS="$CXXFLAGS $M32" LDFLAGS="$LDFLAGS $M32" LDXXFLAGS="$LDXXFLAGS $M64" ;; universal) : ;; *) AC_MSG_ERROR([invalid MACHINE variable: $MACHINE]) ;; esac AC_MSG_CHECKING(whether the toolchain supports the chosen ABI) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [machine_supported=yes], [machine_supported=no], [machine_supported=undefined]) AC_MSG_RESULT($machine_supported) if test "$machine_supported" = no; then AC_MSG_ERROR([toolchain cannot handle MACHINE=$MACHINE]) fi fi # Compiler dependent settings: MPD_PTHREAD= MPD_WARN= MPD_WARNXX= MPD_OPT="-O2" MPD_PGEN= MPD_PUSE= CONFIG_UNIVERSAL_AIX= FILTER_FOR_STATIC= case $CC in *gcc*) CONFIG_UNIVERSAL_AIX=$CONFIG_UNIVERSAL_AIX_UINT128 MPD_PTHREAD="-pthread" MPD_WARN="-Wall -Wextra -Wno-unknown-pragmas -std=c99 -pedantic" MPD_WARNXX="-Wall -Wextra -std=c++11 -pedantic" MPD_OPT="-DNDEBUG -O2" MPD_PGEN="-fprofile-generate -fprofile-values" MPD_PUSE="-fprofile-use -freorder-blocks" FILTER_FOR_STATIC="-flto% -ffat-lto-objects" ;; *icc*) AR=xiar CXX=icpc MPD_PTHREAD="-pthread" MPD_WARN="-Wall -Wextra -Wno-unknown-pragmas -std=c99 -pedantic -diag-disable=11074,11076" MPD_WARNXX="-Wall -Wextra -std=c++11 -pedantic -diag-disable=11074,11076" MPD_OPT="-DNDEBUG -O2" MPD_PGEN="-wd11505 -prof-gen" MPD_PUSE="-wd11505 -prof-use" ;; *clang* | *icx* | *emcc*) CONFIG_UNIVERSAL_AIX=$CONFIG_UNIVERSAL_AIX_UINT128 MPD_PTHREAD="-pthread" MPD_WARN="-Wall -Wextra -Wno-unknown-pragmas -std=c99 -pedantic" MPD_WARNXX="-Wall -Wextra -Wexit-time-destructors -std=c++11 -pedantic" MPD_OPT="-DNDEBUG -O2" ;; *xlc*) CONFIG_UNIVERSAL_AIX=$CONFIG_UNIVERSAL_AIX_ANSI64 CONFIGURE_LDFLAGS="-qmkshrobj -bnoentry -bE:.objs/symbols.exp" LINK_STATIC="-bstatic" LINK_DYNAMIC="-bshared" MPD_PTHREAD="-qthreaded -D_THREAD_SAFE" MPD_WARN="-qlanglvl=stdc99" MPD_OPT="-DNDEBUG -O2 -qalias=ansi -qmaxmem=-1" ;; *suncc*) MPD_WARN="-xc99" MPD_OPT="-DNDEBUG -O2" ;; *ccomp*) ENABLE_SHARED=no LINK_STATIC="-Wl,-znoexecstack" MPD_WARN="-Wall -Wno-unknown-pragmas -std=c99 -fstruct-passing" MPD_OPT="-DNDEBUG -O2" ;; *) ;; esac AC_ARG_VAR(LDXXFLAGS, [C++ linker flags]) # These variables are set unconditionally because CONFIGURE_LDFLAGS etc. # require the compiler frontends. We leave them in the Makefiles in case # someone needs to edit the Makefiles manually. LD="$CC" LDXX="$CXX" AC_SUBST(CC) AC_SUBST(LD) AC_SUBST(CXX) AC_SUBST(LDXX) AC_SUBST(FILTER_FOR_STATIC) AC_SUBST(MPD_PTHREAD) AC_SUBST(MPD_PGEN) AC_SUBST(MPD_PUSE) # ============================================================================== # Headers, types, assembly, install program # ============================================================================== # Check for header files: AC_CHECK_HEADERS(pthread.h) # Type availability checks: AC_TYPE_SIZE_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_CHECK_TYPE(__uint128_t, AC_DEFINE(HAVE_UINT128_T, 1, [Define if your compiler provides __uint128_t.]),,) # Sizes of various types: AC_CHECK_SIZEOF(size_t, 4) AC_CHECK_SIZEOF(__uint128_t, 16) # x64 with gcc asm: AC_MSG_CHECKING(for x64 gcc inline assembler) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ __asm__ __volatile__ ("movq %rcx, %rax"); ]])],[have_gcc_asm_for_x64=yes],[have_gcc_asm_for_x64=no]) AC_MSG_RESULT($have_gcc_asm_for_x64) if test "$have_gcc_asm_for_x64" = yes; then AC_DEFINE(HAVE_GCC_ASM_FOR_X64, 1, [Define if we can use x64 gcc inline assembler.]) fi # x87 with gcc asm: AC_MSG_CHECKING(for x87 gcc inline assembler) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ unsigned short cw; __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); ]])],[have_gcc_asm_for_x87=yes],[have_gcc_asm_for_x87=no]) AC_MSG_RESULT($have_gcc_asm_for_x87) if test "$have_gcc_asm_for_x87" = yes; then AC_DEFINE(HAVE_GCC_ASM_FOR_X87, 1, [Define if we can use x87 gcc inline assembler.]) fi # Install program: AC_PROG_INSTALL AC_SUBST(INSTALL) # ============================================================================== # Detect toolchain bugs # ============================================================================== # _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: # http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html AC_MSG_CHECKING(for glibc _FORTIFY_SOURCE/memmove bug) saved_cflags="$CFLAGS" saved_ldflags="$LDFLAGS" CFLAGS="-O2 -D_FORTIFY_SOURCE=2" if test "$have_O2" = no; then CFLAGS= fi LDFLAGS= AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include #include void foo(void *p, void *q) { memmove(p, q, 19); } int main() { char a[32] = "123456789000000000"; foo(&a[9], a); if (strcmp(a, "123456789123456789000000000") != 0) return 1; foo(a, &a[9]); if (strcmp(a, "123456789000000000") != 0) return 1; return 0; } ]])], [have_glibc_memmove_bug=no], [have_glibc_memmove_bug=yes], [have_glibc_memmove_bug=undefined]) CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" AC_MSG_RESULT($have_glibc_memmove_bug) if test "$have_glibc_memmove_bug" = yes; then AC_DEFINE(HAVE_GLIBC_MEMMOVE_BUG, 1, [Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and bcopy.]) fi # ============================================================================== # Optimized configurations # ============================================================================== # Auto-detect machine dependent settings: AIX_AR= AIX_RANLIB= EXPORTSYMS= OBJECT_SUFFIX= DETECTED_MACHINE= if test $ac_cv_sizeof_size_t -eq 8; then AIX_AR="ar -X64" AIX_RANLIB="ranlib -X64" EXPORTSYMS="symbols64.exp" OBJECT_SUFFIX="4_64.o" if test $have_gcc_asm_for_x64 = yes; then DETECTED_MACHINE="x64" elif test $ac_cv_type___uint128_t = yes; then DETECTED_MACHINE="uint128" else DETECTED_MACHINE="ansi64" fi else AIX_AR="ar -X32" AIX_RANLIB="ranlib -X32" EXPORTSYMS="symbols32.exp" OBJECT_SUFFIX="4.o" DETECTED_MACHINE="ansi32" if test $have_gcc_asm_for_x87 = yes; then case $CC in *gcc* | *clang*) # icc >= 11.0 works as well case $host in *-*-darwin*) ;; *) DETECTED_MACHINE="ppro" ;; esac ;; esac fi fi if test -z "$MACHINE"; then MACHINE="$DETECTED_MACHINE" fi # Set configuration variables: MPD_ABI= MPD_PREC=9 case "$MACHINE" in x64) MPD_HEADER_CONFIG=$CONFIG_64 MPD_ABI=$M64 MPD_CONFIG="-DCONFIG_64 -DASM" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M64" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M64" MPD_PREC=19 ;; uint128) MPD_HEADER_CONFIG=$CONFIG_64 MPD_ABI=$M64 MPD_CONFIG="-DCONFIG_64 -DANSI -DHAVE_UINT128_T" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M64" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M64" MPD_PREC=19 ;; ansi64) MPD_HEADER_CONFIG=$CONFIG_64 MPD_ABI=$M64 MPD_CONFIG="-DCONFIG_64 -DANSI" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M64" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M64" MPD_PREC=19 ;; ppro) MPD_HEADER_CONFIG=$CONFIG_32 MPD_ABI=$M32 MPD_CONFIG="-DCONFIG_32 -DPPRO -DASM" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M32" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M32" # Some versions of gcc miscompile inline asm: # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html case $CC in *gcc*) AC_MSG_CHECKING(for gcc ipa-pure-const bug) saved_cflags="$CFLAGS" saved_ldflags="$LDFLAGS" CFLAGS="-O2" LDFLAGS= AC_RUN_IFELSE([AC_LANG_SOURCE([[ __attribute__((noinline)) int foo(int *p) { int r; asm ( "movl \$6, (%1)\n\t" "xorl %0, %0\n\t" : "=r" (r) : "r" (p) : "memory" ); return r; } int main() { int p = 8; if ((foo(&p) ? : p) != 6) return 1; return 0; } ]])], [have_ipa_pure_const_bug=no], [have_ipa_pure_const_bug=yes], [have_ipa_pure_const_bug=undefined]) CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" AC_MSG_RESULT($have_ipa_pure_const_bug) if test "$have_ipa_pure_const_bug" = yes; then MPD_CONFIG="$MPD_CONFIG -fno-ipa-pure-const" AC_DEFINE(HAVE_IPA_PURE_CONST_BUG, 1, [Define if gcc has the ipa-pure-const bug.]) fi ;; esac ;; ansi32) MPD_HEADER_CONFIG=$CONFIG_32 MPD_ABI=$M32 MPD_CONFIG="-DCONFIG_32 -DANSI" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M32" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M32" ;; ansi-legacy) MPD_HEADER_CONFIG=$CONFIG_32_LEGACY MPD_ABI=$M32 MPD_CONFIG="-DCONFIG_32 -DANSI -DLEGACY_COMPILER" CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $M32" CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $M32" ;; universal) MPD_HEADER_CONFIG=$CONFIG_UNIVERSAL MPD_CONFIG="-DUNIVERSAL" ;; *) AC_MSG_ERROR([cannot detect MACHINE]) ;; esac # Special cases: MPD_CXXOPT= MPD_GNU99= case $host in *-*-aix*) AR=$AIX_AR RANLIB=$AIX_RANLIB MPD_OPT="-D_THREAD_SAFE $MPD_OPT" MPD_CXXOPT="-D_THREAD_SAFE" case "$MACHINE" in universal) MPD_HEADER_CONFIG=$CONFIG_UNIVERSAL_AIX AR="ar -X32_64" RANLIB="ranlib -X32_64" ;; esac ;; *-*-netbsd*) MPD_OPT="-D_REENTRANT $MPD_OPT" MPD_CXXOPT="-D_REENTRANT" ;; *-*-solaris* | *-*-sunos*) MPD_OPT="-D_REENTRANT $MPD_OPT" MPD_CXXOPT="-D_REENTRANT" case $CC in *gcc*) MPD_GNU99=-std=gnu99 ;; esac ;; esac AC_SUBST(AR) AC_SUBST(RANLIB) AC_SUBST(EXPORTSYMS) AC_SUBST(OBJECT_SUFFIX) AC_SUBST(MPD_HEADER_CONFIG) AC_SUBST(MPD_GNU99) AC_SUBST(MPD_PREC) # ============================================================================== # Substitute remaining variables # ============================================================================== if test -z "$INITIAL_CFLAGS"; then CONFIGURE_LIBMPDEC_CFLAGS="$MPD_WARN $MPD_CONFIG $MPD_OPT $MPD_ABI" CONFIGURE_CFLAGS="$MPD_WARN $MPD_OPT $MPD_ABI" else CONFIGURE_LIBMPDEC_CFLAGS="$MPD_WARN $MPD_CONFIG $MPD_OPT $MPD_ABI $INITIAL_CFLAGS" CONFIGURE_CFLAGS="$MPD_WARN $MPD_OPT $MPD_ABI $INITIAL_CFLAGS" fi if test "$have_glibc_memmove_bug" = yes; then CONFIGURE_LIBMPDEC_CFLAGS="$CONFIGURE_LIBMPDEC_CFLAGS -U_FORTIFY_SOURCE" CONFIGURE_CFLAGS="$CONFIGURE_CFLAGS -U_FORTIFY_SOURCE" fi if test -z "$INITIAL_CXXFLAGS"; then CONFIGURE_CXXFLAGS="$MPD_WARNXX $MPD_CXXOPT -DNDEBUG -O3 $MPD_ABI" else CONFIGURE_CXXFLAGS="$MPD_WARNXX $MPD_CXXOPT -DNDEBUG -O3 $MPD_ABI $INITIAL_CXXFLAGS" fi if test -n "$INITIAL_LDFLAGS"; then CONFIGURE_LDFLAGS="$CONFIGURE_LDFLAGS $INITIAL_LDFLAGS" fi if test -n "$INITIAL_LDXXFLAGS"; then CONFIGURE_LDXXFLAGS="$CONFIGURE_LDXXFLAGS $INITIAL_LDXXFLAGS" fi AC_SUBST(CONFIGURE_LIBMPDEC_CFLAGS) AC_SUBST(CONFIGURE_CFLAGS) AC_SUBST(CONFIGURE_LDFLAGS) AC_SUBST(CONFIGURE_CXXFLAGS) AC_SUBST(CONFIGURE_LDXXFLAGS) # ============================================================================== # Write output # ============================================================================== AC_OUTPUT GLIBC_MEMMOVE_BUG_WARN=" ***************************** WARNING ********************************* Detected glibc _FORTIFY_SOURCE/memmove bug. See: http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html Enabling -U_FORTIFY_SOURCE workaround. If -D_FORTIFY_SOURCE is also present in the command line, make sure that the order of the two options is: ... -D_FORTIFY_SOURCE=2 ... -U_FORTIFY_SOURCE ... A better solution is to upgrade glibc or to report the bug to your OS vendor. ***************************** WARNING ********************************* " if test "$have_glibc_memmove_bug" = yes; then echo "$GLIBC_MEMMOVE_BUG_WARN" fi mpdecimal-4.0.1/doc/0000755000000000000000000000000015005764474011156 5ustar00mpdecimal-4.0.1/doc/COPYRIGHT.txt0000644000000000000000000000557715005764474013305 0ustar00 SOURCE CODE LICENSE =================== Copyright (c) 2008-2025 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. DOCUMENTATION LICENSE ===================== Copyright 2010-2025 Stefan Krah. All rights reserved. Redistribution and use in source and 'compiled' forms (HTML, PDF, PostScript and so forth) 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 as the first lines of this file unmodified. 2. Modified documents must carry a notice that modification has occurred. This notice must also be present in any compiled form. 3. Redistributions in compiled form (converted to HTML, PDF, PostScript and other formats) 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 DOCUMENTATION IS PROVIDED BY THE AUTHOR ``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 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 DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. mpdecimal-4.0.1/doc/libmpdec++.30000644000000000000000000000153715005764474013155 0ustar00.TH LIBMPDEC++ 3 2025-05-01 mpdecimal-4.0.1 "Programmer's Manual" .ft C . .SH NAME libmpdec++ \- 4.0.1 . .SH SYNOPSIS .nf C++ library for correctly rounded arbitrary precision decimal floating-point arithmetic. .ne . .SH DESCRIPTION .nf The \fIlibmpdec++\fP library is part of \fImpdecimal\fP and fully implements the General Decimal Arithmetic Specification, see: https://speleotrove.com/decimal/decarith.html As described in the scope section of the specification, the library conforms \- with minor restrictions \- to the \fIIEEE 754\-2008\fP Standard for Floating\-Point Arithmetic if the context is initialized with the appropriate parameters. Depending on the distribution, complete HTML documentation is available in the \fImpdecimal-doc\fP package or at: https://www.bytereef.org/mpdecimal/index.html .ne . .SH SEE ALSO mpdecimal.3, libmpdec.3 mpdecimal-4.0.1/doc/libmpdec.30000644000000000000000000000153115005764474013021 0ustar00.TH LIBMPDEC 3 2025-05-01 mpdecimal-4.0.1 "Programmer's Manual" .ft C . .SH NAME libmpdec \- 4.0.1 . .SH SYNOPSIS .nf C library for correctly rounded arbitrary precision decimal floating-point arithmetic. .ne . .SH DESCRIPTION .nf The \fIlibmpdec\fP library is part of \fImpdecimal\fP and fully implements the General Decimal Arithmetic Specification, see: https://speleotrove.com/decimal/decarith.html As described in the scope section of the specification, the library conforms \- with minor restrictions \- to the \fIIEEE 754\-2008\fP Standard for Floating\-Point Arithmetic if the context is initialized with the appropriate parameters. Depending on the distribution, complete HTML documentation is available in the \fImpdecimal-doc\fP package or at: https://www.bytereef.org/mpdecimal/index.html .ne . .SH SEE ALSO mpdecimal.3, libmpdec++.3 mpdecimal-4.0.1/doc/mpdecimal.30000644000000000000000000000153115005764474013175 0ustar00.TH MPDECIMAL 3 2025-05-01 mpdecimal-4.0.1 "Programmer's Manual" .ft C . .SH NAME mpdecimal \- 4.0.1 . .SH SYNOPSIS .nf C/C++ libraries for correctly rounded arbitrary precision decimal floating- point arithmetic. .ne . .SH DESCRIPTION .nf The \fIlibmpdec\fP and \fIlibmpdec++\fP libraries fully implement the General Decimal Arithmetic Specification, see: https://speleotrove.com/decimal/decarith.html As described in the scope section of the specification, the libraries conform \- with minor restrictions \- to the \fIIEEE 754\-2008\fP Standard for Floating\-Point Arithmetic if the context is initialized with the appropriate parameters. Depending on the distribution, complete HTML documentation is available in the \fImpdecimal-doc\fP package or at: https://www.bytereef.org/mpdecimal/index.html .ne . .SH SEE ALSO libmpdec.3, libmpdec++.3 mpdecimal-4.0.1/install-sh0000755000000000000000000003577615005764474012437 0ustar00#!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: mpdecimal-4.0.1/libmpdec/0000755000000000000000000000000015005764474012170 5ustar00mpdecimal-4.0.1/libmpdec/.objs/0000755000000000000000000000000015005764474013203 5ustar00mpdecimal-4.0.1/libmpdec/.objs/README.txt0000644000000000000000000000023215005764474014676 0ustar00 Directory for shared object files ================================= symbols32.exp ==> 32-bit libmpdec API symbols64.exp ==> 64-bit libmpdec API mpdecimal-4.0.1/libmpdec/.objs/symbols32.exp0000644000000000000000000001067715005764474015571 0ustar00*** libmpdec 32-bit symbols *** mpd_abs mpd_abs_uint mpd_add mpd_add_i32 mpd_add_i64 mpd_add_ssize mpd_addstatus_raise mpd_add_u32 mpd_add_u64 mpd_add_uint mpd_adjexp mpd_alloc mpd_and mpd_arith_sign mpd_as_uint128_triple mpd_basiccontext mpd_calloc mpd_callocfunc mpd_callocfunc_em mpd_canonical mpd_ceil mpd_check_nan mpd_check_nans mpd_clamp_string mpd_class mpd_clear_flags mpd_cmp mpd_cmp_total mpd_cmp_total_mag mpd_compare mpd_compare_signal mpd_compare_total mpd_compare_total_mag mpd_copy mpd_copy_abs mpd_copy_flags mpd_copy_negate mpd_copy_sign mpd_defaultcontext mpd_del mpd_dflt_traphandler mpd_digits_to_size mpd_div mpd_div_i32 mpd_div_i64 mpd_divint mpd_divmod mpd_div_ssize mpd_div_u32 mpd_div_u64 mpd_div_uint mpd_etiny mpd_etop mpd_exp mpd_exp_digits mpd_export_u16 mpd_export_u32 mpd_finalize mpd_floor mpd_fma mpd_format mpd_fprint mpd_free mpd_from_uint128_triple mpd_getclamp mpd_getcr mpd_getemax mpd_getemin mpd_get_i32 mpd_get_i64 mpd_getprec mpd_getround mpd_get_ssize mpd_getstatus mpd_gettraps mpd_get_u32 mpd_get_u64 mpd_get_uint mpd_ieee_context mpd_import_u16 mpd_import_u32 mpd_init mpd_invert mpd_invroot mpd_iscanonical mpd_isconst_data mpd_isdynamic mpd_isdynamic_data mpd_iseven mpd_isfinite mpd_isinfinite mpd_isinteger mpd_isnan mpd_isnegative mpd_isnormal mpd_isodd mpd_isoddcoeff mpd_isoddword mpd_ispositive mpd_isqnan mpd_isshared_data mpd_issigned mpd_issnan mpd_isspecial mpd_isstatic mpd_isstatic_data mpd_issubnormal mpd_iszero mpd_iszerocoeff mpd_ln mpd_log10 mpd_logb mpd_lsd mpd_lsnprint_flags mpd_lsnprint_signals mpd_mallocfunc mpd_max mpd_maxcoeff mpd_maxcontext mpd_max_mag mpd_min mpd_minalloc MPD_MINALLOC mpd_min_mag mpd_minus mpd_msd mpd_msword mpd_mul mpd_mul_i32 mpd_mul_i64 mpd_mul_ssize mpd_mul_u32 mpd_mul_u64 mpd_mul_uint mpd_new mpd_next_minus mpd_next_plus mpd_next_toward mpd_or mpd_parse_fmt_str mpd_plus mpd_pow mpd_powmod mpd_print mpd_qabs mpd_qabs_uint mpd_qadd mpd_qadd_i32 mpd_qadd_i64 mpd_qadd_ssize mpd_qadd_u32 mpd_qadd_u64 mpd_qadd_uint mpd_qand mpd_qceil mpd_qcheck_nan mpd_qcheck_nans mpd_qcmp mpd_qcompare mpd_qcompare_signal mpd_qcopy mpd_qcopy_abs mpd_qcopy_cxx mpd_qcopy_negate mpd_qcopy_sign mpd_qdiv mpd_qdiv_i32 mpd_qdiv_i64 mpd_qdivint mpd_qdivmod mpd_qdiv_ssize mpd_qdiv_u32 mpd_qdiv_u64 mpd_qdiv_uint mpd_qexp mpd_qexport_u16 mpd_qexport_u32 mpd_qfinalize mpd_qfloor mpd_qfma mpd_qformat mpd_qformat_spec mpd_qget_i32 mpd_qget_i64 mpd_qget_ssize mpd_qget_u32 mpd_qget_u64 mpd_qget_uint mpd_qimport_u16 mpd_qimport_u32 mpd_qinvert mpd_qinvroot mpd_qln mpd_qln10 mpd_qlog10 mpd_qlogb mpd_qmax mpd_qmaxcoeff mpd_qmax_mag mpd_qmin mpd_qmin_mag mpd_qminus mpd_qmul mpd_qmul_i32 mpd_qmul_i64 mpd_qmul_ssize mpd_qmul_u32 mpd_qmul_u64 mpd_qmul_uint mpd_qncopy mpd_qnew mpd_qnew_size mpd_qnext_minus mpd_qnext_plus mpd_qnext_toward mpd_qor mpd_qplus mpd_qpow mpd_qpowmod mpd_qquantize mpd_qreduce mpd_qrem mpd_qrem_near mpd_qrescale mpd_qrescale_fmt mpd_qresize mpd_qresize_zero mpd_qrotate mpd_qround_to_int mpd_qround_to_intx mpd_qscaleb mpd_qsetclamp mpd_qsetcr mpd_qsetemax mpd_qsetemin mpd_qset_i32 mpd_qset_i64 mpd_qset_i64_exact mpd_qsetprec mpd_qsetround mpd_qset_ssize mpd_qsetstatus mpd_qset_string mpd_qset_string_exact mpd_qsettraps mpd_qset_u32 mpd_qset_u64 mpd_qset_u64_exact mpd_qset_uint mpd_qshift mpd_qshiftl mpd_qshiftn mpd_qshiftr mpd_qshiftr_inplace mpd_qsqrt mpd_qsset_i32 mpd_qsset_ssize mpd_qsset_u32 mpd_qsset_uint mpd_qsub mpd_qsub_i32 mpd_qsub_i64 mpd_qsub_ssize mpd_qsub_u32 mpd_qsub_u64 mpd_qsub_uint mpd_qtrunc mpd_quantize mpd_qxor mpd_radix mpd_realloc mpd_reallocfunc mpd_reduce mpd_rem mpd_rem_near mpd_rescale mpd_resize mpd_resize_zero mpd_rotate mpd_round_string mpd_round_to_int mpd_round_to_intx mpd_same_quantum mpd_scaleb mpd_set_const_data mpd_setdigits mpd_set_dynamic mpd_set_dynamic_data mpd_seterror mpd_set_flags mpd_set_i32 mpd_set_i64 mpd_set_infinity mpd_setminalloc mpd_set_negative mpd_set_positive mpd_set_qnan mpd_set_shared_data mpd_set_sign mpd_set_snan mpd_setspecial mpd_set_ssize mpd_set_static mpd_set_static_data mpd_set_string mpd_set_u32 mpd_set_u64 mpd_set_uint mpd_sh_alloc mpd_shift mpd_shiftl mpd_shiftn mpd_shiftr mpd_sign mpd_signcpy mpd_sizeinbase mpd_snprint_flags mpd_sqrt mpd_sset_i32 mpd_sset_ssize mpd_sset_u32 mpd_sset_uint mpd_sub mpd_sub_i32 mpd_sub_i64 mpd_sub_ssize mpd_sub_u32 mpd_sub_u64 mpd_sub_uint mpd_to_eng mpd_to_eng_size mpd_to_sci mpd_to_sci_size mpd_trail_zeros mpd_traphandler mpd_trunc mpd_uint_zero mpd_validate_lconv mpd_version mpd_word_digits mpd_xor mpd_zerocoeff mpdecimal-4.0.1/libmpdec/.objs/symbols64.exp0000644000000000000000000001076515005764474015574 0ustar00*** libmpdec 64-bit symbols *** mpd_abs mpd_abs_uint mpd_add mpd_add_i32 mpd_add_i64 mpd_add_ssize mpd_addstatus_raise mpd_add_u32 mpd_add_u64 mpd_add_uint mpd_adjexp mpd_alloc mpd_and mpd_arith_sign mpd_as_uint128_triple mpd_basiccontext mpd_calloc mpd_callocfunc mpd_callocfunc_em mpd_canonical mpd_ceil mpd_check_nan mpd_check_nans mpd_clamp_string mpd_class mpd_clear_flags mpd_cmp mpd_cmp_total mpd_cmp_total_mag mpd_compare mpd_compare_signal mpd_compare_total mpd_compare_total_mag mpd_copy mpd_copy_abs mpd_copy_flags mpd_copy_negate mpd_copy_sign mpd_defaultcontext mpd_del mpd_dflt_traphandler mpd_digits_to_size mpd_div mpd_div_i32 mpd_div_i64 mpd_divint mpd_divmod mpd_div_ssize mpd_div_u32 mpd_div_u64 mpd_div_uint mpd_etiny mpd_etop mpd_exp mpd_exp_digits mpd_export_u16 mpd_export_u32 mpd_finalize mpd_floor mpd_fma mpd_format mpd_fprint mpd_free mpd_from_uint128_triple mpd_getclamp mpd_getcr mpd_getemax mpd_getemin mpd_get_i32 mpd_get_i64 mpd_getprec mpd_getround mpd_get_ssize mpd_getstatus mpd_gettraps mpd_get_u32 mpd_get_u64 mpd_get_uint mpd_ieee_context mpd_import_u16 mpd_import_u32 mpd_init mpd_invert mpd_invroot mpd_iscanonical mpd_isconst_data mpd_isdynamic mpd_isdynamic_data mpd_iseven mpd_isfinite mpd_isinfinite mpd_isinteger mpd_isnan mpd_isnegative mpd_isnormal mpd_isodd mpd_isoddcoeff mpd_isoddword mpd_ispositive mpd_isqnan mpd_isshared_data mpd_issigned mpd_issnan mpd_isspecial mpd_isstatic mpd_isstatic_data mpd_issubnormal mpd_iszero mpd_iszerocoeff mpd_ln mpd_log10 mpd_logb mpd_lsd mpd_lsnprint_flags mpd_lsnprint_signals mpd_mallocfunc mpd_max mpd_maxcoeff mpd_maxcontext mpd_max_mag mpd_min mpd_minalloc MPD_MINALLOC mpd_min_mag mpd_minus mpd_msd mpd_msword mpd_mul mpd_mul_i32 mpd_mul_i64 mpd_mul_ssize mpd_mul_u32 mpd_mul_u64 mpd_mul_uint mpd_new mpd_next_minus mpd_next_plus mpd_next_toward mpd_or mpd_parse_fmt_str mpd_plus mpd_pow mpd_powmod mpd_print mpd_qabs mpd_qabs_uint mpd_qadd mpd_qadd_i32 mpd_qadd_i64 mpd_qadd_ssize mpd_qadd_u32 mpd_qadd_u64 mpd_qadd_uint mpd_qand mpd_qceil mpd_qcheck_nan mpd_qcheck_nans mpd_qcmp mpd_qcompare mpd_qcompare_signal mpd_qcopy mpd_qcopy_abs mpd_qcopy_cxx mpd_qcopy_negate mpd_qcopy_sign mpd_qdiv mpd_qdiv_i32 mpd_qdiv_i64 mpd_qdivint mpd_qdivmod mpd_qdiv_ssize mpd_qdiv_u32 mpd_qdiv_u64 mpd_qdiv_uint mpd_qexp mpd_qexport_u16 mpd_qexport_u32 mpd_qfinalize mpd_qfloor mpd_qfma mpd_qformat mpd_qformat_spec mpd_qget_i32 mpd_qget_i64 mpd_qget_ssize mpd_qget_u32 mpd_qget_u64 mpd_qget_uint mpd_qimport_u16 mpd_qimport_u32 mpd_qinvert mpd_qinvroot mpd_qln mpd_qln10 mpd_qlog10 mpd_qlogb mpd_qmax mpd_qmaxcoeff mpd_qmax_mag mpd_qmin mpd_qmin_mag mpd_qminus mpd_qmul mpd_qmul_i32 mpd_qmul_i64 mpd_qmul_ssize mpd_qmul_u32 mpd_qmul_u64 mpd_qmul_uint mpd_qncopy mpd_qnew mpd_qnew_size mpd_qnext_minus mpd_qnext_plus mpd_qnext_toward mpd_qor mpd_qplus mpd_qpow mpd_qpowmod mpd_qquantize mpd_qreduce mpd_qrem mpd_qrem_near mpd_qrescale mpd_qrescale_fmt mpd_qresize mpd_qresize_zero mpd_qrotate mpd_qround_to_int mpd_qround_to_intx mpd_qscaleb mpd_qsetclamp mpd_qsetcr mpd_qsetemax mpd_qsetemin mpd_qset_i32 mpd_qset_i64 mpd_qset_i64_exact mpd_qsetprec mpd_qsetround mpd_qset_ssize mpd_qsetstatus mpd_qset_string mpd_qset_string_exact mpd_qsettraps mpd_qset_u32 mpd_qset_u64 mpd_qset_u64_exact mpd_qset_uint mpd_qshift mpd_qshiftl mpd_qshiftn mpd_qshiftr mpd_qshiftr_inplace mpd_qsqrt mpd_qsset_i32 mpd_qsset_i64 mpd_qsset_ssize mpd_qsset_u32 mpd_qsset_u64 mpd_qsset_uint mpd_qsub mpd_qsub_i32 mpd_qsub_i64 mpd_qsub_ssize mpd_qsub_u32 mpd_qsub_u64 mpd_qsub_uint mpd_qtrunc mpd_quantize mpd_qxor mpd_radix mpd_realloc mpd_reallocfunc mpd_reduce mpd_rem mpd_rem_near mpd_rescale mpd_resize mpd_resize_zero mpd_rotate mpd_round_string mpd_round_to_int mpd_round_to_intx mpd_same_quantum mpd_scaleb mpd_set_const_data mpd_setdigits mpd_set_dynamic mpd_set_dynamic_data mpd_seterror mpd_set_flags mpd_set_i32 mpd_set_i64 mpd_set_infinity mpd_setminalloc mpd_set_negative mpd_set_positive mpd_set_qnan mpd_set_shared_data mpd_set_sign mpd_set_snan mpd_setspecial mpd_set_ssize mpd_set_static mpd_set_static_data mpd_set_string mpd_set_u32 mpd_set_u64 mpd_set_uint mpd_sh_alloc mpd_shift mpd_shiftl mpd_shiftn mpd_shiftr mpd_sign mpd_signcpy mpd_sizeinbase mpd_snprint_flags mpd_sqrt mpd_sset_i32 mpd_sset_i64 mpd_sset_ssize mpd_sset_u32 mpd_sset_u64 mpd_sset_uint mpd_sub mpd_sub_i32 mpd_sub_i64 mpd_sub_ssize mpd_sub_u32 mpd_sub_u64 mpd_sub_uint mpd_to_eng mpd_to_eng_size mpd_to_sci mpd_to_sci_size mpd_trail_zeros mpd_traphandler mpd_trunc mpd_uint_zero mpd_validate_lconv mpd_version mpd_word_digits mpd_xor mpd_zerocoeff mpdecimal-4.0.1/libmpdec/.pc/0000755000000000000000000000000015005764474012650 5ustar00mpdecimal-4.0.1/libmpdec/.pc/libmpdec.pc.in0000644000000000000000000000040215005764474015354 0ustar00prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libmpdec Description: C library for decimal floating point arithmetic Version: 4.0.1 URL: https://www.bytereef.org Cflags: -I${includedir} Libs: -L${libdir} -lmpdec -lm mpdecimal-4.0.1/libmpdec/.profile/0000755000000000000000000000000015005764474013706 5ustar00mpdecimal-4.0.1/libmpdec/.profile/train.sh0000755000000000000000000000174715005764474015373 0ustar00#!/bin/sh PORTABLE_PWD=`pwd` LD_LIBRARY_PATH="$PORTABLE_PWD:$LD_LIBRARY_PATH" DYLD_LIBRARY_PATH="$PORTABLE_PWD:$DYLD_LIBRARY_PATH" LD_64_LIBRARY_PATH="$PORTABLE_PWD:$LD_64_LIBRARY_PATH" LD_32_LIBRARY_PATH="$PORTABLE_PWD:$LD_32_LIBRARY_PATH" LD_LIBRARY_PATH_64="$PORTABLE_PWD:$LD_LIBRARY_PATH_64" LD_LIBRARY_PATH_32="$PORTABLE_PWD:$LD_LIBRARY_PATH_32" PATH="$LD_LIBRARY_PATH:$PATH" export LD_LIBRARY_PATH export DYLD_LIBRARY_PATH export LD_64_LIBRARY_PATH export LD_32_LIBRARY_PATH export LD_LIBRARY_PATH_64 export LD_LIBRARY_PATH_32 MPD_PREC="$1" MPD_DPREC=`expr "$MPD_PREC" \* 2` if [ ! -f ./bench_full -a ! -f ./bench_shared ]; then printf "\n./train.sh: error: no training files found\n\n" exit 1 fi if [ -f ./bench_full ]; then ./bench_full "$MPD_PREC" 1000 > /dev/null 2>&1 ./bench_full "$MPD_DPREC" 1000 > /dev/null 2>&1 fi if [ -f ./bench_shared ]; then ./bench_shared "$MPD_PREC" 1000000 > /dev/null 2>&1 ./bench_shared "$MPD_DPREC" 1000000 > /dev/null 2>&1 fi mpdecimal-4.0.1/libmpdec/Makefile.in0000644000000000000000000002265515005764474014247 0ustar00 # ============================================================================== # Unix Makefile for libmpdec # ============================================================================== prefix = @prefix@ exec_prefix = @exec_prefix@ libdir = @libdir@ ENABLE_STATIC = @ENABLE_STATIC@ ENABLE_SHARED = @ENABLE_SHARED@ ENABLE_MINGW = @ENABLE_MINGW@ FPIC = @FPIC@ LIBSTATIC = @LIBSTATIC@ LIBNAME = @LIBNAME@ LIBSONAME = @LIBSONAME@ LIBSHARED = @LIBSHARED@ LIBIMPORT = @LIBIMPORT@ LIBSHARED_USE_AR = @LIBSHARED_USE_AR@ LINK_STATIC = @LINK_STATIC@ LINK_DYNAMIC = @LINK_DYNAMIC@ EXPORTSYMS = @EXPORTSYMS@ OBJECT_SUFFIX = @OBJECT_SUFFIX@ COPY = @cp -f $1 $2 CC = @CC@ LD = @LD@ AR = @AR@ RANLIB = @RANLIB@ MPD_PGEN = @MPD_PGEN@ MPD_PUSE = @MPD_PUSE@ MPD_PREC = @MPD_PREC@ # gcc produces a random false positive warning for LTO bytecode in libmpdec.a # (see: bench target). Users of libmpdec.a should not get spurious warnings. FILTER_FOR_STATIC = @FILTER_FOR_STATIC@ CONFIGURE_LIBMPDEC_CFLAGS = @CONFIGURE_LIBMPDEC_CFLAGS@ MPD_CFLAGS_COMMON = $(strip $(filter-out $(CFLAGS),$(CONFIGURE_LIBMPDEC_CFLAGS)) $(CFLAGS)) MPD_CFLAGS_SHARED = $(strip $(filter-out $(FPIC),$(MPD_CFLAGS_COMMON)) $(FPIC)) MPD_CFLAGS = $(strip $(filter-out $(FILTER_FOR_STATIC),$(MPD_CFLAGS_COMMON))) CONFIGURE_CFLAGS = @CONFIGURE_CFLAGS@ MPD_BIN_CFLAGS_SHARED = $(strip $(filter-out $(CFLAGS),$(CONFIGURE_CFLAGS)) $(CFLAGS)) MPD_BIN_CFLAGS = $(strip $(filter-out $(FILTER_FOR_STATIC),$(MPD_BIN_CFLAGS_SHARED))) CONFIGURE_LDFLAGS = @CONFIGURE_LDFLAGS@ MPD_LDFLAGS = $(strip $(filter-out $(LDFLAGS),$(CONFIGURE_LDFLAGS)) $(LDFLAGS)) LINK_LIBSTATIC = $(strip $(LINK_STATIC) $(LIBSTATIC) $(LINK_DYNAMIC)) ifeq ($(MAKECMDGOALS), profile_gen) MPD_CFLAGS_COMMON += $(MPD_PGEN) MPD_BIN_CFLAGS_SHARED += $(MPD_PGEN) MPD_LDFLAGS += $(MPD_PGEN) endif ifeq ($(MAKECMDGOALS), profile_use) MPD_CFLAGS_COMMON += $(MPD_PUSE) MPD_BIN_CFLAGS_SHARED += $(MPD_PUSE) MPD_LDFLAGS += $(MPD_PUSE) endif MPD_TARGETS = ifeq ($(ENABLE_STATIC), yes) MPD_TARGETS += $(LIBSTATIC) endif ifeq ($(ENABLE_SHARED), yes) MPD_TARGETS += $(LIBSHARED) endif default: $(MPD_TARGETS) OBJS := basearith.o context.o constants.o convolute.o crt.o mpdecimal.o \ mpsignal.o difradix2.o fnt.o fourstep.o io.o mpalloc.o numbertheory.o \ sixstep.o transpose.o SHARED_OBJS := .objs/basearith.o .objs/context.o .objs/constants.o \ .objs/convolute.o .objs/crt.o .objs/mpdecimal.o .objs/mpsignal.o \ .objs/difradix2.o .objs/fnt.o .objs/fourstep.o .objs/io.o \ .objs/mpalloc.o .objs/numbertheory.o .objs/sixstep.o \ .objs/transpose.o ifeq ($(LIBSHARED_USE_AR), yes) AR_STATIC_OBJS := $(OBJS:.o=$(OBJECT_SUFFIX)) AR_SHARED_OBJS := $(LIBSHARED:.o=$(OBJECT_SUFFIX)) %$(OBJECT_SUFFIX): %.o $(call COPY,$<,$@) $(LIBSHARED): Makefile $(SHARED_OBJS) cp .objs/$(EXPORTSYMS) .objs/symbols.exp $(LD) $(MPD_LDFLAGS) -o $(LIBSHARED) $(SHARED_OBJS) -lm $(LIBSTATIC): Makefile $(AR_STATIC_OBJS) $(AR_SHARED_OBJS) $(AR) rc $(LIBSTATIC) $(AR_SHARED_OBJS) $(AR_STATIC_OBJS) $(RANLIB) $(LIBSTATIC) else $(LIBSTATIC): Makefile $(OBJS) $(AR) rc $(LIBSTATIC) $(OBJS) $(RANLIB) $(LIBSTATIC) $(LIBSHARED): Makefile $(SHARED_OBJS) $(LD) $(MPD_LDFLAGS) -o $(LIBSHARED) $(SHARED_OBJS) -lm ifeq ($(ENABLE_MINGW), no) ln -sf $(LIBSHARED) $(LIBNAME) ln -sf $(LIBSHARED) $(LIBSONAME) endif endif basearith.o:\ Makefile basearith.c mpdecimal.h basearith.h typearith.h constants.h $(CC) $(MPD_CFLAGS) -c basearith.c .objs/basearith.o:\ Makefile basearith.c mpdecimal.h basearith.h typearith.h constants.h $(CC) $(MPD_CFLAGS_SHARED) -c basearith.c -o .objs/basearith.o constants.o:\ Makefile constants.c mpdecimal.h basearith.h typearith.h constants.h $(CC) $(MPD_CFLAGS) -c constants.c .objs/constants.o:\ Makefile constants.c mpdecimal.h basearith.h typearith.h constants.h $(CC) $(MPD_CFLAGS_SHARED) -c constants.c -o .objs/constants.o context.o:\ Makefile context.c mpdecimal.h $(CC) $(MPD_CFLAGS) -c context.c .objs/context.o:\ Makefile context.c mpdecimal.h $(CC) $(MPD_CFLAGS_SHARED) -c context.c -o .objs/context.o convolute.o:\ Makefile convolute.c mpdecimal.h bits.h constants.h convolute.h fnt.h \ fourstep.h numbertheory.h sixstep.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c convolute.c .objs/convolute.o:\ Makefile convolute.c mpdecimal.h bits.h constants.h convolute.h fnt.h \ fourstep.h numbertheory.h sixstep.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c convolute.c -o .objs/convolute.o crt.o:\ Makefile crt.c mpdecimal.h constants.h crt.h numbertheory.h umodarith.h \ typearith.h $(CC) $(MPD_CFLAGS) -c crt.c .objs/crt.o:\ Makefile crt.c mpdecimal.h constants.h crt.h numbertheory.h umodarith.h \ typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c crt.c -o .objs/crt.o difradix2.o:\ Makefile difradix2.c mpdecimal.h bits.h constants.h difradix2.h \ numbertheory.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c difradix2.c .objs/difradix2.o:\ Makefile difradix2.c mpdecimal.h bits.h constants.h difradix2.h \ numbertheory.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c difradix2.c -o .objs/difradix2.o fnt.o:\ Makefile fnt.c mpdecimal.h bits.h difradix2.h numbertheory.h constants.h \ fnt.h $(CC) $(MPD_CFLAGS) -c fnt.c .objs/fnt.o:\ Makefile fnt.c mpdecimal.h bits.h difradix2.h numbertheory.h constants.h \ fnt.h $(CC) $(MPD_CFLAGS_SHARED) -c fnt.c -o .objs/fnt.o fourstep.o:\ Makefile fourstep.c mpdecimal.h constants.h fourstep.h numbertheory.h \ sixstep.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c fourstep.c .objs/fourstep.o:\ Makefile fourstep.c mpdecimal.h constants.h fourstep.h numbertheory.h \ sixstep.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c fourstep.c -o .objs/fourstep.o io.o:\ Makefile io.c mpdecimal.h typearith.h io.h $(CC) $(MPD_CFLAGS) -c io.c .objs/io.o:\ Makefile io.c mpdecimal.h typearith.h io.h $(CC) $(MPD_CFLAGS_SHARED) -c io.c -o .objs/io.o mpalloc.o:\ Makefile mpalloc.c mpdecimal.h mpalloc.h typearith.h $(CC) $(MPD_CFLAGS) -c mpalloc.c .objs/mpalloc.o:\ Makefile mpalloc.c mpdecimal.h mpalloc.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c mpalloc.c -o .objs/mpalloc.o mpdecimal.o:\ Makefile mpdecimal.c mpdecimal.h basearith.h typearith.h bits.h \ constants.h convolute.h crt.h mpalloc.h $(CC) $(MPD_CFLAGS) -c mpdecimal.c .objs/mpdecimal.o:\ Makefile mpdecimal.c mpdecimal.h basearith.h typearith.h bits.h \ constants.h convolute.h crt.h mpalloc.h $(CC) $(MPD_CFLAGS_SHARED) -c mpdecimal.c -o .objs/mpdecimal.o mpsignal.o:\ Makefile mpsignal.c mpdecimal.h $(CC) $(MPD_CFLAGS) -c mpsignal.c .objs/mpsignal.o:\ Makefile mpsignal.c mpdecimal.h $(CC) $(MPD_CFLAGS_SHARED) -c mpsignal.c -o .objs/mpsignal.o numbertheory.o:\ Makefile numbertheory.c mpdecimal.h bits.h numbertheory.h \ constants.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c numbertheory.c .objs/numbertheory.o:\ Makefile numbertheory.c mpdecimal.h bits.h numbertheory.h \ constants.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c numbertheory.c -o .objs/numbertheory.o sixstep.o:\ Makefile sixstep.c mpdecimal.h bits.h constants.h difradix2.h \ numbertheory.h sixstep.h transpose.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c sixstep.c .objs/sixstep.o:\ Makefile sixstep.c mpdecimal.h bits.h constants.h difradix2.h \ numbertheory.h sixstep.h transpose.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c sixstep.c -o .objs/sixstep.o transpose.o:\ Makefile transpose.c mpdecimal.h bits.h constants.h transpose.h \ typearith.h $(CC) $(MPD_CFLAGS) -c transpose.c .objs/transpose.o:\ Makefile transpose.c mpdecimal.h bits.h constants.h transpose.h \ typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c transpose.c -o .objs/transpose.o bench: bench.c mpdecimal.h $(LIBSTATIC) $(CC) $(MPD_BIN_CFLAGS) -o bench bench.c $(LINK_LIBSTATIC) -lm bench_full: bench_full.c mpdecimal.h $(LIBSTATIC) $(CC) $(MPD_BIN_CFLAGS) -o bench_full bench_full.c $(LINK_LIBSTATIC) -lm bench_shared: bench.c mpdecimal.h $(LIBSHARED) $(CC) -L. $(MPD_BIN_CFLAGS_SHARED) -o bench_shared bench.c -lmpdec -lm bench_full_shared: bench_full.c mpdecimal.h $(LIBSHARED) $(CC) -L. $(MPD_BIN_CFLAGS_SHARED) -o bench_full_shared bench_full.c -lmpdec -lm pow: Makefile examples/pow.c $(LIBSTATIC) $(CC) -I. $(MPD_BIN_CFLAGS) -o pow examples/pow.c $(LINK_LIBSTATIC) -lm sqrt: Makefile examples/sqrt.c $(LIBSTATIC) $(CC) -I. $(MPD_BIN_CFLAGS) -o sqrt examples/sqrt.c $(LINK_LIBSTATIC) -lm examples: pow sqrt GEN_TARGETS = ifeq ($(ENABLE_STATIC), yes) GEN_TARGETS += bench_full endif ifeq ($(ENABLE_SHARED), yes) GEN_TARGETS += bench_shared endif profile_gen: $(GEN_TARGETS) ./.profile/train.sh $(MPD_PREC) profile_clean: rm -f *.o *.so *.gch rm -f bench bench_shared bench_full bench_full_shared pow sqrt rm -f $(LIBSTATIC) $(LIBNAME) $(LIBSONAME) $(LIBSHARED) $(LIBIMPORT) cd .objs && rm -f *.o *.so *.gch symbols.exp profile_use: default profile: $(MAKE) clean $(MAKE) profile_gen $(MAKE) profile_clean $(MAKE) profile_use check: default cd ../tests && $(MAKE) && ./runshort.sh check_local: default cd ../tests && $(MAKE) && ./runshort.sh --local check_alloc: default cd ../tests && $(MAKE) && ./runshort_alloc.sh clean: rm -f *.o *.so *.gch *.gcda *.gcno *.gcov *.dyn *.dpi *.lock rm -f bench bench_shared bench_full bench_full_shared pow sqrt rm -f $(LIBSTATIC) $(LIBNAME) $(LIBSONAME) $(LIBSHARED) $(LIBIMPORT) cd .objs && rm -f *.o *.so *.gch *.gcda *.gcno *.gcov *.dyn *.dpi *.lock symbols.exp distclean: clean rm -f config.h config.log config.status Makefile mpdecimal.h .pc/libmpdec.pc mpdecimal-4.0.1/libmpdec/Makefile.vc0000644000000000000000000002015315005764474014240 0ustar00 # ====================================================================== # Visual C (nmake) Makefile for libmpdec # ====================================================================== LIBSTATIC = libmpdec-4.0.1.lib LIBIMPORT = libmpdec-4.0.1.dll.lib LIBSHARED = libmpdec-4.0.1.dll MPD_HEADER = mpdecimal32vc.h MPD_PREC = 9 MPD_DPREC = 18 !if "$(MACHINE)" == "x64" CONFIG = /DCONFIG_64 /DMASM MPD_HEADER = mpdecimal64vc.h MPD_PREC = 19 MPD_DPREC = 38 !endif !if "$(MACHINE)" == "ansi64" CONFIG = /DCONFIG_64 /DANSI MPD_HEADER = mpdecimal64vc.h MPD_PREC = 19 MPD_DPREC = 38 !endif !if "$(MACHINE)" == "ppro" CONFIG = /DCONFIG_32 /DPPRO /DMASM !endif !if "$(MACHINE)" == "ansi32" CONFIG = /DCONFIG_32 /DANSI !endif !if "$(DEBUG)" == "1" OPT = /MTd /Od /Zi /EHsc OPT_SHARED = /MDd /Od /Zi /EHsc !else OPT = /MT /O2 /GS /EHsc /DNDEBUG OPT_SHARED = /MD /O2 /GS /EHsc /DNDEBUG !endif !if "$(CC)" == "clang-cl" WARN = /W4 /wd4200 /wd4204 /wd4221 -Wno-unknown-pragmas -Wno-undefined-inline /D_CRT_SECURE_NO_WARNINGS !else WARN = /W4 /wd4200 /wd4204 /wd4221 /D_CRT_SECURE_NO_WARNINGS !endif MPD_CFLAGS = $(WARN) /nologo $(CONFIG) $(OPT) MPD_CFLAGS_SHARED = /DBUILD_LIBMPDEC $(WARN) /nologo $(CONFIG) $(OPT_SHARED) $(PGOFLAGS) MPD_BIN_CFLAGS = $(WARN) /nologo $(OPT) MPD_BIN_CFLAGS_SHARED = $(WARN) /nologo $(OPT_SHARED) $(PGOFLAGS) MPD_LDFLAGS= /DLL /MANIFEST $(LDFLAGS) default: $(LIBSTATIC) $(LIBSHARED) OBJS = basearith.obj context.obj constants.obj convolute.obj crt.obj \ mpdecimal.obj mpsignal.obj difradix2.obj fnt.obj fourstep.obj \ io.obj mpalloc.obj numbertheory.obj sixstep.obj transpose.obj SHARED_OBJS = .objs\basearith.obj .objs\context.obj .objs\constants.obj \ .objs\convolute.obj .objs\crt.obj .objs\mpdecimal.obj .objs\mpsignal.obj \ .objs\difradix2.obj .objs\fnt.obj .objs\fourstep.obj .objs\io.obj \ .objs\mpalloc.obj .objs\numbertheory.obj .objs\sixstep.obj \ .objs\transpose.obj !if "$(MACHINE)" == "x64" OBJS = $(OBJS) vcdiv64.obj SHARED_OBJS = $(SHARED_OBJS) vcdiv64.obj !endif $(LIBSTATIC): Makefile $(OBJS) -@if exist $@ del $(LIBSTATIC) lib /out:$(LIBSTATIC) $(OBJS) $(LIBSHARED): Makefile $(SHARED_OBJS) -@if exist $@ del $(LIBSHARED) link $(MPD_LDFLAGS) /out:$(LIBSHARED) /implib:$(LIBIMPORT) $(SHARED_OBJS) mt -manifest $(LIBSHARED).manifest -outputresource:$(LIBSHARED);2 mpdecimal.h:\ Makefile $(MPD_HEADER) -@copy /y $(MPD_HEADER) mpdecimal.h basearith.obj:\ Makefile basearith.c mpdecimal.h basearith.h typearith.h constants.h $(CC) $(MPD_CFLAGS) -c basearith.c .objs\basearith.obj:\ Makefile basearith.c mpdecimal.h basearith.h typearith.h constants.h $(CC) $(MPD_CFLAGS_SHARED) -c basearith.c /Fo.objs\basearith.obj constants.obj:\ Makefile constants.c mpdecimal.h basearith.h typearith.h constants.h $(CC) $(MPD_CFLAGS) -c constants.c .objs\constants.obj:\ Makefile constants.c mpdecimal.h basearith.h typearith.h constants.h $(CC) $(MPD_CFLAGS_SHARED) -c constants.c /Fo.objs\constants.obj context.obj:\ Makefile context.c mpdecimal.h $(CC) $(MPD_CFLAGS) -c context.c .objs\context.obj:\ Makefile context.c mpdecimal.h $(CC) $(MPD_CFLAGS_SHARED) -c context.c /Fo.objs\context.obj convolute.obj:\ Makefile convolute.c mpdecimal.h bits.h constants.h convolute.h fnt.h \ fourstep.h numbertheory.h sixstep.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c convolute.c .objs\convolute.obj:\ Makefile convolute.c mpdecimal.h bits.h constants.h convolute.h fnt.h \ fourstep.h numbertheory.h sixstep.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c convolute.c /Fo.objs\convolute.obj crt.obj:\ Makefile crt.c mpdecimal.h constants.h crt.h numbertheory.h umodarith.h \ typearith.h $(CC) $(MPD_CFLAGS) -c crt.c .objs\crt.obj:\ Makefile crt.c mpdecimal.h constants.h crt.h numbertheory.h umodarith.h \ typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c crt.c /Fo.objs\crt.obj difradix2.obj:\ Makefile difradix2.c mpdecimal.h bits.h constants.h difradix2.h \ numbertheory.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c difradix2.c .objs\difradix2.obj:\ Makefile difradix2.c mpdecimal.h bits.h constants.h difradix2.h \ numbertheory.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c difradix2.c /Fo.objs\difradix2.obj fnt.obj:\ Makefile fnt.c mpdecimal.h bits.h difradix2.h numbertheory.h constants.h \ fnt.h $(CC) $(MPD_CFLAGS) -c fnt.c .objs\fnt.obj:\ Makefile fnt.c mpdecimal.h bits.h difradix2.h numbertheory.h constants.h \ fnt.h $(CC) $(MPD_CFLAGS_SHARED) -c fnt.c /Fo.objs\fnt.obj fourstep.obj:\ Makefile fourstep.c mpdecimal.h constants.h fourstep.h numbertheory.h \ sixstep.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c fourstep.c .objs\fourstep.obj:\ Makefile fourstep.c mpdecimal.h constants.h fourstep.h numbertheory.h \ sixstep.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c fourstep.c /Fo.objs\fourstep.obj io.obj:\ Makefile io.c mpdecimal.h typearith.h io.h $(CC) $(MPD_CFLAGS) -c io.c .objs\io.obj:\ Makefile io.c mpdecimal.h typearith.h io.h $(CC) $(MPD_CFLAGS_SHARED) -c io.c /Fo.objs\io.obj mpalloc.obj:\ Makefile mpalloc.c mpdecimal.h mpalloc.h typearith.h $(CC) $(MPD_CFLAGS) -c mpalloc.c .objs\mpalloc.obj:\ Makefile mpalloc.c mpdecimal.h mpalloc.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c mpalloc.c /Fo.objs\mpalloc.obj mpdecimal.obj:\ Makefile mpdecimal.c mpdecimal.h basearith.h typearith.h bits.h \ constants.h convolute.h crt.h mpalloc.h $(CC) $(MPD_CFLAGS) -c mpdecimal.c .objs\mpdecimal.obj:\ Makefile mpdecimal.c mpdecimal.h basearith.h typearith.h bits.h \ constants.h convolute.h crt.h mpalloc.h $(CC) $(MPD_CFLAGS_SHARED) -c mpdecimal.c /Fo.objs\mpdecimal.obj mpsignal.obj:\ Makefile mpsignal.c mpdecimal.h $(CC) $(MPD_CFLAGS) -c mpsignal.c .objs\mpsignal.obj:\ Makefile mpsignal.c mpdecimal.h $(CC) $(MPD_CFLAGS_SHARED) -c mpsignal.c /Fo.objs\mpsignal.obj numbertheory.obj:\ Makefile numbertheory.c mpdecimal.h bits.h numbertheory.h \ constants.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c numbertheory.c .objs\numbertheory.obj:\ Makefile numbertheory.c mpdecimal.h bits.h numbertheory.h \ constants.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c numbertheory.c /Fo.objs\numbertheory.obj sixstep.obj:\ Makefile sixstep.c mpdecimal.h bits.h constants.h difradix2.h \ numbertheory.h sixstep.h transpose.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS) -c sixstep.c .objs\sixstep.obj:\ Makefile sixstep.c mpdecimal.h bits.h constants.h difradix2.h \ numbertheory.h sixstep.h transpose.h umodarith.h typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c sixstep.c /Fo.objs\sixstep.obj transpose.obj:\ Makefile transpose.c mpdecimal.h bits.h constants.h transpose.h \ typearith.h $(CC) $(MPD_CFLAGS) -c transpose.c .objs\transpose.obj:\ Makefile transpose.c mpdecimal.h bits.h constants.h transpose.h \ typearith.h $(CC) $(MPD_CFLAGS_SHARED) -c transpose.c /Fo.objs\transpose.obj vcdiv64.obj:\ Makefile vcdiv64.asm ml64 /c /Cx vcdiv64.asm FORCE: bench: FORCE $(CC) $(MPD_BIN_CFLAGS) bench.c $(LIBSTATIC) bench_shared: FORCE $(CC) $(MPD_BIN_CFLAGS_SHARED) bench.c /Fobench_shared $(LIBIMPORT) pow: FORCE $(CC) -I. $(MPD_BIN_CFLAGS) examples\pow.c $(LIBSTATIC) sqrt: FORCE $(CC) -I. $(MPD_BIN_CFLAGS) examples\sqrt.c $(LIBSTATIC) examples: pow sqrt profile: FORCE nmake clean nmake "PGOFLAGS=/GL" "LDFLAGS=/LTCG:PGI" nmake "PGOFLAGS=/GL" bench_shared bench_shared.exe $(MPD_PREC) 1000 bench_shared.exe $(MPD_DPREC) 1000 del /Q *.dll bench_shared.exe link /DLL /LTCG:PGO /out:$(LIBSHARED) /implib:$(LIBIMPORT) $(SHARED_OBJS) mt -manifest $(LIBSHARED).manifest -outputresource:$(LIBSHARED);2 nmake bench_shared bench_shared.exe $(MPD_PREC) 1000 bench_shared.exe $(MPD_DPREC) 1000 clean: FORCE -@if exist *.obj del *.obj -@cd .objs -@if exist *.obj del *.obj -@cd .. -@if exist *.dll del *.dll -@if exist *.exp del *.exp -@if exist *.lib del *.lib -@if exist *.ilk del *.ilk -@if exist *.pdb del *.pdb -@if exist *.pgc del *.pgc -@if exist *.pgd del *.pgd -@if exist *.manifest del *.manifest -@if exist *.exe del *.exe -@if exist mpdecimal.h del mpdecimal.h -@cd ..\tests -@if exist Makefile nmake clean distclean: FORCE nmake clean -@if exist Makefile del Makefile -@cd ..\tests -@if exist Makefile nmake distclean mpdecimal-4.0.1/libmpdec/README.txt0000644000000000000000000000673415005764474013700 0ustar00 libmpdec ======== libmpdec is a fast C/C++ library for correctly-rounded arbitrary precision decimal floating point arithmetic. It is a complete implementation of Mike Cowlishaw/IBM's General Decimal Arithmetic Specification. Core files for small and medium precision arithmetic ---------------------------------------------------- basearith.{c,h} -> Core arithmetic in base 10**9 or 10**19. bits.h -> Portable detection of least/most significant one-bit. constants.{c,h} -> Constants that are used in multiple files. context.c -> Context functions. io.{c,h} -> Conversions between mpd_t and ASCII strings, mpd_t formatting (allows UTF-8 fill character). mpalloc.{c,h} -> Allocation handlers with overflow detection and functions for switching between static and dynamic mpd_t. mpdecimal.{c,h} -> All (quiet) functions of the specification. typearith.h -> Fast primitives for double word multiplication, division etc. Visual Studio only: ~~~~~~~~~~~~~~~~~~~ vcdiv64.asm -> Double word division used in typearith.h. VS 2008 does not allow inline asm for x64. Also, it does not provide an intrinsic for double word division. Files for bignum arithmetic: ---------------------------- The following files implement the Fast Number Theoretic Transform used for multiplying coefficients with more than 1024 words (see mpdecimal.c: _mpd_fntmul()). umodarith.h -> Fast low level routines for unsigned modular arithmetic. numbertheory.{c,h} -> Routines for setting up the Number Theoretic Transform. difradix2.{c,h} -> Decimation in frequency transform, used as the "base case" by the following three files: fnt.{c,h} -> Transform arrays up to 4096 words. sixstep.{c,h} -> Transform larger arrays of length 2**n. fourstep.{c,h} -> Transform larger arrays of length 3 * 2**n. convolute.{c,h} -> Fast convolution using one of the three transform functions. transpose.{c,h} -> Transpositions needed for the sixstep algorithm. crt.{c,h} -> Chinese Remainder Theorem: use information from three transforms modulo three different primes to get the final result. Pointers to literature, proofs and more ======================================= literature/ ----------- REFERENCES.txt -> List of relevant papers. bignum.txt -> Explanation of the Fast Number Theoretic Transform (FNT). fnt.py -> Verify constants used in the FNT; Python demo for the O(N**2) discrete transform. matrix-transform.txt -> Proof for the Matrix Fourier Transform used in fourstep.c. six-step.txt -> Show that the algorithm used in sixstep.c is a variant of the Matrix Fourier Transform. mulmod-64.txt -> Proof for the mulmod64 algorithm from umodarith.h. mulmod-ppro.txt -> Proof for the x87 FPU modular multiplication from umodarith.h. umodarith.lisp -> ACL2 proofs for many functions from umodarith.h. Library Author ============== Stefan Krah mpdecimal-4.0.1/libmpdec/basearith.c0000644000000000000000000004103715005764474014303 0ustar00/* * Copyright (c) 2008-2025 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 #include #include "basearith.h" #include "constants.h" #include "mpdecimal.h" #include "typearith.h" /*********************************************************************/ /* Calculations in base MPD_RADIX */ /*********************************************************************/ /* * Knuth, TAOCP, Volume 2, 4.3.1: * w := sum of u (len m) and v (len n) * n > 0 and m >= n * The calling function has to handle a possible final carry. */ mpd_uint_t _mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, mpd_size_t m, mpd_size_t n) { mpd_uint_t s; mpd_uint_t carry = 0; mpd_size_t i; assert(n > 0 && m >= n); /* add n members of u and v */ for (i = 0; i < n; i++) { s = u[i] + (v[i] + carry); carry = (s < u[i]) | (s >= MPD_RADIX); w[i] = carry ? s-MPD_RADIX : s; } /* if there is a carry, propagate it */ for (; carry && i < m; i++) { s = u[i] + carry; carry = (s == MPD_RADIX); w[i] = carry ? 0 : s; } /* copy the rest of u */ for (; i < m; i++) { w[i] = u[i]; } return carry; } /* * Add the contents of u to w. Carries are propagated further. The caller * has to make sure that w is big enough. */ void _mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n) { mpd_uint_t s; mpd_uint_t carry = 0; mpd_size_t i; if (n == 0) return; /* add n members of u to w */ for (i = 0; i < n; i++) { s = w[i] + (u[i] + carry); carry = (s < w[i]) | (s >= MPD_RADIX); w[i] = carry ? s-MPD_RADIX : s; } /* if there is a carry, propagate it */ for (; carry; i++) { s = w[i] + carry; carry = (s == MPD_RADIX); w[i] = carry ? 0 : s; } } /* * Add v to w (len m). The calling function has to handle a possible * final carry. Assumption: m > 0. */ mpd_uint_t _mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v) { mpd_uint_t s; mpd_uint_t carry; mpd_size_t i; assert(m > 0); /* add v to w */ s = w[0] + v; carry = (s < v) | (s >= MPD_RADIX); w[0] = carry ? s-MPD_RADIX : s; /* if there is a carry, propagate it */ for (i = 1; carry && i < m; i++) { s = w[i] + carry; carry = (s == MPD_RADIX); w[i] = carry ? 0 : s; } return carry; } /* Increment u. The calling function has to handle a possible carry. */ mpd_uint_t _mpd_baseincr(mpd_uint_t *u, mpd_size_t n) { mpd_uint_t s; mpd_uint_t carry = 1; mpd_size_t i; assert(n > 0); /* if there is a carry, propagate it */ for (i = 0; carry && i < n; i++) { s = u[i] + carry; carry = (s == MPD_RADIX); u[i] = carry ? 0 : s; } return carry; } /* * Knuth, TAOCP, Volume 2, 4.3.1: * w := difference of u (len m) and v (len n). * number in u >= number in v; */ void _mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, mpd_size_t m, mpd_size_t n) { mpd_uint_t d; mpd_uint_t borrow = 0; mpd_size_t i; assert(m > 0 && n > 0); /* subtract n members of v from u */ for (i = 0; i < n; i++) { d = u[i] - (v[i] + borrow); borrow = (u[i] < d); w[i] = borrow ? d + MPD_RADIX : d; } /* if there is a borrow, propagate it */ for (; borrow && i < m; i++) { d = u[i] - borrow; borrow = (u[i] == 0); w[i] = borrow ? MPD_RADIX-1 : d; } /* copy the rest of u */ for (; i < m; i++) { w[i] = u[i]; } } /* * Subtract the contents of u from w. w is larger than u. Borrows are * propagated further, but eventually w can absorb the final borrow. */ void _mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n) { mpd_uint_t d; mpd_uint_t borrow = 0; mpd_size_t i; if (n == 0) return; /* subtract n members of u from w */ for (i = 0; i < n; i++) { d = w[i] - (u[i] + borrow); borrow = (w[i] < d); w[i] = borrow ? d + MPD_RADIX : d; } /* if there is a borrow, propagate it */ for (; borrow; i++) { d = w[i] - borrow; borrow = (w[i] == 0); w[i] = borrow ? MPD_RADIX-1 : d; } } /* w := product of u (len n) and v (single word) */ void _mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v) { mpd_uint_t hi, lo; mpd_uint_t carry = 0; mpd_size_t i; assert(n > 0); for (i=0; i < n; i++) { _mpd_mul_words(&hi, &lo, u[i], v); lo = carry + lo; if (lo < carry) hi++; _mpd_div_words_r(&carry, &w[i], hi, lo); } w[i] = carry; } /* * Knuth, TAOCP, Volume 2, 4.3.1: * w := product of u (len m) and v (len n) * w must be initialized to zero */ void _mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, mpd_size_t m, mpd_size_t n) { mpd_uint_t hi, lo; mpd_uint_t carry; mpd_size_t i, j; assert(m > 0 && n > 0); for (j=0; j < n; j++) { carry = 0; for (i=0; i < m; i++) { _mpd_mul_words(&hi, &lo, u[i], v[j]); lo = w[i+j] + lo; if (lo < w[i+j]) hi++; lo = carry + lo; if (lo < carry) hi++; _mpd_div_words_r(&carry, &w[i+j], hi, lo); } w[j+m] = carry; } } /* * Knuth, TAOCP Volume 2, 4.3.1, exercise 16: * w := quotient of u (len n) divided by a single word v */ mpd_uint_t _mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v) { mpd_uint_t hi, lo; mpd_uint_t rem = 0; mpd_size_t i; assert(n > 0); for (i=n-1; i != MPD_SIZE_MAX; i--) { _mpd_mul_words(&hi, &lo, rem, MPD_RADIX); lo = u[i] + lo; if (lo < u[i]) hi++; _mpd_div_words(&w[i], &rem, hi, lo, v); } return rem; } /* * Knuth, TAOCP Volume 2, 4.3.1: * q, r := quotient and remainder of uconst (len nplusm) * divided by vconst (len n) * nplusm >= n * * If r is not NULL, r will contain the remainder. If r is NULL, the * return value indicates if there is a remainder: 1 for true, 0 for * false. A return value of -1 indicates an error. */ int _mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r, const mpd_uint_t *uconst, const mpd_uint_t *vconst, mpd_size_t nplusm, mpd_size_t n) { mpd_uint_t ustatic[MPD_MINALLOC_MAX]; mpd_uint_t vstatic[MPD_MINALLOC_MAX]; mpd_uint_t *u = ustatic; mpd_uint_t *v = vstatic; mpd_uint_t d, qhat, rhat, w2[2]; mpd_uint_t hi, lo, x; mpd_uint_t carry; mpd_size_t i, j, m; int retval = 0; assert(n > 1 && nplusm >= n); m = sub_size_t(nplusm, n); /* D1: normalize */ d = MPD_RADIX / (vconst[n-1] + 1); if (nplusm >= MPD_MINALLOC_MAX) { if ((u = mpd_alloc(nplusm+1, sizeof *u)) == NULL) { return -1; } } if (n >= MPD_MINALLOC_MAX) { if ((v = mpd_alloc(n+1, sizeof *v)) == NULL) { mpd_free(u); return -1; } } _mpd_shortmul(u, uconst, nplusm, d); _mpd_shortmul(v, vconst, n, d); /* D2: loop */ for (j=m; j != MPD_SIZE_MAX; j--) { /* D3: calculate qhat and rhat */ rhat = _mpd_shortdiv(w2, u+j+n-1, 2, v[n-1]); qhat = w2[1] * MPD_RADIX + w2[0]; while (1) { if (qhat < MPD_RADIX) { _mpd_singlemul(w2, qhat, v[n-2]); if (w2[1] <= rhat) { if (w2[1] != rhat || w2[0] <= u[j+n-2]) { break; } } } qhat -= 1; rhat += v[n-1]; if (rhat < v[n-1] || rhat >= MPD_RADIX) { break; } } /* D4: multiply and subtract */ carry = 0; for (i=0; i <= n; i++) { _mpd_mul_words(&hi, &lo, qhat, v[i]); lo = carry + lo; if (lo < carry) hi++; _mpd_div_words_r(&hi, &lo, hi, lo); x = u[i+j] - lo; carry = (u[i+j] < x); u[i+j] = carry ? x+MPD_RADIX : x; carry += hi; } q[j] = qhat; /* D5: test remainder */ if (carry) { q[j] -= 1; /* D6: add back */ (void)_mpd_baseadd(u+j, u+j, v, n+1, n); } } /* D8: unnormalize */ if (r != NULL) { _mpd_shortdiv(r, u, n, d); /* we are not interested in the return value here */ retval = 0; } else { retval = !_mpd_isallzero(u, n); } if (u != ustatic) mpd_free(u); if (v != vstatic) mpd_free(v); return retval; } /* * Left shift of src by 'shift' digits; src may equal dest. * * dest := area of n mpd_uint_t with space for srcdigits+shift digits. * src := coefficient with length m. * * The case splits in the function are non-obvious. The following * equations might help: * * Let msdigits denote the number of digits in the most significant * word of src. Then 1 <= msdigits <= rdigits. * * 1) shift = q * rdigits + r * 2) srcdigits = qsrc * rdigits + msdigits * 3) destdigits = shift + srcdigits * = q * rdigits + r + qsrc * rdigits + msdigits * = q * rdigits + (qsrc * rdigits + (r + msdigits)) * * The result has q zero words, followed by the coefficient that is left- * shifted by r. The case r == 0 is trivial. For r > 0, it is important * to keep in mind that we always read m source words, but write m+1 * destination words if r + msdigits > rdigits, m words otherwise. */ void _mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n, mpd_size_t m, mpd_size_t shift) { #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) /* spurious uninitialized warnings */ mpd_uint_t l=l, lprev=lprev, h=h; #else mpd_uint_t l, lprev, h; #endif mpd_uint_t q, r; mpd_uint_t ph; assert(m > 0 && n >= m); _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, src[m--], MPD_RDIGITS-r); if (h != 0) { /* r + msdigits > rdigits <==> h != 0 */ dest[n--] = h; } /* write m-1 shifted words */ for (; m != MPD_SIZE_MAX; m--,n--) { _mpd_divmod_pow10(&h, &l, src[m], MPD_RDIGITS-r); dest[n] = ph * lprev + h; lprev = l; } /* write least significant word */ dest[q] = ph * lprev; } else { while (--m != MPD_SIZE_MAX) { dest[m+q] = src[m]; } } mpd_uint_zero(dest, q); } /* * Right shift of src by 'shift' digits; src may equal dest. * Assumption: srcdigits-shift > 0. * * dest := area with space for srcdigits-shift digits. * src := coefficient with length 'slen'. * * The case splits in the function rely on the following equations: * * Let msdigits denote the number of digits in the most significant * word of src. Then 1 <= msdigits <= rdigits. * * 1) shift = q * rdigits + r * 2) srcdigits = qsrc * rdigits + msdigits * 3) destdigits = srcdigits - shift * = qsrc * rdigits + msdigits - (q * rdigits + r) * = (qsrc - q) * rdigits + msdigits - r * * Since destdigits > 0 and 1 <= msdigits <= rdigits: * * 4) qsrc >= q * 5) qsrc == q ==> msdigits > r * * The result has slen-q words if msdigits > r, slen-q-1 words otherwise. */ mpd_uint_t _mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen, mpd_size_t shift) { #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) /* spurious uninitialized warnings */ mpd_uint_t l=l, h=h, hprev=hprev; /* low, high, previous high */ #else mpd_uint_t l, h, hprev; /* low, high, previous high */ #endif mpd_uint_t rnd, rest; /* rounding digit, rest */ mpd_uint_t q, r; mpd_size_t i, j; mpd_uint_t ph; assert(slen > 0); _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS); rnd = rest = 0; if (r != 0) { ph = mpd_pow10[MPD_RDIGITS-r]; _mpd_divmod_pow10(&hprev, &rest, src[q], r); _mpd_divmod_pow10(&rnd, &rest, rest, r-1); if (rest == 0 && q > 0) { rest = !_mpd_isallzero(src, q); } /* write slen-q-1 words */ for (j=0,i=q+1; i 0) { _mpd_divmod_pow10(&rnd, &rest, src[q-1], MPD_RDIGITS-1); /* is there any non-zero digit below rnd? */ if (rest == 0) rest = !_mpd_isallzero(src, q-1); } for (j = 0; j < slen-q; j++) { dest[j] = src[q+j]; } } /* 0-4 ==> rnd+rest < 0.5 */ /* 5 ==> rnd+rest == 0.5 */ /* 6-9 ==> rnd+rest > 0.5 */ return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd; } /*********************************************************************/ /* Calculations in base b */ /*********************************************************************/ /* * Add v to w (len m). The calling function has to handle a possible * final carry. Assumption: m > 0. */ mpd_uint_t _mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v, mpd_uint_t b) { mpd_uint_t s; mpd_uint_t carry; mpd_size_t i; assert(m > 0); /* add v to w */ s = w[0] + v; carry = (s < v) | (s >= b); w[0] = carry ? s-b : s; /* if there is a carry, propagate it */ for (i = 1; carry && i < m; i++) { s = w[i] + carry; carry = (s == b); w[i] = carry ? 0 : s; } return carry; } /* w := product of u (len n) and v (single word). Return carry. */ mpd_uint_t _mpd_shortmul_c(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v) { mpd_uint_t hi, lo; mpd_uint_t carry = 0; mpd_size_t i; assert(n > 0); for (i=0; i < n; i++) { _mpd_mul_words(&hi, &lo, u[i], v); lo = carry + lo; if (lo < carry) hi++; _mpd_div_words_r(&carry, &w[i], hi, lo); } return carry; } /* w := product of u (len n) and v (single word) */ mpd_uint_t _mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v, mpd_uint_t b) { mpd_uint_t hi, lo; mpd_uint_t carry = 0; mpd_size_t i; assert(n > 0); for (i=0; i < n; i++) { _mpd_mul_words(&hi, &lo, u[i], v); lo = carry + lo; if (lo < carry) hi++; _mpd_div_words(&carry, &w[i], hi, lo, b); } return carry; } /* * Knuth, TAOCP Volume 2, 4.3.1, exercise 16: * w := quotient of u (len n) divided by a single word v */ mpd_uint_t _mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v, mpd_uint_t b) { mpd_uint_t hi, lo; mpd_uint_t rem = 0; mpd_size_t i; assert(n > 0); for (i=n-1; i != MPD_SIZE_MAX; i--) { _mpd_mul_words(&hi, &lo, rem, b); lo = u[i] + lo; if (lo < u[i]) hi++; _mpd_div_words(&w[i], &rem, hi, lo, v); } return rem; } mpdecimal-4.0.1/libmpdec/basearith.h0000644000000000000000000001566515005764474014320 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_BASEARITH_H_ #define LIBMPDEC_BASEARITH_H_ #include "mpdecimal.h" #include "typearith.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) mpd_uint_t _mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, mpd_size_t m, mpd_size_t n); void _mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n); mpd_uint_t _mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v); mpd_uint_t _mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v, mpd_uint_t b); mpd_uint_t _mpd_baseincr(mpd_uint_t *u, mpd_size_t n); void _mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, mpd_size_t m, mpd_size_t n); void _mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n); void _mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, mpd_size_t m, mpd_size_t n); void _mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v); mpd_uint_t _mpd_shortmul_c(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v); mpd_uint_t _mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v, mpd_uint_t b); mpd_uint_t _mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v); mpd_uint_t _mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v, mpd_uint_t b); int _mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r, const mpd_uint_t *uconst, const mpd_uint_t *vconst, mpd_size_t nplusm, mpd_size_t n); void _mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n, mpd_size_t m, mpd_size_t shift); mpd_uint_t _mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen, mpd_size_t shift); #ifdef CONFIG_64 extern const mpd_uint_t mprime_rdx; /* * Algorithm from: Division by Invariant Integers using Multiplication, * T. Granlund and P. L. Montgomery, Proceedings of the SIGPLAN '94 * Conference on Programming Language Design and Implementation. * * http://gmplib.org/~tege/divcnst-pldi94.pdf * * Variables from the paper and their translations (See section 8): * * N := 64 * d := MPD_RADIX * l := 64 * m' := floor((2**(64+64) - 1)/MPD_RADIX) - 2**64 * * Since N-l == 0: * * dnorm := d * n2 := hi * n10 := lo * * ACL2 proof: mpd-div-words-r-correct */ static inline void _mpd_div_words_r(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo) { mpd_uint_t n_adj, h, l, t; mpd_uint_t n1_neg; /* n1_neg = if lo >= 2**63 then MPD_UINT_MAX else 0 */ n1_neg = (lo & (1ULL<<63)) ? MPD_UINT_MAX : 0; /* n_adj = if lo >= 2**63 then lo+MPD_RADIX else lo */ n_adj = lo + (n1_neg & MPD_RADIX); /* (h, l) = if lo >= 2**63 then m'*(hi+1) else m'*hi */ _mpd_mul_words(&h, &l, mprime_rdx, hi-n1_neg); l = l + n_adj; if (l < n_adj) h++; t = h + hi; /* At this point t == qest, with q == qest or q == qest+1: * 1) 0 <= 2**64*hi + lo - qest*MPD_RADIX < 2*MPD_RADIX */ /* t = 2**64-1 - qest = 2**64 - (qest+1) */ t = MPD_UINT_MAX - t; /* (h, l) = 2**64*MPD_RADIX - (qest+1)*MPD_RADIX */ _mpd_mul_words(&h, &l, t, MPD_RADIX); l = l + lo; if (l < lo) h++; h += hi; h -= MPD_RADIX; /* (h, l) = 2**64*hi + lo - (qest+1)*MPD_RADIX (mod 2**128) * Case q == qest+1: * a) h == 0, l == r * b) q := h - t == qest+1 * c) r := l * Case q == qest: * a) h == MPD_UINT_MAX, l == 2**64-(MPD_RADIX-r) * b) q := h - t == qest * c) r := l + MPD_RADIX = r */ *q = (h - t); *r = l + (MPD_RADIX & h); } #else static inline void _mpd_div_words_r(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo) { _mpd_div_words(q, r, hi, lo, MPD_RADIX); } #endif /* Multiply two single base MPD_RADIX words, store result in array w[2]. */ static inline void _mpd_singlemul(mpd_uint_t w[2], mpd_uint_t u, mpd_uint_t v) { mpd_uint_t hi, lo; _mpd_mul_words(&hi, &lo, u, v); _mpd_div_words_r(&w[1], &w[0], hi, lo); } /* Multiply u (len 2) and v (len m, 1 <= m <= 2). */ static inline void _mpd_mul_2_le2(mpd_uint_t w[4], mpd_uint_t u[2], mpd_uint_t v[2], mpd_ssize_t m) { mpd_uint_t hi, lo; _mpd_mul_words(&hi, &lo, u[0], v[0]); _mpd_div_words_r(&w[1], &w[0], hi, lo); _mpd_mul_words(&hi, &lo, u[1], v[0]); lo = w[1] + lo; if (lo < w[1]) hi++; _mpd_div_words_r(&w[2], &w[1], hi, lo); if (m == 1) return; _mpd_mul_words(&hi, &lo, u[0], v[1]); lo = w[1] + lo; if (lo < w[1]) hi++; _mpd_div_words_r(&w[3], &w[1], hi, lo); _mpd_mul_words(&hi, &lo, u[1], v[1]); lo = w[2] + lo; if (lo < w[2]) hi++; lo = w[3] + lo; if (lo < w[3]) hi++; _mpd_div_words_r(&w[3], &w[2], hi, lo); } /* * Test if all words from data[len-1] to data[0] are zero. If len is 0, nothing * is tested and the coefficient is regarded as "all zero". */ static inline int _mpd_isallzero(const mpd_uint_t *data, mpd_ssize_t len) { while (--len >= 0) { if (data[len] != 0) return 0; } return 1; } /* * Test if all full words from data[len-1] to data[0] are MPD_RADIX-1 * (all nines). Return true if len == 0. */ static inline int _mpd_isallnine(const mpd_uint_t *data, mpd_ssize_t len) { while (--len >= 0) { if (data[len] != MPD_RADIX-1) return 0; } return 1; } MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_BASEARITH_H_ */ mpdecimal-4.0.1/libmpdec/bench.c0000644000000000000000000000664115005764474013422 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include #include "mpdecimal.h" static void err_exit(const char *msg) { fprintf(stderr, "%s\n", msg); exit(1); } static mpd_t * new_mpd(void) { mpd_t *x = mpd_qnew(); if (x == NULL) { err_exit("out of memory"); } return x; } /* Nonsense version of escape-time algorithm for calculating a Mandelbrot * set. Just for benchmarking. */ static void color_point(mpd_t *x0, mpd_t *y0, long maxiter, mpd_context_t *ctx) { mpd_t *x, *y, *sq_x, *sq_y; mpd_t *two; x = new_mpd(); y = new_mpd(); mpd_set_u32(x, 0, ctx); mpd_set_u32(y, 0, ctx); sq_x = new_mpd(); sq_y = new_mpd(); mpd_set_u32(sq_x, 0, ctx); mpd_set_u32(sq_y, 0, ctx); two = new_mpd(); mpd_set_u32(two, 2, ctx); for (long i = 0; i < maxiter; i++) { mpd_mul(y, x, y, ctx); mpd_mul(y, y, two, ctx); mpd_add(y, y, y0, ctx); mpd_sub(x, sq_x, sq_y, ctx); mpd_add(x, x, x0, ctx); mpd_mul(sq_x, x, x, ctx); mpd_mul(sq_y, y, y, ctx); } mpd_copy(x0, x, ctx); mpd_del(two); mpd_del(sq_y); mpd_del(sq_x); mpd_del(y); mpd_del(x); } int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *x0, *y0; uint32_t prec = 19; long iter = 10000000; clock_t start_clock, end_clock; if (argc != 3) { err_exit("usage: bench prec iter\n"); } prec = strtoul(argv[1], NULL, 10); iter = strtol(argv[2], NULL, 10); mpd_init(&ctx, prec); /* no more MPD_MINALLOC changes after here */ x0 = new_mpd(); y0 = new_mpd(); mpd_set_string(x0, "0.222", &ctx); mpd_set_string(y0, "0.333", &ctx); if (ctx.status & MPD_Errors) { mpd_del(y0); mpd_del(x0); err_exit("unexpected error during conversion"); } start_clock = clock(); color_point(x0, y0, iter, &ctx); end_clock = clock(); mpd_print(x0); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); mpd_del(y0); mpd_del(x0); return 0; } mpdecimal-4.0.1/libmpdec/bench_full.c0000644000000000000000000001136515005764474014443 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include #include "mpdecimal.h" static void err_exit(const char *msg) { fprintf(stderr, "%s\n", msg); exit(1); } static mpd_t * new_mpd(void) { mpd_t *x = mpd_qnew(); if (x == NULL) { err_exit("out of memory"); } return x; } /* * Example from: http://en.wikipedia.org/wiki/Mandelbrot_set * * Escape time algorithm for drawing the set: * * Point x0, y0 is deemed to be in the Mandelbrot set if the return * value is maxiter. Lower return values indicate how quickly points * escaped and can be used for coloring. */ static int color_point(const mpd_t *x0, const mpd_t *y0, const long maxiter, mpd_context_t *ctx) { mpd_t *x, *y, *sq_x, *sq_y; mpd_t *two, *four, *c; long i; x = new_mpd(); y = new_mpd(); mpd_set_u32(x, 0, ctx); mpd_set_u32(y, 0, ctx); sq_x = new_mpd(); sq_y = new_mpd(); mpd_set_u32(sq_x, 0, ctx); mpd_set_u32(sq_y, 0, ctx); two = new_mpd(); four = new_mpd(); mpd_set_u32(two, 2, ctx); mpd_set_u32(four, 4, ctx); c = new_mpd(); mpd_set_u32(c, 0, ctx); for (i = 0; i < maxiter && mpd_cmp(c, four, ctx) <= 0; i++) { mpd_mul(y, x, y, ctx); mpd_mul(y, y, two, ctx); mpd_add(y, y, y0, ctx); mpd_sub(x, sq_x, sq_y, ctx); mpd_add(x, x, x0, ctx); mpd_mul(sq_x, x, x, ctx); mpd_mul(sq_y, y, y, ctx); mpd_add(c, sq_x, sq_y, ctx); } mpd_del(c); mpd_del(four); mpd_del(two); mpd_del(sq_y); mpd_del(sq_x); mpd_del(y); mpd_del(x); return i; } int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *x0, *y0; mpd_t *sqrt_2, *xstep, *ystep; mpd_ssize_t prec = 19; long iter = 1000; int points[40][80]; int i, j; clock_t start_clock, end_clock; if (argc != 3) { fprintf(stderr, "usage: ./bench prec iter\n"); exit(1); } prec = strtoll(argv[1], NULL, 10); iter = strtol(argv[2], NULL, 10); mpd_init(&ctx, prec); /* no more MPD_MINALLOC changes after here */ sqrt_2 = new_mpd(); xstep = new_mpd(); ystep = new_mpd(); x0 = new_mpd(); y0 = new_mpd(); mpd_set_u32(sqrt_2, 2, &ctx); mpd_sqrt(sqrt_2, sqrt_2, &ctx); mpd_div_u32(xstep, sqrt_2, 40, &ctx); mpd_div_u32(ystep, sqrt_2, 20, &ctx); start_clock = clock(); mpd_copy(y0, sqrt_2, &ctx); for (i = 0; i < 40; i++) { mpd_copy(x0, sqrt_2, &ctx); mpd_set_negative(x0); for (j = 0; j < 80; j++) { points[i][j] = color_point(x0, y0, iter, &ctx); mpd_add(x0, x0, xstep, &ctx); } mpd_sub(y0, y0, ystep, &ctx); } end_clock = clock(); #ifdef BENCH_VERBOSE for (i = 0; i < 40; i++) { for (j = 0; j < 80; j++) { if (points[i][j] == iter) { putchar('*'); } else if (points[i][j] >= 10) { putchar('+'); } else if (points[i][j] >= 5) { putchar('.'); } else { putchar(' '); } } putchar('\n'); } putchar('\n'); #else (void)points; /* suppress gcc warning */ #endif printf("time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); mpd_del(y0); mpd_del(x0); mpd_del(ystep); mpd_del(xstep); mpd_del(sqrt_2); return 0; } mpdecimal-4.0.1/libmpdec/bits.h0000644000000000000000000001052415005764474013304 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_BITS_H_ #define LIBMPDEC_BITS_H_ #include "mpdecimal.h" /* Check if n is a power of 2. */ static inline int ispower2(mpd_size_t n) { return n != 0 && (n & (n-1)) == 0; } #if defined(ANSI) /* * Return the most significant bit position of n from 0 to 31 (63). * Assumptions: n != 0. */ static inline int mpd_bsr(mpd_size_t n) { int pos = 0; mpd_size_t tmp; #ifdef CONFIG_64 tmp = n >> 32; if (tmp != 0) { n = tmp; pos += 32; } #endif tmp = n >> 16; if (tmp != 0) { n = tmp; pos += 16; } tmp = n >> 8; if (tmp != 0) { n = tmp; pos += 8; } tmp = n >> 4; if (tmp != 0) { n = tmp; pos += 4; } tmp = n >> 2; if (tmp != 0) { n = tmp; pos += 2; } tmp = n >> 1; if (tmp != 0) { n = tmp; pos += 1; } return pos + (int)n - 1; } /* * Return the least significant bit position of n from 0 to 31 (63). * Assumptions: n != 0. */ static inline int mpd_bsf(mpd_size_t n) { int pos; #ifdef CONFIG_64 pos = 63; if (n & 0x00000000FFFFFFFFULL) { pos -= 32; } else { n >>= 32; } if (n & 0x000000000000FFFFULL) { pos -= 16; } else { n >>= 16; } if (n & 0x00000000000000FFULL) { pos -= 8; } else { n >>= 8; } if (n & 0x000000000000000FULL) { pos -= 4; } else { n >>= 4; } if (n & 0x0000000000000003ULL) { pos -= 2; } else { n >>= 2; } if (n & 0x0000000000000001ULL) { pos -= 1; } #else pos = 31; if (n & 0x000000000000FFFFUL) { pos -= 16; } else { n >>= 16; } if (n & 0x00000000000000FFUL) { pos -= 8; } else { n >>= 8; } if (n & 0x000000000000000FUL) { pos -= 4; } else { n >>= 4; } if (n & 0x0000000000000003UL) { pos -= 2; } else { n >>= 2; } if (n & 0x0000000000000001UL) { pos -= 1; } #endif return pos; } /* END ANSI */ #elif defined(ASM) /* * Bit scan reverse. Assumptions: a != 0. */ static inline int mpd_bsr(mpd_size_t a) { mpd_size_t retval; __asm__ ( #ifdef CONFIG_64 "bsrq %1, %0\n\t" #else "bsr %1, %0\n\t" #endif :"=r" (retval) :"r" (a) :"cc" ); return (int)retval; } /* * Bit scan forward. Assumptions: a != 0. */ static inline int mpd_bsf(mpd_size_t a) { mpd_size_t retval; __asm__ ( #ifdef CONFIG_64 "bsfq %1, %0\n\t" #else "bsf %1, %0\n\t" #endif :"=r" (retval) :"r" (a) :"cc" ); return (int)retval; } /* END ASM */ #elif defined(MASM) #include /* * Bit scan reverse. Assumptions: a != 0. */ static inline int __cdecl mpd_bsr(mpd_size_t a) { unsigned long retval; #ifdef CONFIG_64 _BitScanReverse64(&retval, a); #else _BitScanReverse(&retval, a); #endif return (int)retval; } /* * Bit scan forward. Assumptions: a != 0. */ static inline int __cdecl mpd_bsf(mpd_size_t a) { unsigned long retval; #ifdef CONFIG_64 _BitScanForward64(&retval, a); #else _BitScanForward(&retval, a); #endif return (int)retval; } /* END MASM (_MSC_VER) */ #else #error "missing preprocessor definitions" #endif /* BSR/BSF */ #endif /* LIBMPDEC_BITS_H_ */ mpdecimal-4.0.1/libmpdec/constants.c0000644000000000000000000001270115005764474014351 0ustar00/* * Copyright (c) 2008-2025 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 "basearith.h" #include "constants.h" #include "mpdecimal.h" #if defined(CONFIG_64) /* number-theory.c */ const mpd_uint_t mpd_moduli[3] = { 18446744069414584321ULL, 18446744056529682433ULL, 18446742974197923841ULL }; const mpd_uint_t mpd_roots[3] = {7ULL, 10ULL, 19ULL}; /* crt.c */ const mpd_uint_t INV_P1_MOD_P2 = 18446744055098026669ULL; const mpd_uint_t INV_P1P2_MOD_P3 = 287064143708160ULL; const mpd_uint_t LH_P1P2 = 18446744052234715137ULL; /* (P1*P2) % 2^64 */ const mpd_uint_t UH_P1P2 = 18446744052234715141ULL; /* (P1*P2) / 2^64 */ /* transpose.c */ const mpd_size_t mpd_bits[64] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648ULL, 4294967296ULL, 8589934592ULL, 17179869184ULL, 34359738368ULL, 68719476736ULL, 137438953472ULL, 274877906944ULL, 549755813888ULL, 1099511627776ULL, 2199023255552ULL, 4398046511104, 8796093022208ULL, 17592186044416ULL, 35184372088832ULL, 70368744177664ULL, 140737488355328ULL, 281474976710656ULL, 562949953421312ULL, 1125899906842624ULL, 2251799813685248ULL, 4503599627370496ULL, 9007199254740992ULL, 18014398509481984ULL, 36028797018963968ULL, 72057594037927936ULL, 144115188075855872ULL, 288230376151711744ULL, 576460752303423488ULL, 1152921504606846976ULL, 2305843009213693952ULL, 4611686018427387904ULL, 9223372036854775808ULL }; /* mpdecimal.c */ const mpd_uint_t mpd_pow10[MPD_RDIGITS+1] = { 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000, 10000000000ULL,100000000000ULL,1000000000000ULL,10000000000000ULL, 100000000000000ULL,1000000000000000ULL,10000000000000000ULL, 100000000000000000ULL,1000000000000000000ULL,10000000000000000000ULL }; /* magic number for constant division by MPD_RADIX */ const mpd_uint_t mprime_rdx = 15581492618384294730ULL; #elif defined(CONFIG_32) /* number-theory.c */ const mpd_uint_t mpd_moduli[3] = {2113929217UL, 2013265921UL, 1811939329UL}; const mpd_uint_t mpd_roots[3] = {5UL, 31UL, 13UL}; /* PentiumPro modular multiplication: These constants have to be loaded as * 80 bit long doubles, which are not supported by certain compilers. */ const uint32_t mpd_invmoduli[3][3] = { {4293885170U, 2181570688U, 16352U}, /* ((long double) 1 / 2113929217UL) */ {1698898177U, 2290649223U, 16352U}, /* ((long double) 1 / 2013265921UL) */ {2716021846U, 2545165803U, 16352U} /* ((long double) 1 / 1811939329UL) */ }; const float MPD_TWO63 = 9223372036854775808.0; /* 2^63 */ /* crt.c */ const mpd_uint_t INV_P1_MOD_P2 = 2013265901UL; const mpd_uint_t INV_P1P2_MOD_P3 = 54UL; const mpd_uint_t LH_P1P2 = 4127195137UL; /* (P1*P2) % 2^32 */ const mpd_uint_t UH_P1P2 = 990904320UL; /* (P1*P2) / 2^32 */ /* transpose.c */ const mpd_size_t mpd_bits[32] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648UL }; /* mpdecimal.c */ const mpd_uint_t mpd_pow10[MPD_RDIGITS+1] = { 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000 }; #else #error "CONFIG_64 or CONFIG_32 must be defined." #endif const char * const mpd_round_string[MPD_ROUND_GUARD] = { "ROUND_UP", /* round away from 0 */ "ROUND_DOWN", /* round toward 0 (truncate) */ "ROUND_CEILING", /* round toward +infinity */ "ROUND_FLOOR", /* round toward -infinity */ "ROUND_HALF_UP", /* 0.5 is rounded up */ "ROUND_HALF_DOWN", /* 0.5 is rounded down */ "ROUND_HALF_EVEN", /* 0.5 is rounded to even */ "ROUND_05UP", /* round zero or five away from 0 */ "ROUND_TRUNC", /* truncate, but set infinity */ }; const char * const mpd_clamp_string[MPD_CLAMP_GUARD] = { "CLAMP_DEFAULT", "CLAMP_IEEE_754" }; mpdecimal-4.0.1/libmpdec/constants.h0000644000000000000000000000661215005764474014362 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_CONSTANTS_H_ #define LIBMPDEC_CONSTANTS_H_ #include #include "mpdecimal.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) /* choice of optimized functions */ #if defined(CONFIG_64) /* x64 */ #define MULMOD(a, b) x64_mulmod(a, b, umod) #define MULMOD2C(a0, a1, w) x64_mulmod2c(a0, a1, w, umod) #define MULMOD2(a0, b0, a1, b1) x64_mulmod2(a0, b0, a1, b1, umod) #define POWMOD(base, exp) x64_powmod(base, exp, umod) #define SETMODULUS(modnum) std_setmodulus(modnum, &umod) #define SIZE3_NTT(x0, x1, x2, w3table) std_size3_ntt(x0, x1, x2, w3table, umod) #elif defined(PPRO) /* PentiumPro (or later) gcc inline asm */ #define MULMOD(a, b) ppro_mulmod(a, b, &dmod, dinvmod) #define MULMOD2C(a0, a1, w) ppro_mulmod2c(a0, a1, w, &dmod, dinvmod) #define MULMOD2(a0, b0, a1, b1) ppro_mulmod2(a0, b0, a1, b1, &dmod, dinvmod) #define POWMOD(base, exp) ppro_powmod(base, exp, &dmod, dinvmod) #define SETMODULUS(modnum) ppro_setmodulus(modnum, &umod, &dmod, dinvmod) #define SIZE3_NTT(x0, x1, x2, w3table) ppro_size3_ntt(x0, x1, x2, w3table, umod, &dmod, dinvmod) #else /* ANSI C99 */ #define MULMOD(a, b) std_mulmod(a, b, umod) #define MULMOD2C(a0, a1, w) std_mulmod2c(a0, a1, w, umod) #define MULMOD2(a0, b0, a1, b1) std_mulmod2(a0, b0, a1, b1, umod) #define POWMOD(base, exp) std_powmod(base, exp, umod) #define SETMODULUS(modnum) std_setmodulus(modnum, &umod) #define SIZE3_NTT(x0, x1, x2, w3table) std_size3_ntt(x0, x1, x2, w3table, umod) #endif /* PentiumPro (or later) gcc inline asm */ extern const float MPD_TWO63; extern const uint32_t mpd_invmoduli[3][3]; enum {P1, P2, P3}; extern const mpd_uint_t mpd_moduli[]; extern const mpd_uint_t mpd_roots[]; extern const mpd_size_t mpd_bits[]; extern const mpd_uint_t mpd_pow10[]; extern const mpd_uint_t INV_P1_MOD_P2; extern const mpd_uint_t INV_P1P2_MOD_P3; extern const mpd_uint_t LH_P1P2; extern const mpd_uint_t UH_P1P2; MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_CONSTANTS_H_ */ mpdecimal-4.0.1/libmpdec/context.c0000644000000000000000000001364215005764474014026 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include "mpdecimal.h" void mpd_dflt_traphandler(mpd_context_t *ctx) { (void)ctx; raise(SIGFPE); } void (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler; /* Set guaranteed minimum number of coefficient words. The function may be used once at program start. Setting MPD_MINALLOC to out-of-bounds values is a catastrophic error, so in that case the function exits rather than relying on the user to check a return value. */ void mpd_setminalloc(mpd_ssize_t n) { static int minalloc_is_set = 0; if (minalloc_is_set) { mpd_err_warn("mpd_setminalloc: ignoring request to set " "MPD_MINALLOC a second time\n"); return; } if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) { mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */ } MPD_MINALLOC = n; minalloc_is_set = 1; } void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec) { mpd_ssize_t ideal_minalloc; mpd_defaultcontext(ctx); if (!mpd_qsetprec(ctx, prec)) { mpd_addstatus_raise(ctx, MPD_Invalid_context); return; } ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS); if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN; if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX; mpd_setminalloc(ideal_minalloc); } void mpd_maxcontext(mpd_context_t *ctx) { ctx->prec=MPD_MAX_PREC; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; ctx->round=MPD_ROUND_HALF_EVEN; ctx->traps=MPD_Traps; ctx->status=0; ctx->newtrap=0; ctx->clamp=0; ctx->allcr=1; } void mpd_defaultcontext(mpd_context_t *ctx) { ctx->prec=2*MPD_RDIGITS; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; ctx->round=MPD_ROUND_HALF_UP; ctx->traps=MPD_Traps; ctx->status=0; ctx->newtrap=0; ctx->clamp=0; ctx->allcr=1; } void mpd_basiccontext(mpd_context_t *ctx) { ctx->prec=9; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; ctx->round=MPD_ROUND_HALF_UP; ctx->traps=MPD_Traps|MPD_Clamped; ctx->status=0; ctx->newtrap=0; ctx->clamp=0; ctx->allcr=1; } int mpd_ieee_context(mpd_context_t *ctx, int bits) { if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) { return -1; } ctx->prec = 9 * (bits/32) - 2; ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3)); ctx->emin = 1 - ctx->emax; ctx->round=MPD_ROUND_HALF_EVEN; ctx->traps=0; ctx->status=0; ctx->newtrap=0; ctx->clamp=1; ctx->allcr=1; return 0; } mpd_ssize_t mpd_getprec(const mpd_context_t *ctx) { return ctx->prec; } mpd_ssize_t mpd_getemax(const mpd_context_t *ctx) { return ctx->emax; } mpd_ssize_t mpd_getemin(const mpd_context_t *ctx) { return ctx->emin; } int mpd_getround(const mpd_context_t *ctx) { return ctx->round; } uint32_t mpd_gettraps(const mpd_context_t *ctx) { return ctx->traps; } uint32_t mpd_getstatus(const mpd_context_t *ctx) { return ctx->status; } int mpd_getclamp(const mpd_context_t *ctx) { return ctx->clamp; } int mpd_getcr(const mpd_context_t *ctx) { return ctx->allcr; } int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec) { if (prec <= 0 || prec > MPD_MAX_PREC) { return 0; } ctx->prec = prec; return 1; } int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax) { if (emax < 0 || emax > MPD_MAX_EMAX) { return 0; } ctx->emax = emax; return 1; } int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin) { if (emin > 0 || emin < MPD_MIN_EMIN) { return 0; } ctx->emin = emin; return 1; } int mpd_qsetround(mpd_context_t *ctx, int round) { if (!(0 <= round && round < MPD_ROUND_GUARD)) { return 0; } ctx->round = round; return 1; } int mpd_qsettraps(mpd_context_t *ctx, uint32_t flags) { if (flags > MPD_Max_status) { return 0; } ctx->traps = flags; return 1; } int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags) { if (flags > MPD_Max_status) { return 0; } ctx->status = flags; return 1; } int mpd_qsetclamp(mpd_context_t *ctx, int c) { if (c != 0 && c != 1) { return 0; } ctx->clamp = c; return 1; } int mpd_qsetcr(mpd_context_t *ctx, int c) { if (c != 0 && c != 1) { return 0; } ctx->allcr = c; return 1; } void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags) { ctx->status |= flags; if (flags&ctx->traps) { ctx->newtrap = (flags&ctx->traps); mpd_traphandler(ctx); } } mpdecimal-4.0.1/libmpdec/convolute.c0000644000000000000000000001065515005764474014361 0ustar00/* * Copyright (c) 2008-2025 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 "bits.h" #include "constants.h" #include "convolute.h" #include "fnt.h" #include "fourstep.h" #include "mpdecimal.h" #include "numbertheory.h" #include "sixstep.h" #include "umodarith.h" /* * Bignum: Fast convolution using the Number Theoretic Transform. Used for * the multiplication of very large coefficients. */ /* Convolute the data in c1 and c2. Result is in c1. */ int fnt_convolute(mpd_uint_t *c1, mpd_uint_t *c2, mpd_size_t n, int modnum) { int (*fnt)(mpd_uint_t *, mpd_size_t, int); int (*inv_fnt)(mpd_uint_t *, mpd_size_t, int); #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_uint_t n_inv, umod; mpd_size_t i; SETMODULUS(modnum); n_inv = POWMOD(n, (umod-2)); if (ispower2(n)) { if (n > SIX_STEP_THRESHOLD) { fnt = six_step_fnt; inv_fnt = inv_six_step_fnt; } else { fnt = std_fnt; inv_fnt = std_inv_fnt; } } else { fnt = four_step_fnt; inv_fnt = inv_four_step_fnt; } if (!fnt(c1, n, modnum)) { return 0; } if (!fnt(c2, n, modnum)) { return 0; } for (i = 0; i < n-1; i += 2) { mpd_uint_t x0 = c1[i]; mpd_uint_t y0 = c2[i]; mpd_uint_t x1 = c1[i+1]; mpd_uint_t y1 = c2[i+1]; MULMOD2(&x0, y0, &x1, y1); c1[i] = x0; c1[i+1] = x1; } if (!inv_fnt(c1, n, modnum)) { return 0; } for (i = 0; i < n-3; i += 4) { mpd_uint_t x0 = c1[i]; mpd_uint_t x1 = c1[i+1]; mpd_uint_t x2 = c1[i+2]; mpd_uint_t x3 = c1[i+3]; MULMOD2C(&x0, &x1, n_inv); MULMOD2C(&x2, &x3, n_inv); c1[i] = x0; c1[i+1] = x1; c1[i+2] = x2; c1[i+3] = x3; } return 1; } /* Autoconvolute the data in c1. Result is in c1. */ int fnt_autoconvolute(mpd_uint_t *c1, mpd_size_t n, int modnum) { int (*fnt)(mpd_uint_t *, mpd_size_t, int); int (*inv_fnt)(mpd_uint_t *, mpd_size_t, int); #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_uint_t n_inv, umod; mpd_size_t i; SETMODULUS(modnum); n_inv = POWMOD(n, (umod-2)); if (ispower2(n)) { if (n > SIX_STEP_THRESHOLD) { fnt = six_step_fnt; inv_fnt = inv_six_step_fnt; } else { fnt = std_fnt; inv_fnt = std_inv_fnt; } } else { fnt = four_step_fnt; inv_fnt = inv_four_step_fnt; } if (!fnt(c1, n, modnum)) { return 0; } for (i = 0; i < n-1; i += 2) { mpd_uint_t x0 = c1[i]; mpd_uint_t x1 = c1[i+1]; MULMOD2(&x0, x0, &x1, x1); c1[i] = x0; c1[i+1] = x1; } if (!inv_fnt(c1, n, modnum)) { return 0; } for (i = 0; i < n-3; i += 4) { mpd_uint_t x0 = c1[i]; mpd_uint_t x1 = c1[i+1]; mpd_uint_t x2 = c1[i+2]; mpd_uint_t x3 = c1[i+3]; MULMOD2C(&x0, &x1, n_inv); MULMOD2C(&x2, &x3, n_inv); c1[i] = x0; c1[i+1] = x1; c1[i+2] = x2; c1[i+3] = x3; } return 1; } mpdecimal-4.0.1/libmpdec/convolute.h0000644000000000000000000000345315005764474014364 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_CONVOLUTE_H_ #define LIBMPDEC_CONVOLUTE_H_ #include "mpdecimal.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) #define SIX_STEP_THRESHOLD 4096 int fnt_convolute(mpd_uint_t *c1, mpd_uint_t *c2, mpd_size_t n, int modnum); int fnt_autoconvolute(mpd_uint_t *c1, mpd_size_t n, int modnum); MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_CONVOLUTE_H_ */ mpdecimal-4.0.1/libmpdec/crt.c0000644000000000000000000001110115005764474013116 0ustar00/* * Copyright (c) 2008-2025 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 #include "constants.h" #include "crt.h" #include "numbertheory.h" #include "mpdecimal.h" #include "typearith.h" #include "umodarith.h" /* Bignum: Chinese Remainder Theorem, extends the maximum transform length. */ /* Multiply P1P2 by v, store result in w. */ static inline void _crt_mulP1P2_3(mpd_uint_t w[3], mpd_uint_t v) { mpd_uint_t hi1, hi2, lo; _mpd_mul_words(&hi1, &lo, LH_P1P2, v); w[0] = lo; _mpd_mul_words(&hi2, &lo, UH_P1P2, v); lo = hi1 + lo; if (lo < hi1) hi2++; w[1] = lo; w[2] = hi2; } /* Add 3 words from v to w. The result is known to fit in w. */ static inline void _crt_add3(mpd_uint_t w[3], mpd_uint_t v[3]) { mpd_uint_t carry; w[0] = w[0] + v[0]; carry = (w[0] < v[0]); w[1] = w[1] + v[1]; if (w[1] < v[1]) w[2]++; w[1] = w[1] + carry; if (w[1] < carry) w[2]++; w[2] += v[2]; } /* Divide 3 words in u by v, store result in w, return remainder. */ static inline mpd_uint_t _crt_div3(mpd_uint_t *w, const mpd_uint_t *u, mpd_uint_t v) { mpd_uint_t r1 = u[2]; mpd_uint_t r2; if (r1 < v) { w[2] = 0; } else { _mpd_div_word(&w[2], &r1, u[2], v); /* GCOV_NOT_REACHED */ } _mpd_div_words(&w[1], &r2, r1, u[1], v); _mpd_div_words(&w[0], &r1, r2, u[0], v); return r1; } /* * Chinese Remainder Theorem: * Algorithm from Joerg Arndt, "Matters Computational", * Chapter 37.4.1 [http://www.jjj.de/fxt/] * * See also Knuth, TAOCP, Volume 2, 4.3.2, exercise 7. */ /* * CRT with carry: x1, x2, x3 contain numbers modulo p1, p2, p3. For each * triple of members of the arrays, find the unique z modulo p1*p2*p3, with * zmax = p1*p2*p3 - 1. * * In each iteration of the loop, split z into result[i] = z % MPD_RADIX * and carry = z / MPD_RADIX. Let N be the size of carry[] and cmax the * maximum carry. * * Limits for the 32-bit build: * * N = 2**96 * cmax = 7711435591312380274 * * Limits for the 64 bit build: * * N = 2**192 * cmax = 627710135393475385904124401220046371710 * * The following statements hold for both versions: * * 1) cmax + zmax < N, so the addition does not overflow. * * 2) (cmax + zmax) / MPD_RADIX == cmax. * * 3) If c <= cmax, then c_next = (c + zmax) / MPD_RADIX <= cmax. */ void crt3(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_size_t rsize) { mpd_uint_t p1 = mpd_moduli[P1]; mpd_uint_t umod; #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_uint_t a1, a2, a3; mpd_uint_t s; mpd_uint_t z[3], t[3]; mpd_uint_t carry[3] = {0,0,0}; mpd_uint_t hi, lo; mpd_size_t i; for (i = 0; i < rsize; i++) { a1 = x1[i]; a2 = x2[i]; a3 = x3[i]; SETMODULUS(P2); s = ext_submod(a2, a1, umod); s = MULMOD(s, INV_P1_MOD_P2); _mpd_mul_words(&hi, &lo, s, p1); lo = lo + a1; if (lo < a1) hi++; SETMODULUS(P3); s = dw_submod(a3, hi, lo, umod); s = MULMOD(s, INV_P1P2_MOD_P3); z[0] = lo; z[1] = hi; z[2] = 0; _crt_mulP1P2_3(t, s); _crt_add3(z, t); _crt_add3(carry, z); x1[i] = _crt_div3(carry, carry, MPD_RADIX); } assert(carry[0] == 0 && carry[1] == 0 && carry[2] == 0); } mpdecimal-4.0.1/libmpdec/crt.h0000644000000000000000000000326615005764474013140 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_CRT_H_ #define LIBMPDEC_CRT_H_ #include "mpdecimal.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) void crt3(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_size_t rsize); MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_CRT_H_ */ mpdecimal-4.0.1/libmpdec/difradix2.c0000644000000000000000000001055115005764474014212 0ustar00/* * Copyright (c) 2008-2025 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 #include "bits.h" #include "constants.h" #include "difradix2.h" #include "mpdecimal.h" #include "numbertheory.h" #include "umodarith.h" /* Bignum: The actual transform routine (decimation in frequency). */ /* * Generate index pairs (x, bitreverse(x)) and carry out the permutation. * n must be a power of two. * Algorithm due to Brent/Lehmann, see Joerg Arndt, "Matters Computational", * Chapter 1.14.4. [http://www.jjj.de/fxt/] */ static inline void bitreverse_permute(mpd_uint_t a[], mpd_size_t n) { mpd_size_t x = 0; mpd_size_t r = 0; mpd_uint_t t; do { /* Invariant: r = bitreverse(x) */ if (r > x) { t = a[x]; a[x] = a[r]; a[r] = t; } /* Flip trailing consecutive 1 bits and the first zero bit * that absorbs a possible carry. */ x += 1; /* Mirror the operation on r: Flip n_trailing_zeros(x)+1 high bits of r. */ r ^= (n - (n >> (mpd_bsf(x)+1))); /* The loop invariant is preserved. */ } while (x < n); } /* Fast Number Theoretic Transform, decimation in frequency. */ void fnt_dif2(mpd_uint_t a[], mpd_size_t n, struct fnt_params *tparams) { mpd_uint_t *wtable = tparams->wtable; mpd_uint_t umod; #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_uint_t u0, u1, v0, v1; mpd_uint_t w, w0, w1, wstep; mpd_size_t m, mhalf; mpd_size_t j, r; assert(ispower2(n)); assert(n >= 4); SETMODULUS(tparams->modnum); /* m == n */ mhalf = n / 2; for (j = 0; j < mhalf; j += 2) { w0 = wtable[j]; w1 = wtable[j+1]; u0 = a[j]; v0 = a[j+mhalf]; u1 = a[j+1]; v1 = a[j+1+mhalf]; a[j] = addmod(u0, v0, umod); v0 = submod(u0, v0, umod); a[j+1] = addmod(u1, v1, umod); v1 = submod(u1, v1, umod); MULMOD2(&v0, w0, &v1, w1); a[j+mhalf] = v0; a[j+1+mhalf] = v1; } wstep = 2; for (m = n/2; m >= 2; m>>=1, wstep<<=1) { mhalf = m / 2; /* j == 0 */ for (r = 0; r < n; r += 2*m) { u0 = a[r]; v0 = a[r+mhalf]; u1 = a[m+r]; v1 = a[m+r+mhalf]; a[r] = addmod(u0, v0, umod); v0 = submod(u0, v0, umod); a[m+r] = addmod(u1, v1, umod); v1 = submod(u1, v1, umod); a[r+mhalf] = v0; a[m+r+mhalf] = v1; } for (j = 1; j < mhalf; j++) { w = wtable[j*wstep]; for (r = 0; r < n; r += 2*m) { u0 = a[r+j]; v0 = a[r+j+mhalf]; u1 = a[m+r+j]; v1 = a[m+r+j+mhalf]; a[r+j] = addmod(u0, v0, umod); v0 = submod(u0, v0, umod); a[m+r+j] = addmod(u1, v1, umod); v1 = submod(u1, v1, umod); MULMOD2C(&v0, &v1, w); a[r+j+mhalf] = v0; a[m+r+j+mhalf] = v1; } } } bitreverse_permute(a, n); } mpdecimal-4.0.1/libmpdec/difradix2.h0000644000000000000000000000333615005764474014222 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_DIFRADIX2_H_ #define LIBMPDEC_DIFRADIX2_H_ #include "mpdecimal.h" #include "numbertheory.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) void fnt_dif2(mpd_uint_t a[], mpd_size_t n, struct fnt_params *tparams); MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_DIFRADIX2_H_ */ mpdecimal-4.0.1/libmpdec/examples/0000755000000000000000000000000015005764474014006 5ustar00mpdecimal-4.0.1/libmpdec/examples/README.txt0000644000000000000000000000021515005764474015502 0ustar00 This directory contains a number of examples. In order to compile, run (for example): gcc -Wall -W -O2 -o powmod powmod.c -lmpdec -lm mpdecimal-4.0.1/libmpdec/examples/compare.c0000644000000000000000000000435215005764474015604 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *a, *b; mpd_t *result; char *rstring; char status_str[MPD_MAX_FLAG_STRING]; clock_t start_clock, end_clock; if (argc != 3) { fprintf(stderr, "compare: usage: ./compare x y\n"); exit(1); } mpd_init(&ctx, 38); ctx.traps = 0; result = mpd_new(&ctx); a = mpd_new(&ctx); b = mpd_new(&ctx); mpd_set_string(a, argv[1], &ctx); mpd_set_string(b, argv[2], &ctx); start_clock = clock(); mpd_compare(result, a, b, &ctx); end_clock = clock(); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); rstring = mpd_to_sci(result, 1); mpd_snprint_flags(status_str, MPD_MAX_FLAG_STRING, ctx.status); printf("%s %s\n", rstring, status_str); mpd_del(a); mpd_del(b); mpd_del(result); mpd_free(rstring); return 0; } mpdecimal-4.0.1/libmpdec/examples/div.c0000644000000000000000000000433615005764474014742 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *a, *b; mpd_t *result; char *rstring; char status_str[MPD_MAX_FLAG_STRING]; clock_t start_clock, end_clock; if (argc != 3) { fprintf(stderr, "div: usage: ./div x y\n"); exit(1); } mpd_init(&ctx, 38); ctx.traps = 0; result = mpd_new(&ctx); a = mpd_new(&ctx); b = mpd_new(&ctx); mpd_set_string(a, argv[1], &ctx); mpd_set_string(b, argv[2], &ctx); start_clock = clock(); mpd_div(result, a, b, &ctx); end_clock = clock(); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); rstring = mpd_to_sci(result, 1); mpd_snprint_flags(status_str, MPD_MAX_FLAG_STRING, ctx.status); printf("%s %s\n", rstring, status_str); mpd_del(a); mpd_del(b); mpd_del(result); mpd_free(rstring); return 0; } mpdecimal-4.0.1/libmpdec/examples/divmod.c0000644000000000000000000000442515005764474015441 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *a, *b; mpd_t *q, *r; char *qs, *rs; char status_str[MPD_MAX_FLAG_STRING]; clock_t start_clock, end_clock; if (argc != 3) { fprintf(stderr, "divmod: usage: ./divmod x y\n"); exit(1); } mpd_init(&ctx, 38); ctx.traps = 0; q = mpd_new(&ctx); r = mpd_new(&ctx); a = mpd_new(&ctx); b = mpd_new(&ctx); mpd_set_string(a, argv[1], &ctx); mpd_set_string(b, argv[2], &ctx); start_clock = clock(); mpd_divmod(q, r, a, b, &ctx); end_clock = clock(); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); qs = mpd_to_sci(q, 1); rs = mpd_to_sci(r, 1); mpd_snprint_flags(status_str, MPD_MAX_FLAG_STRING, ctx.status); printf("%s %s %s\n", qs, rs, status_str); mpd_del(q); mpd_del(r); mpd_del(a); mpd_del(b); mpd_free(qs); mpd_free(rs); return 0; } mpdecimal-4.0.1/libmpdec/examples/multiply.c0000644000000000000000000000435015005764474016033 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *a, *b; mpd_t *result; char *rstring; char status_str[MPD_MAX_FLAG_STRING]; clock_t start_clock, end_clock; if (argc != 3) { fprintf(stderr, "multiply: usage: ./multiply x y\n"); exit(1); } mpd_init(&ctx, 38); ctx.traps = 0; result = mpd_new(&ctx); a = mpd_new(&ctx); b = mpd_new(&ctx); mpd_set_string(a, argv[1], &ctx); mpd_set_string(b, argv[2], &ctx); start_clock = clock(); mpd_mul(result, a, b, &ctx); end_clock = clock(); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); rstring = mpd_to_sci(result, 1); mpd_snprint_flags(status_str, MPD_MAX_FLAG_STRING, ctx.status); printf("%s %s\n", rstring, status_str); mpd_del(a); mpd_del(b); mpd_del(result); mpd_free(rstring); return 0; } mpdecimal-4.0.1/libmpdec/examples/pow.c0000644000000000000000000000433615005764474014765 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *a, *b; mpd_t *result; char *rstring; char status_str[MPD_MAX_FLAG_STRING]; clock_t start_clock, end_clock; if (argc != 3) { fprintf(stderr, "pow: usage: ./pow x y\n"); exit(1); } mpd_init(&ctx, 38); ctx.traps = 0; result = mpd_new(&ctx); a = mpd_new(&ctx); b = mpd_new(&ctx); mpd_set_string(a, argv[1], &ctx); mpd_set_string(b, argv[2], &ctx); start_clock = clock(); mpd_pow(result, a, b, &ctx); end_clock = clock(); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); rstring = mpd_to_sci(result, 1); mpd_snprint_flags(status_str, MPD_MAX_FLAG_STRING, ctx.status); printf("%s %s\n", rstring, status_str); mpd_del(a); mpd_del(b); mpd_del(result); mpd_free(rstring); return 0; } mpdecimal-4.0.1/libmpdec/examples/powmod.c0000644000000000000000000000446415005764474015467 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *a, *b, *c; mpd_t *result; char *rstring; char status_str[MPD_MAX_FLAG_STRING]; clock_t start_clock, end_clock; if (argc != 4) { fprintf(stderr, "powmod: usage: ./powmod x y z\n"); exit(1); } mpd_init(&ctx, 38); ctx.traps = 0; result = mpd_new(&ctx); a = mpd_new(&ctx); b = mpd_new(&ctx); c = mpd_new(&ctx); mpd_set_string(a, argv[1], &ctx); mpd_set_string(b, argv[2], &ctx); mpd_set_string(c, argv[3], &ctx); start_clock = clock(); mpd_powmod(result, a, b, c, &ctx); end_clock = clock(); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); rstring = mpd_to_sci(result, 1); mpd_snprint_flags(status_str, MPD_MAX_FLAG_STRING, ctx.status); printf("%s %s\n", rstring, status_str); mpd_del(a); mpd_del(b); mpd_del(c); mpd_del(result); mpd_free(rstring); return 0; } mpdecimal-4.0.1/libmpdec/examples/shift.c0000644000000000000000000000434415005764474015274 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *a, *b; mpd_t *result; char *rstring; char status_str[MPD_MAX_FLAG_STRING]; clock_t start_clock, end_clock; if (argc != 3) { fprintf(stderr, "shift: usage: ./shift x y\n"); exit(1); } mpd_init(&ctx, 38); ctx.traps = 0; result = mpd_new(&ctx); a = mpd_new(&ctx); b = mpd_new(&ctx); mpd_set_string(a, argv[1], &ctx); mpd_set_string(b, argv[2], &ctx); start_clock = clock(); mpd_shift(result, a, b, &ctx); end_clock = clock(); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); rstring = mpd_to_sci(result, 1); mpd_snprint_flags(status_str, MPD_MAX_FLAG_STRING, ctx.status); printf("%s %s\n", rstring, status_str); mpd_del(a); mpd_del(b); mpd_del(result); mpd_free(rstring); return 0; } mpdecimal-4.0.1/libmpdec/examples/sqrt.c0000644000000000000000000000422415005764474015145 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include int main(int argc, char **argv) { mpd_context_t ctx; mpd_t *a; mpd_t *result; char *rstring; char status_str[MPD_MAX_FLAG_STRING]; clock_t start_clock, end_clock; if (argc != 2) { fprintf(stderr, "sqrt: usage: ./sqrt x\n"); exit(1); } mpd_init(&ctx, 38); ctx.traps = 0; result = mpd_new(&ctx); a = mpd_new(&ctx); mpd_set_string(a, argv[1], &ctx); start_clock = clock(); mpd_sqrt(result, a, &ctx); end_clock = clock(); fprintf(stderr, "time: %f\n\n", (double)(end_clock-start_clock)/(double)CLOCKS_PER_SEC); rstring = mpd_to_sci(result, 1); mpd_snprint_flags(status_str, MPD_MAX_FLAG_STRING, ctx.status); printf("%s %s\n", rstring, status_str); mpd_del(a); mpd_del(result); mpd_free(rstring); return 0; } mpdecimal-4.0.1/libmpdec/fnt.c0000644000000000000000000000440715005764474013130 0ustar00/* * Copyright (c) 2008-2025 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 #include #include "bits.h" #include "difradix2.h" #include "fnt.h" #include "mpdecimal.h" #include "numbertheory.h" /* Bignum: Fast transform for medium-sized coefficients */ /* forward transform, sign = -1 */ int std_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) { struct fnt_params *tparams; assert(ispower2(n)); assert(n >= 4); assert(n <= 3*MPD_MAXTRANSFORM_2N); if ((tparams = _mpd_init_fnt_params(n, -1, modnum)) == NULL) { return 0; } fnt_dif2(a, n, tparams); mpd_free(tparams); return 1; } /* reverse transform, sign = 1 */ int std_inv_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) { struct fnt_params *tparams; assert(ispower2(n)); assert(n >= 4); assert(n <= 3*MPD_MAXTRANSFORM_2N); if ((tparams = _mpd_init_fnt_params(n, 1, modnum)) == NULL) { return 0; } fnt_dif2(a, n, tparams); mpd_free(tparams); return 1; } mpdecimal-4.0.1/libmpdec/fnt.h0000644000000000000000000000333115005764474013130 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_FNT_H_ #define LIBMPDEC_FNT_H_ #include "mpdecimal.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) int std_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); int std_inv_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_FNT_H_ */ mpdecimal-4.0.1/libmpdec/fourstep.c0000644000000000000000000001406415005764474014210 0ustar00/* * Copyright (c) 2008-2025 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 #include "constants.h" #include "fourstep.h" #include "mpdecimal.h" #include "numbertheory.h" #include "sixstep.h" #include "umodarith.h" /* Bignum: Cache efficient Matrix Fourier Transform for arrays of the form 3 * 2**n (See literature/matrix-transform.txt). */ #ifndef PPRO static inline void std_size3_ntt(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_uint_t w3table[3], mpd_uint_t umod) { mpd_uint_t r1, r2; mpd_uint_t w; mpd_uint_t s, tmp; /* k = 0 -> w = 1 */ s = *x1; s = addmod(s, *x2, umod); s = addmod(s, *x3, umod); r1 = s; /* k = 1 */ s = *x1; w = w3table[1]; tmp = MULMOD(*x2, w); s = addmod(s, tmp, umod); w = w3table[2]; tmp = MULMOD(*x3, w); s = addmod(s, tmp, umod); r2 = s; /* k = 2 */ s = *x1; w = w3table[2]; tmp = MULMOD(*x2, w); s = addmod(s, tmp, umod); w = w3table[1]; tmp = MULMOD(*x3, w); s = addmod(s, tmp, umod); *x3 = s; *x2 = r2; *x1 = r1; } #else /* PPRO */ static inline void ppro_size3_ntt(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_uint_t w3table[3], mpd_uint_t umod, double *dmod, uint32_t dinvmod[3]) { mpd_uint_t r1, r2; mpd_uint_t w; mpd_uint_t s, tmp; /* k = 0 -> w = 1 */ s = *x1; s = addmod(s, *x2, umod); s = addmod(s, *x3, umod); r1 = s; /* k = 1 */ s = *x1; w = w3table[1]; tmp = ppro_mulmod(*x2, w, dmod, dinvmod); s = addmod(s, tmp, umod); w = w3table[2]; tmp = ppro_mulmod(*x3, w, dmod, dinvmod); s = addmod(s, tmp, umod); r2 = s; /* k = 2 */ s = *x1; w = w3table[2]; tmp = ppro_mulmod(*x2, w, dmod, dinvmod); s = addmod(s, tmp, umod); w = w3table[1]; tmp = ppro_mulmod(*x3, w, dmod, dinvmod); s = addmod(s, tmp, umod); *x3 = s; *x2 = r2; *x1 = r1; } #endif /* forward transform, sign = -1; transform length = 3 * 2**n */ int four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) { mpd_size_t R = 3; /* number of rows */ mpd_size_t C = n / 3; /* number of columns */ mpd_uint_t w3table[3]; mpd_uint_t kernel, w0, w1, wstep; mpd_uint_t *s, *p0, *p1, *p2; mpd_uint_t umod; #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_size_t i, k; assert(n >= 48); assert(n <= 3*MPD_MAXTRANSFORM_2N); /* Length R transform on the columns. */ SETMODULUS(modnum); _mpd_init_w3table(w3table, -1, modnum); for (p0=a, p1=p0+C, p2=p0+2*C; p0= 48); assert(n <= 3*MPD_MAXTRANSFORM_2N); /* Length C transform on the rows. */ for (s = a; s < a+n; s += C) { if (!inv_six_step_fnt(s, C, modnum)) { return 0; } } /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ SETMODULUS(modnum); kernel = _mpd_getkernel(n, 1, modnum); for (i = 1; i < R; i++) { w0 = 1; w1 = POWMOD(kernel, i); wstep = MULMOD(w1, w1); for (k = 0; k < C; k += 2) { mpd_uint_t x0 = a[i*C+k]; mpd_uint_t x1 = a[i*C+k+1]; MULMOD2(&x0, w0, &x1, w1); MULMOD2C(&w0, &w1, wstep); a[i*C+k] = x0; a[i*C+k+1] = x1; } } /* Length R transform on the columns. */ _mpd_init_w3table(w3table, 1, modnum); for (p0=a, p1=p0+C, p2=p0+2*C; p0 #include #include #include #include #include #include #include #include "io.h" #include "mpdecimal.h" #include "typearith.h" /* This file contains functions for decimal <-> string conversions, including PEP-3101 formatting for numeric types. */ #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && __GNUC__ >= 7 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #pragma GCC diagnostic ignored "-Wmisleading-indentation" #pragma GCC diagnostic ignored "-Warray-bounds" #endif /* * Work around the behavior of tolower() and strcasecmp() in certain * locales. For example, in tr_TR.utf8: * * tolower((unsigned char)'I') == 'I' * * u is the exact uppercase version of l; n is strlen(l) or strlen(l)+1 */ static inline int _mpd_strneq(const char *s, const char *l, const char *u, size_t n) { while (--n != SIZE_MAX) { if (*s != *l && *s != *u) { return 0; } s++; u++; l++; } return 1; } static mpd_ssize_t strtoexp(const char *s) { char *end; mpd_ssize_t retval; errno = 0; retval = mpd_strtossize(s, &end, 10); if (errno == 0 && !(*s != '\0' && *end == '\0')) errno = EINVAL; return retval; } /* * Scan 'len' words. The most significant word contains 'r' digits, * the remaining words are full words. Skip dpoint. The string 's' must * consist of digits and an optional single decimal point at 'dpoint'. */ static void string_to_coeff(mpd_uint_t *data, const char *s, const char *dpoint, int r, size_t len) { int j; if (r > 0) { data[--len] = 0; for (j = 0; j < r; j++, s++) { if (s == dpoint) s++; data[len] = 10 * data[len] + (*s - '0'); } } while (--len != SIZE_MAX) { data[len] = 0; for (j = 0; j < MPD_RDIGITS; j++, s++) { if (s == dpoint) s++; data[len] = 10 * data[len] + (*s - '0'); } } } /* * Partially verify a numeric string of the form: * * [cdigits][.][cdigits][eE][+-][edigits] * * If successful, return a pointer to the location of the first * relevant coefficient digit. This digit is either non-zero or * part of one of the following patterns: * * ["0\x00", "0.\x00", "0.E", "0.e", "0E", "0e"] * * The locations of a single optional dot or indicator are stored * in 'dpoint' and 'exp'. * * The end of the string is stored in 'end'. If an indicator [eE] * occurs without trailing [edigits], the condition is caught * later by strtoexp(). */ static const char * scan_dpoint_exp(const char *s, const char **dpoint, const char **exp, const char **end) { const char *coeff = NULL; *dpoint = NULL; *exp = NULL; for (; *s != '\0'; s++) { switch (*s) { case '.': if (*dpoint != NULL || *exp != NULL) return NULL; *dpoint = s; break; case 'E': case 'e': if (*exp != NULL) return NULL; *exp = s; if (*(s+1) == '+' || *(s+1) == '-') s++; break; default: if (!isdigit((unsigned char)*s)) return NULL; if (coeff == NULL && *exp == NULL) { if (*s == '0') { if (!isdigit((unsigned char)*(s+1))) if (!(*(s+1) == '.' && isdigit((unsigned char)*(s+2)))) coeff = s; } else { coeff = s; } } break; } } *end = s; return coeff; } /* scan the payload of a NaN */ static const char * scan_payload(const char *s, const char **end) { const char *coeff; while (*s == '0') s++; coeff = s; while (isdigit((unsigned char)*s)) s++; *end = s; return (*s == '\0') ? coeff : NULL; } /* convert a character string to a decimal */ void mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, uint32_t *status) { mpd_ssize_t q, r, len; const char *coeff, *end; const char *dpoint = NULL, *exp = NULL; size_t digits; uint8_t sign = MPD_POS; mpd_set_flags(dec, 0); dec->len = 0; dec->exp = 0; /* sign */ if (*s == '+') { s++; } else if (*s == '-') { mpd_set_negative(dec); sign = MPD_NEG; s++; } if (_mpd_strneq(s, "nan", "NAN", 3)) { /* NaN */ s += 3; mpd_setspecial(dec, sign, MPD_NAN); if (*s == '\0') return; /* validate payload: digits only */ if ((coeff = scan_payload(s, &end)) == NULL) goto conversion_error; /* payload consists entirely of zeros */ if (*coeff == '\0') return; digits = end - coeff; /* prec >= 1, clamp is 0 or 1 */ if (digits > (size_t)(ctx->prec-ctx->clamp)) goto conversion_error; } /* sNaN */ else if (_mpd_strneq(s, "snan", "SNAN", 4)) { s += 4; mpd_setspecial(dec, sign, MPD_SNAN); if (*s == '\0') return; /* validate payload: digits only */ if ((coeff = scan_payload(s, &end)) == NULL) goto conversion_error; /* payload consists entirely of zeros */ if (*coeff == '\0') return; digits = end - coeff; if (digits > (size_t)(ctx->prec-ctx->clamp)) goto conversion_error; } else if (_mpd_strneq(s, "inf", "INF", 3)) { s += 3; if (*s == '\0' || _mpd_strneq(s, "inity", "INITY", 6)) { /* numeric-value: infinity */ mpd_setspecial(dec, sign, MPD_INF); return; } goto conversion_error; } else { /* scan for start of coefficient, decimal point, indicator, end */ if ((coeff = scan_dpoint_exp(s, &dpoint, &exp, &end)) == NULL) goto conversion_error; /* numeric-value: [exponent-part] */ if (exp) { /* exponent-part */ end = exp; exp++; dec->exp = strtoexp(exp); if (errno) { if (!(errno == ERANGE && (dec->exp == MPD_SSIZE_MAX || dec->exp == MPD_SSIZE_MIN))) goto conversion_error; } } digits = end - coeff; if (dpoint) { size_t fracdigits = end-dpoint-1; if (dpoint > coeff) digits--; if (fracdigits > MPD_MAX_PREC) { goto conversion_error; } if (dec->exp < MPD_SSIZE_MIN+(mpd_ssize_t)fracdigits) { dec->exp = MPD_SSIZE_MIN; } else { dec->exp -= (mpd_ssize_t)fracdigits; } } if (digits > MPD_MAX_PREC) { goto conversion_error; } if (dec->exp > MPD_EXP_INF) { dec->exp = MPD_EXP_INF; } if (dec->exp == MPD_SSIZE_MIN) { dec->exp = MPD_SSIZE_MIN+1; } } _mpd_idiv_word(&q, &r, (mpd_ssize_t)digits, MPD_RDIGITS); len = (r == 0) ? q : q+1; if (len == 0) { goto conversion_error; /* GCOV_NOT_REACHED */ } if (!mpd_qresize(dec, len, status)) { mpd_seterror(dec, MPD_Malloc_error, status); return; } dec->len = len; string_to_coeff(dec->data, coeff, dpoint, (int)r, len); mpd_setdigits(dec); mpd_qfinalize(dec, ctx, status); return; conversion_error: /* standard wants a positive NaN */ mpd_seterror(dec, MPD_Conversion_syntax, status); } /* convert a character string to a decimal, use a maxcontext for conversion */ void mpd_qset_string_exact(mpd_t *dec, const char *s, uint32_t *status) { mpd_context_t maxcontext; uint32_t workstatus = 0; mpd_maxcontext(&maxcontext); mpd_qset_string(dec, s, &maxcontext, &workstatus); if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) { /* we want exact results */ mpd_seterror(dec, MPD_Invalid_operation, status); } *status |= (workstatus&MPD_Errors); } /* Print word x with n decimal digits to string s. dot is either NULL or the location of a decimal point. */ #define EXTRACT_DIGIT(s, x, d, dot) \ if (s == dot) *s++ = '.'; *s++ = '0' + (char)(x / d); x %= d static inline char * word_to_string(char *s, mpd_uint_t x, int n, char *dot) { switch(n) { #ifdef CONFIG_64 case 20: EXTRACT_DIGIT(s, x, 10000000000000000000ULL, dot); /* GCOV_NOT_REACHED */ case 19: EXTRACT_DIGIT(s, x, 1000000000000000000ULL, dot); case 18: EXTRACT_DIGIT(s, x, 100000000000000000ULL, dot); case 17: EXTRACT_DIGIT(s, x, 10000000000000000ULL, dot); case 16: EXTRACT_DIGIT(s, x, 1000000000000000ULL, dot); case 15: EXTRACT_DIGIT(s, x, 100000000000000ULL, dot); case 14: EXTRACT_DIGIT(s, x, 10000000000000ULL, dot); case 13: EXTRACT_DIGIT(s, x, 1000000000000ULL, dot); case 12: EXTRACT_DIGIT(s, x, 100000000000ULL, dot); case 11: EXTRACT_DIGIT(s, x, 10000000000ULL, dot); #endif case 10: EXTRACT_DIGIT(s, x, 1000000000UL, dot); case 9: EXTRACT_DIGIT(s, x, 100000000UL, dot); case 8: EXTRACT_DIGIT(s, x, 10000000UL, dot); case 7: EXTRACT_DIGIT(s, x, 1000000UL, dot); case 6: EXTRACT_DIGIT(s, x, 100000UL, dot); case 5: EXTRACT_DIGIT(s, x, 10000UL, dot); case 4: EXTRACT_DIGIT(s, x, 1000UL, dot); case 3: EXTRACT_DIGIT(s, x, 100UL, dot); case 2: EXTRACT_DIGIT(s, x, 10UL, dot); default: if (s == dot) *s++ = '.'; *s++ = '0' + (char)x; } *s = '\0'; return s; } /* Print exponent x to string s. Undefined for MPD_SSIZE_MIN. */ static inline char * exp_to_string(char *s, mpd_ssize_t x) { char sign = '+'; if (x < 0) { sign = '-'; x = -x; } *s++ = sign; return word_to_string(s, x, mpd_word_digits(x), NULL); } /* Print the coefficient of dec to string s. len(dec) > 0. */ static inline char * coeff_to_string(char *s, const mpd_t *dec) { mpd_uint_t x; mpd_ssize_t i; /* most significant word */ x = mpd_msword(dec); s = word_to_string(s, x, mpd_word_digits(x), NULL); /* remaining full words */ for (i=dec->len-2; i >= 0; --i) { x = dec->data[i]; s = word_to_string(s, x, MPD_RDIGITS, NULL); } return s; } /* Print the coefficient of dec to string s. len(dec) > 0. dot is either NULL or a pointer to the location of a decimal point. */ static inline char * coeff_to_string_dot(char *s, char *dot, const mpd_t *dec) { mpd_uint_t x; mpd_ssize_t i; /* most significant word */ x = mpd_msword(dec); s = word_to_string(s, x, mpd_word_digits(x), dot); /* remaining full words */ for (i=dec->len-2; i >= 0; --i) { x = dec->data[i]; s = word_to_string(s, x, MPD_RDIGITS, dot); } return s; } /* Format type */ #define MPD_FMT_LOWER 0x00000000 #define MPD_FMT_UPPER 0x00000001 #define MPD_FMT_TOSCI 0x00000002 #define MPD_FMT_TOENG 0x00000004 #define MPD_FMT_EXP 0x00000008 #define MPD_FMT_FIXED 0x00000010 #define MPD_FMT_PERCENT 0x00000020 #define MPD_FMT_SIGN_SPACE 0x00000040 #define MPD_FMT_SIGN_PLUS 0x00000080 #define MPD_FMT_SIGN_COERCE 0x00000100 /* Default place of the decimal point for MPD_FMT_TOSCI, MPD_FMT_EXP */ #define MPD_DEFAULT_DOTPLACE 1 /* * Set *result to the string representation of a decimal. Return the length * of *result, not including the terminating '\0' character. * * Formatting is done according to 'flags'. A return value of -1 with *result * set to NULL indicates MPD_Malloc_error. * * 'dplace' is the default place of the decimal point. It is always set to * MPD_DEFAULT_DOTPLACE except for zeros in combination with MPD_FMT_EXP. */ static mpd_ssize_t _mpd_to_string(char **result, const mpd_t *dec, int flags, mpd_ssize_t dplace) { char *decstring = NULL, *cp = NULL; mpd_ssize_t ldigits; mpd_ssize_t mem = 0, k; if (mpd_isspecial(dec)) { mem = sizeof "-Infinity%"; if (mpd_isnan(dec) && dec->len > 0) { /* diagnostic code */ mem += dec->digits; } cp = decstring = mpd_alloc(mem, sizeof *decstring); if (cp == NULL) { *result = NULL; return -1; } if (mpd_isnegative(dec)) { *cp++ = '-'; } else if (flags&MPD_FMT_SIGN_SPACE) { *cp++ = ' '; } else if (flags&MPD_FMT_SIGN_PLUS) { *cp++ = '+'; } if (mpd_isnan(dec)) { if (mpd_isqnan(dec)) { strcpy(cp, "NaN"); cp += 3; } else { strcpy(cp, "sNaN"); cp += 4; } if (dec->len > 0) { /* diagnostic code */ cp = coeff_to_string(cp, dec); } } else if (mpd_isinfinite(dec)) { strcpy(cp, "Infinity"); cp += 8; } else { /* debug */ abort(); /* GCOV_NOT_REACHED */ } } else { assert(dec->len > 0); /* * For easier manipulation of the decimal point's location * and the exponent that is finally printed, the number is * rescaled to a virtual representation with exp = 0. Here * ldigits denotes the number of decimal digits to the left * of the decimal point and remains constant once initialized. * * dplace is the location of the decimal point relative to * the start of the coefficient. Note that 3) always holds * when dplace is shifted. * * 1) ldigits := dec->digits - dec->exp * 2) dplace := ldigits (initially) * 3) exp := ldigits - dplace (initially exp = 0) * * 0.00000_.____._____000000. * ^ ^ ^ ^ * | | | | * | | | `- dplace >= digits * | | `- dplace in the middle of the coefficient * | ` dplace = 1 (after the first coefficient digit) * `- dplace <= 0 */ ldigits = dec->digits + dec->exp; if (flags&MPD_FMT_EXP) { ; } else if (flags&MPD_FMT_FIXED || (dec->exp <= 0 && ldigits > -6)) { /* MPD_FMT_FIXED: always use fixed point notation. * MPD_FMT_TOSCI, MPD_FMT_TOENG: for a certain range, * override exponent notation. */ dplace = ldigits; } else if (flags&MPD_FMT_TOENG) { if (mpd_iszero(dec)) { /* If the exponent is divisible by three, * dplace = 1. Otherwise, move dplace one * or two places to the left. */ dplace = -1 + mod_mpd_ssize_t(dec->exp+2, 3); } else { /* ldigits-1 is the adjusted exponent, which * should be divisible by three. If not, move * dplace one or two places to the right. */ dplace += mod_mpd_ssize_t(ldigits-1, 3); } } /* * Basic space requirements: * * [-][.][coeffdigits][E][-][expdigits+1][%]['\0'] * * If the decimal point lies outside of the coefficient digits, * space is adjusted accordingly. */ if (dplace <= 0) { mem = -dplace + dec->digits + 2; } else if (dplace >= dec->digits) { mem = dplace; } else { mem = dec->digits; } mem += (MPD_EXPDIGITS+1+6); cp = decstring = mpd_alloc(mem, sizeof *decstring); if (cp == NULL) { *result = NULL; return -1; } if (mpd_isnegative(dec) && !(flags&MPD_FMT_SIGN_COERCE && mpd_iszero(dec))) { *cp++ = '-'; } else if (flags&MPD_FMT_SIGN_SPACE) { *cp++ = ' '; } else if (flags&MPD_FMT_SIGN_PLUS) { *cp++ = '+'; } if (dplace <= 0) { /* space: -dplace+dec->digits+2 */ *cp++ = '0'; *cp++ = '.'; for (k = 0; k < -dplace; k++) { *cp++ = '0'; } cp = coeff_to_string(cp, dec); } else if (dplace >= dec->digits) { /* space: dplace */ cp = coeff_to_string(cp, dec); for (k = 0; k < dplace-dec->digits; k++) { *cp++ = '0'; } } else { /* space: dec->digits+1 */ cp = coeff_to_string_dot(cp, cp+dplace, dec); } /* * Conditions for printing an exponent: * * MPD_FMT_TOSCI, MPD_FMT_TOENG: only if ldigits != dplace * MPD_FMT_FIXED: never (ldigits == dplace) * MPD_FMT_EXP: always */ if (ldigits != dplace || flags&MPD_FMT_EXP) { /* space: expdigits+2 */ *cp++ = (flags&MPD_FMT_UPPER) ? 'E' : 'e'; cp = exp_to_string(cp, ldigits-dplace); } } if (flags&MPD_FMT_PERCENT) { *cp++ = '%'; } assert(cp < decstring+mem); assert(cp-decstring < MPD_SSIZE_MAX); *cp = '\0'; *result = decstring; return (mpd_ssize_t)(cp-decstring); } char * mpd_to_sci(const mpd_t *dec, int fmt) { char *res; int flags = MPD_FMT_TOSCI; flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE); return res; } char * mpd_to_eng(const mpd_t *dec, int fmt) { char *res; int flags = MPD_FMT_TOENG; flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE); return res; } mpd_ssize_t mpd_to_sci_size(char **res, const mpd_t *dec, int fmt) { int flags = MPD_FMT_TOSCI; flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE); } mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt) { int flags = MPD_FMT_TOENG; flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE); } /* Copy a single UTF-8 char to dest. See: The Unicode Standard, version 5.2, chapter 3.9: Well-formed UTF-8 byte sequences. */ static int _mpd_copy_utf8(char dest[5], const char *s) { const unsigned char *cp = (const unsigned char *)s; unsigned char lb, ub; int count, i; if (*cp == 0) { /* empty string */ dest[0] = '\0'; return 0; } else if (*cp <= 0x7f) { /* ascii */ dest[0] = *cp; dest[1] = '\0'; return 1; } else if (0xc2 <= *cp && *cp <= 0xdf) { lb = 0x80; ub = 0xbf; count = 2; } else if (*cp == 0xe0) { lb = 0xa0; ub = 0xbf; count = 3; } else if (*cp <= 0xec) { lb = 0x80; ub = 0xbf; count = 3; } else if (*cp == 0xed) { lb = 0x80; ub = 0x9f; count = 3; } else if (*cp <= 0xef) { lb = 0x80; ub = 0xbf; count = 3; } else if (*cp == 0xf0) { lb = 0x90; ub = 0xbf; count = 4; } else if (*cp <= 0xf3) { lb = 0x80; ub = 0xbf; count = 4; } else if (*cp == 0xf4) { lb = 0x80; ub = 0x8f; count = 4; } else { /* invalid */ goto error; } dest[0] = (char)*cp++; if (*cp < lb || ub < *cp) { goto error; } dest[1] = (char)*cp++; for (i = 2; i < count; i++) { if (*cp < 0x80 || 0xbf < *cp) { goto error; } dest[i] = (char)*cp++; } dest[i] = '\0'; return count; error: dest[0] = '\0'; return -1; } int mpd_validate_lconv(mpd_spec_t *spec) { size_t n; #if CHAR_MAX == SCHAR_MAX const char *cp = spec->grouping; while (*cp != '\0') { if (*cp++ < 0) { return -1; } } #endif n = strlen(spec->dot); if (n == 0 || n > 4) { return -1; } if (strlen(spec->sep) > 4) { return -1; } return 0; } int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps) { char *cp = (char *)fmt; int have_align = 0, n; /* defaults */ spec->min_width = 0; spec->prec = -1; spec->type = caps ? 'G' : 'g'; spec->align = '>'; spec->sign = '-'; spec->sign_coerce = 0; spec->dot = ""; spec->sep = ""; spec->grouping = ""; /* presume that the first character is a UTF-8 fill character */ if ((n = _mpd_copy_utf8(spec->fill, cp)) < 0) { return 0; } /* alignment directive, prefixed by a fill character */ if (*cp && (*(cp+n) == '<' || *(cp+n) == '>' || *(cp+n) == '=' || *(cp+n) == '^')) { cp += n; spec->align = *cp++; have_align = 1; } /* alignment directive */ else { /* default fill character */ spec->fill[0] = ' '; spec->fill[1] = '\0'; if (*cp == '<' || *cp == '>' || *cp == '=' || *cp == '^') { spec->align = *cp++; have_align = 1; } } /* sign formatting */ if (*cp == '+' || *cp == '-' || *cp == ' ') { spec->sign = *cp++; } /* coerce to positive zero */ if (*cp == 'z') { spec->sign_coerce = 1; cp++; } /* zero padding */ if (*cp == '0') { /* zero padding implies alignment, which should not be * specified twice. */ if (have_align) { return 0; } spec->align = 'z'; spec->fill[0] = *cp++; spec->fill[1] = '\0'; } /* minimum width */ if (isdigit((unsigned char)*cp)) { if (*cp == '0') { return 0; } errno = 0; spec->min_width = mpd_strtossize(cp, &cp, 10); if (errno == ERANGE || errno == EINVAL) { return 0; } } /* thousands separator */ if (*cp == ',') { spec->dot = "."; spec->sep = ","; spec->grouping = "\003\003"; cp++; } /* fraction digits or significant digits */ if (*cp == '.') { cp++; if (!isdigit((unsigned char)*cp)) { return 0; } errno = 0; spec->prec = mpd_strtossize(cp, &cp, 10); if (errno == ERANGE || errno == EINVAL) { return 0; } } /* type */ if (*cp == 'E' || *cp == 'e' || *cp == 'F' || *cp == 'f' || *cp == 'G' || *cp == 'g' || *cp == '%') { spec->type = *cp++; } else if (*cp == 'N' || *cp == 'n') { /* locale specific conversion */ struct lconv *lc; /* separator has already been specified */ if (*spec->sep) { return 0; } spec->type = *cp++; spec->type = (spec->type == 'N') ? 'G' : 'g'; lc = localeconv(); spec->dot = lc->decimal_point; spec->sep = lc->thousands_sep; spec->grouping = lc->grouping; if (mpd_validate_lconv(spec) < 0) { return 0; /* GCOV_NOT_REACHED */ } } /* check correctness */ if (*cp != '\0') { return 0; } return 1; } /* * The following functions assume that spec->min_width <= MPD_MAX_PREC, which * is made sure in mpd_qformat_spec. Then, even with a spec that inserts a * four-byte separator after each digit, nbytes in the following struct * cannot overflow. */ /* Multibyte string */ typedef struct { mpd_ssize_t nbytes; /* length in bytes */ mpd_ssize_t nchars; /* length in chars */ mpd_ssize_t cur; /* current write index */ char *data; } mpd_mbstr_t; static inline void _mpd_bcopy(char *dest, const char *src, mpd_ssize_t n) { while (--n >= 0) { dest[n] = src[n]; } } static inline void _mbstr_copy_char(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n) { dest->nbytes += n; dest->nchars += (n > 0 ? 1 : 0); dest->cur -= n; if (dest->data != NULL) { _mpd_bcopy(dest->data+dest->cur, src, n); } } static inline void _mbstr_copy_ascii(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n) { dest->nbytes += n; dest->nchars += n; dest->cur -= n; if (dest->data != NULL) { _mpd_bcopy(dest->data+dest->cur, src, n); } } static inline void _mbstr_copy_pad(mpd_mbstr_t *dest, mpd_ssize_t n) { dest->nbytes += n; dest->nchars += n; dest->cur -= n; if (dest->data != NULL) { char *cp = dest->data + dest->cur; while (--n >= 0) { cp[n] = '0'; } } } /* * Copy a numeric string to dest->data, adding separators in the integer * part according to spec->grouping. If leading zero padding is enabled * and the result is smaller than spec->min_width, continue adding zeros * and separators until the minimum width is reached. * * The final length of dest->data is stored in dest->nbytes. The number * of UTF-8 characters is stored in dest->nchars. * * First run (dest->data == NULL): determine the length of the result * string and store it in dest->nbytes. * * Second run (write to dest->data): data is written in chunks and in * reverse order, starting with the rest of the numeric string. */ static void _mpd_add_sep_dot(mpd_mbstr_t *dest, const char *sign, /* location of optional sign */ const char *src, mpd_ssize_t n_src, /* integer part and length */ const char *dot, /* location of optional decimal point */ const char *rest, mpd_ssize_t n_rest, /* remaining part and length */ const mpd_spec_t *spec) { mpd_ssize_t n_sep, n_sign, consume; const char *g; int pad = 0; n_sign = sign ? 1 : 0; n_sep = (mpd_ssize_t)strlen(spec->sep); /* Initial write index: set to location of '\0' in the output string. * Irrelevant for the first run. */ dest->cur = dest->nbytes; dest->nbytes = dest->nchars = 0; _mbstr_copy_ascii(dest, rest, n_rest); if (dot) { _mbstr_copy_char(dest, dot, (mpd_ssize_t)strlen(dot)); } g = spec->grouping; consume = *g; while (1) { /* If the group length is 0 or CHAR_MAX or greater than the * number of source bytes, consume all remaining bytes. */ if (*g == 0 || *g == CHAR_MAX || consume > n_src) { consume = n_src; } n_src -= consume; if (pad) { _mbstr_copy_pad(dest, consume); } else { _mbstr_copy_ascii(dest, src+n_src, consume); } if (n_src == 0) { /* Either the real source of intpart digits or the virtual * source of padding zeros is exhausted. */ if (spec->align == 'z' && dest->nchars + n_sign < spec->min_width) { /* Zero padding is set and length < min_width: * Generate n_src additional characters. */ n_src = spec->min_width - (dest->nchars + n_sign); /* Next iteration: * case *g == 0 || *g == CHAR_MAX: * consume all padding characters * case consume < g*: * fill remainder of current group * case consume == g* * copying is a no-op */ consume = *g - consume; /* Switch on virtual source of zeros. */ pad = 1; continue; } break; } if (n_sep > 0) { /* If padding is switched on, separators are counted * as padding characters. This rule does not apply if * the separator would be the first character of the * result string. */ if (pad && n_src > 1) n_src -= 1; _mbstr_copy_char(dest, spec->sep, n_sep); } /* If non-NUL, use the next value for grouping. */ if (*g && *(g+1)) g++; consume = *g; } if (sign) { _mbstr_copy_ascii(dest, sign, 1); } if (dest->data) { dest->data[dest->nbytes] = '\0'; } } /* * Convert a numeric-string to its locale-specific appearance. * The string must have one of these forms: * * 1) [sign] digits [exponent-part] * 2) [sign] digits '.' [digits] [exponent-part] * * Not allowed, since _mpd_to_string() never returns this form: * * 3) [sign] '.' digits [exponent-part] * * Input: result->data := original numeric string (ASCII) * result->bytes := strlen(result->data) * result->nchars := strlen(result->data) * * Output: result->data := modified or original string * result->bytes := strlen(result->data) * result->nchars := number of characters (possibly UTF-8) */ static int _mpd_apply_lconv(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status) { const char *sign = NULL, *intpart = NULL, *dot = NULL; const char *rest, *dp; char *decstring; mpd_ssize_t n_int, n_rest; /* original numeric string */ dp = result->data; /* sign */ if (*dp == '+' || *dp == '-' || *dp == ' ') { sign = dp++; } /* integer part */ assert(isdigit((unsigned char)*dp)); intpart = dp++; while (isdigit((unsigned char)*dp)) { dp++; } n_int = (mpd_ssize_t)(dp-intpart); /* decimal point */ if (*dp == '.') { dp++; dot = spec->dot; } /* rest */ rest = dp; n_rest = result->nbytes - (mpd_ssize_t)(dp-result->data); if (dot == NULL && (*spec->sep == '\0' || *spec->grouping == '\0')) { /* _mpd_add_sep_dot() would not change anything */ return 1; } /* Determine the size of the new decimal string after inserting the * decimal point, optional separators and optional padding. */ decstring = result->data; result->data = NULL; _mpd_add_sep_dot(result, sign, intpart, n_int, dot, rest, n_rest, spec); result->data = mpd_alloc(result->nbytes+1, 1); if (result->data == NULL) { *status |= MPD_Malloc_error; mpd_free(decstring); return 0; } /* Perform actual writes. */ _mpd_add_sep_dot(result, sign, intpart, n_int, dot, rest, n_rest, spec); mpd_free(decstring); return 1; } /* Add padding to the formatted string if necessary. */ static int _mpd_add_pad(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status) { if (result->nchars < spec->min_width) { mpd_ssize_t add_chars, add_bytes; size_t lpad = 0, rpad = 0; size_t n_fill, len, i, j; char align = spec->align; uint8_t err = 0; char *cp; n_fill = strlen(spec->fill); add_chars = (spec->min_width - result->nchars); /* max value: MPD_MAX_PREC * 4 */ add_bytes = add_chars * (mpd_ssize_t)n_fill; cp = result->data = mpd_realloc(result->data, result->nbytes+add_bytes+1, sizeof *result->data, &err); if (err) { *status |= MPD_Malloc_error; mpd_free(result->data); return 0; } if (align == 'z') { align = '='; } if (align == '<') { rpad = add_chars; } else if (align == '>' || align == '=') { lpad = add_chars; } else { /* align == '^' */ lpad = add_chars/2; rpad = add_chars-lpad; } len = result->nbytes; if (align == '=' && (*cp == '-' || *cp == '+' || *cp == ' ')) { /* leave sign in the leading position */ cp++; len--; } memmove(cp+n_fill*lpad, cp, len); for (i = 0; i < lpad; i++) { for (j = 0; j < n_fill; j++) { cp[i*n_fill+j] = spec->fill[j]; } } cp += (n_fill*lpad + len); for (i = 0; i < rpad; i++) { for (j = 0; j < n_fill; j++) { cp[i*n_fill+j] = spec->fill[j]; } } result->nbytes += add_bytes; result->nchars += add_chars; result->data[result->nbytes] = '\0'; } return 1; } /* Round a number to prec digits. The adjusted exponent stays the same or increases by one if rounding up crosses a power of ten boundary. If result->digits would exceed MPD_MAX_PREC+1, MPD_Invalid_operation is set and the result is NaN. */ static inline void _mpd_round(mpd_t *result, const mpd_t *a, mpd_ssize_t prec, const mpd_context_t *ctx, uint32_t *status) { mpd_ssize_t exp = a->exp + a->digits - prec; if (prec <= 0) { mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_NOT_REACHED */ return; /* GCOV_NOT_REACHED */ } if (mpd_isspecial(a) || mpd_iszero(a)) { mpd_qcopy(result, a, status); /* GCOV_NOT_REACHED */ return; /* GCOV_NOT_REACHED */ } mpd_qrescale_fmt(result, a, exp, ctx, status); if (result->digits > prec) { mpd_qrescale_fmt(result, result, exp+1, ctx, status); } } /* * Return the string representation of an mpd_t, formatted according to 'spec'. * The format specification is assumed to be valid. Memory errors are indicated * as usual. This function is quiet. */ char * mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status) { mpd_uint_t dt[MPD_MINALLOC_MAX]; mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt}; mpd_ssize_t dplace = MPD_DEFAULT_DOTPLACE; mpd_mbstr_t result; mpd_spec_t stackspec; char type = spec->type; int flags = 0; if (spec->min_width > MPD_MAX_PREC) { *status |= MPD_Invalid_operation; return NULL; } if (isupper((unsigned char)type)) { type = (char)tolower((unsigned char)type); flags |= MPD_FMT_UPPER; } if (spec->sign_coerce) { flags |= MPD_FMT_SIGN_COERCE; } if (spec->sign == ' ') { flags |= MPD_FMT_SIGN_SPACE; } else if (spec->sign == '+') { flags |= MPD_FMT_SIGN_PLUS; } if (mpd_isspecial(dec)) { if (spec->align == 'z') { stackspec = *spec; stackspec.fill[0] = ' '; stackspec.fill[1] = '\0'; stackspec.align = '>'; spec = &stackspec; } if (type == '%') { flags |= MPD_FMT_PERCENT; } } else { uint32_t workstatus = 0; mpd_ssize_t prec; switch (type) { case 'g': flags |= MPD_FMT_TOSCI; break; case 'e': flags |= MPD_FMT_EXP; break; case '%': flags |= MPD_FMT_PERCENT; if (!mpd_qcopy(&tmp, dec, status)) { return NULL; } tmp.exp += 2; dec = &tmp; type = 'f'; /* fall through */ case 'f': flags |= MPD_FMT_FIXED; break; default: abort(); /* debug: GCOV_NOT_REACHED */ } if (spec->prec >= 0) { if (spec->prec > MPD_MAX_PREC) { *status |= MPD_Invalid_operation; goto error; } switch (type) { case 'g': prec = (spec->prec == 0) ? 1 : spec->prec; if (dec->digits > prec) { _mpd_round(&tmp, dec, prec, ctx, &workstatus); dec = &tmp; } break; case 'e': if (mpd_iszero(dec)) { dplace = 1-spec->prec; } else { _mpd_round(&tmp, dec, spec->prec+1, ctx, &workstatus); dec = &tmp; } break; case 'f': mpd_qrescale(&tmp, dec, -spec->prec, ctx, &workstatus); dec = &tmp; break; } } if (type == 'f') { if (mpd_iszero(dec) && dec->exp > 0) { mpd_qrescale(&tmp, dec, 0, ctx, &workstatus); dec = &tmp; } } if (workstatus&MPD_Errors) { *status |= (workstatus&MPD_Errors); goto error; } } /* * At this point, for all scaled or non-scaled decimals: * 1) 1 <= digits <= MAX_PREC+1 * 2) adjexp(scaled) = adjexp(orig) [+1] * 3) case 'g': MIN_ETINY <= exp <= MAX_EMAX+1 * case 'e': MIN_ETINY-MAX_PREC <= exp <= MAX_EMAX+1 * case 'f': MIN_ETINY <= exp <= MAX_EMAX+1 * 4) max memory alloc in _mpd_to_string: * case 'g': MAX_PREC+36 * case 'e': MAX_PREC+36 * case 'f': 2*MPD_MAX_PREC+30 */ result.nbytes = _mpd_to_string(&result.data, dec, flags, dplace); result.nchars = result.nbytes; if (result.nbytes < 0) { *status |= MPD_Malloc_error; goto error; } if (*spec->dot != '\0' && !mpd_isspecial(dec)) { if (result.nchars > MPD_MAX_PREC+36) { /* Since a group length of one is not explicitly * disallowed, ensure that it is always possible to * insert a four byte separator after each digit. */ *status |= MPD_Invalid_operation; mpd_free(result.data); goto error; } if (!_mpd_apply_lconv(&result, spec, status)) { goto error; } } if (spec->min_width) { if (!_mpd_add_pad(&result, spec, status)) { goto error; } } mpd_del(&tmp); return result.data; error: mpd_del(&tmp); return NULL; } char * mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status) { mpd_spec_t spec; if (!mpd_parse_fmt_str(&spec, fmt, 1)) { *status |= MPD_Invalid_operation; return NULL; } return mpd_qformat_spec(dec, &spec, ctx, status); } /* * The specification has a *condition* called Invalid_operation and an * IEEE *signal* called Invalid_operation. The former corresponds to * MPD_Invalid_operation, the latter to MPD_IEEE_Invalid_operation. * MPD_IEEE_Invalid_operation comprises the following conditions: * * [MPD_Conversion_syntax, MPD_Division_impossible, MPD_Division_undefined, * MPD_Fpu_error, MPD_Invalid_context, MPD_Invalid_operation, * MPD_Malloc_error] * * In the following functions, 'flag' denotes the condition, 'signal' * denotes the IEEE signal. */ static const char *mpd_flag_string[MPD_NUM_FLAGS] = { "Clamped", "Conversion_syntax", "Division_by_zero", "Division_impossible", "Division_undefined", "Fpu_error", "Inexact", "Invalid_context", "Invalid_operation", "Malloc_error", "Not_implemented", "Overflow", "Rounded", "Subnormal", "Underflow", }; static const char *mpd_signal_string[MPD_NUM_FLAGS] = { "Clamped", "IEEE_Invalid_operation", "Division_by_zero", "IEEE_Invalid_operation", "IEEE_Invalid_operation", "IEEE_Invalid_operation", "Inexact", "IEEE_Invalid_operation", "IEEE_Invalid_operation", "IEEE_Invalid_operation", "Not_implemented", "Overflow", "Rounded", "Subnormal", "Underflow", }; /* print conditions to buffer, separated by spaces */ int mpd_snprint_flags(char *dest, int nmemb, uint32_t flags) { char *cp; int n, j; assert(nmemb >= MPD_MAX_FLAG_STRING); *dest = '\0'; cp = dest; for (j = 0; j < MPD_NUM_FLAGS; j++) { if (flags & (1U<= nmemb) return -1; cp += n; nmemb -= n; } } if (cp != dest) { *(--cp) = '\0'; } return (int)(cp-dest); } /* print conditions to buffer, in list form */ int mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]) { char *cp; int n, j; assert(nmemb >= MPD_MAX_FLAG_LIST); if (flag_string == NULL) { flag_string = mpd_flag_string; } *dest = '['; *(dest+1) = '\0'; cp = dest+1; --nmemb; for (j = 0; j < MPD_NUM_FLAGS; j++) { if (flags & (1U<= nmemb) return -1; cp += n; nmemb -= n; } } /* erase the last ", " */ if (cp != dest+1) { cp -= 2; } *cp++ = ']'; *cp = '\0'; return (int)(cp-dest); /* strlen, without NUL terminator */ } /* print signals to buffer, in list form */ int mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]) { char *cp; int n, j; int ieee_invalid_done = 0; assert(nmemb >= MPD_MAX_SIGNAL_LIST); if (signal_string == NULL) { signal_string = mpd_signal_string; } *dest = '['; *(dest+1) = '\0'; cp = dest+1; --nmemb; for (j = 0; j < MPD_NUM_FLAGS; j++) { uint32_t f = flags & (1U<= nmemb) return -1; cp += n; nmemb -= n; } } /* erase the last ", " */ if (cp != dest+1) { cp -= 2; } *cp++ = ']'; *cp = '\0'; return (int)(cp-dest); /* strlen, without NUL terminator */ } /* The following two functions are mainly intended for debugging. */ void mpd_fprint(FILE *file, const mpd_t *dec) { char *decstring; decstring = mpd_to_sci(dec, 1); if (decstring != NULL) { fprintf(file, "%s\n", decstring); mpd_free(decstring); } else { fputs("mpd_fprint: output error\n", file); /* GCOV_NOT_REACHED */ } } void mpd_print(const mpd_t *dec) { char *decstring; decstring = mpd_to_sci(dec, 1); if (decstring != NULL) { printf("%s\n", decstring); mpd_free(decstring); } else { fputs("mpd_fprint: output error\n", stderr); /* GCOV_NOT_REACHED */ } } mpdecimal-4.0.1/libmpdec/io.h0000644000000000000000000000367715005764474012765 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_IO_H_ #define LIBMPDEC_IO_H_ #include #include "mpdecimal.h" #if SIZE_MAX == MPD_SIZE_MAX #define mpd_strtossize _mpd_strtossize #else #include static inline mpd_ssize_t mpd_strtossize(const char *s, char **end, int base) { int64_t retval; errno = 0; retval = _mpd_strtossize(s, end, base); if (errno == 0 && (retval > MPD_SSIZE_MAX || retval < MPD_SSIZE_MIN)) { errno = ERANGE; } if (errno == ERANGE) { return (retval < 0) ? MPD_SSIZE_MIN : MPD_SSIZE_MAX; } return (mpd_ssize_t)retval; } #endif #endif /* LIBMPDEC_IO_H_ */ mpdecimal-4.0.1/libmpdec/literature/0000755000000000000000000000000015005764474014350 5ustar00mpdecimal-4.0.1/libmpdec/literature/REFERENCES.txt0000644000000000000000000000270515005764474016536 0ustar00 This document contains links to the literature used in the process of creating the library. The list is probably not complete. Mike Cowlishaw: General Decimal Arithmetic Specification http://speleotrove.com/decimal/decarith.html Jean-Michel Muller: On the definition of ulp (x) lara.inist.fr/bitstream/2332/518/1/LIP-RR2005-09.pdf T. E. Hull, A. Abrham: Properly rounded variable precision square root http://portal.acm.org/citation.cfm?id=214413 T. E. Hull, A. Abrham: Variable precision exponential function http://portal.acm.org/citation.cfm?id=6498 T. Granlund, P. L. Montgomery: Division by Invariant Integers using Multiplication http://gmplib.org/~tege/divcnst-pldi94.pdf Roman E. Maeder: Storage allocation for the Karatsuba integer multiplication algorithm. http://www.springerlink.com/content/w15058mj6v59t565/ J. M. Pollard: The fast Fourier transform in a finite field http://www.ams.org/journals/mcom/1971-25-114/S0025-5718-1971-0301966-0/home.html David H. Bailey: FFTs in External or Hierarchical Memory http://crd.lbl.gov/~dhbailey/dhbpapers/ W. Morven Gentleman: Matrix Multiplication and Fast Fourier Transforms http://www.alcatel-lucent.com/bstj/vol47-1968/articles/bstj47-6-1099.pdf Mikko Tommila: Apfloat documentation http://www.apfloat.org/apfloat/2.41/apfloat.pdf Joerg Arndt: "Matters Computational" http://www.jjj.de/fxt/ Karl Hasselstrom: Fast Division of Large Integers www.treskal.com/kalle/exjobb/original-report.pdf mpdecimal-4.0.1/libmpdec/literature/bignum.txt0000644000000000000000000000555015005764474016377 0ustar00 Bignum support (Fast Number Theoretic Transform or FNT): ======================================================== Bignum arithmetic in libmpdec uses the scheme for fast convolution of integer sequences from: J. M. Pollard: The fast Fourier transform in a finite field http://www.ams.org/journals/mcom/1971-25-114/S0025-5718-1971-0301966-0/home.html The transform in a finite field can be used for convolution in the same way as the Fourier Transform. The main advantages of the Number Theoretic Transform are that it is both exact and very memory efficient. Convolution in pseudo-code: ~~~~~~~~~~~~~~~~~~~~~~~~~~~ fnt_convolute(a, b): x = fnt(a) # forward transform of a y = fnt(b) # forward transform of b z = pairwise multiply x[i] and y[i] result = inv_fnt(z) # backward transform of z. Extending the maximum transform length (Chinese Remainder Theorem): ------------------------------------------------------------------- The maximum transform length is quite limited when using a single prime field. However, it is possible to use multiple primes and recover the result using the Chinese Remainder Theorem. Multiplication in pseudo-code: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mpd_fntmul(u, v): c1 = fnt_convolute(u, v, P1) # convolute modulo prime1 c2 = fnt_convolute(u, v, P2) # convolute modulo prime2 c3 = fnt_convolute(u, v, P3) # convolute modulo prime3 result = crt3(c1, c2, c3) # Chinese Remainder Theorem Optimized transform functions: ------------------------------ There are three different fnt() functions: std_fnt: "standard" decimation in frequency transform for array lengths of 2**n. Performs well up to 1024 words. sixstep: Cache-friendly algorithm for array lengths of 2**n. Outperforms std_fnt for large arrays. fourstep: Algorithm for array lengths of 3 * 2**n. Also cache friendly in large parts. List of bignum-only files: -------------------------- Functions from these files are only used in _mpd_fntmul(). umodarith.h -> fast low level routines for unsigned modular arithmetic numbertheory.c -> routines for setting up the FNT difradix2.c -> decimation in frequency transform, used as the "base case" by the following three files: fnt.c -> standard transform for smaller arrays sixstep.c -> transform large arrays of length 2**n fourstep.c -> transform arrays of length 3 * 2**n convolute.c -> do the actual fast convolution, using one of the three transform functions. transpose.c -> transpositions needed for the sixstep algorithm. crt.c -> Chinese Remainder Theorem: use information from three transforms modulo three different primes to get the final result. mpdecimal-4.0.1/libmpdec/literature/fnt.py0000644000000000000000000001600115005764474015507 0ustar00# # Copyright (c) 2008-2025 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. # ###################################################################### # This file lists and checks some of the constants and limits used # # in libmpdec's Number Theoretic Transform. At the end of the file # # there is an example function for the plain DFT transform. # ###################################################################### # # Number theoretic transforms are done in subfields of F(p). P[i] # are the primes, D[i] = P[i] - 1 are highly composite and w[i] # are the respective primitive roots of F(p). # # The strategy is to convolute two coefficients modulo all three # primes, then use the Chinese Remainder Theorem on the three # result arrays to recover the result in the usual base RADIX # form. # # ====================================================================== # Primitive roots # ====================================================================== # # Verify primitive roots: # # For a prime field, r is a primitive root if and only if for all prime # factors f of p-1, r**((p-1)/f) =/= 1 (mod p). # def prod(F, E): """Check that the factorization of P-1 is correct. F is the list of factors of P-1, E lists the number of occurrences of each factor.""" x = 1 for y, z in zip(F, E): x *= y**z return x def is_primitive_root(r, p, factors, exponents): """Check if r is a primitive root of F(p).""" if p != prod(factors, exponents) + 1: return False for f in factors: q, control = divmod(p-1, f) if control != 0: return False if pow(r, q, p) == 1: return False return True # ================================================================= # Constants and limits for the 64-bit version # ================================================================= RADIX = 10**19 # Primes P1, P2 and P3: P = [2**64-2**32+1, 2**64-2**34+1, 2**64-2**40+1] # P-1, highly composite. The transform length d is variable and # must divide D = P-1. Since all D are divisible by 3 * 2**32, # transform lengths can be 2**n or 3 * 2**n (where n <= 32). D = [2**32 * 3 * (5 * 17 * 257 * 65537), 2**34 * 3**2 * (7 * 11 * 31 * 151 * 331), 2**40 * 3**2 * (5 * 7 * 13 * 17 * 241)] # Prime factors of P-1 and their exponents: F = [(2,3,5,17,257,65537), (2,3,7,11,31,151,331), (2,3,5,7,13,17,241)] E = [(32,1,1,1,1,1), (34,2,1,1,1,1,1), (40,2,1,1,1,1,1)] # Maximum transform length for 2**n. Above that only 3 * 2**31 # or 3 * 2**32 are possible. MPD_MAXTRANSFORM_2N = 2**32 # Limits in the terminology of Pollard's paper: m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array. M1 = M2 = RADIX-1 # Maximum value per single word. L = m2 * M1 * M2 P[0] * P[1] * P[2] > 2 * L # Primitive roots of F(P1), F(P2) and F(P3): w = [7, 10, 19] # The primitive roots are correct: for i in range(3): if not is_primitive_root(w[i], P[i], F[i], E[i]): print("FAIL") # ================================================================= # Constants and limits for the 32-bit version # ================================================================= RADIX = 10**9 # Primes P1, P2 and P3: P = [2113929217, 2013265921, 1811939329] # P-1, highly composite. All D = P-1 are divisible by 3 * 2**25, # allowing for transform lengths up to 3 * 2**25 words. D = [2**25 * 3**2 * 7, 2**27 * 3 * 5, 2**26 * 3**3] # Prime factors of P-1 and their exponents: F = [(2,3,7), (2,3,5), (2,3)] E = [(25,2,1), (27,1,1), (26,3)] # Maximum transform length for 2**n. Above that only 3 * 2**24 or # 3 * 2**25 are possible. MPD_MAXTRANSFORM_2N = 2**25 # Limits in the terminology of Pollard's paper: m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array. M1 = M2 = RADIX-1 # Maximum value per single word. L = m2 * M1 * M2 P[0] * P[1] * P[2] > 2 * L # Primitive roots of F(P1), F(P2) and F(P3): w = [5, 31, 13] # The primitive roots are correct: for i in range(3): if not is_primitive_root(w[i], P[i], F[i], E[i]): print("FAIL") # ====================================================================== # Example transform using a single prime # ====================================================================== def ntt(lst, dir): """Perform a transform on the elements of lst. len(lst) must be 2**n or 3 * 2**n, where n <= 25. This is the slow DFT.""" p = 2113929217 # prime d = len(lst) # transform length d_prime = pow(d, (p-2), p) # inverse of d xi = (p-1)//d w = 5 # primitive root of F(p) r = pow(w, xi, p) # primitive root of the subfield r_prime = pow(w, (p-1-xi), p) # inverse of r if dir == 1: # forward transform a = lst # input array A = [0] * d # transformed values for i in range(d): s = 0 for j in range(d): s += a[j] * pow(r, i*j, p) A[i] = s % p return A elif dir == -1: # backward transform A = lst # input array a = [0] * d # transformed values for j in range(d): s = 0 for i in range(d): s += A[i] * pow(r_prime, i*j, p) a[j] = (d_prime * s) % p return a def ntt_convolute(a, b): """convolute arrays a and b.""" assert(len(a) == len(b)) x = ntt(a, 1) y = ntt(b, 1) for i in range(len(a)): y[i] = y[i] * x[i] r = ntt(y, -1) return r # Example: Two arrays representing 21 and 81 in little-endian: a = [1, 2, 0, 0] b = [1, 8, 0, 0] assert(ntt_convolute(a, b) == [1, 10, 16, 0]) assert(21 * 81 == (1*10**0 + 10*10**1 + 16*10**2 + 0*10**3)) mpdecimal-4.0.1/libmpdec/literature/matrix-transform.txt0000644000000000000000000002021415005764474020425 0ustar00 (* Copyright (c) 2011-2025 Stefan Krah. All rights reserved. *) The Matrix Fourier Transform: ============================= In libmpdec, the Matrix Fourier Transform [1] is called four-step transform after a variant that appears in [2]. The algorithm requires that the input array can be viewed as an R*C matrix. All operations are done modulo p. For readability, the proofs drop all instances of (mod p). Algorithm four-step (forward transform): ---------------------------------------- a := input array d := len(a) = R * C p := prime w := primitive root of unity of the prime field r := w**((p-1)/d) A := output array 1) Apply a length R FNT to each column. 2) Multiply each matrix element (addressed by j*C+m) by r**(j*m). 3) Apply a length C FNT to each row. 4) Transpose the matrix. Proof (forward transform): -------------------------- The algorithm can be derived starting from the regular definition of the finite-field transform of length d: d-1 ,---- \ A[k] = | a[l] * r**(k * l) / `---- l = 0 The sum can be rearranged into the sum of the sums of columns: C-1 R-1 ,---- ,---- \ \ = | | a[i * C + j] * r**(k * (i * C + j)) / / `---- `---- j = 0 i = 0 Extracting a constant from the inner sum: C-1 R-1 ,---- ,---- \ \ = | r**k*j * | a[i * C + j] * r**(k * i * C) / / `---- `---- j = 0 i = 0 Without any loss of generality, let k = n * R + m, where n < C and m < R: C-1 R-1 ,---- ,---- \ \ A[n*R+m] = | r**(R*n*j) * r**(m*j) * | a[i*C+j] * r**(R*C*n*i) * r**(C*m*i) / / `---- `---- j = 0 i = 0 Since r = w ** ((p-1) / (R*C)): a) r**(R*C*n*i) = w**((p-1)*n*i) = 1 b) r**(C*m*i) = w**((p-1) / R) ** (m*i) = r_R ** (m*i) c) r**(R*n*j) = w**((p-1) / C) ** (n*j) = r_C ** (n*j) r_R := root of the subfield of length R. r_C := root of the subfield of length C. C-1 R-1 ,---- ,---- \ \ A[n*R+m] = | r_C**(n*j) * [ r**(m*j) * | a[i*C+j] * r_R**(m*i) ] / ^ / `---- | `---- 1) transform the columns j = 0 | i = 0 ^ | | `-- 2) multiply | `-- 3) transform the rows Note that the entire RHS is a function of n and m and that the results for each pair (n, m) are stored in Fortran order. Let the term in square brackets be f(m, j). Step 1) and 2) precalculate the term for all (m, j). After that, the original matrix is now a lookup table with the mth element in the jth column at location m * C + j. Let the complete RHS be g(m, n). Step 3) does an in-place transform of length n on all rows. After that, the original matrix is now a lookup table with the mth element in the nth column at location m * C + n. But each (m, n) pair should be written to location n * R + m. Therefore, step 4) transposes the result of step 3). Algorithm four-step (inverse transform): ---------------------------------------- A := input array d := len(A) = R * C p := prime d' := d**(p-2) # inverse of d w := primitive root of unity of the prime field r := w**((p-1)/d) # root of the subfield r' := w**((p-1) - (p-1)/d) # inverse of r a := output array 0) View the matrix as a C*R matrix. 1) Transpose the matrix, producing an R*C matrix. 2) Apply a length C FNT to each row. 3) Multiply each matrix element (addressed by i*C+n) by r**(i*n). 4) Apply a length R FNT to each column. Proof (inverse transform): -------------------------- The algorithm can be derived starting from the regular definition of the finite-field inverse transform of length d: d-1 ,---- \ a[k] = d' * | A[l] * r' ** (k * l) / `---- l = 0 The sum can be rearranged into the sum of the sums of columns. Note that at this stage we still have a C*R matrix, so C denotes the number of rows: R-1 C-1 ,---- ,---- \ \ = d' * | | a[j * R + i] * r' ** (k * (j * R + i)) / / `---- `---- i = 0 j = 0 Extracting a constant from the inner sum: R-1 C-1 ,---- ,---- \ \ = d' * | r' ** (k*i) * | a[j * R + i] * r' ** (k * j * R) / / `---- `---- i = 0 j = 0 Without any loss of generality, let k = m * C + n, where m < R and n < C: R-1 C-1 ,---- ,---- \ \ A[m*C+n] = d' * | r' ** (C*m*i) * r' ** (n*i) * | a[j*R+i] * r' ** (R*C*m*j) * r' ** (R*n*j) / / `---- `---- i = 0 j = 0 Since r' = w**((p-1) - (p-1)/d) and d = R*C: a) r' ** (R*C*m*j) = w**((p-1)*R*C*m*j - (p-1)*m*j) = 1 b) r' ** (C*m*i) = w**((p-1)*C - (p-1)/R) ** (m*i) = r_R' ** (m*i) c) r' ** (R*n*j) = r_C' ** (n*j) d) d' = d**(p-2) = (R*C) ** (p-2) = R**(p-2) * C**(p-2) = R' * C' r_R' := inverse of the root of the subfield of length R. r_C' := inverse of the root of the subfield of length C. R' := inverse of R C' := inverse of C R-1 C-1 ,---- ,---- 2) transform the rows of a^T \ \ A[m*C+n] = R' * | r_R' ** (m*i) * [ r' ** (n*i) * C' * | a[j*R+i] * r_C' ** (n*j) ] / ^ / ^ `---- | `---- | i = 0 | j = 0 | ^ | `-- 1) Transpose input matrix | `-- 3) multiply to address elements by | i * C + j `-- 3) transform the columns Note that the entire RHS is a function of m and n and that the results for each pair (m, n) are stored in C order. Let the term in square brackets be f(n, i). Without step 1), the sum would perform a length C transform on the columns of the input matrix. This is a) inefficient and b) the results are needed in C order, so step 1) exchanges rows and columns. Step 2) and 3) precalculate f(n, i) for all (n, i). After that, the original matrix is now a lookup table with the ith element in the nth column at location i * C + n. Let the complete RHS be g(m, n). Step 4) does an in-place transform of length m on all columns. After that, the original matrix is now a lookup table with the mth element in the nth column at location m * C + n, which means that all A[k] = A[m * C + n] are in the correct order. -- [1] Joerg Arndt: "Matters Computational" http://www.jjj.de/fxt/ [2] David H. Bailey: FFTs in External or Hierarchical Memory http://crd.lbl.gov/~dhbailey/dhbpapers/ mpdecimal-4.0.1/libmpdec/literature/mulmod-64.txt0000644000000000000000000000563015005764474016641 0ustar00 (* Copyright (c) 2011-2025 Stefan Krah. All rights reserved. *) ========================================================================== Calculate (a * b) % p using special primes ========================================================================== A description of the algorithm can be found in the apfloat manual by Tommila [1]. Definitions: ------------ In the whole document, "==" stands for "is congruent with". Result of a * b in terms of high/low words: (1) hi * 2**64 + lo = a * b Special primes: (2) p = 2**64 - z + 1, where z = 2**n Single step modular reduction: (3) R(hi, lo) = hi * z - hi + lo Strategy: --------- a) Set (hi, lo) to the result of a * b. b) Set (hi', lo') to the result of R(hi, lo). c) Repeat step b) until 0 <= hi' * 2**64 + lo' < 2*p. d) If the result is less than p, return lo'. Otherwise return lo' - p. The reduction step b) preserves congruence: ------------------------------------------- hi * 2**64 + lo == hi * z - hi + lo (mod p) Proof: ~~~~~~ hi * 2**64 + lo = (2**64 - z + 1) * hi + z * hi - hi + lo = p * hi + z * hi - hi + lo == z * hi - hi + lo (mod p) Maximum numbers of step b): --------------------------- # To avoid unnecessary formalism, define: def R(hi, lo, z): return divmod(hi * z - hi + lo, 2**64) # For simplicity, assume hi=2**64-1, lo=2**64-1 after the # initial multiplication a * b. This is of course impossible # but certainly covers all cases. # Then, for p1: hi=2**64-1; lo=2**64-1; z=2**32 p1 = 2**64 - z + 1 hi, lo = R(hi, lo, z) # First reduction hi, lo = R(hi, lo, z) # Second reduction hi * 2**64 + lo < 2 * p1 # True # For p2: hi=2**64-1; lo=2**64-1; z=2**34 p2 = 2**64 - z + 1 hi, lo = R(hi, lo, z) # First reduction hi, lo = R(hi, lo, z) # Second reduction hi, lo = R(hi, lo, z) # Third reduction hi * 2**64 + lo < 2 * p2 # True # For p3: hi=2**64-1; lo=2**64-1; z=2**40 p3 = 2**64 - z + 1 hi, lo = R(hi, lo, z) # First reduction hi, lo = R(hi, lo, z) # Second reduction hi, lo = R(hi, lo, z) # Third reduction hi * 2**64 + lo < 2 * p3 # True Step d) preserves congruence and yields a result < p: ----------------------------------------------------- Case hi = 0: Case lo < p: trivial. Case lo >= p: lo == lo - p (mod p) # result is congruent p <= lo < 2*p -> 0 <= lo - p < p # result is in the correct range Case hi = 1: p < 2**64 /\ 2**64 + lo < 2*p -> lo < p # lo is always less than p 2**64 + lo == 2**64 + (lo - p) (mod p) # result is congruent = lo - p # exactly the same value as the previous RHS # in uint64_t arithmetic. p < 2**64 + lo < 2*p -> 0 < 2**64 + (lo - p) < p # correct range [1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf mpdecimal-4.0.1/libmpdec/literature/mulmod-ppro.txt0000644000000000000000000001551015005764474017366 0ustar00 (* Copyright (c) 2011-2025 Stefan Krah. All rights reserved. *) ======================================================================== Calculate (a * b) % p using the 80-bit x87 FPU ======================================================================== A description of the algorithm can be found in the apfloat manual by Tommila [1]. The proof follows an argument made by Granlund/Montgomery in [2]. Definitions and assumptions: ---------------------------- The 80-bit extended precision format uses 64 bits for the significand: (1) F = 64 The modulus is prime and less than 2**31: (2) 2 <= p < 2**31 The factors are less than p: (3) 0 <= a < p (4) 0 <= b < p The product a * b is less than 2**62 and is thus exact in 64 bits: (5) n = a * b The product can be represented in terms of quotient and remainder: (6) n = q * p + r Using (3), (4) and the fact that p is prime, the remainder is always greater than zero: (7) 0 <= q < p /\ 1 <= r < p Strategy: --------- Precalculate the 80-bit long double inverse of p, with a maximum relative error of 2**(1-F): (8) pinv = (long double)1.0 / p Calculate an estimate for q = floor(n/p). The multiplication has another maximum relative error of 2**(1-F): (9) qest = n * pinv If we can show that q < qest < q+1, then trunc(qest) = q. It is then easy to recover the remainder r. The complete algorithm is: a) Set the control word to 64-bit precision and truncation mode. b) n = a * b # Calculate exact product. c) qest = n * pinv # Calculate estimate for the quotient. d) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient. f) r = n - q * p # Calculate remainder. Proof for q < qest < q+1: ------------------------- Using the cumulative error, the error bounds for qest are: n n * (1 + 2**(1-F))**2 (9) --------------------- <= qest <= --------------------- p * (1 + 2**(1-F))**2 p Lemma 1: -------- n q * p + r (10) q < --------------------- = --------------------- p * (1 + 2**(1-F))**2 p * (1 + 2**(1-F))**2 Proof: ~~~~~~ (I) q * p * (1 + 2**(1-F))**2 < q * p + r (II) q * p * 2**(2-F) + q * p * 2**(2-2*F) < r Using (1) and (7), it is sufficient to show that: (III) q * p * 2**(-62) + q * p * 2**(-126) < 1 <= r (III) can easily be verified by substituting the largest possible values p = 2**31-1 and q = 2**31-2. The critical cases occur when r = 1, n = m * p + 1. These cases can be exhaustively verified with a test program. Lemma 2: -------- n * (1 + 2**(1-F))**2 (q * p + r) * (1 + 2**(1-F))**2 (11) --------------------- = ------------------------------- < q + 1 p p Proof: ~~~~~~ (I) (q * p + r) + (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < q * p + p (II) (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < p - r Using (1) and (7), it is sufficient to show that: (III) (q * p + r) * 2**(-62) + (q * p + r) * 2**(-126) < 1 <= p - r (III) can easily be verified by substituting the largest possible values p = 2**31-1, q = 2**31-2 and r = 2**31-2. The critical cases occur when r = (p - 1), n = m * p - 1. These cases can be exhaustively verified with a test program. [1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf [2] http://gmplib.org/~tege/divcnst-pldi94.pdf [Section 7: "Use of floating point"] (* Coq proof for (10) and (11) *) Require Import ZArith. Require Import QArith. Require Import Qpower. Require Import Qabs. Require Import Psatz. Open Scope Q_scope. Ltac qreduce T := rewrite <- (Qred_correct (T)); simpl (Qred (T)). Theorem Qlt_move_right : forall x y z:Q, x + z < y <-> x < y - z. Proof. intros. split. intros. psatzl Q. intros. psatzl Q. Qed. Theorem Qlt_mult_by_z : forall x y z:Q, 0 < z -> (x < y <-> x * z < y * z). Proof. intros. split. intros. apply Qmult_lt_compat_r. trivial. trivial. intros. rewrite <- (Qdiv_mult_l x z). rewrite <- (Qdiv_mult_l y z). apply Qmult_lt_compat_r. apply Qlt_shift_inv_l. trivial. psatzl Q. trivial. psatzl Q. psatzl Q. Qed. Theorem Qle_mult_quad : forall (a b c d:Q), 0 <= a -> a <= c -> 0 <= b -> b <= d -> a * b <= c * d. intros. psatz Q. Qed. Theorem q_lt_qest: forall (p q r:Q), (0 < p) -> (p <= (2#1)^31 - 1) -> (0 <= q) -> (q <= p - 1) -> (1 <= r) -> (r <= p - 1) -> q < (q * p + r) / (p * (1 + (2#1)^(-63))^2). Proof. intros. rewrite Qlt_mult_by_z with (z := (p * (1 + (2#1)^(-63))^2)). unfold Qdiv. rewrite <- Qmult_assoc. rewrite (Qmult_comm (/ (p * (1 + (2 # 1) ^ (-63)) ^ 2)) (p * (1 + (2 # 1) ^ (-63)) ^ 2)). rewrite Qmult_inv_r. rewrite Qmult_1_r. assert (q * (p * (1 + (2 # 1) ^ (-63)) ^ 2) == q * p + (q * p) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))). qreduce ((1 + (2 # 1) ^ (-63)) ^ 2). qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). ring_simplify. reflexivity. rewrite H5. rewrite Qplus_comm. rewrite Qlt_move_right. ring_simplify (q * p + r - q * p). qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). apply Qlt_le_trans with (y := 1). rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617). ring_simplify. apply Qle_lt_trans with (y := ((2 # 1) ^ 31 - (2#1)) * ((2 # 1) ^ 31 - 1)). apply Qle_mult_quad. assumption. psatzl Q. psatzl Q. psatzl Q. psatzl Q. psatzl Q. assumption. psatzl Q. psatzl Q. Qed. Theorem qest_lt_qplus1: forall (p q r:Q), (0 < p) -> (p <= (2#1)^31 - 1) -> (0 <= q) -> (q <= p - 1) -> (1 <= r) -> (r <= p - 1) -> ((q * p + r) * (1 + (2#1)^(-63))^2) / p < q + 1. Proof. intros. rewrite Qlt_mult_by_z with (z := p). unfold Qdiv. rewrite <- Qmult_assoc. rewrite (Qmult_comm (/ p) p). rewrite Qmult_inv_r. rewrite Qmult_1_r. assert ((q * p + r) * (1 + (2 # 1) ^ (-63)) ^ 2 == q * p + r + (q * p + r) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))). qreduce ((1 + (2 # 1) ^ (-63)) ^ 2). qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). ring_simplify. reflexivity. rewrite H5. rewrite <- Qplus_assoc. rewrite <- Qplus_comm. rewrite Qlt_move_right. ring_simplify ((q + 1) * p - q * p). rewrite <- Qplus_comm. rewrite Qlt_move_right. apply Qlt_le_trans with (y := 1). qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617). ring_simplify. ring_simplify in H0. apply Qle_lt_trans with (y := (2147483646 # 1) * (2147483647 # 1) + (2147483646 # 1)). apply Qplus_le_compat. apply Qle_mult_quad. assumption. psatzl Q. auto with qarith. assumption. psatzl Q. auto with qarith. auto with qarith. psatzl Q. psatzl Q. assumption. Qed. mpdecimal-4.0.1/libmpdec/literature/six-step.txt0000644000000000000000000000271715005764474016674 0ustar00 (* Copyright (c) 2011-2025 Stefan Krah. All rights reserved. *) The Six Step Transform: ======================= In libmpdec, the six-step transform is the Matrix Fourier Transform (See matrix-transform.txt) in disguise. It is called six-step transform after a variant that appears in [1]. The algorithm requires that the input array can be viewed as an R*C matrix. Algorithm six-step (forward transform): --------------------------------------- 1a) Transpose the matrix. 1b) Apply a length R FNT to each row. 1c) Transpose the matrix. 2) Multiply each matrix element (addressed by j*C+m) by r**(j*m). 3) Apply a length C FNT to each row. 4) Transpose the matrix. Note that steps 1a) - 1c) are exactly equivalent to step 1) of the Matrix Fourier Transform. For large R, it is faster to transpose twice and do a transform on the rows than to perform a column transpose directly. Algorithm six-step (inverse transform): --------------------------------------- 0) View the matrix as a C*R matrix. 1) Transpose the matrix, producing an R*C matrix. 2) Apply a length C FNT to each row. 3) Multiply each matrix element (addressed by i*C+n) by r**(i*n). 4a) Transpose the matrix. 4b) Apply a length R FNT to each row. 4c) Transpose the matrix. Again, steps 4a) - 4c) are equivalent to step 4) of the Matrix Fourier Transform. -- [1] David H. Bailey: FFTs in External or Hierarchical Memory http://crd.lbl.gov/~dhbailey/dhbpapers/ mpdecimal-4.0.1/libmpdec/literature/umodarith.lisp0000644000000000000000000006000215005764474017233 0ustar00; ; Copyright (c) 2008-2025 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. ; (in-package "ACL2") (include-book "arithmetic/top-with-meta" :dir :system) (include-book "arithmetic-2/floor-mod/floor-mod" :dir :system) ;; ===================================================================== ;; Proofs for several functions in umodarith.h ;; ===================================================================== ;; ===================================================================== ;; Helper theorems ;; ===================================================================== (defthm elim-mod-m= s m) (mod (- s m) base) s))) s)) (defthmd addmod-correct (implies (and (< 0 m) (< m base) (< a m) (<= b m) (natp m) (natp base) (natp a) (natp b)) (equal (addmod a b m base) (mod (+ a b) m))) :hints (("Goal" :cases ((<= base (+ a b)))) ("Subgoal 2.1'" :use ((:instance elim-mod-m= a m) (- a m) a)) (b (if (>= b m) (- b m) b)) (d (mod (- a b) base)) (d (if (< a b) (mod (+ d m) base) d))) d)) ; a < 2*m, b < 2*m (defun ext-submod-2 (a b m base) (let* ((a (mod a m)) (b (mod b m)) (d (mod (- a b) base)) (d (if (< a b) (mod (+ d m) base) d))) d)) (defthmd ext-submod-ext-submod-2-equal (implies (and (< 0 m) (< m base) (< a (* 2 m)) (< b (* 2 m)) (natp m) (natp base) (natp a) (natp b)) (equal (ext-submod a b m base) (ext-submod-2 a b m base)))) (defthmd ext-submod-2-correct (implies (and (< 0 m) (< m base) (< a (* 2 m)) (< b (* 2 m)) (natp m) (natp base) (natp a) (natp b)) (equal (ext-submod-2 a b m base) (mod (- a b) m)))) ;; ========================================================================= ;; dw-reduce is correct ;; ========================================================================= (defun dw-reduce (hi lo m base) (let* ((r1 (mod hi m)) (r2 (mod (+ (* r1 base) lo) m))) r2)) (defthmd dw-reduce-correct (implies (and (< 0 m) (< m base) (< hi base) (< lo base) (natp m) (natp base) (natp hi) (natp lo)) (equal (dw-reduce hi lo m base) (mod (+ (* hi base) lo) m)))) (defthmd <=-multiply-both-sides-by-z (implies (and (rationalp x) (rationalp y) (< 0 z) (rationalp z)) (equal (<= x y) (<= (* z x) (* z y))))) (defthmd dw-reduce-aux1 (implies (and (< 0 m) (< m base) (natp m) (natp base) (< lo base) (natp lo) (< x m) (natp x)) (< (+ lo (* base x)) (* base m))) :hints (("Goal" :cases ((<= (+ x 1) m))) ("Subgoal 1''" :cases ((<= (* base (+ x 1)) (* base m)))) ("subgoal 1.2" :use ((:instance <=-multiply-both-sides-by-z (x (+ 1 x)) (y m) (z base)))))) (defthm dw-reduce-aux2 (implies (and (< x (* base m)) (< 0 m) (< m base) (natp m) (natp base) (natp x)) (< (floor x m) base))) ;; This is the necessary condition for using _mpd_div_words(). (defthmd dw-reduce-second-quotient-fits-in-single-word (implies (and (< 0 m) (< m base) (< hi base) (< lo base) (natp m) (natp base) (natp hi) (natp lo) (equal r1 (mod hi m))) (< (floor (+ (* r1 base) lo) m) base)) :hints (("Goal" :cases ((< r1 m))) ("Subgoal 1''" :cases ((< (+ lo (* base (mod hi m))) (* base m)))) ("Subgoal 1.2" :use ((:instance dw-reduce-aux1 (x (mod hi m))))))) ;; ========================================================================= ;; dw-submod is correct ;; ========================================================================= (defun dw-submod (a hi lo m base) (let* ((r (dw-reduce hi lo m base)) (d (mod (- a r) base)) (d (if (< a r) (mod (+ d m) base) d))) d)) (defthmd dw-submod-aux1 (implies (and (natp a) (< 0 m) (natp m) (natp x) (equal r (mod x m))) (equal (mod (- a x) m) (mod (- a r) m)))) (defthmd dw-submod-correct (implies (and (< 0 m) (< m base) (natp a) (< a m) (< hi base) (< lo base) (natp m) (natp base) (natp hi) (natp lo)) (equal (dw-submod a hi lo m base) (mod (- a (+ (* base hi) lo)) m))) :hints (("Goal" :in-theory (disable dw-reduce) :use ((:instance dw-submod-aux1 (x (+ lo (* base hi))) (r (dw-reduce hi lo m base))) (:instance dw-reduce-correct))))) ;; ========================================================================= ;; ANSI C arithmetic for uint64_t ;; ========================================================================= (defun add (a b) (mod (+ a b) (expt 2 64))) (defun sub (a b) (mod (- a b) (expt 2 64))) (defun << (w n) (mod (* w (expt 2 n)) (expt 2 64))) (defun >> (w n) (floor w (expt 2 n))) ;; join upper and lower half of a double word, yielding a 128 bit number (defun join (hi lo) (+ (* (expt 2 64) hi) lo)) ;; ============================================================================= ;; Fast modular reduction ;; ============================================================================= ;; These are the three primes used in the Number Theoretic Transform. ;; A fast modular reduction scheme exists for all of them. (defmacro p1 () (+ (expt 2 64) (- (expt 2 32)) 1)) (defmacro p2 () (+ (expt 2 64) (- (expt 2 34)) 1)) (defmacro p3 () (+ (expt 2 64) (- (expt 2 40)) 1)) ;; reduce the double word number hi*2**64 + lo (mod p1) (defun simple-mod-reduce-p1 (hi lo) (+ (* (expt 2 32) hi) (- hi) lo)) ;; reduce the double word number hi*2**64 + lo (mod p2) (defun simple-mod-reduce-p2 (hi lo) (+ (* (expt 2 34) hi) (- hi) lo)) ;; reduce the double word number hi*2**64 + lo (mod p3) (defun simple-mod-reduce-p3 (hi lo) (+ (* (expt 2 40) hi) (- hi) lo)) ; ---------------------------------------------------------- ; The modular reductions given above are correct ; ---------------------------------------------------------- (defthmd congruence-p1-aux (equal (* (expt 2 64) hi) (+ (* (p1) hi) (* (expt 2 32) hi) (- hi)))) (defthmd congruence-p2-aux (equal (* (expt 2 64) hi) (+ (* (p2) hi) (* (expt 2 34) hi) (- hi)))) (defthmd congruence-p3-aux (equal (* (expt 2 64) hi) (+ (* (p3) hi) (* (expt 2 40) hi) (- hi)))) (defthmd mod-augment (implies (and (rationalp x) (rationalp y) (rationalp m)) (equal (mod (+ x y) m) (mod (+ x (mod y m)) m)))) (defthmd simple-mod-reduce-p1-congruent (implies (and (integerp hi) (integerp lo)) (equal (mod (simple-mod-reduce-p1 hi lo) (p1)) (mod (join hi lo) (p1)))) :hints (("Goal''" :use ((:instance congruence-p1-aux) (:instance mod-augment (m (p1)) (x (+ (- hi) lo (* (expt 2 32) hi))) (y (* (p1) hi))))))) (defthmd simple-mod-reduce-p2-congruent (implies (and (integerp hi) (integerp lo)) (equal (mod (simple-mod-reduce-p2 hi lo) (p2)) (mod (join hi lo) (p2)))) :hints (("Goal''" :use ((:instance congruence-p2-aux) (:instance mod-augment (m (p2)) (x (+ (- hi) lo (* (expt 2 34) hi))) (y (* (p2) hi))))))) (defthmd simple-mod-reduce-p3-congruent (implies (and (integerp hi) (integerp lo)) (equal (mod (simple-mod-reduce-p3 hi lo) (p3)) (mod (join hi lo) (p3)))) :hints (("Goal''" :use ((:instance congruence-p3-aux) (:instance mod-augment (m (p3)) (x (+ (- hi) lo (* (expt 2 40) hi))) (y (* (p3) hi))))))) ; --------------------------------------------------------------------- ; We need a number less than 2*p, so that we can use the trick from ; elim-mod-m> hi 32)) (x (sub lo x)) (hi (if (> x lo) (+ hi -1) hi)) (y (<< y 32)) (lo (add y x)) (hi (if (< lo y) (+ hi 1) hi))) (+ (* hi (expt 2 64)) lo))) (defun mod-reduce-p2 (hi lo) (let* ((y hi) (x y) (hi (>> hi 30)) (x (sub lo x)) (hi (if (> x lo) (+ hi -1) hi)) (y (<< y 34)) (lo (add y x)) (hi (if (< lo y) (+ hi 1) hi))) (+ (* hi (expt 2 64)) lo))) (defun mod-reduce-p3 (hi lo) (let* ((y hi) (x y) (hi (>> hi 24)) (x (sub lo x)) (hi (if (> x lo) (+ hi -1) hi)) (y (<< y 40)) (lo (add y x)) (hi (if (< lo y) (+ hi 1) hi))) (+ (* hi (expt 2 64)) lo))) ; ------------------------------------------------------------------------- ; The compiler friendly versions are equal to the simple versions ; ------------------------------------------------------------------------- (defthm mod-reduce-aux1 (implies (and (<= 0 a) (natp a) (natp m) (< (- m) b) (<= b 0) (integerp b) (< (mod (+ b a) m) (mod a m))) (equal (mod (+ b a) m) (+ b (mod a m)))) :hints (("Subgoal 2" :use ((:instance modaux-1b (x (+ a b))))))) (defthm mod-reduce-aux2 (implies (and (<= 0 a) (natp a) (natp m) (< b m) (natp b) (< (mod (+ b a) m) (mod a m))) (equal (+ m (mod (+ b a) m)) (+ b (mod a m))))) (defthm mod-reduce-aux3 (implies (and (< 0 a) (natp a) (natp m) (< (- m) b) (< b 0) (integerp b) (<= (mod a m) (mod (+ b a) m))) (equal (+ (- m) (mod (+ b a) m)) (+ b (mod a m)))) :hints (("Subgoal 1.2'" :use ((:instance modaux-1b (x b)))) ("Subgoal 1''" :use ((:instance modaux-2d (x I)))))) (defthm mod-reduce-aux4 (implies (and (< 0 a) (natp a) (natp m) (< b m) (natp b) (<= (mod a m) (mod (+ b a) m))) (equal (mod (+ b a) m) (+ b (mod a m))))) (defthm mod-reduce-p1==simple-mod-reduce-p1 (implies (and (< hi (expt 2 64)) (< lo (expt 2 64)) (natp hi) (natp lo)) (equal (mod-reduce-p1 hi lo) (simple-mod-reduce-p1 hi lo))) :hints (("Goal" :in-theory (disable expt) :cases ((< 0 hi))) ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 32) hi))))) ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 32) hi))))) ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 32) hi))))) ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 32) hi))))))) (defthm mod-reduce-p2==simple-mod-reduce-p2 (implies (and (< hi (expt 2 64)) (< lo (expt 2 64)) (natp hi) (natp lo)) (equal (mod-reduce-p2 hi lo) (simple-mod-reduce-p2 hi lo))) :hints (("Goal" :cases ((< 0 hi))) ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 34) hi))))) ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 34) hi))))) ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 34) hi))))) ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 34) hi))))))) (defthm mod-reduce-p3==simple-mod-reduce-p3 (implies (and (< hi (expt 2 64)) (< lo (expt 2 64)) (natp hi) (natp lo)) (equal (mod-reduce-p3 hi lo) (simple-mod-reduce-p3 hi lo))) :hints (("Goal" :cases ((< 0 hi))) ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 40) hi))))) ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 40) hi))))) ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 40) hi))))) ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 (m (expt 2 64)) (b (+ (- HI) LO)) (a (* (expt 2 40) hi))))))) mpdecimal-4.0.1/libmpdec/mpalloc.c0000644000000000000000000002202415005764474013763 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include #include "mpalloc.h" #include "mpdecimal.h" #include "typearith.h" #if defined(_MSC_VER) #pragma warning(disable : 4232) #endif /* Guaranteed minimum allocation for a coefficient. May be changed once at program start using mpd_setminalloc(). */ mpd_ssize_t MPD_MINALLOC = MPD_MINALLOC_MIN; /* Custom allocation and free functions */ void *(* mpd_mallocfunc)(size_t size) = malloc; void *(* mpd_reallocfunc)(void *ptr, size_t size) = realloc; void *(* mpd_callocfunc)(size_t nmemb, size_t size) = calloc; void (* mpd_free)(void *ptr) = free; /* emulate calloc if it is not available */ void * mpd_callocfunc_em(size_t nmemb, size_t size) { void *ptr; size_t req; mpd_size_t overflow; req = mul_size_t_overflow((mpd_size_t)nmemb, (mpd_size_t)size, &overflow); if (overflow) { return NULL; } ptr = mpd_mallocfunc(req); if (ptr == NULL) { return NULL; } /* used on uint32_t or uint64_t */ memset(ptr, 0, req); return ptr; } /* malloc with overflow checking */ void * mpd_alloc(mpd_size_t nmemb, mpd_size_t size) { mpd_size_t req, overflow; req = mul_size_t_overflow(nmemb, size, &overflow); if (overflow) { return NULL; } return mpd_mallocfunc(req); } /* calloc with overflow checking */ void * mpd_calloc(mpd_size_t nmemb, mpd_size_t size) { mpd_size_t overflow; (void)mul_size_t_overflow(nmemb, size, &overflow); if (overflow) { return NULL; } return mpd_callocfunc(nmemb, size); } /* realloc with overflow checking */ void * mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err) { void *new; mpd_size_t req, overflow; req = mul_size_t_overflow(nmemb, size, &overflow); if (overflow) { *err = 1; return ptr; } new = mpd_reallocfunc(ptr, req); if (new == NULL) { *err = 1; return ptr; } return new; } /* struct hack malloc with overflow checking */ void * mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size) { mpd_size_t req, overflow; req = mul_size_t_overflow(nmemb, size, &overflow); if (overflow) { return NULL; } req = add_size_t_overflow(req, struct_size, &overflow); if (overflow) { return NULL; } return mpd_mallocfunc(req); } /* Allocate a new decimal with a coefficient of length 'nwords'. In case of an error the return value is NULL. */ mpd_t * mpd_qnew_size(mpd_ssize_t nwords) { mpd_t *result; nwords = (nwords < MPD_MINALLOC) ? MPD_MINALLOC : nwords; result = mpd_alloc(1, sizeof *result); if (result == NULL) { return NULL; } result->data = mpd_alloc(nwords, sizeof *result->data); if (result->data == NULL) { mpd_free(result); return NULL; } result->flags = 0; result->exp = 0; result->digits = 0; result->len = 0; result->alloc = nwords; return result; } /* Allocate a new decimal with a coefficient of length MPD_MINALLOC. In case of an error the return value is NULL. */ mpd_t * mpd_qnew(void) { return mpd_qnew_size(MPD_MINALLOC); } /* Allocate new decimal. Caller can check for NULL or MPD_Malloc_error. Raises on error. */ mpd_t * mpd_new(mpd_context_t *ctx) { mpd_t *result; result = mpd_qnew(); if (result == NULL) { mpd_addstatus_raise(ctx, MPD_Malloc_error); } return result; } /* * Input: 'result' is a static mpd_t with a static coefficient. * Assumption: 'nwords' >= result->alloc. * * Resize the static coefficient to a larger dynamic one and copy the * existing data. If successful, the value of 'result' is unchanged. * Otherwise, set 'result' to NaN and update 'status' with MPD_Malloc_error. */ int mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) { mpd_uint_t *p = result->data; assert(nwords >= result->alloc); result->data = mpd_alloc(nwords, sizeof *result->data); if (result->data == NULL) { result->data = p; mpd_set_qnan(result); mpd_set_positive(result); result->exp = result->digits = result->len = 0; *status |= MPD_Malloc_error; return 0; } memcpy(result->data, p, result->alloc * (sizeof *result->data)); result->alloc = nwords; mpd_set_dynamic_data(result); return 1; } /* * Input: 'result' is a static mpd_t with a static coefficient. * * Convert the coefficient to a dynamic one that is initialized to zero. If * malloc fails, set 'result' to NaN and update 'status' with MPD_Malloc_error. */ int mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) { mpd_uint_t *p = result->data; result->data = mpd_calloc(nwords, sizeof *result->data); if (result->data == NULL) { result->data = p; mpd_set_qnan(result); mpd_set_positive(result); result->exp = result->digits = result->len = 0; *status |= MPD_Malloc_error; return 0; } result->alloc = nwords; mpd_set_dynamic_data(result); return 1; } /* * Input: 'result' is a static or a dynamic mpd_t with a dynamic coefficient. * Resize the coefficient to length 'nwords': * Case nwords > result->alloc: * If realloc is successful: * 'result' has a larger coefficient but the same value. Return 1. * Otherwise: * Set 'result' to NaN, update status with MPD_Malloc_error and return 0. * Case nwords < result->alloc: * If realloc is successful: * 'result' has a smaller coefficient. result->len is undefined. Return 1. * Otherwise (unlikely): * 'result' is unchanged. Reuse the now oversized coefficient. Return 1. */ int mpd_realloc_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) { uint8_t err = 0; result->data = mpd_realloc(result->data, nwords, sizeof *result->data, &err); if (!err) { result->alloc = nwords; } else if (nwords > result->alloc) { mpd_set_qnan(result); mpd_set_positive(result); result->exp = result->digits = result->len = 0; *status |= MPD_Malloc_error; return 0; } return 1; } /* * Input: 'result' is a static mpd_t with a static coefficient. * Assumption: 'nwords' >= result->alloc. * * Resize the static coefficient to a larger dynamic one and copy the * existing data. * * On failure the value of 'result' is unchanged. */ int mpd_switch_to_dyn_cxx(mpd_t *result, mpd_ssize_t nwords) { assert(nwords >= result->alloc); mpd_uint_t *data = mpd_alloc(nwords, sizeof *result->data); if (data == NULL) { return 0; } memcpy(data, result->data, result->alloc * (sizeof *result->data)); result->data = data; result->alloc = nwords; mpd_set_dynamic_data(result); return 1; } /* * Input: 'result' is a static or a dynamic mpd_t with a dynamic coefficient. * Resize the coefficient to length 'nwords': * Case nwords > result->alloc: * If realloc is successful: * 'result' has a larger coefficient but the same value. Return 1. * Otherwise: * 'result' has a the same coefficient. Return 0. * Case nwords < result->alloc: * If realloc is successful: * 'result' has a smaller coefficient. result->len is undefined. Return 1. * Otherwise (unlikely): * 'result' is unchanged. Reuse the now oversized coefficient. Return 1. */ int mpd_realloc_dyn_cxx(mpd_t *result, mpd_ssize_t nwords) { uint8_t err = 0; mpd_uint_t *p = mpd_realloc(result->data, nwords, sizeof *result->data, &err); if (!err) { result->data = p; result->alloc = nwords; } else if (nwords > result->alloc) { return 0; } return 1; } mpdecimal-4.0.1/libmpdec/mpalloc.h0000644000000000000000000000375515005764474014002 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_MPALLOC_H_ #define LIBMPDEC_MPALLOC_H_ #include #include "mpdecimal.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) int mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); int mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); int mpd_realloc_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); int mpd_switch_to_dyn_cxx(mpd_t *result, mpd_ssize_t nwords); int mpd_realloc_dyn_cxx(mpd_t *result, mpd_ssize_t nwords); MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_MPALLOC_H_ */ mpdecimal-4.0.1/libmpdec/mpdecimal.c0000644000000000000000000075526315005764474014311 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include #include #include #include "basearith.h" #include "bits.h" #include "constants.h" #include "convolute.h" #include "crt.h" #include "mpalloc.h" #include "mpdecimal.h" #include "typearith.h" #ifdef PPRO #if defined(_MSC_VER) #include #pragma float_control(precise, on) #pragma fenv_access(on) #elif !defined(__OpenBSD__) && !defined(__NetBSD__) /* The C99 standard requires the pragma */ #include #pragma STDC FENV_ACCESS ON #endif #endif /* Disable warning that is part of -Wextra since gcc 7.0 */ #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && __GNUC__ >= 7 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #endif #if defined(_MSC_VER) #define ALWAYS_INLINE __forceinline #elif defined (__IBMC__) || defined(__COMPCERT__) || defined(LEGACY_COMPILER) #define ALWAYS_INLINE #undef inline #define inline #else #ifdef TEST_COVERAGE #define ALWAYS_INLINE #else #define ALWAYS_INLINE inline #endif #endif #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, const mpd_t *b, uint32_t *status); 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); static mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n); /******************************************************************************/ /* Version */ /******************************************************************************/ const char * mpd_version(void) { return MPD_VERSION; } /******************************************************************************/ /* Performance critical inline functions */ /******************************************************************************/ #ifdef CONFIG_64 /* Digits in a word, primarily useful for the most significant word. */ 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; } #else ALWAYS_INLINE int mpd_word_digits(mpd_uint_t word) { 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 (word < mpd_pow10[9]) ? 9 : 10; } #endif /* Adjusted exponent */ ALWAYS_INLINE mpd_ssize_t mpd_adjexp(const mpd_t *dec) { return (dec->exp + dec->digits) - 1; } /* Etiny */ 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 */ ALWAYS_INLINE mpd_ssize_t mpd_etop(const mpd_context_t *ctx) { return ctx->emax - (ctx->prec - 1); } /* Most significant word */ 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 */ ALWAYS_INLINE mpd_uint_t mpd_lsd(mpd_uint_t word) { return word % 10; } /* Coefficient size needed to store 'digits' */ 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 */ ALWAYS_INLINE int mpd_iscanonical(const mpd_t *dec) { (void)dec; return 1; } /* Finite */ ALWAYS_INLINE int mpd_isfinite(const mpd_t *dec) { return !(dec->flags & MPD_SPECIAL); } /* Infinite */ ALWAYS_INLINE int mpd_isinfinite(const mpd_t *dec) { return dec->flags & MPD_INF; } /* NaN */ ALWAYS_INLINE int mpd_isnan(const mpd_t *dec) { return dec->flags & (MPD_NAN|MPD_SNAN); } /* Negative */ ALWAYS_INLINE int mpd_isnegative(const mpd_t *dec) { return dec->flags & MPD_NEG; } /* Positive */ ALWAYS_INLINE int mpd_ispositive(const mpd_t *dec) { return !(dec->flags & MPD_NEG); } /* qNaN */ ALWAYS_INLINE int mpd_isqnan(const mpd_t *dec) { return dec->flags & MPD_NAN; } /* Signed */ ALWAYS_INLINE int mpd_issigned(const mpd_t *dec) { return dec->flags & MPD_NEG; } /* sNaN */ ALWAYS_INLINE int mpd_issnan(const mpd_t *dec) { return dec->flags & MPD_SNAN; } /* Special */ ALWAYS_INLINE int mpd_isspecial(const mpd_t *dec) { return dec->flags & MPD_SPECIAL; } /* Zero */ 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 */ 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 */ ALWAYS_INLINE int mpd_isoddword(mpd_uint_t word) { return word & 1; } /* Odd coefficient */ 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 */ 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 */ ALWAYS_INLINE int mpd_arith_sign(const mpd_t *dec) { return 1 - 2 * mpd_isnegative(dec); } /* Radix */ ALWAYS_INLINE long mpd_radix(void) { return 10; } /* Dynamic decimal */ ALWAYS_INLINE int mpd_isdynamic(const mpd_t *dec) { return !(dec->flags & MPD_STATIC); } /* Static decimal */ ALWAYS_INLINE int mpd_isstatic(const mpd_t *dec) { return dec->flags & MPD_STATIC; } /* Data of decimal is dynamic */ ALWAYS_INLINE int mpd_isdynamic_data(const mpd_t *dec) { return !(dec->flags & MPD_DATAFLAGS); } /* Data of decimal is static */ ALWAYS_INLINE int mpd_isstatic_data(const mpd_t *dec) { return dec->flags & MPD_STATIC_DATA; } /* Data of decimal is shared */ ALWAYS_INLINE int mpd_isshared_data(const mpd_t *dec) { return dec->flags & MPD_SHARED_DATA; } /* Data of decimal is const */ ALWAYS_INLINE int mpd_isconst_data(const mpd_t *dec) { return dec->flags & MPD_CONST_DATA; } /******************************************************************************/ /* Inline memory handling */ /******************************************************************************/ /* Fill destination with zeros */ 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 */ 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. */ 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 do not set the result to NaN on failure. */ static ALWAYS_INLINE int mpd_qresize_cxx(mpd_t *result, mpd_ssize_t nwords) { 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_cxx(result, nwords); } return 1; } return mpd_realloc_dyn_cxx(result, nwords); } /* Same as mpd_qresize, but the complete coefficient (including the old * memory area!) is initialized to zero. */ 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. */ 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 */ ALWAYS_INLINE void mpd_set_sign(mpd_t *result, uint8_t sign) { result->flags &= ~MPD_NEG; result->flags |= sign; } /* Copy sign from another decimal */ 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 */ ALWAYS_INLINE void mpd_set_infinity(mpd_t *result) { result->flags &= ~MPD_SPECIAL; result->flags |= MPD_INF; } /* Set qNaN */ ALWAYS_INLINE void mpd_set_qnan(mpd_t *result) { result->flags &= ~MPD_SPECIAL; result->flags |= MPD_NAN; } /* Set sNaN */ ALWAYS_INLINE void mpd_set_snan(mpd_t *result) { result->flags &= ~MPD_SPECIAL; result->flags |= MPD_SNAN; } /* Set to negative */ ALWAYS_INLINE void mpd_set_negative(mpd_t *result) { result->flags |= MPD_NEG; } /* Set to positive */ ALWAYS_INLINE void mpd_set_positive(mpd_t *result) { result->flags &= ~MPD_NEG; } /* Set to dynamic */ ALWAYS_INLINE void mpd_set_dynamic(mpd_t *result) { result->flags &= ~MPD_STATIC; } /* Set to static */ ALWAYS_INLINE void mpd_set_static(mpd_t *result) { result->flags |= MPD_STATIC; } /* Set data to dynamic */ ALWAYS_INLINE void mpd_set_dynamic_data(mpd_t *result) { result->flags &= ~MPD_DATAFLAGS; } /* Set data to static */ ALWAYS_INLINE void mpd_set_static_data(mpd_t *result) { result->flags &= ~MPD_DATAFLAGS; result->flags |= MPD_STATIC_DATA; } /* Set data to shared */ ALWAYS_INLINE void mpd_set_shared_data(mpd_t *result) { result->flags &= ~MPD_DATAFLAGS; result->flags |= MPD_SHARED_DATA; } /* Set data to const */ ALWAYS_INLINE void mpd_set_const_data(mpd_t *result) { result->flags &= ~MPD_DATAFLAGS; result->flags |= MPD_CONST_DATA; } /* Clear flags, preserving memory attributes. */ ALWAYS_INLINE void mpd_clear_flags(mpd_t *result) { result->flags &= (MPD_STATIC|MPD_DATAFLAGS); } /* Set flags, preserving memory attributes. */ 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. */ 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); } #ifdef CONFIG_64 /* 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); } #endif /* 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); } #if defined(CONFIG_32) && !defined(LEGACY_COMPILER) /* set a decimal from a uint64_t */ static void _c32setu64(mpd_t *result, uint64_t u, uint8_t sign, uint32_t *status) { mpd_uint_t w[3]; uint64_t q; int i, len; len = 0; do { q = u / MPD_RADIX; w[len] = (mpd_uint_t)(u - q * MPD_RADIX); u = q; len++; } while (u != 0); if (!mpd_qresize(result, len, status)) { return; } for (i = 0; i < len; i++) { result->data[i] = w[i]; } mpd_set_flags(result, sign); result->exp = 0; result->len = len; mpd_setdigits(result); } static void _c32_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status) { _c32setu64(result, a, MPD_POS, status); mpd_qfinalize(result, ctx, status); } /* set a decimal from an int64_t */ static void _c32_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status) { uint64_t u; uint8_t sign = MPD_POS; if (a < 0) { if (a == INT64_MIN) { u = (uint64_t)INT64_MAX + (-(INT64_MIN+INT64_MAX)); } else { u = -a; } sign = MPD_NEG; } else { u = a; } _c32setu64(result, u, sign, status); mpd_qfinalize(result, ctx, status); } #endif /* CONFIG_32 && !LEGACY_COMPILER */ #ifndef LEGACY_COMPILER /* 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) { #ifdef CONFIG_64 mpd_qset_ssize(result, a, ctx, status); #else _c32_qset_i64(result, a, ctx, status); #endif } /* quietly set a decimal from an int64_t, use a maxcontext for conversion */ void mpd_qset_i64_exact(mpd_t *result, int64_t a, uint32_t *status) { mpd_context_t maxcontext; uint32_t workstatus = 0; mpd_maxcontext(&maxcontext); #ifdef CONFIG_64 mpd_qset_ssize(result, a, &maxcontext, &workstatus); #else _c32_qset_i64(result, a, &maxcontext, &workstatus); #endif if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) { /* we want exact results */ mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_NOT_REACHED */ } *status |= (workstatus&MPD_Errors); } /* 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) { #ifdef CONFIG_64 mpd_qset_uint(result, a, ctx, status); #else _c32_qset_u64(result, a, ctx, status); #endif } /* quietly set a decimal from a uint64_t, use a maxcontext for conversion */ void mpd_qset_u64_exact(mpd_t *result, uint64_t a, uint32_t *status) { mpd_context_t maxcontext; uint32_t workstatus = 0; mpd_maxcontext(&maxcontext); #ifdef CONFIG_64 mpd_qset_uint(result, a, &maxcontext, &workstatus); #else _c32_qset_u64(result, a, &maxcontext, &workstatus); #endif if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) { /* we want exact results */ mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_NOT_REACHED */ } *status |= (workstatus&MPD_Errors); } #endif /* !LEGACY_COMPILER */ /* * 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) { uint32_t workstatus = 0; mpd_uint_t u; int isneg; u = mpd_qabs_uint(a, &workstatus); if (workstatus&MPD_Invalid_operation) { *status |= workstatus; 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_uint_t)(MPD_SSIZE_MIN+MPD_SSIZE_MAX) == MPD_SSIZE_MAX) { return MPD_SSIZE_MIN; } *status |= MPD_Invalid_operation; return MPD_SSIZE_MAX; } #if defined(CONFIG_32) && !defined(LEGACY_COMPILER) /* * Quietly get a uint64_t from a decimal. If the operation is impossible, * MPD_Invalid_operation is set. */ static uint64_t _c32_qget_u64(int use_sign, const mpd_t *a, uint32_t *status) { MPD_NEW_STATIC(tmp,0,0,20,3); mpd_context_t maxcontext; uint64_t ret; tmp_data[0] = 709551615; tmp_data[1] = 446744073; tmp_data[2] = 18; if (mpd_isspecial(a)) { *status |= MPD_Invalid_operation; return UINT64_MAX; } if (mpd_iszero(a)) { return 0; } if (use_sign && mpd_isnegative(a)) { *status |= MPD_Invalid_operation; return UINT64_MAX; } if (!_mpd_isint(a)) { *status |= MPD_Invalid_operation; return UINT64_MAX; } if (_mpd_cmp_abs(a, &tmp) > 0) { *status |= MPD_Invalid_operation; return UINT64_MAX; } mpd_maxcontext(&maxcontext); mpd_qrescale(&tmp, a, 0, &maxcontext, &maxcontext.status); maxcontext.status &= ~MPD_Rounded; if (maxcontext.status != 0) { *status |= (maxcontext.status|MPD_Invalid_operation); /* GCOV_NOT_REACHED */ return UINT64_MAX; /* GCOV_NOT_REACHED */ } ret = 0; switch (tmp.len) { case 3: ret += (uint64_t)tmp_data[2] * 1000000000000000000ULL; case 2: ret += (uint64_t)tmp_data[1] * 1000000000ULL; case 1: ret += tmp_data[0]; break; default: abort(); /* GCOV_NOT_REACHED */ } return ret; } static int64_t _c32_qget_i64(const mpd_t *a, uint32_t *status) { uint64_t u; int isneg; u = _c32_qget_u64(0, a, status); if (*status&MPD_Invalid_operation) { return INT64_MAX; } isneg = mpd_isnegative(a); if (u <= INT64_MAX) { return isneg ? -((int64_t)u) : (int64_t)u; } else if (isneg && u+(uint64_t)(INT64_MIN+INT64_MAX) == INT64_MAX) { return INT64_MIN; } *status |= MPD_Invalid_operation; return INT64_MAX; } #endif /* CONFIG_32 && !LEGACY_COMPILER */ #ifdef CONFIG_64 /* quietly get a uint64_t from a decimal */ uint64_t 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) { uint32_t workstatus = 0; uint64_t x = mpd_qget_uint(a, &workstatus); if (workstatus&MPD_Invalid_operation) { *status |= workstatus; 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) { uint32_t workstatus = 0; int64_t x = mpd_qget_ssize(a, &workstatus); if (workstatus&MPD_Invalid_operation) { *status |= workstatus; return INT32_MAX; } if (x < INT32_MIN || x > INT32_MAX) { *status |= MPD_Invalid_operation; return INT32_MAX; } return (int32_t)x; } #else #ifndef LEGACY_COMPILER /* quietly get a uint64_t from a decimal */ uint64_t mpd_qget_u64(const mpd_t *a, uint32_t *status) { uint32_t workstatus = 0; uint64_t x = _c32_qget_u64(1, a, &workstatus); *status |= workstatus; return x; } /* quietly get an int64_t from a decimal */ int64_t mpd_qget_i64(const mpd_t *a, uint32_t *status) { uint32_t workstatus = 0; int64_t x = _c32_qget_i64(a, &workstatus); *status |= workstatus; return x; } #endif /* quietly get a uint32_t from a decimal */ uint32_t mpd_qget_u32(const mpd_t *a, uint32_t *status) { return mpd_qget_uint(a, status); } /* quietly get an int32_t from a decimal */ int32_t mpd_qget_i32(const mpd_t *a, uint32_t *status) { return mpd_qget_ssize(a, status); } #endif /******************************************************************************/ /* 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; } /* Same as mpd_qcopy, but do not set the result to NaN on failure. */ int mpd_qcopy_cxx(mpd_t *result, const mpd_t *a) { if (result == a) return 1; if (!mpd_qresize_cxx(result, a->len)) { 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) { #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) /* spurious uninitialized warnings */ mpd_uint_t l=l, lprev=lprev, h=h; #else mpd_uint_t l, lprev, h; #endif 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; #ifndef LEGACY_COMPILER int64_t exp; #else mpd_uint_t x; int x_sign, n_sign; mpd_ssize_t exp; #endif 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; } #ifndef LEGACY_COMPILER 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; #else x = (a->exp < 0) ? -a->exp : a->exp; x_sign = (a->exp < 0) ? 1 : 0; n_sign = mpd_isnegative(b) ? 1 : 0; if (x_sign == n_sign) { x = x + n; if (x < n) x = MPD_UINT_MAX; } else { x_sign = (x >= n) ? x_sign : n_sign; x = (x >= n) ? x - n : n - x; } if (!x_sign && x > MPD_EXP_INF) x = MPD_EXP_INF; if (x_sign && x > -MPD_EXP_CLAMP) x = -MPD_EXP_CLAMP; exp = x_sign ? -((mpd_ssize_t)x) : (mpd_ssize_t)x; #endif 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); } #ifdef CONFIG_64 /* 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); } #elif !defined(LEGACY_COMPILER) /* Add decimal and int64_t. */ void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status) { mpd_context_t maxcontext; MPD_NEW_STATIC(bb,0,0,0,0); mpd_maxcontext(&maxcontext); mpd_qset_i64(&bb, b, &maxcontext, status); mpd_qadd(result, a, &bb, ctx, status); mpd_del(&bb); } /* Add decimal and uint64_t. */ void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status) { mpd_context_t maxcontext; MPD_NEW_STATIC(bb,0,0,0,0); mpd_maxcontext(&maxcontext); mpd_qset_u64(&bb, b, &maxcontext, status); mpd_qadd(result, a, &bb, ctx, status); mpd_del(&bb); } #endif /* Subtract int32_t from decimal. */ 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); } #ifdef CONFIG_64 /* 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); } #elif !defined(LEGACY_COMPILER) /* Subtract int64_t from decimal. */ void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status) { mpd_context_t maxcontext; MPD_NEW_STATIC(bb,0,0,0,0); mpd_maxcontext(&maxcontext); mpd_qset_i64(&bb, b, &maxcontext, status); mpd_qsub(result, a, &bb, ctx, status); mpd_del(&bb); } /* Subtract uint64_t from decimal. */ void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status) { mpd_context_t maxcontext; MPD_NEW_STATIC(bb,0,0,0,0); mpd_maxcontext(&maxcontext); mpd_qset_u64(&bb, b, &maxcontext, status); mpd_qsub(result, a, &bb, ctx, status); mpd_del(&bb); } #endif /* 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_NEW_STATIC(aa,0,0,0,0); MPD_NEW_STATIC(bb,0,0,0,0); uint32_t xstatus = 0; if (q == a) { if (!mpd_qcopy(&aa, a, status)) { mpd_seterror(q, MPD_Malloc_error, status); goto out; } a = &aa; } if (q == b) { if (!mpd_qcopy(&bb, b, status)) { mpd_seterror(q, MPD_Malloc_error, status); goto out; } b = &bb; } _mpd_qdiv(SET_IDEAL_EXP, q, a, b, ctx, &xstatus); if (xstatus & (MPD_Malloc_error|MPD_Division_impossible)) { /* Inexact quotients (the usual case) fill the entire context precision, * which can lead to the above errors for very high precisions. Retry * the operation with a lower precision in case the result is exact. * * We need an upper bound for the number of digits of a_coeff / b_coeff * when the result is exact. If a_coeff' * 1 / b_coeff' is in lowest * terms, then maxdigits(a_coeff') + maxdigits(1 / b_coeff') is a suitable * bound. * * 1 / b_coeff' is exact iff b_coeff' exclusively has prime factors 2 or 5. * The largest amount of digits is generated if b_coeff' is a power of 2 or * a power of 5 and is less than or equal to log5(b_coeff') <= log2(b_coeff'). * * We arrive at a total upper bound: * * maxdigits(a_coeff') + maxdigits(1 / b_coeff') <= * log10(a_coeff) + log2(b_coeff) = * log10(a_coeff) + log10(b_coeff) / log10(2) <= * a->digits + b->digits * 4; */ uint32_t ystatus = 0; mpd_context_t workctx; mpd_workcontext(&workctx, ctx); workctx.prec = a->digits + b->digits * 4; if (workctx.prec >= ctx->prec) { *status |= (xstatus&MPD_Errors); goto out; /* No point in retrying, keep the original error. */ } _mpd_qdiv(SET_IDEAL_EXP, q, a, b, &workctx, &ystatus); if (ystatus != 0) { ystatus = *status | ((ystatus|xstatus)&MPD_Errors); mpd_seterror(q, ystatus, status); } } else { *status |= xstatus; } out: mpd_del(&aa); mpd_del(&bb); } /* 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) { assert(b->data[0] != 0); /* annotation for scan-build */ 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; } /* debug */ abort(); /* GCOV_NOT_REACHED */ } 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); } #ifdef CONFIG_64 /* 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); } #elif !defined(LEGACY_COMPILER) /* Divide decimal by int64_t. */ void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status) { mpd_context_t maxcontext; MPD_NEW_STATIC(bb,0,0,0,0); mpd_maxcontext(&maxcontext); mpd_qset_i64(&bb, b, &maxcontext, status); mpd_qdiv(result, a, &bb, ctx, status); mpd_del(&bb); } /* Divide decimal by uint64_t. */ void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status) { mpd_context_t maxcontext; MPD_NEW_STATIC(bb,0,0,0,0); mpd_maxcontext(&maxcontext); mpd_qset_u64(&bb, b, &maxcontext, status); mpd_qdiv(result, a, &bb, ctx, status); mpd_del(&bb); } #endif /* Pad the result with trailing zeros if it has fewer digits than prec. */ 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); #ifdef CONFIG_64 if (p > (mpd_ssize_t)(1ULL<<52)) { return MPD_SSIZE_MAX; } #endif /* * 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 int _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 1; } /* * 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 */ #if defined(CONFIG_64) #define MPD_EXP_MAX_T 19 #elif defined(CONFIG_32) #define MPD_EXP_MAX_T 10 #endif 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 1; } /* abs(a) <= 9 * 10**(-prec-1) */ if (_mpd_qexp_check_one(result, a, ctx, status)) { return 1; } 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 1; } 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 1; /* 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); } #ifdef CONFIG_64 _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status); #else if (t <= MPD_MAX_POW10) { _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status); } else { t -= MPD_MAX_POW10; _mpd_qpow_uint(&tmp, &sum, mpd_pow10[MPD_MAX_POW10], MPD_POS, &workctx, status); _mpd_qpow_uint(result, &tmp, mpd_pow10[t], MPD_POS, &workctx, status); } #endif mpd_del(&tmp); mpd_del(&sum); *status |= (workctx.status&MPD_Errors); *status |= (MPD_Inexact|MPD_Rounded); return 0; } /* 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; } mpd_workcontext(&workctx, ctx); workctx.round = MPD_ROUND_HALF_EVEN; if (ctx->allcr) { MPD_NEW_STATIC(hi, 0,0,0,0); MPD_NEW_STATIC(lo, 0,0,0,0); MPD_NEW_STATIC(ulp, 0,0,0,0); MPD_NEW_STATIC(aa, 0,0,0,0); uint32_t loop_protect = 0; mpd_ssize_t prec; mpd_ssize_t ulpexp; 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) { uint32_t status_res = 0; uint32_t status_hi = 0; uint32_t status_lo = 0; int shortcut; int bounds_eq; int subnormal_eq; workctx.prec = prec; shortcut = _mpd_qexp(result, a, &workctx, &status_res); if (mpd_isnan(result)) { mpd_seterror(result, status_res, status); break; } if (shortcut || mpd_isinfinite(result) || mpd_iszero(result)) { *status |= status_res; workctx.prec = ctx->prec; workctx.clamp = ctx->clamp; _mpd_zeropad(result, &workctx, status); mpd_qfinalize(result, &workctx, status); break; } ulpexp = result->exp + result->digits - workctx.prec; if (status_res & 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(&hi, result, &ulp, &workctx, &status_hi); mpd_qsub(&lo, result, &ulp, &workctx, &status_lo); if (mpd_isnan(&hi) || mpd_isnan(&lo)) { mpd_seterror(result, status_hi|status_lo, status); break; } subnormal_eq = (status_hi&MPD_Subnormal) == (status_lo&MPD_Subnormal); bounds_eq = mpd_qcmp(&hi, &lo, status) == 0; if (bounds_eq && ++loop_protect > 5) { /* If the bounds are equal, the result is always correctly rounded. Resolving the subnormal status can take more iterations (around three) in extremely rare cases. 'hi' and 'lo' are so close that subnormal/underflow is largely cosmetic, so allow a maximum of five additional iterations. */ subnormal_eq = 1; /* GCOV_NOT_REACHED */ } if (subnormal_eq && bounds_eq) { *status |= status_lo; workctx.clamp = ctx->clamp; _mpd_zeropad(result, &workctx, status); mpd_qfinalize(result, &workctx, status); break; } if (subnormal_eq) { prec += MPD_RDIGITS; } else { prec *= 2; } if (prec > MPD_MAX_PREC) { mpd_seterror(result, MPD_Invalid_operation, status); break; } } mpd_del(&hi); mpd_del(&lo); 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; } /* The constants have been verified with both decimal.py and mpfr. */ #ifdef CONFIG_64 #if MPD_RDIGITS != 19 #error "mpdecimal.c: MPD_RDIGITS must be 19." #endif 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 }; #else #if MPD_RDIGITS != 9 #error "mpdecimal.c: MPD_RDIGITS must be 9." #endif static const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = { 401682692UL, 708474699UL, 720754403UL, 30896345UL, 602301057UL, 765871416UL, 192920333UL, 763113569UL, 589402567UL, 956890167UL, 82413146UL, 589257242UL, 245544057UL, 811364292UL, 734206705UL, 868569356UL, 167465505UL, 775026849UL, 706480002UL, 18064450UL, 636167921UL, 569476834UL, 734507478UL, 156591213UL, 148046637UL, 283552201UL, 677432162UL, 470806855UL, 880840126UL, 417480036UL, 210510171UL, 940440022UL, 939147961UL, 893431493UL, 436515504UL, 440424327UL, 654366747UL, 821988674UL, 622228769UL, 884616336UL, 537773262UL, 350530896UL, 319852839UL, 989482623UL, 468084379UL, 720832555UL, 168948290UL, 736909878UL, 675666628UL, 546508280UL, 863340952UL, 404228624UL, 834196778UL, 508959829UL, 23599720UL, 967735248UL, 96757260UL, 603332790UL, 862877297UL, 760110148UL, 468436420UL, 401799145UL, 299404568UL, 230258509UL }; #endif /* _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 int _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 = 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 ret = 1; 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); ret = 0; finish: *status |= (MPD_Inexact|MPD_Rounded); mpd_del(&v); mpd_del(&vtmp); mpd_del(&tmp); return ret; } /* 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; } mpd_workcontext(&workctx, ctx); workctx.round = MPD_ROUND_HALF_EVEN; if (ctx->allcr) { MPD_NEW_STATIC(hi, 0,0,0,0); MPD_NEW_STATIC(lo, 0,0,0,0); MPD_NEW_STATIC(ulp, 0,0,0,0); MPD_NEW_STATIC(aa, 0,0,0,0); uint32_t loop_protect = 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) { uint32_t status_res = 0; uint32_t status_hi = 0; uint32_t status_lo = 0; int shortcut; int bounds_eq; int subnormal_eq; workctx.prec = prec; shortcut = _mpd_qln(result, a, &workctx, &status_res); if (mpd_isnan(result)) { mpd_seterror(result, status_res, status); break; } if (shortcut || mpd_isinfinite(result) || mpd_iszero(result)) { *status |= status_res; workctx.prec = ctx->prec; workctx.clamp = ctx->clamp; mpd_qfinalize(result, &workctx, status); break; } _ssettriple(&ulp, MPD_POS, 1, result->exp + result->digits-workctx.prec); workctx.prec = ctx->prec; mpd_qadd(&hi, result, &ulp, &workctx, &status_hi); mpd_qsub(&lo, result, &ulp, &workctx, &status_lo); if (mpd_isnan(&hi) || mpd_isnan(&lo)) { mpd_seterror(result, status_hi|status_lo, status); break; } subnormal_eq = (status_hi&MPD_Subnormal) == (status_lo&MPD_Subnormal); bounds_eq = mpd_qcmp(&hi, &lo, status) == 0; if (bounds_eq && ++loop_protect > 5) { /* If the bounds are equal, the result is always correctly rounded. Resolving the subnormal status can take more iterations (around three) in extremely rare cases. 'hi' and 'lo' are so close that subnormal/underflow is largely cosmetic, so allow a maximum of five additional iterations. */ subnormal_eq = 1; /* GCOV_NOT_REACHED */ } if (subnormal_eq && bounds_eq) { *status |= status_lo; workctx.clamp = ctx->clamp; mpd_qfinalize(result, &workctx, status); break; } if (subnormal_eq) { prec += MPD_RDIGITS; } else { prec *= 2; } if (prec > MPD_MAX_PREC) { mpd_seterror(result, MPD_Invalid_operation, status); break; } } mpd_del(&hi); mpd_del(&lo); 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 int _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); int ret; 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. */ ret = _mpd_qln(result, a, &workctx, status); /* relative error: 5 * 10**(-p-3) */ mpd_qln10(&ln10, workctx.prec, status); if (action == DO_FINALIZE) { mpd_workcontext(&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); return ret; } /* 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; mpd_workcontext(&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(hi, 0,0,0,0); MPD_NEW_STATIC(lo, 0,0,0,0); MPD_NEW_STATIC(ulp, 0,0,0,0); MPD_NEW_STATIC(aa, 0,0,0,0); uint32_t loop_protect = 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) { uint32_t status_res = 0; uint32_t status_hi = 0; uint32_t status_lo = 0; int shortcut; int bounds_eq; int subnormal_eq; workctx.prec = prec; shortcut = _mpd_qlog10(SKIP_FINALIZE, result, a, &workctx, &status_res); if (mpd_isnan(result)) { mpd_seterror(result, status_res, status); break; } if (shortcut || mpd_isinfinite(result) || mpd_iszero(result)) { *status |= status_res; workctx.prec = ctx->prec; workctx.clamp = ctx->clamp; mpd_qfinalize(result, &workctx, status); break; } _ssettriple(&ulp, MPD_POS, 1, result->exp + result->digits-workctx.prec); workctx.prec = ctx->prec; mpd_qadd(&hi, result, &ulp, &workctx, &status_hi); mpd_qsub(&lo, result, &ulp, &workctx, &status_lo); if (mpd_isnan(&hi) || mpd_isnan(&lo)) { mpd_seterror(result, status_hi|status_lo, status); break; } subnormal_eq = (status_hi&MPD_Subnormal) == (status_lo&MPD_Subnormal); bounds_eq = mpd_qcmp(&hi, &lo, status) == 0; if (bounds_eq && ++loop_protect > 5) { /* If the bounds are equal, the result is always correctly rounded. Resolving the subnormal status can take more iterations (around three) in extremely rare cases. 'hi' and 'lo' are so close that subnormal/underflow is largely cosmetic, so allow a maximum of five additional iterations. */ subnormal_eq = 1; /* GCOV_NOT_REACHED */ } if (subnormal_eq && bounds_eq) { *status |= status_lo; workctx.clamp = ctx->clamp; mpd_qfinalize(result, &workctx, status); break; } if (subnormal_eq) { prec += MPD_RDIGITS; } else { prec *= 2; } if (prec > MPD_MAX_PREC) { mpd_seterror(result, MPD_Invalid_operation, status); break; } } mpd_del(&hi); mpd_del(&lo); 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); } /* * 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)<>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; } } #ifdef PPRO #ifndef _MSC_VER static inline unsigned short _mpd_get_control87(void) { unsigned short cw; __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); return cw; } static inline void _mpd_set_control87(unsigned short cw) { __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); } #endif static unsigned int mpd_set_fenv(void) { unsigned int cw; #ifdef _MSC_VER unsigned int flags = _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFLOW| _EM_UNDERFLOW|_EM_INEXACT|_RC_CHOP|_PC_64; unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC; unsigned int dummy; __control87_2(0, 0, &cw, NULL); __control87_2(flags, mask, &dummy, NULL); #else cw = _mpd_get_control87(); _mpd_set_control87(cw|0xF3F); #endif return cw; } static void mpd_restore_fenv(unsigned int cw) { #ifdef _MSC_VER unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC; unsigned int dummy; __control87_2(cw, mask, &dummy, NULL); #else _mpd_set_control87((unsigned short)cw); #endif } #endif /* PPRO */ /* * 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; #ifdef PPRO unsigned int cw; cw = mpd_set_fenv(); #endif *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: #ifdef PPRO mpd_restore_fenv(cw); #endif 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); } #ifdef CONFIG_64 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); } #elif !defined(LEGACY_COMPILER) /* Multiply decimal and int64_t. */ void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status) { mpd_context_t maxcontext; MPD_NEW_STATIC(bb,0,0,0,0); mpd_maxcontext(&maxcontext); mpd_qset_i64(&bb, b, &maxcontext, status); mpd_qmul(result, a, &bb, ctx, status); mpd_del(&bb); } /* Multiply decimal and uint64_t. */ void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status) { mpd_context_t maxcontext; MPD_NEW_STATIC(bb,0,0,0,0); mpd_maxcontext(&maxcontext); mpd_qset_u64(&bb, b, &maxcontext, status); mpd_qmul(result, a, &bb, ctx, status); mpd_del(&bb); } #endif /* Like the minus operator. */ 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_uint_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)) { uint32_t workstatus = 0; workctx.prec += 1; mpd_qdiv(&tbase, &one, base, &workctx, &workstatus); *status |= workstatus; if (workstatus&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; assert(r != NULL); /* annotation for scan-build */ 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) { if (mpd_isspecial(a)) { mpd_seterror(result, MPD_Invalid_operation, status); return; } (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; mpd_workcontext(&workctx, ctx); if (mpd_isspecial(a)) { mpd_seterror(result, MPD_Invalid_operation, status); return; } 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; mpd_workcontext(&workctx, ctx); if (mpd_isspecial(a)) { mpd_seterror(result, MPD_Invalid_operation, status); return; } 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; } mpd_workcontext(&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 */ static 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); mpd_workcontext(&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; } void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status) { MPD_NEW_STATIC(aa,0,0,0,0); uint32_t xstatus = 0; if (result == a) { if (!mpd_qcopy(&aa, a, status)) { mpd_seterror(result, MPD_Malloc_error, status); goto out; } a = &aa; } _mpd_qsqrt(result, a, ctx, &xstatus); if (xstatus & (MPD_Malloc_error|MPD_Division_impossible)) { /* The above conditions can occur at very high context precisions * if intermediate values get too large. Retry the operation with * a lower context precision in case the result is exact. * * If the result is exact, an upper bound for the number of digits * is the number of digits in the input. * * NOTE: sqrt(40e9) = 2.0e+5 /\ digits(40e9) = digits(2.0e+5) = 2 */ uint32_t ystatus = 0; mpd_context_t workctx; mpd_workcontext(&workctx, ctx); workctx.prec = a->digits; if (workctx.prec >= ctx->prec) { *status |= (xstatus|MPD_Errors); goto out; /* No point in repeating this, keep the original error. */ } _mpd_qsqrt(result, a, &workctx, &ystatus); if (ystatus != 0) { ystatus = *status | ((xstatus|ystatus)&MPD_Errors); mpd_seterror(result, ystatus, status); } } else { *status |= xstatus; } out: mpd_del(&aa); } /******************************************************************************/ /* 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; double upper_bound; assert(mpd_isinteger(a)); assert(base >= 2); if (mpd_iszero(a)) { return 1; } digits = a->digits+a->exp; #ifdef CONFIG_64 /* ceil(2711437152599294 / log10(2)) + 4 == 2**53 */ if (digits > 2711437152599294ULL) { return SIZE_MAX; } upper_bound = (double)((1ULL<<53)-1); #else upper_bound = (double)(SIZE_MAX-1); #endif x = (double)digits / log10(base); return (x > upper_bound) ? 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; double upper_bound; assert(srclen > 0); assert(base >= 2); #if SIZE_MAX == UINT64_MAX if (srclen > (1ULL<<53)) { return MPD_SSIZE_MAX; } assert((1ULL<<53) <= MPD_MAXIMPORT); upper_bound = (double)((1ULL<<53)-1); #else upper_bound = MPD_MAXIMPORT-1; #endif x = (double)srclen * (log10(base)/MPD_RDIGITS); return (x > upper_bound) ? 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; } #ifdef CONFIG_32 /* target base 'wbase' == source base 'ubase' */ static size_t _copy_equal_base(uint32_t **w, size_t wlen, const uint32_t *u, size_t ulen) { if (wlen < ulen) { if (!mpd_resize_u32(w, ulen)) { return SIZE_MAX; } } memcpy(*w, u, ulen * (sizeof **w)); return ulen; } /* target base 'wbase' > source base 'ubase' */ static size_t _baseconv_to_larger(uint32_t **w, size_t wlen, mpd_uint_t wbase, const mpd_uint_t *u, size_t ulen, mpd_uint_t ubase) { size_t n = 0; mpd_uint_t carry; assert(wlen > 0 && ulen > 0); assert(ubase < wbase); (*w)[n++] = u[--ulen]; while (--ulen != SIZE_MAX) { carry = _mpd_shortmul_b(*w, *w, n, ubase, wbase); if (carry) { if (n >= wlen) { if (!mpd_resize_u32(w, n+1)) { return SIZE_MAX; } wlen = n+1; } (*w)[n++] = carry; } carry = _mpd_shortadd_b(*w, n, u[ulen], wbase); if (carry) { if (n >= wlen) { if (!mpd_resize_u32(w, n+1)) { return SIZE_MAX; } wlen = n+1; } (*w)[n++] = carry; } } return n; } /* target base wbase < source base ubase */ static size_t _coeff_from_larger_base(mpd_t *w, size_t wlen, mpd_uint_t wbase, mpd_uint_t *u, mpd_ssize_t ulen, mpd_uint_t ubase, uint32_t *status) { size_t n = 0; assert(wlen > 0 && ulen > 0); assert(wbase < ubase); do { if (n >= wlen) { if (!mpd_qresize(w, n+1, status)) { return SIZE_MAX; } wlen = n+1; } w->data[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; } #endif /* 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; } } #ifdef CONFIG_64 n = _baseconv_to_smaller(rdata, rlen, rbase, tsrc.data, tsrc.len, MPD_RADIX); #else if (rbase == MPD_RADIX) { n = _copy_equal_base(rdata, rlen, tsrc.data, tsrc.len); } else if (rbase < MPD_RADIX) { n = _baseconv_to_smaller(rdata, rlen, rbase, tsrc.data, tsrc.len, MPD_RADIX); } else { n = _baseconv_to_larger(rdata, rlen, rbase, tsrc.data, tsrc.len, MPD_RADIX); } #endif 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; } #ifdef CONFIG_64 n = _coeff_from_smaller_base(result, rlen, MPD_RADIX, srcdata, srclen, srcbase, status); #else if (srcbase == MPD_RADIX) { if (!mpd_qresize(result, srclen, status)) { return; } memcpy(result->data, srcdata, srclen * (sizeof *srcdata)); n = srclen; } else if (srcbase < MPD_RADIX) { n = _coeff_from_smaller_base(result, rlen, MPD_RADIX, srcdata, srclen, srcbase, status); } else { mpd_uint_t *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]; } n = _coeff_from_larger_base(result, rlen, MPD_RADIX, usrc, (mpd_ssize_t)srclen, srcbase, status); mpd_free(usrc); } #endif 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); } /******************************************************************************/ /* From triple */ /******************************************************************************/ #if defined(CONFIG_64) && defined(__SIZEOF_INT128__) && !defined(_MSC_VER) static mpd_ssize_t _set_coeff(uint64_t data[3], uint64_t hi, uint64_t lo) { __uint128_t d = ((__uint128_t)hi << 64) + lo; __uint128_t q, r; q = d / MPD_RADIX; r = d % MPD_RADIX; data[0] = (uint64_t)r; d = q; q = d / MPD_RADIX; r = d % MPD_RADIX; data[1] = (uint64_t)r; d = q; q = d / MPD_RADIX; r = d % MPD_RADIX; data[2] = (uint64_t)r; if (q != 0) { abort(); /* GCOV_NOT_REACHED */ } return data[2] != 0 ? 3 : (data[1] != 0 ? 2 : 1); } #else static size_t _uint_from_u16(mpd_uint_t *w, mpd_ssize_t wlen, const uint16_t *u, size_t ulen) { const mpd_uint_t ubase = 1U<<16; mpd_ssize_t n = 0; mpd_uint_t carry; assert(wlen > 0 && ulen > 0); w[n++] = u[--ulen]; while (--ulen != SIZE_MAX) { carry = _mpd_shortmul_c(w, w, n, ubase); if (carry) { if (n >= wlen) { abort(); /* GCOV_NOT_REACHED */ } w[n++] = carry; } carry = _mpd_shortadd(w, n, u[ulen]); if (carry) { if (n >= wlen) { abort(); /* GCOV_NOT_REACHED */ } w[n++] = carry; } } return n; } static mpd_ssize_t _set_coeff(mpd_uint_t *data, mpd_ssize_t len, uint64_t hi, uint64_t lo) { uint16_t u16[8] = {0}; u16[7] = (uint16_t)((hi & 0xFFFF000000000000ULL) >> 48); u16[6] = (uint16_t)((hi & 0x0000FFFF00000000ULL) >> 32); u16[5] = (uint16_t)((hi & 0x00000000FFFF0000ULL) >> 16); u16[4] = (uint16_t) (hi & 0x000000000000FFFFULL); u16[3] = (uint16_t)((lo & 0xFFFF000000000000ULL) >> 48); u16[2] = (uint16_t)((lo & 0x0000FFFF00000000ULL) >> 32); u16[1] = (uint16_t)((lo & 0x00000000FFFF0000ULL) >> 16); u16[0] = (uint16_t) (lo & 0x000000000000FFFFULL); return (mpd_ssize_t)_uint_from_u16(data, len, u16, 8); } #endif static int _set_uint128_coeff_exp(mpd_t *result, uint64_t hi, uint64_t lo, mpd_ssize_t exp) { mpd_uint_t data[5] = {0}; uint32_t status = 0; mpd_ssize_t len; #if defined(CONFIG_64) && defined(__SIZEOF_INT128__) && !defined(_MSC_VER) len = _set_coeff(data, hi, lo); #else len = _set_coeff(data, 5, hi, lo); #endif if (!mpd_qresize(result, len, &status)) { return -1; } for (mpd_ssize_t i = 0; i < len; i++) { result->data[i] = data[i]; } result->exp = exp; result->len = len; mpd_setdigits(result); return 0; } int mpd_from_uint128_triple(mpd_t *result, const mpd_uint128_triple_t *triple, uint32_t *status) { static const mpd_context_t maxcontext = { .prec=MPD_MAX_PREC, .emax=MPD_MAX_EMAX, .emin=MPD_MIN_EMIN, .round=MPD_ROUND_HALF_EVEN, .traps=MPD_Traps, .status=0, .newtrap=0, .clamp=0, .allcr=1, }; const enum mpd_triple_class tag = triple->tag; const uint8_t sign = triple->sign; const uint64_t hi = triple->hi; const uint64_t lo = triple->lo; mpd_ssize_t exp; #ifdef CONFIG_32 if (triple->exp < MPD_SSIZE_MIN || triple->exp > MPD_SSIZE_MAX) { goto conversion_error; } #endif exp = (mpd_ssize_t)triple->exp; switch (tag) { case MPD_TRIPLE_QNAN: case MPD_TRIPLE_SNAN: { if (sign > 1 || exp != 0) { goto conversion_error; } const uint8_t flags = tag == MPD_TRIPLE_QNAN ? MPD_NAN : MPD_SNAN; mpd_setspecial(result, sign, flags); if (hi == 0 && lo == 0) { /* no payload */ return 0; } if (_set_uint128_coeff_exp(result, hi, lo, exp) < 0) { goto malloc_error; } return 0; } case MPD_TRIPLE_INF: { if (sign > 1 || hi != 0 || lo != 0 || exp != 0) { goto conversion_error; } mpd_setspecial(result, sign, MPD_INF); return 0; } case MPD_TRIPLE_NORMAL: { if (sign > 1) { goto conversion_error; } const uint8_t flags = sign ? MPD_NEG : MPD_POS; mpd_set_flags(result, flags); if (exp > MPD_EXP_INF) { exp = MPD_EXP_INF; } if (exp == MPD_SSIZE_MIN) { exp = MPD_SSIZE_MIN+1; } if (_set_uint128_coeff_exp(result, hi, lo, exp) < 0) { goto malloc_error; } uint32_t workstatus = 0; mpd_qfinalize(result, &maxcontext, &workstatus); if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) { goto conversion_error; } return 0; } default: goto conversion_error; } conversion_error: mpd_seterror(result, MPD_Conversion_syntax, status); return -1; malloc_error: mpd_seterror(result, MPD_Malloc_error, status); return -1; } /******************************************************************************/ /* As triple */ /******************************************************************************/ #if defined(CONFIG_64) && defined(__SIZEOF_INT128__) && !defined(_MSC_VER) static void _get_coeff(uint64_t *hi, uint64_t *lo, const mpd_t *a) { __uint128_t u128 = 0; switch (a->len) { case 3: u128 = a->data[2]; /* fall through */ case 2: u128 = u128 * MPD_RADIX + a->data[1]; /* fall through */ case 1: u128 = u128 * MPD_RADIX + a->data[0]; break; default: abort(); /* GCOV_NOT_REACHED */ } *hi = u128 >> 64; *lo = (uint64_t)u128; } #else static size_t _uint_to_u16(uint16_t w[8], mpd_uint_t *u, mpd_ssize_t ulen) { const mpd_uint_t wbase = 1U<<16; size_t n = 0; assert(ulen > 0); do { if (n >= 8) { abort(); /* GCOV_NOT_REACHED */ } 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 void _get_coeff(uint64_t *hi, uint64_t *lo, const mpd_t *a) { uint16_t u16[8] = {0}; mpd_uint_t data[5] = {0}; switch (a->len) { case 5: data[4] = a->data[4]; /* fall through */ case 4: data[3] = a->data[3]; /* fall through */ case 3: data[2] = a->data[2]; /* fall through */ case 2: data[1] = a->data[1]; /* fall through */ case 1: data[0] = a->data[0]; break; default: abort(); /* GCOV_NOT_REACHED */ } _uint_to_u16(u16, data, a->len); *hi = (uint64_t)u16[7] << 48; *hi |= (uint64_t)u16[6] << 32; *hi |= (uint64_t)u16[5] << 16; *hi |= (uint64_t)u16[4]; *lo = (uint64_t)u16[3] << 48; *lo |= (uint64_t)u16[2] << 32; *lo |= (uint64_t)u16[1] << 16; *lo |= (uint64_t)u16[0]; } #endif static enum mpd_triple_class _coeff_as_uint128(uint64_t *hi, uint64_t *lo, const mpd_t *a) { #ifdef CONFIG_64 static mpd_uint_t uint128_max_data[3] = { 3374607431768211455ULL, 4028236692093846346ULL, 3ULL }; static const mpd_t uint128_max = { MPD_STATIC|MPD_CONST_DATA, 0, 39, 3, 3, uint128_max_data }; #else static mpd_uint_t uint128_max_data[5] = { 768211455U, 374607431U, 938463463U, 282366920U, 340U }; static const mpd_t uint128_max = { MPD_STATIC|MPD_CONST_DATA, 0, 39, 5, 5, uint128_max_data }; #endif enum mpd_triple_class ret = MPD_TRIPLE_NORMAL; uint32_t status = 0; mpd_t coeff; *hi = *lo = 0ULL; if (mpd_isspecial(a)) { if (mpd_isinfinite(a)) { return MPD_TRIPLE_INF; } ret = mpd_isqnan(a) ? MPD_TRIPLE_QNAN : MPD_TRIPLE_SNAN; if (a->len == 0) { /* no payload */ return ret; } } else if (mpd_iszero(a)) { return ret; } _mpd_copy_shared(&coeff, a); mpd_set_flags(&coeff, 0); coeff.exp = 0; if (mpd_qcmp(&coeff, &uint128_max, &status) > 0) { return MPD_TRIPLE_ERROR; } _get_coeff(hi, lo, &coeff); return ret; } mpd_uint128_triple_t mpd_as_uint128_triple(const mpd_t *a) { mpd_uint128_triple_t triple = { MPD_TRIPLE_ERROR, 0, 0, 0, 0 }; triple.tag = _coeff_as_uint128(&triple.hi, &triple.lo, a); if (triple.tag == MPD_TRIPLE_ERROR) { return triple; } triple.sign = !!mpd_isnegative(a); if (triple.tag == MPD_TRIPLE_NORMAL) { triple.exp = a->exp; } return triple; } mpdecimal-4.0.1/libmpdec/mpdecimal.h.in0000644000000000000000000011660215005764474014707 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_MPDECIMAL_H_ #define LIBMPDEC_MPDECIMAL_H_ #ifdef __cplusplus #include #include #include #include #include #define MPD_UINT8_C(x) (static_cast(x)) extern "C" { #else #include #include #include #include #include #define MPD_UINT8_C(x) ((uint8_t)x) #endif #if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) && \ defined(__GNUC__) && __GNUC__ >= 4 && !defined(__INTEL_COMPILER) #define MPD_PRAGMA(x) _Pragma(x) #define MPD_HIDE_SYMBOLS_START "GCC visibility push(hidden)" #define MPD_HIDE_SYMBOLS_END "GCC visibility pop" #else #define MPD_PRAGMA(x) #define MPD_HIDE_SYMBOLS_START #define MPD_HIDE_SYMBOLS_END #endif /******************************************************************************/ /* Version */ /******************************************************************************/ #define MPD_MAJOR_VERSION 4 #define MPD_MINOR_VERSION 0 #define MPD_MICRO_VERSION 1 #define MPD_VERSION "4.0.1" #define MPD_VERSION_HEX ((MPD_MAJOR_VERSION << 24) | \ (MPD_MINOR_VERSION << 16) | \ (MPD_MICRO_VERSION << 8)) const char *mpd_version(void); /******************************************************************************/ /* Configuration */ /******************************************************************************/ @MPD_HEADER_CONFIG@ /* BEGIN MPD_CONFIG_64 */ #if defined(MPD_CONFIG_64) /* types for modular and base arithmetic */ #define MPD_UINT_MAX UINT64_MAX #define MPD_BITS_PER_UINT 64 typedef uint64_t mpd_uint_t; /* unsigned mod type */ #define MPD_SIZE_MAX SIZE_MAX typedef size_t mpd_size_t; /* unsigned size type */ /* type for exp, digits, len, prec */ #define MPD_SSIZE_MAX INT64_MAX #define MPD_SSIZE_MIN INT64_MIN typedef int64_t mpd_ssize_t; #define _mpd_strtossize strtoll /* decimal arithmetic */ #define MPD_RADIX 10000000000000000000ULL /* 10**19 */ #define MPD_RDIGITS 19 #define MPD_MAX_POW10 19 #define MPD_EXPDIGITS 19 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */ #define MPD_MAXTRANSFORM_2N 4294967296ULL /* 2**32 */ #define MPD_MAX_PREC 999999999999999999LL #define MPD_MAX_PREC_LOG2 64 #define MPD_ELIMIT 1000000000000000000LL #define MPD_MAX_EMAX 999999999999999999LL /* ELIMIT-1 */ #define MPD_MIN_EMIN (-999999999999999999LL) /* -EMAX */ #define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1)) #define MPD_EXP_INF 2000000000000000001LL #define MPD_EXP_CLAMP (-4000000000000000001LL) #define MPD_MAXIMPORT 105263157894736842L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */ #define MPD_IEEE_CONTEXT_MAX_BITS 512 /* 16*(log2(MPD_MAX_EMAX / 3)-3) */ /* conversion specifiers */ #define PRI_mpd_uint_t PRIu64 #define PRI_mpd_ssize_t PRIi64 /* END MPD_CONFIG_64 */ /* BEGIN MPD_CONFIG_32 */ #elif defined(MPD_CONFIG_32) /* types for modular and base arithmetic */ #define MPD_UINT_MAX UINT32_MAX #define MPD_BITS_PER_UINT 32 typedef uint32_t mpd_uint_t; /* unsigned mod type */ #ifndef MPD_LEGACY_COMPILER #define MPD_UUINT_MAX UINT64_MAX typedef uint64_t mpd_uuint_t; /* double width unsigned mod type */ #endif #define MPD_SIZE_MAX SIZE_MAX typedef size_t mpd_size_t; /* unsigned size type */ /* type for dec->len, dec->exp, ctx->prec */ #define MPD_SSIZE_MAX INT32_MAX #define MPD_SSIZE_MIN INT32_MIN typedef int32_t mpd_ssize_t; #define _mpd_strtossize strtol /* decimal arithmetic */ #define MPD_RADIX 1000000000UL /* 10**9 */ #define MPD_RDIGITS 9 #define MPD_MAX_POW10 9 #define MPD_EXPDIGITS 10 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */ #define MPD_MAXTRANSFORM_2N 33554432UL /* 2**25 */ #define MPD_MAX_PREC 425000000L #define MPD_MAX_PREC_LOG2 32 #define MPD_ELIMIT 425000001L #define MPD_MAX_EMAX 425000000L /* ELIMIT-1 */ #define MPD_MIN_EMIN (-425000000L) /* -EMAX */ #define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1)) #define MPD_EXP_INF 1000000001L /* allows for emax=999999999 in the tests */ #define MPD_EXP_CLAMP (-2000000001L) /* allows for emin=-999999999 in the tests */ #define MPD_MAXIMPORT 94444445L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */ #define MPD_IEEE_CONTEXT_MAX_BITS 256 /* 16*(log2(MPD_MAX_EMAX / 3)-3) */ /* conversion specifiers */ #define PRI_mpd_uint_t PRIu32 #define PRI_mpd_ssize_t PRIi32 /* END MPD_CONFIG_32 */ #else #error "define MPD_CONFIG_64 or MPD_CONFIG_32" #endif /* END CONFIG */ #if MPD_SIZE_MAX != MPD_UINT_MAX #error "unsupported platform: need mpd_size_t == mpd_uint_t" #endif /******************************************************************************/ /* Context */ /******************************************************************************/ enum { MPD_ROUND_UP, /* round away from 0 */ MPD_ROUND_DOWN, /* round toward 0 (truncate) */ MPD_ROUND_CEILING, /* round toward +infinity */ MPD_ROUND_FLOOR, /* round toward -infinity */ MPD_ROUND_HALF_UP, /* 0.5 is rounded up */ MPD_ROUND_HALF_DOWN, /* 0.5 is rounded down */ MPD_ROUND_HALF_EVEN, /* 0.5 is rounded to even */ MPD_ROUND_05UP, /* round zero or five away from 0 */ MPD_ROUND_TRUNC, /* truncate, but set infinity */ MPD_ROUND_GUARD }; enum { MPD_CLAMP_DEFAULT, MPD_CLAMP_IEEE_754, MPD_CLAMP_GUARD }; extern const char * const mpd_round_string[MPD_ROUND_GUARD]; extern const char * const mpd_clamp_string[MPD_CLAMP_GUARD]; typedef struct mpd_context_t { mpd_ssize_t prec; /* precision */ mpd_ssize_t emax; /* max positive exp */ mpd_ssize_t emin; /* min negative exp */ uint32_t traps; /* status events that should be trapped */ uint32_t status; /* status flags */ uint32_t newtrap; /* set by mpd_addstatus_raise() */ int round; /* rounding mode */ int clamp; /* clamp mode */ int allcr; /* all functions correctly rounded */ } mpd_context_t; /* Status flags */ #define MPD_Clamped 0x00000001U #define MPD_Conversion_syntax 0x00000002U #define MPD_Division_by_zero 0x00000004U #define MPD_Division_impossible 0x00000008U #define MPD_Division_undefined 0x00000010U #define MPD_Fpu_error 0x00000020U #define MPD_Inexact 0x00000040U #define MPD_Invalid_context 0x00000080U #define MPD_Invalid_operation 0x00000100U #define MPD_Malloc_error 0x00000200U #define MPD_Not_implemented 0x00000400U #define MPD_Overflow 0x00000800U #define MPD_Rounded 0x00001000U #define MPD_Subnormal 0x00002000U #define MPD_Underflow 0x00004000U #define MPD_Max_status (0x00008000U-1U) /* Conditions that result in an IEEE 754 exception */ #define MPD_IEEE_Invalid_operation (MPD_Conversion_syntax | \ MPD_Division_impossible | \ MPD_Division_undefined | \ MPD_Fpu_error | \ MPD_Invalid_context | \ MPD_Invalid_operation | \ MPD_Malloc_error) \ /* Errors that require the result of an operation to be set to NaN */ #define MPD_Errors (MPD_IEEE_Invalid_operation | \ MPD_Division_by_zero) /* Default traps */ #define MPD_Traps (MPD_IEEE_Invalid_operation | \ MPD_Division_by_zero | \ MPD_Overflow | \ MPD_Underflow) /* Official name */ #define MPD_Insufficient_storage MPD_Malloc_error /* IEEE 754 interchange format contexts */ #define MPD_DECIMAL32 32 #define MPD_DECIMAL64 64 #define MPD_DECIMAL128 128 #define MPD_MINALLOC_MIN 2 #define MPD_MINALLOC_MAX 64 extern mpd_ssize_t MPD_MINALLOC; extern void (* mpd_traphandler)(mpd_context_t *); void mpd_dflt_traphandler(mpd_context_t *); void mpd_setminalloc(mpd_ssize_t n); void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec); void mpd_maxcontext(mpd_context_t *ctx); void mpd_defaultcontext(mpd_context_t *ctx); void mpd_basiccontext(mpd_context_t *ctx); int mpd_ieee_context(mpd_context_t *ctx, int bits); mpd_ssize_t mpd_getprec(const mpd_context_t *ctx); mpd_ssize_t mpd_getemax(const mpd_context_t *ctx); mpd_ssize_t mpd_getemin(const mpd_context_t *ctx); int mpd_getround(const mpd_context_t *ctx); uint32_t mpd_gettraps(const mpd_context_t *ctx); uint32_t mpd_getstatus(const mpd_context_t *ctx); int mpd_getclamp(const mpd_context_t *ctx); int mpd_getcr(const mpd_context_t *ctx); int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec); int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax); int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin); int mpd_qsetround(mpd_context_t *ctx, int newround); int mpd_qsettraps(mpd_context_t *ctx, uint32_t flags); int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags); int mpd_qsetclamp(mpd_context_t *ctx, int c); int mpd_qsetcr(mpd_context_t *ctx, int c); void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags); /******************************************************************************/ /* Decimal Arithmetic */ /******************************************************************************/ /* mpd_t flags */ #define MPD_POS MPD_UINT8_C(0) #define MPD_NEG MPD_UINT8_C(1) #define MPD_INF MPD_UINT8_C(2) #define MPD_NAN MPD_UINT8_C(4) #define MPD_SNAN MPD_UINT8_C(8) #define MPD_SPECIAL (MPD_INF|MPD_NAN|MPD_SNAN) #define MPD_STATIC MPD_UINT8_C(16) #define MPD_STATIC_DATA MPD_UINT8_C(32) #define MPD_SHARED_DATA MPD_UINT8_C(64) #define MPD_CONST_DATA MPD_UINT8_C(128) #define MPD_DATAFLAGS (MPD_STATIC_DATA|MPD_SHARED_DATA|MPD_CONST_DATA) /* mpd_t */ typedef struct mpd_t { uint8_t flags; mpd_ssize_t exp; mpd_ssize_t digits; mpd_ssize_t len; mpd_ssize_t alloc; mpd_uint_t *data; } mpd_t; /******************************************************************************/ /* Triple */ /******************************************************************************/ /* status cases for getting a triple */ enum mpd_triple_class { MPD_TRIPLE_NORMAL, MPD_TRIPLE_INF, MPD_TRIPLE_QNAN, MPD_TRIPLE_SNAN, MPD_TRIPLE_ERROR, }; typedef struct { enum mpd_triple_class tag; uint8_t sign; uint64_t hi; uint64_t lo; int64_t exp; } mpd_uint128_triple_t; int mpd_from_uint128_triple(mpd_t *result, const mpd_uint128_triple_t *triple, uint32_t *status); mpd_uint128_triple_t mpd_as_uint128_triple(const mpd_t *a); /******************************************************************************/ /* Quiet, thread-safe functions */ /******************************************************************************/ /* format specification */ typedef struct mpd_spec_t { mpd_ssize_t min_width; /* minimum field width */ mpd_ssize_t prec; /* fraction digits or significant digits */ char type; /* conversion specifier */ char align; /* alignment */ char sign; /* sign printing/alignment */ char sign_coerce; /* coerce to positive zero */ char fill[5]; /* fill character */ const char *dot; /* decimal point */ const char *sep; /* thousands separator */ const char *grouping; /* grouping of digits */ } mpd_spec_t; /* output to a string */ char *mpd_to_sci(const mpd_t *dec, int fmt); char *mpd_to_eng(const mpd_t *dec, int fmt); mpd_ssize_t mpd_to_sci_size(char **res, const mpd_t *dec, int fmt); mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt); int mpd_validate_lconv(mpd_spec_t *spec); int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps); char *mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); char *mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status); #define MPD_NUM_FLAGS 15 #define MPD_MAX_FLAG_STRING 208 #define MPD_MAX_FLAG_LIST (MPD_MAX_FLAG_STRING+18) #define MPD_MAX_SIGNAL_LIST 121 int mpd_snprint_flags(char *dest, int nmemb, uint32_t flags); int mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]); int mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]); /* output to a file */ void mpd_fprint(FILE *file, const mpd_t *dec); void mpd_print(const mpd_t *dec); /* assignment from a string */ void mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, uint32_t *status); void mpd_qset_string_exact(mpd_t *dec, const char *s, uint32_t *status); /* set to NaN with error flags */ void mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status); /* set a special with sign and type */ void mpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type); /* set coefficient to zero or all nines */ void mpd_zerocoeff(mpd_t *result); void mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); /* quietly assign a C integer type to an mpd_t */ void mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); #ifndef MPD_LEGACY_COMPILER void mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qset_i64_exact(mpd_t *result, int64_t a, uint32_t *status); void mpd_qset_u64_exact(mpd_t *result, uint64_t a, uint32_t *status); #endif /* quietly assign a C integer type to an mpd_t with a static coefficient */ void mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); /* quietly get a C integer type from an mpd_t */ mpd_ssize_t mpd_qget_ssize(const mpd_t *dec, uint32_t *status); mpd_uint_t mpd_qget_uint(const mpd_t *dec, uint32_t *status); mpd_uint_t mpd_qabs_uint(const mpd_t *dec, uint32_t *status); int32_t mpd_qget_i32(const mpd_t *dec, uint32_t *status); uint32_t mpd_qget_u32(const mpd_t *dec, uint32_t *status); #ifndef MPD_LEGACY_COMPILER int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status); uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status); #endif /* quiet functions */ int mpd_qcheck_nan(mpd_t *nanresult, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); int mpd_qcheck_nans(mpd_t *nanresult, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); const char *mpd_class(const mpd_t *a, const mpd_context_t *ctx); int mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status); int mpd_qcopy_cxx(mpd_t *result, const mpd_t *a); mpd_t *mpd_qncopy(const mpd_t *a); int mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status); int mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status); int mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status); void mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); int mpd_same_quantum(const mpd_t *a, const mpd_t *b); void mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); int mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); mpd_uint_t mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); mpd_uint_t mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n); void mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx, uint32_t *status); int mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status); int mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); int mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); int mpd_cmp_total(const mpd_t *a, const mpd_t *b); int mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b); int mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b); int mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b); void mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); void mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); void mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); 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); void mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); 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); void mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_context_t *ctx, uint32_t *status); 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); void mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status); void mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); void mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); #ifndef MPD_LEGACY_COMPILER void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); #endif size_t mpd_sizeinbase(const mpd_t *a, uint32_t base); void mpd_qimport_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t srcbase, const mpd_context_t *ctx, uint32_t *status); 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); size_t mpd_qexport_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, uint32_t *status); size_t mpd_qexport_u32(uint32_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, uint32_t *status); /******************************************************************************/ /* Signalling functions */ /******************************************************************************/ char *mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); size_t mpd_export_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); size_t mpd_export_u32(uint32_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); void mpd_finalize(mpd_t *result, mpd_context_t *ctx); int mpd_check_nan(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); int mpd_check_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_set_string(mpd_t *result, const char *s, mpd_context_t *ctx); void mpd_maxcoeff(mpd_t *result, mpd_context_t *ctx); void mpd_sset_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); void mpd_sset_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); void mpd_sset_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); void mpd_sset_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); void mpd_set_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); void mpd_set_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); void mpd_set_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); void mpd_set_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER void mpd_set_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); #endif mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx); mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx); mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx); int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx); uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx); uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx); #endif void mpd_and(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_canonical(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_copy_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_copy_negate(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_copy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_invert(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_logb(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_or(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_rotate(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_scaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_shiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); mpd_uint_t mpd_shiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); void mpd_shiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); void mpd_shift(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_xor(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); int mpd_cmp(const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); int mpd_compare(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); int mpd_compare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_add(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_add_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); void mpd_add_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); void mpd_add_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); void mpd_add_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); void mpd_sub(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_sub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); void mpd_sub_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); void mpd_sub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); void mpd_sub_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); void mpd_div(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_div_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); void mpd_div_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); void mpd_div_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); void mpd_div_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); void mpd_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_divint(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_exp(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_fma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, mpd_context_t *ctx); void mpd_ln(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_log10(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_max(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_max_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_min(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_min_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_mul(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_mul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); void mpd_mul_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); void mpd_mul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); void mpd_mul_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); void mpd_next_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_next_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_next_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_pow(mpd_t *result, const mpd_t *base, const mpd_t *exp, mpd_context_t *ctx); void mpd_powmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, mpd_context_t *ctx); void mpd_quantize(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_rescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, mpd_context_t *ctx); void mpd_reduce(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_rem(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_rem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); void mpd_round_to_intx(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_round_to_int(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_trunc(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_floor(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_ceil(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_sqrt(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); void mpd_invroot(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER void mpd_add_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); void mpd_add_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); void mpd_sub_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); void mpd_sub_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); void mpd_div_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); void mpd_div_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); void mpd_mul_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); void mpd_mul_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); #endif /******************************************************************************/ /* Configuration specific */ /******************************************************************************/ #ifdef MPD_CONFIG_64 void mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); #endif /******************************************************************************/ /* Get attributes of a decimal */ /******************************************************************************/ mpd_ssize_t mpd_adjexp(const mpd_t *dec); mpd_ssize_t mpd_etiny(const mpd_context_t *ctx); mpd_ssize_t mpd_etop(const mpd_context_t *ctx); mpd_uint_t mpd_msword(const mpd_t *dec); int mpd_word_digits(mpd_uint_t word); /* most significant digit of a word */ mpd_uint_t mpd_msd(mpd_uint_t word); /* least significant digit of a word */ mpd_uint_t mpd_lsd(mpd_uint_t word); /* coefficient size needed to store 'digits' */ mpd_ssize_t mpd_digits_to_size(mpd_ssize_t digits); /* number of digits in the exponent, undefined for MPD_SSIZE_MIN */ int mpd_exp_digits(mpd_ssize_t exp); int mpd_iscanonical(const mpd_t *dec); int mpd_isfinite(const mpd_t *dec); int mpd_isinfinite(const mpd_t *dec); int mpd_isinteger(const mpd_t *dec); int mpd_isnan(const mpd_t *dec); int mpd_isnegative(const mpd_t *dec); int mpd_ispositive(const mpd_t *dec); int mpd_isqnan(const mpd_t *dec); int mpd_issigned(const mpd_t *dec); int mpd_issnan(const mpd_t *dec); int mpd_isspecial(const mpd_t *dec); int mpd_iszero(const mpd_t *dec); /* undefined for special numbers */ int mpd_iszerocoeff(const mpd_t *dec); int mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx); int mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx); /* odd word */ int mpd_isoddword(mpd_uint_t word); /* odd coefficient */ int mpd_isoddcoeff(const mpd_t *dec); /* odd decimal, only defined for integers */ int mpd_isodd(const mpd_t *dec); /* even decimal, only defined for integers */ int mpd_iseven(const mpd_t *dec); /* 0 if dec is positive, 1 if dec is negative */ uint8_t mpd_sign(const mpd_t *dec); /* 1 if dec is positive, -1 if dec is negative */ int mpd_arith_sign(const mpd_t *dec); long mpd_radix(void); int mpd_isdynamic(const mpd_t *dec); int mpd_isstatic(const mpd_t *dec); int mpd_isdynamic_data(const mpd_t *dec); int mpd_isstatic_data(const mpd_t *dec); int mpd_isshared_data(const mpd_t *dec); int mpd_isconst_data(const mpd_t *dec); mpd_ssize_t mpd_trail_zeros(const mpd_t *dec); /******************************************************************************/ /* Set attributes of a decimal */ /******************************************************************************/ /* set number of decimal digits in the coefficient */ void mpd_setdigits(mpd_t *result); void mpd_set_sign(mpd_t *result, uint8_t sign); /* copy sign from another decimal */ void mpd_signcpy(mpd_t *result, const mpd_t *a); void mpd_set_infinity(mpd_t *result); void mpd_set_qnan(mpd_t *result); void mpd_set_snan(mpd_t *result); void mpd_set_negative(mpd_t *result); void mpd_set_positive(mpd_t *result); void mpd_set_dynamic(mpd_t *result); void mpd_set_static(mpd_t *result); void mpd_set_dynamic_data(mpd_t *result); void mpd_set_static_data(mpd_t *result); void mpd_set_shared_data(mpd_t *result); void mpd_set_const_data(mpd_t *result); void mpd_clear_flags(mpd_t *result); void mpd_set_flags(mpd_t *result, uint8_t flags); void mpd_copy_flags(mpd_t *result, const mpd_t *a); /******************************************************************************/ /* Error Macros */ /******************************************************************************/ #define mpd_err_fatal(...) \ do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ abort(); \ } while (0) #define mpd_err_warn(...) \ do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ } while (0) /******************************************************************************/ /* Memory handling */ /******************************************************************************/ extern void *(* mpd_mallocfunc)(size_t size); extern void *(* mpd_callocfunc)(size_t nmemb, size_t size); extern void *(* mpd_reallocfunc)(void *ptr, size_t size); extern void (* mpd_free)(void *ptr); void *mpd_callocfunc_em(size_t nmemb, size_t size); void *mpd_alloc(mpd_size_t nmemb, mpd_size_t size); void *mpd_calloc(mpd_size_t nmemb, mpd_size_t size); void *mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err); void *mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size); mpd_t *mpd_qnew(void); mpd_t *mpd_new(mpd_context_t *ctx); mpd_t *mpd_qnew_size(mpd_ssize_t nwords); void mpd_del(mpd_t *dec); void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len); int mpd_qresize(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); int mpd_qresize_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); void mpd_minalloc(mpd_t *result); int mpd_resize(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx); int mpd_resize_zero(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx); #ifdef __cplusplus } /* END extern "C" */ #endif #endif /* LIBMPDEC_MPDECIMAL_H_ */ mpdecimal-4.0.1/libmpdec/mpdecimal32vc.h0000644000000000000000000012475415005764474015007 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_MPDECIMAL_H_ #define LIBMPDEC_MPDECIMAL_H_ #ifdef __cplusplus #include #include #include #include #include #define MPD_UINT8_C(x) (static_cast(x)) extern "C" { #else #include #include #include #include #include #define MPD_UINT8_C(x) ((uint8_t)x) #undef inline #define inline __inline #endif #define MPD_PRAGMA(x) #define MPD_HIDE_SYMBOLS_START #define MPD_HIDE_SYMBOLS_END #define EXTINLINE extern inline #define IMPORTEXPORT #if defined (BUILD_LIBMPDEC) #undef IMPORTEXPORT #define IMPORTEXPORT __declspec(dllexport) #elif defined(_DLL) #undef IMPORTEXPORT #define IMPORTEXPORT __declspec(dllimport) #endif /******************************************************************************/ /* Version */ /******************************************************************************/ #define MPD_MAJOR_VERSION 4 #define MPD_MINOR_VERSION 0 #define MPD_MICRO_VERSION 1 #define MPD_VERSION "4.0.1" #define MPD_VERSION_HEX ((MPD_MAJOR_VERSION << 24) | \ (MPD_MINOR_VERSION << 16) | \ (MPD_MICRO_VERSION << 8)) IMPORTEXPORT const char *mpd_version(void); /******************************************************************************/ /* Types for 32 bit architectures */ /******************************************************************************/ /* ABI: 32-bit */ #define MPD_CONFIG_32 1 #ifdef MPD_CONFIG_64 #error "cannot use MPD_CONFIG_64 with 32-bit header." #endif #ifdef CONFIG_64 #error "cannot use CONFIG_64 with 32-bit header." #endif /* types for modular and base arithmetic */ #define MPD_UINT_MAX UINT32_MAX #define MPD_BITS_PER_UINT 32 typedef uint32_t mpd_uint_t; /* unsigned mod type */ #ifndef MPD_LEGACY_COMPILER #define MPD_UUINT_MAX UINT64_MAX typedef uint64_t mpd_uuint_t; /* double width unsigned mod type */ #endif #define MPD_SIZE_MAX SIZE_MAX typedef size_t mpd_size_t; /* unsigned size type */ /* type for dec->len, dec->exp, ctx->prec */ #define MPD_SSIZE_MAX INT32_MAX #define MPD_SSIZE_MIN INT32_MIN typedef int32_t mpd_ssize_t; #define _mpd_strtossize strtol /* decimal arithmetic */ #define MPD_RADIX 1000000000UL /* 10**9 */ #define MPD_RDIGITS 9 #define MPD_MAX_POW10 9 #define MPD_EXPDIGITS 10 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */ #define MPD_MAXTRANSFORM_2N 33554432UL /* 2**25 */ #define MPD_MAX_PREC 425000000L #define MPD_MAX_PREC_LOG2 32 #define MPD_ELIMIT 425000001L #define MPD_MAX_EMAX 425000000L /* ELIMIT-1 */ #define MPD_MIN_EMIN (-425000000L) /* -EMAX */ #define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1)) #define MPD_EXP_INF 1000000001L /* allows for emax=999999999 in the tests */ #define MPD_EXP_CLAMP (-2000000001L) /* allows for emin=-999999999 in the tests */ #define MPD_MAXIMPORT 94444445L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */ #define MPD_IEEE_CONTEXT_MAX_BITS 256 /* 16*(log2(MPD_MAX_EMAX / 3)-3) */ /* conversion specifiers */ #define PRI_mpd_uint_t PRIu32 #define PRI_mpd_ssize_t PRIi32 #if MPD_SIZE_MAX != MPD_UINT_MAX #error "unsupported platform: need mpd_size_t == mpd_uint_t" #endif /******************************************************************************/ /* Context */ /******************************************************************************/ enum { MPD_ROUND_UP, /* round away from 0 */ MPD_ROUND_DOWN, /* round toward 0 (truncate) */ MPD_ROUND_CEILING, /* round toward +infinity */ MPD_ROUND_FLOOR, /* round toward -infinity */ MPD_ROUND_HALF_UP, /* 0.5 is rounded up */ MPD_ROUND_HALF_DOWN, /* 0.5 is rounded down */ MPD_ROUND_HALF_EVEN, /* 0.5 is rounded to even */ MPD_ROUND_05UP, /* round zero or five away from 0 */ MPD_ROUND_TRUNC, /* truncate, but set infinity */ MPD_ROUND_GUARD }; enum { MPD_CLAMP_DEFAULT, MPD_CLAMP_IEEE_754, MPD_CLAMP_GUARD }; IMPORTEXPORT extern const char * const mpd_round_string[MPD_ROUND_GUARD]; IMPORTEXPORT extern const char * const mpd_clamp_string[MPD_CLAMP_GUARD]; typedef struct mpd_context_t { mpd_ssize_t prec; /* precision */ mpd_ssize_t emax; /* max positive exp */ mpd_ssize_t emin; /* min negative exp */ uint32_t traps; /* status events that should be trapped */ uint32_t status; /* status flags */ uint32_t newtrap; /* set by mpd_addstatus_raise() */ int round; /* rounding mode */ int clamp; /* clamp mode */ int allcr; /* all functions correctly rounded */ } mpd_context_t; /* Status flags */ #define MPD_Clamped 0x00000001U #define MPD_Conversion_syntax 0x00000002U #define MPD_Division_by_zero 0x00000004U #define MPD_Division_impossible 0x00000008U #define MPD_Division_undefined 0x00000010U #define MPD_Fpu_error 0x00000020U #define MPD_Inexact 0x00000040U #define MPD_Invalid_context 0x00000080U #define MPD_Invalid_operation 0x00000100U #define MPD_Malloc_error 0x00000200U #define MPD_Not_implemented 0x00000400U #define MPD_Overflow 0x00000800U #define MPD_Rounded 0x00001000U #define MPD_Subnormal 0x00002000U #define MPD_Underflow 0x00004000U #define MPD_Max_status (0x00008000U-1U) /* Conditions that result in an IEEE 754 exception */ #define MPD_IEEE_Invalid_operation (MPD_Conversion_syntax | \ MPD_Division_impossible | \ MPD_Division_undefined | \ MPD_Fpu_error | \ MPD_Invalid_context | \ MPD_Invalid_operation | \ MPD_Malloc_error) \ /* Errors that require the result of an operation to be set to NaN */ #define MPD_Errors (MPD_IEEE_Invalid_operation | \ MPD_Division_by_zero) /* Default traps */ #define MPD_Traps (MPD_IEEE_Invalid_operation | \ MPD_Division_by_zero | \ MPD_Overflow | \ MPD_Underflow) /* Official name */ #define MPD_Insufficient_storage MPD_Malloc_error /* IEEE 754 interchange format contexts */ #define MPD_DECIMAL32 32 #define MPD_DECIMAL64 64 #define MPD_DECIMAL128 128 #define MPD_MINALLOC_MIN 2 #define MPD_MINALLOC_MAX 64 IMPORTEXPORT extern mpd_ssize_t MPD_MINALLOC; IMPORTEXPORT extern void (* mpd_traphandler)(mpd_context_t *); IMPORTEXPORT void mpd_dflt_traphandler(mpd_context_t *); IMPORTEXPORT void mpd_setminalloc(mpd_ssize_t n); IMPORTEXPORT void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec); IMPORTEXPORT void mpd_maxcontext(mpd_context_t *ctx); IMPORTEXPORT void mpd_defaultcontext(mpd_context_t *ctx); IMPORTEXPORT void mpd_basiccontext(mpd_context_t *ctx); IMPORTEXPORT int mpd_ieee_context(mpd_context_t *ctx, int bits); IMPORTEXPORT mpd_ssize_t mpd_getprec(const mpd_context_t *ctx); IMPORTEXPORT mpd_ssize_t mpd_getemax(const mpd_context_t *ctx); IMPORTEXPORT mpd_ssize_t mpd_getemin(const mpd_context_t *ctx); IMPORTEXPORT int mpd_getround(const mpd_context_t *ctx); IMPORTEXPORT uint32_t mpd_gettraps(const mpd_context_t *ctx); IMPORTEXPORT uint32_t mpd_getstatus(const mpd_context_t *ctx); IMPORTEXPORT int mpd_getclamp(const mpd_context_t *ctx); IMPORTEXPORT int mpd_getcr(const mpd_context_t *ctx); IMPORTEXPORT int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec); IMPORTEXPORT int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax); IMPORTEXPORT int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin); IMPORTEXPORT int mpd_qsetround(mpd_context_t *ctx, int newround); IMPORTEXPORT int mpd_qsettraps(mpd_context_t *ctx, uint32_t flags); IMPORTEXPORT int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags); IMPORTEXPORT int mpd_qsetclamp(mpd_context_t *ctx, int c); IMPORTEXPORT int mpd_qsetcr(mpd_context_t *ctx, int c); IMPORTEXPORT void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags); /******************************************************************************/ /* Decimal Arithmetic */ /******************************************************************************/ /* mpd_t flags */ #define MPD_POS MPD_UINT8_C(0) #define MPD_NEG MPD_UINT8_C(1) #define MPD_INF MPD_UINT8_C(2) #define MPD_NAN MPD_UINT8_C(4) #define MPD_SNAN MPD_UINT8_C(8) #define MPD_SPECIAL (MPD_INF|MPD_NAN|MPD_SNAN) #define MPD_STATIC MPD_UINT8_C(16) #define MPD_STATIC_DATA MPD_UINT8_C(32) #define MPD_SHARED_DATA MPD_UINT8_C(64) #define MPD_CONST_DATA MPD_UINT8_C(128) #define MPD_DATAFLAGS (MPD_STATIC_DATA|MPD_SHARED_DATA|MPD_CONST_DATA) /* mpd_t */ typedef struct mpd_t { uint8_t flags; mpd_ssize_t exp; mpd_ssize_t digits; mpd_ssize_t len; mpd_ssize_t alloc; mpd_uint_t *data; } mpd_t; /******************************************************************************/ /* Triple */ /******************************************************************************/ /* status cases for getting a triple */ enum mpd_triple_class { MPD_TRIPLE_NORMAL, MPD_TRIPLE_INF, MPD_TRIPLE_QNAN, MPD_TRIPLE_SNAN, MPD_TRIPLE_ERROR, }; typedef struct { enum mpd_triple_class tag; uint8_t sign; uint64_t hi; uint64_t lo; int64_t exp; } mpd_uint128_triple_t; IMPORTEXPORT int mpd_from_uint128_triple(mpd_t *result, const mpd_uint128_triple_t *triple, uint32_t *status); IMPORTEXPORT mpd_uint128_triple_t mpd_as_uint128_triple(const mpd_t *a); /******************************************************************************/ /* Quiet, thread-safe functions */ /******************************************************************************/ /* format specification */ typedef struct mpd_spec_t { mpd_ssize_t min_width; /* minimum field width */ mpd_ssize_t prec; /* fraction digits or significant digits */ char type; /* conversion specifier */ char align; /* alignment */ char sign; /* sign printing/alignment */ char sign_coerce; /* coerce to positive zero */ char fill[5]; /* fill character */ const char *dot; /* decimal point */ const char *sep; /* thousands separator */ const char *grouping; /* grouping of digits */ } mpd_spec_t; /* output to a string */ IMPORTEXPORT char *mpd_to_sci(const mpd_t *dec, int fmt); IMPORTEXPORT char *mpd_to_eng(const mpd_t *dec, int fmt); IMPORTEXPORT mpd_ssize_t mpd_to_sci_size(char **res, const mpd_t *dec, int fmt); IMPORTEXPORT mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt); IMPORTEXPORT int mpd_validate_lconv(mpd_spec_t *spec); IMPORTEXPORT int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps); IMPORTEXPORT char *mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT char *mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status); #define MPD_NUM_FLAGS 15 #define MPD_MAX_FLAG_STRING 208 #define MPD_MAX_FLAG_LIST (MPD_MAX_FLAG_STRING+18) #define MPD_MAX_SIGNAL_LIST 121 IMPORTEXPORT int mpd_snprint_flags(char *dest, int nmemb, uint32_t flags); IMPORTEXPORT int mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]); IMPORTEXPORT int mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]); /* output to a file */ IMPORTEXPORT void mpd_fprint(FILE *file, const mpd_t *dec); IMPORTEXPORT void mpd_print(const mpd_t *dec); /* assignment from a string */ IMPORTEXPORT void mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_string_exact(mpd_t *dec, const char *s, uint32_t *status); /* set to NaN with error flags */ IMPORTEXPORT void mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status); /* set a special with sign and type */ IMPORTEXPORT void mpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type); /* set coefficient to zero or all nines */ IMPORTEXPORT void mpd_zerocoeff(mpd_t *result); IMPORTEXPORT void mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); /* quietly assign a C integer type to an mpd_t */ IMPORTEXPORT void mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT void mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_i64_exact(mpd_t *result, int64_t a, uint32_t *status); IMPORTEXPORT void mpd_qset_u64_exact(mpd_t *result, uint64_t a, uint32_t *status); #endif /* quietly assign a C integer type to an mpd_t with a static coefficient */ IMPORTEXPORT void mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); /* quietly get a C integer type from an mpd_t */ IMPORTEXPORT mpd_ssize_t mpd_qget_ssize(const mpd_t *dec, uint32_t *status); IMPORTEXPORT mpd_uint_t mpd_qget_uint(const mpd_t *dec, uint32_t *status); IMPORTEXPORT mpd_uint_t mpd_qabs_uint(const mpd_t *dec, uint32_t *status); IMPORTEXPORT int32_t mpd_qget_i32(const mpd_t *dec, uint32_t *status); IMPORTEXPORT uint32_t mpd_qget_u32(const mpd_t *dec, uint32_t *status); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status); IMPORTEXPORT uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status); #endif /* quiet functions */ IMPORTEXPORT int mpd_qcheck_nan(mpd_t *nanresult, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_qcheck_nans(mpd_t *nanresult, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT const char *mpd_class(const mpd_t *a, const mpd_context_t *ctx); IMPORTEXPORT int mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status); IMPORTEXPORT int mpd_qcopy_cxx(mpd_t *result, const mpd_t *a); IMPORTEXPORT mpd_t *mpd_qncopy(const mpd_t *a); IMPORTEXPORT int mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status); IMPORTEXPORT int mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status); IMPORTEXPORT int mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status); IMPORTEXPORT void mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_same_quantum(const mpd_t *a, const mpd_t *b); IMPORTEXPORT void mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); IMPORTEXPORT mpd_uint_t mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); IMPORTEXPORT mpd_uint_t mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n); IMPORTEXPORT void mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status); IMPORTEXPORT int mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_cmp_total(const mpd_t *a, const mpd_t *b); IMPORTEXPORT int mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b); IMPORTEXPORT int mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b); IMPORTEXPORT int mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b); IMPORTEXPORT void mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT 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); IMPORTEXPORT void mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT 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); IMPORTEXPORT void mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT 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); IMPORTEXPORT void mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status); IMPORTEXPORT void mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); #endif IMPORTEXPORT size_t mpd_sizeinbase(const mpd_t *a, uint32_t base); IMPORTEXPORT 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); IMPORTEXPORT 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); IMPORTEXPORT size_t mpd_qexport_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, uint32_t *status); IMPORTEXPORT size_t mpd_qexport_u32(uint32_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, uint32_t *status); /******************************************************************************/ /* Signalling functions */ /******************************************************************************/ IMPORTEXPORT char *mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); IMPORTEXPORT void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); IMPORTEXPORT void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); IMPORTEXPORT size_t mpd_export_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); IMPORTEXPORT size_t mpd_export_u32(uint32_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); IMPORTEXPORT void mpd_finalize(mpd_t *result, mpd_context_t *ctx); IMPORTEXPORT int mpd_check_nan(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT int mpd_check_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_string(mpd_t *result, const char *s, mpd_context_t *ctx); IMPORTEXPORT void mpd_maxcoeff(mpd_t *result, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT void mpd_set_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); #endif IMPORTEXPORT mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx); #endif IMPORTEXPORT void mpd_and(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_canonical(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_copy_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_copy_negate(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_copy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_invert(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_logb(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_or(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_rotate(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_scaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_shiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); IMPORTEXPORT mpd_uint_t mpd_shiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); IMPORTEXPORT void mpd_shiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); IMPORTEXPORT void mpd_shift(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_xor(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT int mpd_cmp(const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT int mpd_compare(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT int mpd_compare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_divint(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_exp(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_fma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, mpd_context_t *ctx); IMPORTEXPORT void mpd_ln(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_log10(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_max(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_max_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_min(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_min_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_next_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_next_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_next_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_pow(mpd_t *result, const mpd_t *base, const mpd_t *exp, mpd_context_t *ctx); IMPORTEXPORT void mpd_powmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, mpd_context_t *ctx); IMPORTEXPORT void mpd_quantize(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_rescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, mpd_context_t *ctx); IMPORTEXPORT void mpd_reduce(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_rem(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_rem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_round_to_intx(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_round_to_int(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_trunc(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_floor(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_ceil(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sqrt(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_invroot(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT void mpd_add_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); #endif /******************************************************************************/ /* Get attributes of a decimal */ /******************************************************************************/ IMPORTEXPORT EXTINLINE mpd_ssize_t mpd_adjexp(const mpd_t *dec); IMPORTEXPORT EXTINLINE mpd_ssize_t mpd_etiny(const mpd_context_t *ctx); IMPORTEXPORT EXTINLINE mpd_ssize_t mpd_etop(const mpd_context_t *ctx); IMPORTEXPORT EXTINLINE mpd_uint_t mpd_msword(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_word_digits(mpd_uint_t word); /* most significant digit of a word */ IMPORTEXPORT EXTINLINE mpd_uint_t mpd_msd(mpd_uint_t word); /* least significant digit of a word */ IMPORTEXPORT EXTINLINE mpd_uint_t mpd_lsd(mpd_uint_t word); /* coefficient size needed to store 'digits' */ IMPORTEXPORT EXTINLINE mpd_ssize_t mpd_digits_to_size(mpd_ssize_t digits); /* number of digits in the exponent, undefined for MPD_SSIZE_MIN */ IMPORTEXPORT EXTINLINE int mpd_exp_digits(mpd_ssize_t exp); IMPORTEXPORT EXTINLINE int mpd_iscanonical(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isfinite(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isinfinite(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isinteger(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isnan(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isnegative(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_ispositive(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isqnan(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_issigned(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_issnan(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isspecial(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_iszero(const mpd_t *dec); /* undefined for special numbers */ IMPORTEXPORT EXTINLINE int mpd_iszerocoeff(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx); IMPORTEXPORT EXTINLINE int mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx); /* odd word */ IMPORTEXPORT EXTINLINE int mpd_isoddword(mpd_uint_t word); /* odd coefficient */ IMPORTEXPORT EXTINLINE int mpd_isoddcoeff(const mpd_t *dec); /* odd decimal, only defined for integers */ IMPORTEXPORT int mpd_isodd(const mpd_t *dec); /* even decimal, only defined for integers */ IMPORTEXPORT int mpd_iseven(const mpd_t *dec); /* 0 if dec is positive, 1 if dec is negative */ IMPORTEXPORT EXTINLINE uint8_t mpd_sign(const mpd_t *dec); /* 1 if dec is positive, -1 if dec is negative */ IMPORTEXPORT EXTINLINE int mpd_arith_sign(const mpd_t *dec); IMPORTEXPORT EXTINLINE long mpd_radix(void); IMPORTEXPORT EXTINLINE int mpd_isdynamic(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isstatic(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isdynamic_data(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isstatic_data(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isshared_data(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isconst_data(const mpd_t *dec); IMPORTEXPORT mpd_ssize_t mpd_trail_zeros(const mpd_t *dec); /******************************************************************************/ /* Set attributes of a decimal */ /******************************************************************************/ /* set number of decimal digits in the coefficient */ IMPORTEXPORT EXTINLINE void mpd_setdigits(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_sign(mpd_t *result, uint8_t sign); /* copy sign from another decimal */ IMPORTEXPORT EXTINLINE void mpd_signcpy(mpd_t *result, const mpd_t *a); IMPORTEXPORT EXTINLINE void mpd_set_infinity(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_qnan(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_snan(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_negative(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_positive(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_dynamic(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_static(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_dynamic_data(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_static_data(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_shared_data(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_const_data(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_clear_flags(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_flags(mpd_t *result, uint8_t flags); IMPORTEXPORT EXTINLINE void mpd_copy_flags(mpd_t *result, const mpd_t *a); /******************************************************************************/ /* Error Macros */ /******************************************************************************/ #define mpd_err_fatal(...) \ do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ abort(); \ } while (0) #define mpd_err_warn(...) \ do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ } while (0) /******************************************************************************/ /* Memory handling */ /******************************************************************************/ IMPORTEXPORT extern void *(* mpd_mallocfunc)(size_t size); IMPORTEXPORT extern void *(* mpd_callocfunc)(size_t nmemb, size_t size); IMPORTEXPORT extern void *(* mpd_reallocfunc)(void *ptr, size_t size); IMPORTEXPORT extern void (* mpd_free)(void *ptr); IMPORTEXPORT void *mpd_callocfunc_em(size_t nmemb, size_t size); IMPORTEXPORT void *mpd_alloc(mpd_size_t nmemb, mpd_size_t size); IMPORTEXPORT void *mpd_calloc(mpd_size_t nmemb, mpd_size_t size); IMPORTEXPORT void *mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err); IMPORTEXPORT void *mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size); IMPORTEXPORT mpd_t *mpd_qnew(void); IMPORTEXPORT mpd_t *mpd_new(mpd_context_t *ctx); IMPORTEXPORT mpd_t *mpd_qnew_size(mpd_ssize_t nwords); IMPORTEXPORT EXTINLINE void mpd_del(mpd_t *dec); IMPORTEXPORT EXTINLINE void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len); IMPORTEXPORT EXTINLINE int mpd_qresize(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); IMPORTEXPORT EXTINLINE int mpd_qresize_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); IMPORTEXPORT EXTINLINE void mpd_minalloc(mpd_t *result); IMPORTEXPORT int mpd_resize(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx); IMPORTEXPORT int mpd_resize_zero(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx); #undef IMPORTEXPORT #undef EXTINLINE #ifdef __cplusplus } /* END extern "C" */ #endif #endif /* LIBMPDEC_MPDECIMAL_H_ */ mpdecimal-4.0.1/libmpdec/mpdecimal64vc.h0000644000000000000000000012567015005764474015012 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_MPDECIMAL_H_ #define LIBMPDEC_MPDECIMAL_H_ #ifdef __cplusplus #include #include #include #include #include #define MPD_UINT8_C(x) (static_cast(x)) extern "C" { #else #include #include #include #include #include #define MPD_UINT8_C(x) ((uint8_t)x) #undef inline #define inline __inline #endif #define MPD_PRAGMA(x) #define MPD_HIDE_SYMBOLS_START #define MPD_HIDE_SYMBOLS_END #define EXTINLINE extern inline #define IMPORTEXPORT #if defined (BUILD_LIBMPDEC) #undef IMPORTEXPORT #define IMPORTEXPORT __declspec(dllexport) #elif defined(_DLL) #undef IMPORTEXPORT #define IMPORTEXPORT __declspec(dllimport) #endif /******************************************************************************/ /* Version */ /******************************************************************************/ #define MPD_MAJOR_VERSION 4 #define MPD_MINOR_VERSION 0 #define MPD_MICRO_VERSION 1 #define MPD_VERSION "4.0.1" #define MPD_VERSION_HEX ((MPD_MAJOR_VERSION << 24) | \ (MPD_MINOR_VERSION << 16) | \ (MPD_MICRO_VERSION << 8)) IMPORTEXPORT const char *mpd_version(void); /******************************************************************************/ /* Types for 64 bit architectures */ /******************************************************************************/ /* ABI: 64-bit */ #define MPD_CONFIG_64 1 #ifdef MPD_CONFIG_32 #error "cannot use MPD_CONFIG_32 with 64-bit header." #endif #ifdef CONFIG_32 #error "cannot use CONFIG_32 with 64-bit header." #endif /* types for modular and base arithmetic */ #define MPD_UINT_MAX UINT64_MAX #define MPD_BITS_PER_UINT 64 typedef uint64_t mpd_uint_t; /* unsigned mod type */ #define MPD_SIZE_MAX SIZE_MAX typedef size_t mpd_size_t; /* unsigned size type */ /* type for exp, digits, len, prec */ #define MPD_SSIZE_MAX INT64_MAX #define MPD_SSIZE_MIN INT64_MIN typedef int64_t mpd_ssize_t; #define _mpd_strtossize strtoll /* decimal arithmetic */ #define MPD_RADIX 10000000000000000000ULL /* 10**19 */ #define MPD_RDIGITS 19 #define MPD_MAX_POW10 19 #define MPD_EXPDIGITS 19 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */ #define MPD_MAXTRANSFORM_2N 4294967296ULL /* 2**32 */ #define MPD_MAX_PREC 999999999999999999LL #define MPD_MAX_PREC_LOG2 64 #define MPD_ELIMIT 1000000000000000000LL #define MPD_MAX_EMAX 999999999999999999LL /* ELIMIT-1 */ #define MPD_MIN_EMIN (-999999999999999999LL) /* -EMAX */ #define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1)) #define MPD_EXP_INF 2000000000000000001LL #define MPD_EXP_CLAMP (-4000000000000000001LL) #define MPD_MAXIMPORT 105263157894736842L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */ #define MPD_IEEE_CONTEXT_MAX_BITS 512 /* 16*(log2(MPD_MAX_EMAX / 3)-3) */ /* conversion specifiers */ #define PRI_mpd_uint_t PRIu64 #define PRI_mpd_ssize_t PRIi64 #if MPD_SIZE_MAX != MPD_UINT_MAX #error "unsupported platform: need mpd_size_t == mpd_uint_t" #endif /******************************************************************************/ /* Context */ /******************************************************************************/ enum { MPD_ROUND_UP, /* round away from 0 */ MPD_ROUND_DOWN, /* round toward 0 (truncate) */ MPD_ROUND_CEILING, /* round toward +infinity */ MPD_ROUND_FLOOR, /* round toward -infinity */ MPD_ROUND_HALF_UP, /* 0.5 is rounded up */ MPD_ROUND_HALF_DOWN, /* 0.5 is rounded down */ MPD_ROUND_HALF_EVEN, /* 0.5 is rounded to even */ MPD_ROUND_05UP, /* round zero or five away from 0 */ MPD_ROUND_TRUNC, /* truncate, but set infinity */ MPD_ROUND_GUARD }; enum { MPD_CLAMP_DEFAULT, MPD_CLAMP_IEEE_754, MPD_CLAMP_GUARD }; IMPORTEXPORT extern const char * const mpd_round_string[MPD_ROUND_GUARD]; IMPORTEXPORT extern const char * const mpd_clamp_string[MPD_CLAMP_GUARD]; typedef struct mpd_context_t { mpd_ssize_t prec; /* precision */ mpd_ssize_t emax; /* max positive exp */ mpd_ssize_t emin; /* min negative exp */ uint32_t traps; /* status events that should be trapped */ uint32_t status; /* status flags */ uint32_t newtrap; /* set by mpd_addstatus_raise() */ int round; /* rounding mode */ int clamp; /* clamp mode */ int allcr; /* all functions correctly rounded */ } mpd_context_t; /* Status flags */ #define MPD_Clamped 0x00000001U #define MPD_Conversion_syntax 0x00000002U #define MPD_Division_by_zero 0x00000004U #define MPD_Division_impossible 0x00000008U #define MPD_Division_undefined 0x00000010U #define MPD_Fpu_error 0x00000020U #define MPD_Inexact 0x00000040U #define MPD_Invalid_context 0x00000080U #define MPD_Invalid_operation 0x00000100U #define MPD_Malloc_error 0x00000200U #define MPD_Not_implemented 0x00000400U #define MPD_Overflow 0x00000800U #define MPD_Rounded 0x00001000U #define MPD_Subnormal 0x00002000U #define MPD_Underflow 0x00004000U #define MPD_Max_status (0x00008000U-1U) /* Conditions that result in an IEEE 754 exception */ #define MPD_IEEE_Invalid_operation (MPD_Conversion_syntax | \ MPD_Division_impossible | \ MPD_Division_undefined | \ MPD_Fpu_error | \ MPD_Invalid_context | \ MPD_Invalid_operation | \ MPD_Malloc_error) \ /* Errors that require the result of an operation to be set to NaN */ #define MPD_Errors (MPD_IEEE_Invalid_operation | \ MPD_Division_by_zero) /* Default traps */ #define MPD_Traps (MPD_IEEE_Invalid_operation | \ MPD_Division_by_zero | \ MPD_Overflow | \ MPD_Underflow) /* Official name */ #define MPD_Insufficient_storage MPD_Malloc_error /* IEEE 754 interchange format contexts */ #define MPD_DECIMAL32 32 #define MPD_DECIMAL64 64 #define MPD_DECIMAL128 128 #define MPD_MINALLOC_MIN 2 #define MPD_MINALLOC_MAX 64 IMPORTEXPORT extern mpd_ssize_t MPD_MINALLOC; IMPORTEXPORT extern void (* mpd_traphandler)(mpd_context_t *); IMPORTEXPORT void mpd_dflt_traphandler(mpd_context_t *); IMPORTEXPORT void mpd_setminalloc(mpd_ssize_t n); IMPORTEXPORT void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec); IMPORTEXPORT void mpd_maxcontext(mpd_context_t *ctx); IMPORTEXPORT void mpd_defaultcontext(mpd_context_t *ctx); IMPORTEXPORT void mpd_basiccontext(mpd_context_t *ctx); IMPORTEXPORT int mpd_ieee_context(mpd_context_t *ctx, int bits); IMPORTEXPORT mpd_ssize_t mpd_getprec(const mpd_context_t *ctx); IMPORTEXPORT mpd_ssize_t mpd_getemax(const mpd_context_t *ctx); IMPORTEXPORT mpd_ssize_t mpd_getemin(const mpd_context_t *ctx); IMPORTEXPORT int mpd_getround(const mpd_context_t *ctx); IMPORTEXPORT uint32_t mpd_gettraps(const mpd_context_t *ctx); IMPORTEXPORT uint32_t mpd_getstatus(const mpd_context_t *ctx); IMPORTEXPORT int mpd_getclamp(const mpd_context_t *ctx); IMPORTEXPORT int mpd_getcr(const mpd_context_t *ctx); IMPORTEXPORT int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec); IMPORTEXPORT int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax); IMPORTEXPORT int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin); IMPORTEXPORT int mpd_qsetround(mpd_context_t *ctx, int newround); IMPORTEXPORT int mpd_qsettraps(mpd_context_t *ctx, uint32_t flags); IMPORTEXPORT int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags); IMPORTEXPORT int mpd_qsetclamp(mpd_context_t *ctx, int c); IMPORTEXPORT int mpd_qsetcr(mpd_context_t *ctx, int c); IMPORTEXPORT void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags); /******************************************************************************/ /* Decimal Arithmetic */ /******************************************************************************/ /* mpd_t flags */ #define MPD_POS MPD_UINT8_C(0) #define MPD_NEG MPD_UINT8_C(1) #define MPD_INF MPD_UINT8_C(2) #define MPD_NAN MPD_UINT8_C(4) #define MPD_SNAN MPD_UINT8_C(8) #define MPD_SPECIAL (MPD_INF|MPD_NAN|MPD_SNAN) #define MPD_STATIC MPD_UINT8_C(16) #define MPD_STATIC_DATA MPD_UINT8_C(32) #define MPD_SHARED_DATA MPD_UINT8_C(64) #define MPD_CONST_DATA MPD_UINT8_C(128) #define MPD_DATAFLAGS (MPD_STATIC_DATA|MPD_SHARED_DATA|MPD_CONST_DATA) /* mpd_t */ typedef struct mpd_t { uint8_t flags; mpd_ssize_t exp; mpd_ssize_t digits; mpd_ssize_t len; mpd_ssize_t alloc; mpd_uint_t *data; } mpd_t; /******************************************************************************/ /* Triple */ /******************************************************************************/ /* status cases for getting a triple */ enum mpd_triple_class { MPD_TRIPLE_NORMAL, MPD_TRIPLE_INF, MPD_TRIPLE_QNAN, MPD_TRIPLE_SNAN, MPD_TRIPLE_ERROR, }; typedef struct { enum mpd_triple_class tag; uint8_t sign; uint64_t hi; uint64_t lo; int64_t exp; } mpd_uint128_triple_t; IMPORTEXPORT int mpd_from_uint128_triple(mpd_t *result, const mpd_uint128_triple_t *triple, uint32_t *status); IMPORTEXPORT mpd_uint128_triple_t mpd_as_uint128_triple(const mpd_t *a); /******************************************************************************/ /* Quiet, thread-safe functions */ /******************************************************************************/ /* format specification */ typedef struct mpd_spec_t { mpd_ssize_t min_width; /* minimum field width */ mpd_ssize_t prec; /* fraction digits or significant digits */ char type; /* conversion specifier */ char align; /* alignment */ char sign; /* sign printing/alignment */ char sign_coerce; /* coerce to positive zero */ char fill[5]; /* fill character */ const char *dot; /* decimal point */ const char *sep; /* thousands separator */ const char *grouping; /* grouping of digits */ } mpd_spec_t; /* output to a string */ IMPORTEXPORT char *mpd_to_sci(const mpd_t *dec, int fmt); IMPORTEXPORT char *mpd_to_eng(const mpd_t *dec, int fmt); IMPORTEXPORT mpd_ssize_t mpd_to_sci_size(char **res, const mpd_t *dec, int fmt); IMPORTEXPORT mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt); IMPORTEXPORT int mpd_validate_lconv(mpd_spec_t *spec); IMPORTEXPORT int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps); IMPORTEXPORT char *mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT char *mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status); #define MPD_NUM_FLAGS 15 #define MPD_MAX_FLAG_STRING 208 #define MPD_MAX_FLAG_LIST (MPD_MAX_FLAG_STRING+18) #define MPD_MAX_SIGNAL_LIST 121 IMPORTEXPORT int mpd_snprint_flags(char *dest, int nmemb, uint32_t flags); IMPORTEXPORT int mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]); IMPORTEXPORT int mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]); /* output to a file */ IMPORTEXPORT void mpd_fprint(FILE *file, const mpd_t *dec); IMPORTEXPORT void mpd_print(const mpd_t *dec); /* assignment from a string */ IMPORTEXPORT void mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_string_exact(mpd_t *dec, const char *s, uint32_t *status); /* set to NaN with error flags */ IMPORTEXPORT void mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status); /* set a special with sign and type */ IMPORTEXPORT void mpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type); /* set coefficient to zero or all nines */ IMPORTEXPORT void mpd_zerocoeff(mpd_t *result); IMPORTEXPORT void mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); /* quietly assign a C integer type to an mpd_t */ IMPORTEXPORT void mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT void mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qset_i64_exact(mpd_t *result, int64_t a, uint32_t *status); IMPORTEXPORT void mpd_qset_u64_exact(mpd_t *result, uint64_t a, uint32_t *status); #endif /* quietly assign a C integer type to an mpd_t with a static coefficient */ IMPORTEXPORT void mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); /* quietly get a C integer type from an mpd_t */ IMPORTEXPORT mpd_ssize_t mpd_qget_ssize(const mpd_t *dec, uint32_t *status); IMPORTEXPORT mpd_uint_t mpd_qget_uint(const mpd_t *dec, uint32_t *status); IMPORTEXPORT mpd_uint_t mpd_qabs_uint(const mpd_t *dec, uint32_t *status); IMPORTEXPORT int32_t mpd_qget_i32(const mpd_t *dec, uint32_t *status); IMPORTEXPORT uint32_t mpd_qget_u32(const mpd_t *dec, uint32_t *status); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status); IMPORTEXPORT uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status); #endif /* quiet functions */ IMPORTEXPORT int mpd_qcheck_nan(mpd_t *nanresult, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_qcheck_nans(mpd_t *nanresult, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT const char *mpd_class(const mpd_t *a, const mpd_context_t *ctx); IMPORTEXPORT int mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status); IMPORTEXPORT int mpd_qcopy_cxx(mpd_t *result, const mpd_t *a); IMPORTEXPORT mpd_t *mpd_qncopy(const mpd_t *a); IMPORTEXPORT int mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status); IMPORTEXPORT int mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status); IMPORTEXPORT int mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status); IMPORTEXPORT void mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_same_quantum(const mpd_t *a, const mpd_t *b); IMPORTEXPORT void mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); IMPORTEXPORT mpd_uint_t mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); IMPORTEXPORT mpd_uint_t mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n); IMPORTEXPORT void mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status); IMPORTEXPORT int mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT int mpd_cmp_total(const mpd_t *a, const mpd_t *b); IMPORTEXPORT int mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b); IMPORTEXPORT int mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b); IMPORTEXPORT int mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b); IMPORTEXPORT void mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT 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); IMPORTEXPORT void mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT 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); IMPORTEXPORT void mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT 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); IMPORTEXPORT void mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status); IMPORTEXPORT void mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); #endif IMPORTEXPORT size_t mpd_sizeinbase(const mpd_t *a, uint32_t base); IMPORTEXPORT 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); IMPORTEXPORT 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); IMPORTEXPORT size_t mpd_qexport_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, uint32_t *status); IMPORTEXPORT size_t mpd_qexport_u32(uint32_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, uint32_t *status); /******************************************************************************/ /* Signalling functions */ /******************************************************************************/ IMPORTEXPORT char *mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); IMPORTEXPORT void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); IMPORTEXPORT void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); IMPORTEXPORT size_t mpd_export_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); IMPORTEXPORT size_t mpd_export_u32(uint32_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); IMPORTEXPORT void mpd_finalize(mpd_t *result, mpd_context_t *ctx); IMPORTEXPORT int mpd_check_nan(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT int mpd_check_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_string(mpd_t *result, const char *s, mpd_context_t *ctx); IMPORTEXPORT void mpd_maxcoeff(mpd_t *result, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT void mpd_set_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); #endif IMPORTEXPORT mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx); #endif IMPORTEXPORT void mpd_and(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_canonical(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_copy_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_copy_negate(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_copy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_invert(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_logb(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_or(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_rotate(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_scaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_shiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); IMPORTEXPORT mpd_uint_t mpd_shiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); IMPORTEXPORT void mpd_shiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); IMPORTEXPORT void mpd_shift(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_xor(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT int mpd_cmp(const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT int mpd_compare(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT int mpd_compare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_divint(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_exp(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_fma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, mpd_context_t *ctx); IMPORTEXPORT void mpd_ln(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_log10(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_max(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_max_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_min(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_min_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_next_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_next_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_next_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_pow(mpd_t *result, const mpd_t *base, const mpd_t *exp, mpd_context_t *ctx); IMPORTEXPORT void mpd_powmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, mpd_context_t *ctx); IMPORTEXPORT void mpd_quantize(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_rescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, mpd_context_t *ctx); IMPORTEXPORT void mpd_reduce(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_rem(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_rem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); IMPORTEXPORT void mpd_round_to_intx(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_round_to_int(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_trunc(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_floor(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_ceil(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sqrt(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); IMPORTEXPORT void mpd_invroot(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); #ifndef MPD_LEGACY_COMPILER IMPORTEXPORT void mpd_add_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_add_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_sub_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_div_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); IMPORTEXPORT void mpd_mul_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); #endif /******************************************************************************/ /* Configuration specific */ /******************************************************************************/ IMPORTEXPORT void mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); IMPORTEXPORT void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); IMPORTEXPORT void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); /******************************************************************************/ /* Get attributes of a decimal */ /******************************************************************************/ IMPORTEXPORT EXTINLINE mpd_ssize_t mpd_adjexp(const mpd_t *dec); IMPORTEXPORT EXTINLINE mpd_ssize_t mpd_etiny(const mpd_context_t *ctx); IMPORTEXPORT EXTINLINE mpd_ssize_t mpd_etop(const mpd_context_t *ctx); IMPORTEXPORT EXTINLINE mpd_uint_t mpd_msword(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_word_digits(mpd_uint_t word); /* most significant digit of a word */ IMPORTEXPORT EXTINLINE mpd_uint_t mpd_msd(mpd_uint_t word); /* least significant digit of a word */ IMPORTEXPORT EXTINLINE mpd_uint_t mpd_lsd(mpd_uint_t word); /* coefficient size needed to store 'digits' */ IMPORTEXPORT EXTINLINE mpd_ssize_t mpd_digits_to_size(mpd_ssize_t digits); /* number of digits in the exponent, undefined for MPD_SSIZE_MIN */ IMPORTEXPORT EXTINLINE int mpd_exp_digits(mpd_ssize_t exp); IMPORTEXPORT EXTINLINE int mpd_iscanonical(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isfinite(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isinfinite(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isinteger(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isnan(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isnegative(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_ispositive(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isqnan(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_issigned(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_issnan(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isspecial(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_iszero(const mpd_t *dec); /* undefined for special numbers */ IMPORTEXPORT EXTINLINE int mpd_iszerocoeff(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx); IMPORTEXPORT EXTINLINE int mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx); /* odd word */ IMPORTEXPORT EXTINLINE int mpd_isoddword(mpd_uint_t word); /* odd coefficient */ IMPORTEXPORT EXTINLINE int mpd_isoddcoeff(const mpd_t *dec); /* odd decimal, only defined for integers */ IMPORTEXPORT int mpd_isodd(const mpd_t *dec); /* even decimal, only defined for integers */ IMPORTEXPORT int mpd_iseven(const mpd_t *dec); /* 0 if dec is positive, 1 if dec is negative */ IMPORTEXPORT EXTINLINE uint8_t mpd_sign(const mpd_t *dec); /* 1 if dec is positive, -1 if dec is negative */ IMPORTEXPORT EXTINLINE int mpd_arith_sign(const mpd_t *dec); IMPORTEXPORT EXTINLINE long mpd_radix(void); IMPORTEXPORT EXTINLINE int mpd_isdynamic(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isstatic(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isdynamic_data(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isstatic_data(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isshared_data(const mpd_t *dec); IMPORTEXPORT EXTINLINE int mpd_isconst_data(const mpd_t *dec); IMPORTEXPORT mpd_ssize_t mpd_trail_zeros(const mpd_t *dec); /******************************************************************************/ /* Set attributes of a decimal */ /******************************************************************************/ /* set number of decimal digits in the coefficient */ IMPORTEXPORT EXTINLINE void mpd_setdigits(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_sign(mpd_t *result, uint8_t sign); /* copy sign from another decimal */ IMPORTEXPORT EXTINLINE void mpd_signcpy(mpd_t *result, const mpd_t *a); IMPORTEXPORT EXTINLINE void mpd_set_infinity(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_qnan(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_snan(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_negative(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_positive(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_dynamic(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_static(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_dynamic_data(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_static_data(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_shared_data(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_const_data(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_clear_flags(mpd_t *result); IMPORTEXPORT EXTINLINE void mpd_set_flags(mpd_t *result, uint8_t flags); IMPORTEXPORT EXTINLINE void mpd_copy_flags(mpd_t *result, const mpd_t *a); /******************************************************************************/ /* Error Macros */ /******************************************************************************/ #define mpd_err_fatal(...) \ do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ abort(); \ } while (0) #define mpd_err_warn(...) \ do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ } while (0) /******************************************************************************/ /* Memory handling */ /******************************************************************************/ IMPORTEXPORT extern void *(* mpd_mallocfunc)(size_t size); IMPORTEXPORT extern void *(* mpd_callocfunc)(size_t nmemb, size_t size); IMPORTEXPORT extern void *(* mpd_reallocfunc)(void *ptr, size_t size); IMPORTEXPORT extern void (* mpd_free)(void *ptr); IMPORTEXPORT void *mpd_callocfunc_em(size_t nmemb, size_t size); IMPORTEXPORT void *mpd_alloc(mpd_size_t nmemb, mpd_size_t size); IMPORTEXPORT void *mpd_calloc(mpd_size_t nmemb, mpd_size_t size); IMPORTEXPORT void *mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err); IMPORTEXPORT void *mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size); IMPORTEXPORT mpd_t *mpd_qnew(void); IMPORTEXPORT mpd_t *mpd_new(mpd_context_t *ctx); IMPORTEXPORT mpd_t *mpd_qnew_size(mpd_ssize_t nwords); IMPORTEXPORT EXTINLINE void mpd_del(mpd_t *dec); IMPORTEXPORT EXTINLINE void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len); IMPORTEXPORT EXTINLINE int mpd_qresize(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); IMPORTEXPORT EXTINLINE int mpd_qresize_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status); IMPORTEXPORT EXTINLINE void mpd_minalloc(mpd_t *result); IMPORTEXPORT int mpd_resize(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx); IMPORTEXPORT int mpd_resize_zero(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx); #undef IMPORTEXPORT #undef EXTINLINE #ifdef __cplusplus } /* END extern "C" */ #endif #endif /* LIBMPDEC_MPDECIMAL_H_ */ mpdecimal-4.0.1/libmpdec/mpsignal.c0000644000000000000000000005425515005764474014161 0ustar00/* * Copyright (c) 2008-2025 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 #include #include "mpdecimal.h" /* Signaling wrappers for the quiet functions in mpdecimal.c. */ char * mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx) { char *ret; uint32_t status = 0; ret = mpd_qformat(dec, fmt, ctx, &status); mpd_addstatus_raise(ctx, status); return ret; } void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx) { uint32_t status = 0; mpd_qimport_u16(result, srcdata, srclen, srcsign, base, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx) { uint32_t status = 0; mpd_qimport_u32(result, srcdata, srclen, srcsign, base, ctx, &status); mpd_addstatus_raise(ctx, status); } size_t mpd_export_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx) { size_t n; uint32_t status = 0; n = mpd_qexport_u16(rdata, rlen, base, src, &status); mpd_addstatus_raise(ctx, status); return n; } size_t mpd_export_u32(uint32_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx) { size_t n; uint32_t status = 0; n = mpd_qexport_u32(rdata, rlen, base, src, &status); mpd_addstatus_raise(ctx, status); return n; } void mpd_finalize(mpd_t *result, mpd_context_t *ctx) { uint32_t status = 0; mpd_qfinalize(result, ctx, &status); mpd_addstatus_raise(ctx, status); } int mpd_check_nan(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; if (mpd_qcheck_nan(result, a, ctx, &status)) { mpd_addstatus_raise(ctx, status); return 1; } return 0; } int mpd_check_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; if (mpd_qcheck_nans(result, a, b, ctx, &status)) { mpd_addstatus_raise(ctx, status); return 1; } return 0; } void mpd_set_string(mpd_t *result, const char *s, mpd_context_t *ctx) { uint32_t status = 0; mpd_qset_string(result, s, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_maxcoeff(mpd_t *result, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmaxcoeff(result, ctx, &status); mpd_addstatus_raise(ctx, status); } /* set static mpd from signed integer */ void mpd_sset_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsset_ssize(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_sset_i32(mpd_t *result, int32_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsset_i32(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifdef CONFIG_64 void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsset_i64(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif /* set static mpd from unsigned integer */ void mpd_sset_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsset_uint(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_sset_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsset_u32(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifdef CONFIG_64 void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsset_u64(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif /* set mpd from signed integer */ void mpd_set_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qset_ssize(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_set_i32(mpd_t *result, int32_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qset_i32(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_set_i64(mpd_t *result, int64_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qset_i64(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif /* set mpd from unsigned integer */ void mpd_set_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qset_uint(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_set_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qset_u32(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qset_u64(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif /* convert mpd to signed integer */ mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_ssize_t ret; ret = mpd_qget_ssize(a, &status); mpd_addstatus_raise(ctx, status); return ret; } int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; int32_t ret; ret = mpd_qget_i32(a, &status); mpd_addstatus_raise(ctx, status); return ret; } #ifndef LEGACY_COMPILER int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; int64_t ret; ret = mpd_qget_i64(a, &status); mpd_addstatus_raise(ctx, status); return ret; } #endif mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_uint_t ret; ret = mpd_qget_uint(a, &status); mpd_addstatus_raise(ctx, status); return ret; } mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_uint_t ret; ret = mpd_qabs_uint(a, &status); mpd_addstatus_raise(ctx, status); return ret; } uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; uint32_t ret; ret = mpd_qget_u32(a, &status); mpd_addstatus_raise(ctx, status); return ret; } #ifndef LEGACY_COMPILER uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; uint64_t ret; ret = mpd_qget_u64(a, &status); mpd_addstatus_raise(ctx, status); return ret; } #endif void mpd_and(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qand(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; if (!mpd_qcopy(result, a, &status)) { mpd_addstatus_raise(ctx, status); } } void mpd_canonical(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { mpd_copy(result, a, ctx); } void mpd_copy_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; if (!mpd_qcopy_abs(result, a, &status)) { mpd_addstatus_raise(ctx, status); } } void mpd_copy_negate(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; if (!mpd_qcopy_negate(result, a, &status)) { mpd_addstatus_raise(ctx, status); } } void mpd_copy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; if (!mpd_qcopy_sign(result, a, b, &status)) { mpd_addstatus_raise(ctx, status); } } void mpd_invert(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qinvert(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_logb(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qlogb(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_or(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qor(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_rotate(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qrotate(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_scaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qscaleb(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_shiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx) { uint32_t status = 0; mpd_qshiftl(result, a, n, &status); mpd_addstatus_raise(ctx, status); } mpd_uint_t mpd_shiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx) { uint32_t status = 0; mpd_uint_t rnd; rnd = mpd_qshiftr(result, a, n, &status); mpd_addstatus_raise(ctx, status); return rnd; } void mpd_shiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx) { uint32_t status = 0; mpd_qshiftn(result, a, n, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_shift(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qshift(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_xor(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qxor(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qabs(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } int mpd_cmp(const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; int c; c = mpd_qcmp(a, b, &status); mpd_addstatus_raise(ctx, status); return c; } int mpd_compare(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; int c; c = mpd_qcompare(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); return c; } int mpd_compare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; int c; c = mpd_qcompare_signal(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); return c; } void mpd_add(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qadd(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_sub(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsub(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_add_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qadd_ssize(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_add_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qadd_i32(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_add_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qadd_i64(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif void mpd_add_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qadd_uint(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_add_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qadd_u32(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_add_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qadd_u64(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif void mpd_sub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsub_ssize(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_sub_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsub_i32(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_sub_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsub_i64(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif void mpd_sub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsub_uint(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_sub_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsub_u32(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_sub_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsub_u64(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif void mpd_div(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdiv(q, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_div_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdiv_ssize(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_div_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdiv_i32(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_div_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdiv_i64(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif void mpd_div_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdiv_uint(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_div_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdiv_u32(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_div_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdiv_u64(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif void mpd_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdivmod(q, r, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_divint(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qdivint(q, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_exp(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qexp(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_fma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, mpd_context_t *ctx) { uint32_t status = 0; mpd_qfma(result, a, b, c, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_ln(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qln(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_log10(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qlog10(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_max(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmax(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_max_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmax_mag(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_min(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmin(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_min_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmin_mag(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qminus(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_mul(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmul(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_mul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmul_ssize(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_mul_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmul_i32(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_mul_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmul_i64(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif void mpd_mul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmul_uint(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_mul_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmul_u32(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #ifndef LEGACY_COMPILER void mpd_mul_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qmul_u64(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } #endif void mpd_next_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qnext_minus(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_next_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qnext_plus(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_next_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qnext_toward(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qplus(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_pow(mpd_t *result, const mpd_t *base, const mpd_t *exp, mpd_context_t *ctx) { uint32_t status = 0; mpd_qpow(result, base, exp, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_powmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, mpd_context_t *ctx) { uint32_t status = 0; mpd_qpowmod(result, base, exp, mod, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_quantize(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qquantize(result, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_rescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, mpd_context_t *ctx) { uint32_t status = 0; mpd_qrescale(result, a, exp, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_reduce(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qreduce(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_rem(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qrem(r, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_rem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx) { uint32_t status = 0; mpd_qrem_near(r, a, b, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_round_to_intx(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qround_to_intx(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_round_to_int(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qround_to_int(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_trunc(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qtrunc(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_floor(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qfloor(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_ceil(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qceil(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_sqrt(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qsqrt(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } void mpd_invroot(mpd_t *result, const mpd_t *a, mpd_context_t *ctx) { uint32_t status = 0; mpd_qinvroot(result, a, ctx, &status); mpd_addstatus_raise(ctx, status); } mpdecimal-4.0.1/libmpdec/numbertheory.c0000644000000000000000000000703115005764474015060 0ustar00/* * Copyright (c) 2008-2025 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 #include #include "bits.h" #include "numbertheory.h" #include "mpdecimal.h" #include "umodarith.h" /* Bignum: Initialize the Number Theoretic Transform. */ /* * Return the nth root of unity in F(p). This corresponds to e**((2*pi*i)/n) * in the Fourier transform. We have w**n == 1 (mod p). * n := transform length. * sign := -1 for forward transform, 1 for backward transform. * modnum := one of {P1, P2, P3}. */ mpd_uint_t _mpd_getkernel(mpd_uint_t n, int sign, int modnum) { mpd_uint_t umod, p, r, xi; #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif SETMODULUS(modnum); r = mpd_roots[modnum]; /* primitive root of F(p) */ p = umod; xi = (p-1) / n; if (sign == -1) return POWMOD(r, (p-1-xi)); else return POWMOD(r, xi); } /* * Initialize and return transform parameters. * n := transform length. * sign := -1 for forward transform, 1 for backward transform. * modnum := one of {P1, P2, P3}. */ struct fnt_params * _mpd_init_fnt_params(mpd_size_t n, int sign, int modnum) { struct fnt_params *tparams; mpd_uint_t umod; #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_uint_t kernel, w; mpd_uint_t i; mpd_size_t nhalf; assert(ispower2(n)); assert(sign == -1 || sign == 1); assert(P1 <= modnum && modnum <= P3); nhalf = n/2; tparams = mpd_sh_alloc(sizeof *tparams, nhalf, sizeof (mpd_uint_t)); if (tparams == NULL) { return NULL; } SETMODULUS(modnum); kernel = _mpd_getkernel(n, sign, modnum); tparams->modnum = modnum; tparams->modulus = umod; tparams->kernel = kernel; /* wtable[] := w**0, w**1, ..., w**(nhalf-1) */ w = 1; for (i = 0; i < nhalf; i++) { tparams->wtable[i] = w; w = MULMOD(w, kernel); } return tparams; } /* Initialize wtable of size three. */ void _mpd_init_w3table(mpd_uint_t w3table[3], int sign, int modnum) { mpd_uint_t umod; #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_uint_t kernel; SETMODULUS(modnum); kernel = _mpd_getkernel(3, sign, modnum); w3table[0] = 1; w3table[1] = kernel; w3table[2] = POWMOD(kernel, 2); } mpdecimal-4.0.1/libmpdec/numbertheory.h0000644000000000000000000000461215005764474015067 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_NUMBERTHEORY_H_ #define LIBMPDEC_NUMBERTHEORY_H_ #include "constants.h" #include "mpdecimal.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) /* transform parameters */ struct fnt_params { int modnum; mpd_uint_t modulus; mpd_uint_t kernel; mpd_uint_t wtable[]; }; mpd_uint_t _mpd_getkernel(mpd_uint_t n, int sign, int modnum); struct fnt_params *_mpd_init_fnt_params(mpd_size_t n, int sign, int modnum); void _mpd_init_w3table(mpd_uint_t w3table[3], int sign, int modnum); #ifdef PPRO static inline void ppro_setmodulus(int modnum, mpd_uint_t *umod, double *dmod, uint32_t dinvmod[3]) { *dmod = *umod = mpd_moduli[modnum]; dinvmod[0] = mpd_invmoduli[modnum][0]; dinvmod[1] = mpd_invmoduli[modnum][1]; dinvmod[2] = mpd_invmoduli[modnum][2]; } #else static inline void std_setmodulus(int modnum, mpd_uint_t *umod) { *umod = mpd_moduli[modnum]; } #endif MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_NUMBERTHEORY_H_ */ mpdecimal-4.0.1/libmpdec/sixstep.c0000644000000000000000000001332715005764474014041 0ustar00/* * Copyright (c) 2008-2025 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 #include #include "bits.h" #include "constants.h" #include "difradix2.h" #include "numbertheory.h" #include "mpdecimal.h" #include "sixstep.h" #include "transpose.h" #include "umodarith.h" /* Bignum: Cache efficient Matrix Fourier Transform for arrays of the form 2**n (See literature/six-step.txt). */ /* forward transform with sign = -1 */ int six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) { struct fnt_params *tparams; mpd_size_t log2n, C, R; mpd_uint_t kernel; mpd_uint_t umod; #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_uint_t *x, w0, w1, wstep; mpd_size_t i, k; assert(ispower2(n)); assert(n >= 16); assert(n <= MPD_MAXTRANSFORM_2N); log2n = mpd_bsr(n); C = ((mpd_size_t)1) << (log2n / 2); /* number of columns */ R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */ /* Transpose the matrix. */ if (!transpose_pow2(a, R, C)) { return 0; } /* Length R transform on the rows. */ if ((tparams = _mpd_init_fnt_params(R, -1, modnum)) == NULL) { return 0; } for (x = a; x < a+n; x += R) { fnt_dif2(x, R, tparams); } /* Transpose the matrix. */ if (!transpose_pow2(a, C, R)) { mpd_free(tparams); return 0; } /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ SETMODULUS(modnum); kernel = _mpd_getkernel(n, -1, modnum); for (i = 1; i < R; i++) { w0 = 1; /* r**(i*0): initial value for k=0 */ w1 = POWMOD(kernel, i); /* r**(i*1): initial value for k=1 */ wstep = MULMOD(w1, w1); /* r**(2*i) */ for (k = 0; k < C; k += 2) { mpd_uint_t x0 = a[i*C+k]; mpd_uint_t x1 = a[i*C+k+1]; MULMOD2(&x0, w0, &x1, w1); MULMOD2C(&w0, &w1, wstep); /* r**(i*(k+2)) = r**(i*k) * r**(2*i) */ a[i*C+k] = x0; a[i*C+k+1] = x1; } } /* Length C transform on the rows. */ if (C != R) { mpd_free(tparams); if ((tparams = _mpd_init_fnt_params(C, -1, modnum)) == NULL) { return 0; } } for (x = a; x < a+n; x += C) { fnt_dif2(x, C, tparams); } mpd_free(tparams); #if 0 /* An unordered transform is sufficient for convolution. */ /* Transpose the matrix. */ if (!transpose_pow2(a, R, C)) { return 0; } #endif return 1; } /* reverse transform, sign = 1 */ int inv_six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) { struct fnt_params *tparams; mpd_size_t log2n, C, R; mpd_uint_t kernel; mpd_uint_t umod; #ifdef PPRO double dmod; uint32_t dinvmod[3]; #endif mpd_uint_t *x, w0, w1, wstep; mpd_size_t i, k; assert(ispower2(n)); assert(n >= 16); assert(n <= MPD_MAXTRANSFORM_2N); log2n = mpd_bsr(n); C = ((mpd_size_t)1) << (log2n / 2); /* number of columns */ R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */ #if 0 /* An unordered transform is sufficient for convolution. */ /* Transpose the matrix, producing an R*C matrix. */ if (!transpose_pow2(a, C, R)) { return 0; } #endif /* Length C transform on the rows. */ if ((tparams = _mpd_init_fnt_params(C, 1, modnum)) == NULL) { return 0; } for (x = a; x < a+n; x += C) { fnt_dif2(x, C, tparams); } /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ SETMODULUS(modnum); kernel = _mpd_getkernel(n, 1, modnum); for (i = 1; i < R; i++) { w0 = 1; w1 = POWMOD(kernel, i); wstep = MULMOD(w1, w1); for (k = 0; k < C; k += 2) { mpd_uint_t x0 = a[i*C+k]; mpd_uint_t x1 = a[i*C+k+1]; MULMOD2(&x0, w0, &x1, w1); MULMOD2C(&w0, &w1, wstep); a[i*C+k] = x0; a[i*C+k+1] = x1; } } /* Transpose the matrix. */ if (!transpose_pow2(a, R, C)) { mpd_free(tparams); return 0; } /* Length R transform on the rows. */ if (R != C) { mpd_free(tparams); if ((tparams = _mpd_init_fnt_params(R, 1, modnum)) == NULL) { return 0; } } for (x = a; x < a+n; x += R) { fnt_dif2(x, R, tparams); } mpd_free(tparams); /* Transpose the matrix. */ if (!transpose_pow2(a, C, R)) { return 0; } return 1; } mpdecimal-4.0.1/libmpdec/sixstep.h0000644000000000000000000000335715005764474014050 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_SIXSTEP_H_ #define LIBMPDEC_SIXSTEP_H_ #include "mpdecimal.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) int six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); int inv_six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_SIXSTEP_H_ */ mpdecimal-4.0.1/libmpdec/transpose.c0000644000000000000000000001655115005764474014362 0ustar00/* * Copyright (c) 2008-2025 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 #include #include #include #include #include "bits.h" #include "constants.h" #include "mpdecimal.h" #include "transpose.h" #include "typearith.h" #define BUFSIZE 4096 #define SIDE 128 /* Bignum: The transpose functions are used for very large transforms in sixstep.c and fourstep.c. */ /* Definition of the matrix transpose */ void std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols) { mpd_size_t idest, isrc; mpd_size_t r, c; for (r = 0; r < rows; r++) { isrc = r * cols; idest = r; for (c = 0; c < cols; c++) { dest[idest] = src[isrc]; isrc += 1; idest += rows; } } } /* * Swap half-rows of 2^n * (2*2^n) matrix. * FORWARD_CYCLE: even/odd permutation of the halfrows. * BACKWARD_CYCLE: reverse the even/odd permutation. */ static int swap_halfrows_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols, int dir) { mpd_uint_t buf1[BUFSIZE]; mpd_uint_t buf2[BUFSIZE]; mpd_uint_t *readbuf, *writebuf, *hp; mpd_size_t *done, dbits; mpd_size_t b = BUFSIZE, stride; mpd_size_t hn, hmax; /* halfrow number */ mpd_size_t m, r=0; mpd_size_t offset; mpd_size_t next; assert(cols == mul_size_t(2, rows)); if (dir == FORWARD_CYCLE) { r = rows; } else if (dir == BACKWARD_CYCLE) { r = 2; } else { abort(); /* GCOV_NOT_REACHED */ } m = cols - 1; hmax = rows; /* cycles start at odd halfrows */ dbits = 8 * sizeof *done; if ((done = mpd_calloc(hmax/(sizeof *done) + 1, sizeof *done)) == NULL) { return 0; } for (hn = 1; hn <= hmax; hn += 2) { if (done[hn/dbits] & mpd_bits[hn%dbits]) { continue; } readbuf = buf1; writebuf = buf2; for (offset = 0; offset < cols/2; offset += b) { stride = (offset + b < cols/2) ? b : cols/2-offset; hp = matrix + hn*cols/2; memcpy(readbuf, hp+offset, stride*(sizeof *readbuf)); pointerswap(&readbuf, &writebuf); next = mulmod_size_t(hn, r, m); hp = matrix + next*cols/2; while (next != hn) { memcpy(readbuf, hp+offset, stride*(sizeof *readbuf)); memcpy(hp+offset, writebuf, stride*(sizeof *writebuf)); pointerswap(&readbuf, &writebuf); done[next/dbits] |= mpd_bits[next%dbits]; next = mulmod_size_t(next, r, m); hp = matrix + next*cols/2; } memcpy(hp+offset, writebuf, stride*(sizeof *writebuf)); done[hn/dbits] |= mpd_bits[hn%dbits]; } } mpd_free(done); return 1; } /* In-place transpose of a square matrix */ static inline void squaretrans(mpd_uint_t *buf, mpd_size_t cols) { mpd_uint_t tmp; mpd_size_t idest, isrc; mpd_size_t r, c; for (r = 0; r < cols; r++) { c = r+1; isrc = r*cols + c; idest = c*cols + r; for (c = r+1; c < cols; c++) { tmp = buf[isrc]; buf[isrc] = buf[idest]; buf[idest] = tmp; isrc += 1; idest += cols; } } } /* * Transpose 2^n * 2^n matrix. For cache efficiency, the matrix is split into * square blocks with side length 'SIDE'. First, the blocks are transposed, * then a square transposition is done on each individual block. */ static void squaretrans_pow2(mpd_uint_t *matrix, mpd_size_t size) { mpd_uint_t buf1[SIDE*SIDE]; mpd_uint_t buf2[SIDE*SIDE]; mpd_uint_t *to, *from; mpd_size_t b = size; mpd_size_t r, c; mpd_size_t i; while (b > SIDE) b >>= 1; for (r = 0; r < size; r += b) { for (c = r; c < size; c += b) { from = matrix + r*size + c; to = buf1; for (i = 0; i < b; i++) { memcpy(to, from, b*(sizeof *to)); from += size; to += b; } squaretrans(buf1, b); if (r == c) { to = matrix + r*size + c; from = buf1; for (i = 0; i < b; i++) { memcpy(to, from, b*(sizeof *to)); from += b; to += size; } continue; } else { from = matrix + c*size + r; to = buf2; for (i = 0; i < b; i++) { memcpy(to, from, b*(sizeof *to)); from += size; to += b; } squaretrans(buf2, b); to = matrix + c*size + r; from = buf1; for (i = 0; i < b; i++) { memcpy(to, from, b*(sizeof *to)); from += b; to += size; } to = matrix + r*size + c; from = buf2; for (i = 0; i < b; i++) { memcpy(to, from, b*(sizeof *to)); from += b; to += size; } } } } } /* * In-place transposition of a 2^n x 2^n or a 2^n x (2*2^n) * or a (2*2^n) x 2^n matrix. */ int transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols) { mpd_size_t size = mul_size_t(rows, cols); assert(ispower2(rows)); assert(ispower2(cols)); if (cols == rows) { squaretrans_pow2(matrix, rows); } else if (cols == mul_size_t(2, rows)) { if (!swap_halfrows_pow2(matrix, rows, cols, FORWARD_CYCLE)) { return 0; } squaretrans_pow2(matrix, rows); squaretrans_pow2(matrix+(size/2), rows); } else if (rows == mul_size_t(2, cols)) { squaretrans_pow2(matrix, cols); squaretrans_pow2(matrix+(size/2), cols); if (!swap_halfrows_pow2(matrix, cols, rows, BACKWARD_CYCLE)) { return 0; } } else { abort(); /* GCOV_NOT_REACHED */ } return 1; } mpdecimal-4.0.1/libmpdec/transpose.h0000644000000000000000000000402515005764474014360 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_TRANSPOSE_H_ #define LIBMPDEC_TRANSPOSE_H_ #include "mpdecimal.h" /* Internal header file: all symbols have local scope in the DSO */ MPD_PRAGMA(MPD_HIDE_SYMBOLS_START) enum {FORWARD_CYCLE, BACKWARD_CYCLE}; void std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols); int transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols); void transpose_3xpow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols); static inline void pointerswap(mpd_uint_t **a, mpd_uint_t **b) { mpd_uint_t *tmp; tmp = *b; *b = *a; *a = tmp; } MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */ #endif /* LIBMPDEC_TRANSPOSE_H_ */ mpdecimal-4.0.1/libmpdec/typearith.h0000644000000000000000000004156715005764474014367 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_TYPEARITH_H_ #define LIBMPDEC_TYPEARITH_H_ #include #include "mpdecimal.h" /*****************************************************************************/ /* Low level native arithmetic on basic types */ /*****************************************************************************/ /** ------------------------------------------------------------ ** Double width multiplication and division ** ------------------------------------------------------------ */ #if defined(CONFIG_64) #if defined(ANSI) #if defined(HAVE_UINT128_T) static inline void _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) { __uint128_t hl; hl = (__uint128_t)a * b; *hi = hl >> 64; *lo = (mpd_uint_t)hl; } static inline void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t d) { __uint128_t hl; hl = ((__uint128_t)hi<<64) + lo; *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */ *r = (mpd_uint_t)(hl - (__uint128_t)(*q) * d); } #else static inline void _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) { uint32_t w[4], carry; uint32_t ah, al, bh, bl; uint64_t hl; ah = (uint32_t)(a>>32); al = (uint32_t)a; bh = (uint32_t)(b>>32); bl = (uint32_t)b; hl = (uint64_t)al * bl; w[0] = (uint32_t)hl; carry = (uint32_t)(hl>>32); hl = (uint64_t)ah * bl + carry; w[1] = (uint32_t)hl; w[2] = (uint32_t)(hl>>32); hl = (uint64_t)al * bh + w[1]; w[1] = (uint32_t)hl; carry = (uint32_t)(hl>>32); hl = ((uint64_t)ah * bh + w[2]) + carry; w[2] = (uint32_t)hl; w[3] = (uint32_t)(hl>>32); *hi = ((uint64_t)w[3]<<32) + w[2]; *lo = ((uint64_t)w[1]<<32) + w[0]; } /* * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt * http://www.hackersdelight.org/permissions.htm: * "You are free to use, copy, and distribute any of the code on this web * site, whether modified by you or not. You need not give attribution." * * Slightly modified, comments are mine. */ static inline int nlz(uint64_t x) { int n; if (x == 0) return(64); n = 0; if (x <= 0x00000000FFFFFFFF) {n = n +32; x = x <<32;} if (x <= 0x0000FFFFFFFFFFFF) {n = n +16; x = x <<16;} if (x <= 0x00FFFFFFFFFFFFFF) {n = n + 8; x = x << 8;} if (x <= 0x0FFFFFFFFFFFFFFF) {n = n + 4; x = x << 4;} if (x <= 0x3FFFFFFFFFFFFFFF) {n = n + 2; x = x << 2;} if (x <= 0x7FFFFFFFFFFFFFFF) {n = n + 1;} return n; } static inline void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0, mpd_uint_t v) { const mpd_uint_t b = 4294967296; mpd_uint_t un1, un0, vn1, vn0, q1, q0, un32, un21, un10, rhat, t; int s; assert(u1 < v); s = nlz(v); v = v << s; vn1 = v >> 32; vn0 = v & 0xFFFFFFFF; t = (s == 0) ? 0 : u0 >> (64 - s); un32 = (u1 << s) | t; un10 = u0 << s; un1 = un10 >> 32; un0 = un10 & 0xFFFFFFFF; q1 = un32 / vn1; rhat = un32 - q1*vn1; again1: if (q1 >= b || q1*vn0 > b*rhat + un1) { q1 = q1 - 1; rhat = rhat + vn1; if (rhat < b) goto again1; } /* * Before again1 we had: * (1) q1*vn1 + rhat = un32 * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1 * * The statements inside the if-clause do not change the value * of the left-hand side of (2), and the loop is only exited * if q1*vn0 <= rhat*b + un1, so: * * (3) q1*vn1*b + q1*vn0 <= un32*b + un1 * (4) q1*v <= un32*b + un1 * (5) 0 <= un32*b + un1 - q1*v * * By (5) we are certain that the possible add-back step from * Knuth's algorithm D is never required. * * Since the final quotient is less than 2**64, the following * must be true: * * (6) un32*b + un1 - q1*v <= UINT64_MAX * * This means that in the following line, the high words * of un32*b and q1*v can be discarded without any effect * on the result. */ un21 = un32*b + un1 - q1*v; q0 = un21 / vn1; rhat = un21 - q0*vn1; again2: if (q0 >= b || q0*vn0 > b*rhat + un0) { q0 = q0 - 1; rhat = rhat + vn1; if (rhat < b) goto again2; } *q = q1*b + q0; *r = (un21*b + un0 - q0*v) >> s; } #endif /* END ANSI */ #elif defined(ASM) static inline void _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) { mpd_uint_t h, l; __asm__ ( "mulq %3\n\t" : "=d" (h), "=a" (l) : "%a" (a), "rm" (b) : "cc" ); *hi = h; *lo = l; } static inline void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t d) { mpd_uint_t qq, rr; __asm__ ( "divq %4\n\t" : "=a" (qq), "=d" (rr) : "a" (lo), "d" (hi), "rm" (d) : "cc" ); *q = qq; *r = rr; } /* END GCC ASM */ #elif defined(MASM) #include #pragma intrinsic(_umul128) static inline void _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) { *lo = _umul128(a, b, hi); } void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t d); /* END MASM (_MSC_VER) */ #else #error "need platform specific 128 bit multiplication and division" #endif #define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d static inline void _mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp) { assert(exp <= 19); if (exp <= 9) { if (exp <= 4) { switch (exp) { case 0: *q = v; *r = 0; break; case 1: DIVMOD(q, r, v, 10UL); break; case 2: DIVMOD(q, r, v, 100UL); break; case 3: DIVMOD(q, r, v, 1000UL); break; case 4: DIVMOD(q, r, v, 10000UL); break; } } else { switch (exp) { case 5: DIVMOD(q, r, v, 100000UL); break; case 6: DIVMOD(q, r, v, 1000000UL); break; case 7: DIVMOD(q, r, v, 10000000UL); break; case 8: DIVMOD(q, r, v, 100000000UL); break; case 9: DIVMOD(q, r, v, 1000000000UL); break; } } } else { if (exp <= 14) { switch (exp) { case 10: DIVMOD(q, r, v, 10000000000ULL); break; case 11: DIVMOD(q, r, v, 100000000000ULL); break; case 12: DIVMOD(q, r, v, 1000000000000ULL); break; case 13: DIVMOD(q, r, v, 10000000000000ULL); break; case 14: DIVMOD(q, r, v, 100000000000000ULL); break; } } else { switch (exp) { case 15: DIVMOD(q, r, v, 1000000000000000ULL); break; case 16: DIVMOD(q, r, v, 10000000000000000ULL); break; case 17: DIVMOD(q, r, v, 100000000000000000ULL); break; case 18: DIVMOD(q, r, v, 1000000000000000000ULL); break; case 19: DIVMOD(q, r, v, 10000000000000000000ULL); break; /* GCOV_NOT_REACHED */ } } } } /* END CONFIG_64 */ #elif defined(CONFIG_32) #if defined(ANSI) #if !defined(LEGACY_COMPILER) static inline void _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) { mpd_uuint_t hl; hl = (mpd_uuint_t)a * b; *hi = hl >> 32; *lo = (mpd_uint_t)hl; } static inline void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t d) { mpd_uuint_t hl; hl = ((mpd_uuint_t)hi<<32) + lo; *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */ *r = (mpd_uint_t)(hl - (mpd_uuint_t)(*q) * d); } /* END ANSI + uint64_t */ #else static inline void _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) { uint16_t w[4], carry; uint16_t ah, al, bh, bl; uint32_t hl; ah = (uint16_t)(a>>16); al = (uint16_t)a; bh = (uint16_t)(b>>16); bl = (uint16_t)b; hl = (uint32_t)al * bl; w[0] = (uint16_t)hl; carry = (uint16_t)(hl>>16); hl = (uint32_t)ah * bl + carry; w[1] = (uint16_t)hl; w[2] = (uint16_t)(hl>>16); hl = (uint32_t)al * bh + w[1]; w[1] = (uint16_t)hl; carry = (uint16_t)(hl>>16); hl = ((uint32_t)ah * bh + w[2]) + carry; w[2] = (uint16_t)hl; w[3] = (uint16_t)(hl>>16); *hi = ((uint32_t)w[3]<<16) + w[2]; *lo = ((uint32_t)w[1]<<16) + w[0]; } /* * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt * http://www.hackersdelight.org/permissions.htm: * "You are free to use, copy, and distribute any of the code on this web * site, whether modified by you or not. You need not give attribution." * * Slightly modified, comments are mine. */ static inline int nlz(uint32_t x) { int n; if (x == 0) return(32); n = 0; if (x <= 0x0000FFFF) {n = n +16; x = x <<16;} if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;} if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;} if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;} if (x <= 0x7FFFFFFF) {n = n + 1;} return n; } static inline void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0, mpd_uint_t v) { const mpd_uint_t b = 65536; mpd_uint_t un1, un0, vn1, vn0, q1, q0, un32, un21, un10, rhat, t; int s; assert(u1 < v); s = nlz(v); v = v << s; vn1 = v >> 16; vn0 = v & 0xFFFF; t = (s == 0) ? 0 : u0 >> (32 - s); un32 = (u1 << s) | t; un10 = u0 << s; un1 = un10 >> 16; un0 = un10 & 0xFFFF; q1 = un32 / vn1; rhat = un32 - q1*vn1; again1: if (q1 >= b || q1*vn0 > b*rhat + un1) { q1 = q1 - 1; rhat = rhat + vn1; if (rhat < b) goto again1; } /* * Before again1 we had: * (1) q1*vn1 + rhat = un32 * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1 * * The statements inside the if-clause do not change the value * of the left-hand side of (2), and the loop is only exited * if q1*vn0 <= rhat*b + un1, so: * * (3) q1*vn1*b + q1*vn0 <= un32*b + un1 * (4) q1*v <= un32*b + un1 * (5) 0 <= un32*b + un1 - q1*v * * By (5) we are certain that the possible add-back step from * Knuth's algorithm D is never required. * * Since the final quotient is less than 2**32, the following * must be true: * * (6) un32*b + un1 - q1*v <= UINT32_MAX * * This means that in the following line, the high words * of un32*b and q1*v can be discarded without any effect * on the result. */ un21 = un32*b + un1 - q1*v; q0 = un21 / vn1; rhat = un21 - q0*vn1; again2: if (q0 >= b || q0*vn0 > b*rhat + un0) { q0 = q0 - 1; rhat = rhat + vn1; if (rhat < b) goto again2; } *q = q1*b + q0; *r = (un21*b + un0 - q0*v) >> s; } #endif /* END ANSI + LEGACY_COMPILER */ /* END ANSI */ #elif defined(ASM) static inline void _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) { mpd_uint_t h, l; __asm__ ( "mull %3\n\t" : "=d" (h), "=a" (l) : "%a" (a), "rm" (b) : "cc" ); *hi = h; *lo = l; } static inline void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t d) { mpd_uint_t qq, rr; __asm__ ( "divl %4\n\t" : "=a" (qq), "=d" (rr) : "a" (lo), "d" (hi), "rm" (d) : "cc" ); *q = qq; *r = rr; } /* END GCC ASM */ #elif defined(MASM) static inline void __cdecl _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) { mpd_uint_t h, l; __asm { mov eax, a mul b mov h, edx mov l, eax } *hi = h; *lo = l; } static inline void __cdecl _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t d) { mpd_uint_t qq, rr; __asm { mov eax, lo mov edx, hi div d mov qq, eax mov rr, edx } *q = qq; *r = rr; } /* END MASM (_MSC_VER) */ #else #error "need platform specific 64 bit multiplication and division" #endif #define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d static inline void _mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp) { assert(exp <= 9); if (exp <= 4) { switch (exp) { case 0: *q = v; *r = 0; break; case 1: DIVMOD(q, r, v, 10UL); break; case 2: DIVMOD(q, r, v, 100UL); break; case 3: DIVMOD(q, r, v, 1000UL); break; case 4: DIVMOD(q, r, v, 10000UL); break; } } else { switch (exp) { case 5: DIVMOD(q, r, v, 100000UL); break; case 6: DIVMOD(q, r, v, 1000000UL); break; case 7: DIVMOD(q, r, v, 10000000UL); break; case 8: DIVMOD(q, r, v, 100000000UL); break; case 9: DIVMOD(q, r, v, 1000000000UL); break; /* GCOV_NOT_REACHED */ } } } /* END CONFIG_32 */ /* NO CONFIG */ #else #error "define CONFIG_64 or CONFIG_32" #endif /* CONFIG */ static inline void _mpd_div_word(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t d) { *q = v / d; *r = v - *q * d; } static inline void _mpd_idiv_word(mpd_ssize_t *q, mpd_ssize_t *r, mpd_ssize_t v, mpd_ssize_t d) { *q = v / d; *r = v - *q * d; } /** ------------------------------------------------------------ ** Arithmetic with overflow checking ** ------------------------------------------------------------ */ /* The following macros do call exit() in case of an overflow. If the library is used correctly (i.e. with valid context parameters), such overflows cannot occur. The macros are used as sanity checks in a couple of strategic places and should be viewed as a handwritten version of gcc's -ftrapv option. */ static inline mpd_size_t add_size_t(mpd_size_t a, mpd_size_t b) { if (a > MPD_SIZE_MAX - b) { mpd_err_fatal("add_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ } return a + b; } static inline mpd_size_t sub_size_t(mpd_size_t a, mpd_size_t b) { if (b > a) { mpd_err_fatal("sub_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ } return a - b; } #if MPD_SIZE_MAX != MPD_UINT_MAX #error "adapt mul_size_t() and mulmod_size_t()" #endif static inline mpd_size_t mul_size_t(mpd_size_t a, mpd_size_t b) { mpd_uint_t hi, lo; _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b); if (hi) { mpd_err_fatal("mul_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ } return lo; } static inline mpd_size_t add_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow) { mpd_size_t ret; *overflow = 0; ret = a + b; if (ret < a) *overflow = 1; return ret; } static inline mpd_size_t mul_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow) { mpd_uint_t hi, lo; _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b); *overflow = (mpd_size_t)hi; return lo; } static inline mpd_ssize_t mod_mpd_ssize_t(mpd_ssize_t a, mpd_ssize_t m) { mpd_ssize_t r = a % m; return (r < 0) ? r + m : r; } static inline mpd_size_t mulmod_size_t(mpd_size_t a, mpd_size_t b, mpd_size_t m) { mpd_uint_t hi, lo; mpd_uint_t q, r; _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b); _mpd_div_words(&q, &r, hi, lo, (mpd_uint_t)m); return r; } #endif /* LIBMPDEC_TYPEARITH_H_ */ mpdecimal-4.0.1/libmpdec/umodarith.h0000644000000000000000000003722115005764474014342 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_UMODARITH_H_ #define LIBMPDEC_UMODARITH_H_ #include "constants.h" #include "mpdecimal.h" #include "typearith.h" /* Bignum: Low level routines for unsigned modular arithmetic. These are used in the fast convolution functions for very large coefficients. */ /**************************************************************************/ /* ANSI modular arithmetic */ /**************************************************************************/ /* * Restrictions: a < m and b < m * ACL2 proof: umodarith.lisp: addmod-correct */ static inline mpd_uint_t addmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) { mpd_uint_t s; s = a + b; s = (s < a) ? s - m : s; s = (s >= m) ? s - m : s; return s; } /* * Restrictions: a < m and b < m * ACL2 proof: umodarith.lisp: submod-2-correct */ static inline mpd_uint_t submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) { mpd_uint_t d; d = a - b; d = (a < b) ? d + m : d; return d; } /* * Restrictions: a < 2m and b < 2m * ACL2 proof: umodarith.lisp: section ext-submod */ static inline mpd_uint_t ext_submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) { mpd_uint_t d; a = (a >= m) ? a - m : a; b = (b >= m) ? b - m : b; d = a - b; d = (a < b) ? d + m : d; return d; } /* * Reduce double word modulo m. * Restrictions: m != 0 * ACL2 proof: umodarith.lisp: section dw-reduce */ static inline mpd_uint_t dw_reduce(mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t m) { mpd_uint_t r1, r2, w; _mpd_div_word(&w, &r1, hi, m); _mpd_div_words(&w, &r2, r1, lo, m); return r2; } /* * Subtract double word from a. * Restrictions: a < m * ACL2 proof: umodarith.lisp: section dw-submod */ static inline mpd_uint_t dw_submod(mpd_uint_t a, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t m) { mpd_uint_t d, r; r = dw_reduce(hi, lo, m); d = a - r; d = (a < r) ? d + m : d; return d; } #ifdef CONFIG_64 /**************************************************************************/ /* 64-bit modular arithmetic */ /**************************************************************************/ /* * A proof of the algorithm is in literature/mulmod-64.txt. An ACL2 * proof is in umodarith.lisp: section "Fast modular reduction". * * Algorithm: calculate (a * b) % p: * * a) hi, lo <- a * b # Calculate a * b. * * b) hi, lo <- R(hi, lo) # Reduce modulo p. * * c) Repeat step b) until 0 <= hi * 2**64 + lo < 2*p. * * d) If the result is less than p, return lo. Otherwise return lo - p. */ static inline mpd_uint_t x64_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) { mpd_uint_t hi, lo, x, y; _mpd_mul_words(&hi, &lo, a, b); if (m & (1ULL<<32)) { /* P1 */ /* first reduction */ x = y = hi; hi >>= 32; x = lo - x; if (x > lo) hi--; y <<= 32; lo = y + x; if (lo < y) hi++; /* second reduction */ x = y = hi; hi >>= 32; x = lo - x; if (x > lo) hi--; y <<= 32; lo = y + x; if (lo < y) hi++; return (hi || lo >= m ? lo - m : lo); } else if (m & (1ULL<<34)) { /* P2 */ /* first reduction */ x = y = hi; hi >>= 30; x = lo - x; if (x > lo) hi--; y <<= 34; lo = y + x; if (lo < y) hi++; /* second reduction */ x = y = hi; hi >>= 30; x = lo - x; if (x > lo) hi--; y <<= 34; lo = y + x; if (lo < y) hi++; /* third reduction */ x = y = hi; hi >>= 30; x = lo - x; if (x > lo) hi--; y <<= 34; lo = y + x; if (lo < y) hi++; return (hi || lo >= m ? lo - m : lo); } else { /* P3 */ /* first reduction */ x = y = hi; hi >>= 24; x = lo - x; if (x > lo) hi--; y <<= 40; lo = y + x; if (lo < y) hi++; /* second reduction */ x = y = hi; hi >>= 24; x = lo - x; if (x > lo) hi--; y <<= 40; lo = y + x; if (lo < y) hi++; /* third reduction */ x = y = hi; hi >>= 24; x = lo - x; if (x > lo) hi--; y <<= 40; lo = y + x; if (lo < y) hi++; return (hi || lo >= m ? lo - m : lo); } } static inline void x64_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) { *a = x64_mulmod(*a, w, m); *b = x64_mulmod(*b, w, m); } static inline void x64_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, mpd_uint_t m) { *a0 = x64_mulmod(*a0, b0, m); *a1 = x64_mulmod(*a1, b1, m); } static inline mpd_uint_t x64_powmod(mpd_uint_t base, mpd_uint_t exp, mpd_uint_t umod) { mpd_uint_t r = 1; while (exp > 0) { if (exp & 1) r = x64_mulmod(r, base, umod); base = x64_mulmod(base, base, umod); exp >>= 1; } return r; } /* END CONFIG_64 */ #else /* CONFIG_32 */ /**************************************************************************/ /* 32-bit modular arithmetic */ /**************************************************************************/ #if defined(ANSI) #if !defined(LEGACY_COMPILER) /* HAVE_UINT64_T */ static inline mpd_uint_t std_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) { return ((mpd_uuint_t) a * b) % m; } static inline void std_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) { *a = ((mpd_uuint_t) *a * w) % m; *b = ((mpd_uuint_t) *b * w) % m; } static inline void std_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, mpd_uint_t m) { *a0 = ((mpd_uuint_t) *a0 * b0) % m; *a1 = ((mpd_uuint_t) *a1 * b1) % m; } /* END HAVE_UINT64_T */ #else /* LEGACY_COMPILER */ static inline mpd_uint_t std_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) { mpd_uint_t hi, lo, q, r; _mpd_mul_words(&hi, &lo, a, b); _mpd_div_words(&q, &r, hi, lo, m); return r; } static inline void std_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) { *a = std_mulmod(*a, w, m); *b = std_mulmod(*b, w, m); } static inline void std_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, mpd_uint_t m) { *a0 = std_mulmod(*a0, b0, m); *a1 = std_mulmod(*a1, b1, m); } /* END LEGACY_COMPILER */ #endif static inline mpd_uint_t std_powmod(mpd_uint_t base, mpd_uint_t exp, mpd_uint_t umod) { mpd_uint_t r = 1; while (exp > 0) { if (exp & 1) r = std_mulmod(r, base, umod); base = std_mulmod(base, base, umod); exp >>= 1; } return r; } #endif /* ANSI CONFIG_32 */ /**************************************************************************/ /* Pentium Pro modular arithmetic */ /**************************************************************************/ /* * A proof of the algorithm is in literature/mulmod-ppro.txt. The FPU * control word must be set to 64-bit precision and truncation mode * prior to using these functions. * * Algorithm: calculate (a * b) % p: * * p := prime < 2**31 * pinv := (long double)1.0 / p (precalculated) * * a) n = a * b # Calculate exact product. * b) qest = n * pinv # Calculate estimate for q = n / p. * c) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient. * d) r = n - q * p # Calculate remainder. * * Remarks: * * - p = dmod and pinv = dinvmod. * - dinvmod points to an array of three uint32_t, which is interpreted * as an 80 bit long double by fldt. * - Intel compilers prior to version 11 do not seem to handle the * __GNUC__ inline assembly correctly. * - random tests are provided in tests/extended/ppro_mulmod.c */ #if defined(PPRO) #if defined(ASM) /* Return (a * b) % dmod */ static inline mpd_uint_t ppro_mulmod(mpd_uint_t a, mpd_uint_t b, double *dmod, uint32_t *dinvmod) { mpd_uint_t retval; __asm__ ( "fildl %2\n\t" "fildl %1\n\t" "fmulp %%st, %%st(1)\n\t" "fldt (%4)\n\t" "fmul %%st(1), %%st\n\t" "flds %5\n\t" "fadd %%st, %%st(1)\n\t" "fsubrp %%st, %%st(1)\n\t" "fldl (%3)\n\t" "fmulp %%st, %%st(1)\n\t" "fsubrp %%st, %%st(1)\n\t" "fistpl %0\n\t" : "=m" (retval) : "m" (a), "m" (b), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63) : "st", "memory" ); return retval; } /* * Two modular multiplications in parallel: * *a0 = (*a0 * w) % dmod * *a1 = (*a1 * w) % dmod */ static inline void ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w, double *dmod, uint32_t *dinvmod) { __asm__ ( "fildl %2\n\t" "fildl (%1)\n\t" "fmul %%st(1), %%st\n\t" "fxch %%st(1)\n\t" "fildl (%0)\n\t" "fmulp %%st, %%st(1) \n\t" "fldt (%4)\n\t" "flds %5\n\t" "fld %%st(2)\n\t" "fmul %%st(2)\n\t" "fadd %%st(1)\n\t" "fsub %%st(1)\n\t" "fmull (%3)\n\t" "fsubrp %%st, %%st(3)\n\t" "fxch %%st(2)\n\t" "fistpl (%0)\n\t" "fmul %%st(2)\n\t" "fadd %%st(1)\n\t" "fsubp %%st, %%st(1)\n\t" "fmull (%3)\n\t" "fsubrp %%st, %%st(1)\n\t" "fistpl (%1)\n\t" : : "r" (a0), "r" (a1), "m" (w), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63) : "st", "memory" ); } /* * Two modular multiplications in parallel: * *a0 = (*a0 * b0) % dmod * *a1 = (*a1 * b1) % dmod */ static inline void ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, double *dmod, uint32_t *dinvmod) { __asm__ ( "fildl %3\n\t" "fildl (%2)\n\t" "fmulp %%st, %%st(1)\n\t" "fildl %1\n\t" "fildl (%0)\n\t" "fmulp %%st, %%st(1)\n\t" "fldt (%5)\n\t" "fld %%st(2)\n\t" "fmul %%st(1), %%st\n\t" "fxch %%st(1)\n\t" "fmul %%st(2), %%st\n\t" "flds %6\n\t" "fldl (%4)\n\t" "fxch %%st(3)\n\t" "fadd %%st(1), %%st\n\t" "fxch %%st(2)\n\t" "fadd %%st(1), %%st\n\t" "fxch %%st(2)\n\t" "fsub %%st(1), %%st\n\t" "fxch %%st(2)\n\t" "fsubp %%st, %%st(1)\n\t" "fxch %%st(1)\n\t" "fmul %%st(2), %%st\n\t" "fxch %%st(1)\n\t" "fmulp %%st, %%st(2)\n\t" "fsubrp %%st, %%st(3)\n\t" "fsubrp %%st, %%st(1)\n\t" "fxch %%st(1)\n\t" "fistpl (%2)\n\t" "fistpl (%0)\n\t" : : "r" (a0), "m" (b0), "r" (a1), "m" (b1), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63) : "st", "memory" ); } /* END PPRO GCC ASM */ #elif defined(MASM) /* Return (a * b) % dmod */ static inline mpd_uint_t __cdecl ppro_mulmod(mpd_uint_t a, mpd_uint_t b, double *dmod, uint32_t *dinvmod) { mpd_uint_t retval; __asm { mov eax, dinvmod mov edx, dmod fild b fild a fmulp st(1), st fld TBYTE PTR [eax] fmul st, st(1) fld MPD_TWO63 fadd st(1), st fsubp st(1), st fld QWORD PTR [edx] fmulp st(1), st fsubp st(1), st fistp retval } return retval; } /* * Two modular multiplications in parallel: * *a0 = (*a0 * w) % dmod * *a1 = (*a1 * w) % dmod */ static inline mpd_uint_t __cdecl ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w, double *dmod, uint32_t *dinvmod) { __asm { mov ecx, dmod mov edx, a1 mov ebx, dinvmod mov eax, a0 fild w fild DWORD PTR [edx] fmul st, st(1) fxch st(1) fild DWORD PTR [eax] fmulp st(1), st fld TBYTE PTR [ebx] fld MPD_TWO63 fld st(2) fmul st, st(2) fadd st, st(1) fsub st, st(1) fmul QWORD PTR [ecx] fsubp st(3), st fxch st(2) fistp DWORD PTR [eax] fmul st, st(2) fadd st, st(1) fsubrp st(1), st fmul QWORD PTR [ecx] fsubp st(1), st fistp DWORD PTR [edx] } } /* * Two modular multiplications in parallel: * *a0 = (*a0 * b0) % dmod * *a1 = (*a1 * b1) % dmod */ static inline void __cdecl ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, double *dmod, uint32_t *dinvmod) { __asm { mov ecx, dmod mov edx, a1 mov ebx, dinvmod mov eax, a0 fild b1 fild DWORD PTR [edx] fmulp st(1), st fild b0 fild DWORD PTR [eax] fmulp st(1), st fld TBYTE PTR [ebx] fld st(2) fmul st, st(1) fxch st(1) fmul st, st(2) fld DWORD PTR MPD_TWO63 fld QWORD PTR [ecx] fxch st(3) fadd st, st(1) fxch st(2) fadd st, st(1) fxch st(2) fsub st, st(1) fxch st(2) fsubrp st(1), st fxch st(1) fmul st, st(2) fxch st(1) fmulp st(2), st fsubp st(3), st fsubp st(1), st fxch st(1) fistp DWORD PTR [edx] fistp DWORD PTR [eax] } } #endif /* PPRO MASM (_MSC_VER) */ /* Return (base ** exp) % dmod */ static inline mpd_uint_t ppro_powmod(mpd_uint_t base, mpd_uint_t exp, double *dmod, uint32_t *dinvmod) { mpd_uint_t r = 1; while (exp > 0) { if (exp & 1) r = ppro_mulmod(r, base, dmod, dinvmod); base = ppro_mulmod(base, base, dmod, dinvmod); exp >>= 1; } return r; } #endif /* PPRO */ #endif /* CONFIG_32 */ #endif /* LIBMPDEC_UMODARITH_H_ */ mpdecimal-4.0.1/libmpdec/vcdiv64.asm0000644000000000000000000000315115005764474014157 0ustar00; ; Copyright (c) 2008-2025 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. ; PUBLIC _mpd_div_words _TEXT SEGMENT q$ = 8 r$ = 16 hi$ = 24 lo$ = 32 d$ = 40 _mpd_div_words PROC mov r10, rdx mov rdx, r8 mov rax, r9 div QWORD PTR d$[rsp] mov QWORD PTR [r10], rdx mov QWORD PTR [rcx], rax ret 0 _mpd_div_words ENDP _TEXT ENDS END mpdecimal-4.0.1/libmpdec++/0000755000000000000000000000000015005764474012316 5ustar00mpdecimal-4.0.1/libmpdec++/.objs/0000755000000000000000000000000015005764474013331 5ustar00mpdecimal-4.0.1/libmpdec++/.objs/README.txt0000644000000000000000000000004515005764474015026 0ustar00 Directory for shared object files. mpdecimal-4.0.1/libmpdec++/.pc/0000755000000000000000000000000015005764474012776 5ustar00mpdecimal-4.0.1/libmpdec++/.pc/libmpdec++.pc.in0000644000000000000000000000045015005764474015633 0ustar00prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libmpdec++ Description: C++ library for decimal floating point arithmetic Version: 4.0.1 URL: https://www.bytereef.org Requires: libmpdec = 4.0.1 Cflags: -I${includedir} Libs: -L${libdir} -lmpdec++ -pthread mpdecimal-4.0.1/libmpdec++/.profile/0000755000000000000000000000000015005764474014034 5ustar00mpdecimal-4.0.1/libmpdec++/.profile/train.sh0000755000000000000000000000220315005764474015505 0ustar00#!/bin/sh PORTABLE_PWD=`pwd` LD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD:$LD_LIBRARY_PATH" DYLD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD:$DYLD_LIBRARY_PATH" LD_64_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD:$LD_64_LIBRARY_PATH" LD_32_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD:$LD_32_LIBRARY_PATH" LD_LIBRARY_PATH_64="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD:$LD_LIBRARY_PATH_64" LD_LIBRARY_PATH_32="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD:$LD_LIBRARY_PATH_32" PATH="$LD_LIBRARY_PATH:$PATH" export LD_LIBRARY_PATH export DYLD_LIBRARY_PATH export LD_64_LIBRARY_PATH export LD_32_LIBRARY_PATH export LD_LIBRARY_PATH_64 export LD_LIBRARY_PATH_32 MPD_PREC="$1" MPD_DPREC=`expr "$MPD_PREC" \* 2` if [ ! -f ./bench_full -a ! -f ./bench_shared ]; then printf "\n./train.sh: error: no training files found\n\n" exit 1 fi if [ -f ./bench_full ]; then ./bench_full "$MPD_PREC" 1000 > /dev/null 2>&1 ./bench_full "$MPD_DPREC" 1000 > /dev/null 2>&1 fi if [ -f ./bench_shared ]; then ./bench_shared "$MPD_PREC" 1000000 > /dev/null 2>&1 ./bench_shared "$MPD_DPREC" 1000000 > /dev/null 2>&1 fi mpdecimal-4.0.1/libmpdec++/Makefile.in0000644000000000000000000001241315005764474014364 0ustar00 # ============================================================================== # Unix Makefile for libmpdec++ # ============================================================================== prefix = @prefix@ exec_prefix = @exec_prefix@ libdir = @libdir@ ENABLE_STATIC = @ENABLE_STATIC@ ENABLE_SHARED = @ENABLE_SHARED@ ENABLE_MINGW = @ENABLE_MINGW@ FPIC = @FPIC@ LIBSTATIC = @LIBSTATIC@ LIBNAME = @LIBNAME@ LIBSONAME = @LIBSONAME@ LIBSHARED = @LIBSHARED@ LIBIMPORT = @LIBIMPORT@ LIBSTATIC_CXX = @LIBSTATIC_CXX@ LIBNAME_CXX = @LIBNAME_CXX@ LIBSONAME_CXX = @LIBSONAME_CXX@ LIBSHARED_CXX = @LIBSHARED_CXX@ LIBIMPORT_CXX = @LIBIMPORT_CXX@ LIBSHARED_USE_AR = @LIBSHARED_USE_AR@ LINK_STATIC = @LINK_STATIC@ LINK_DYNAMIC = @LINK_DYNAMIC@ OBJECT_SUFFIX = @OBJECT_SUFFIX@ COPY = @cp -f $1 $2 CXX = @CXX@ LDXX = @LDXX@ AR = @AR@ RANLIB = @RANLIB@ MPD_PTHREAD = @MPD_PTHREAD@ MPD_PGEN = @MPD_PGEN@ MPD_PUSE = @MPD_PUSE@ MPD_PREC = @MPD_PREC@ MPD_CXX = $(strip $(CXX) $(MPD_PTHREAD)) MPD_LDXX = $(strip $(LDXX) $(MPD_PTHREAD)) FILTER_FOR_STATIC = @FILTER_FOR_STATIC@ CONFIGURE_CXXFLAGS = @CONFIGURE_CXXFLAGS@ MPD_CXXFLAGS_COMMON = $(strip $(filter-out $(CXXFLAGS),$(CONFIGURE_CXXFLAGS)) $(CXXFLAGS)) MPD_CXXFLAGS_SHARED = $(strip $(filter-out $(FPIC),$(MPD_CXXFLAGS_COMMON)) $(FPIC)) MPD_CXXFLAGS = $(strip $(filter-out $(FILTER_FOR_STATIC),$(MPD_CXXFLAGS_COMMON))) CONFIGURE_LDXXFLAGS = @CONFIGURE_LDXXFLAGS@ MPD_LDXXFLAGS = $(strip $(filter-out $(LDXXFLAGS),$(CONFIGURE_LDXXFLAGS)) $(LDXXFLAGS)) LINK_LIBSTATIC = $(strip $(LINK_STATIC) $(LIBSTATIC_CXX) ../libmpdec/$(LIBSTATIC) $(LINK_DYNAMIC)) ifeq ($(MAKECMDGOALS), profile_gen) MPD_CXXFLAGS_COMMON += $(MPD_PGEN) MPD_LDXXFLAGS += $(MPD_PGEN) endif ifeq ($(MAKECMDGOALS), profile_use) MPD_CXXFLAGS_COMMON += $(MPD_PUSE) MPD_LDXXFLAGS += $(MPD_PUSE) endif MPD_TARGETS = ifeq ($(ENABLE_STATIC), yes) MPD_TARGETS += $(LIBSTATIC_CXX) endif ifeq ($(ENABLE_SHARED), yes) MPD_TARGETS += $(LIBSHARED_CXX) endif default: $(MPD_TARGETS) OBJS := decimal.o SHARED_OBJS := .objs/decimal.o ifeq ($(LIBSHARED_USE_AR), yes) AR_STATIC_OBJS := $(OBJS:.o=$(OBJECT_SUFFIX)) AR_SHARED_OBJS := $(LIBSHARED:.o=$(OBJECT_SUFFIX)) %$(OBJECT_SUFFIX): %.o $(call COPY,$<,$@) # Disabled: C++ symbol extraction is not reliable. $(LIBSHARED_CXX): $(LIBSTATIC_CXX): Makefile $(AR_STATIC_OBJS) $(AR) rc $(LIBSTATIC_CXX) $(AR_STATIC_OBJS) $(RANLIB) $(LIBSTATIC_CXX) else $(LIBSTATIC_CXX): Makefile $(OBJS) $(AR) rc $(LIBSTATIC_CXX) $(OBJS) $(RANLIB) $(LIBSTATIC_CXX) $(LIBSHARED_CXX): Makefile $(SHARED_OBJS) ifeq ($(ENABLE_MINGW), yes) $(LDXX) $(MPD_LDXXFLAGS) -o $(LIBSHARED_CXX) $(SHARED_OBJS) ../libmpdec/$(LIBIMPORT) -lm else $(MPD_LDXX) -L../libmpdec $(MPD_LDXXFLAGS) -o $(LIBSHARED_CXX) $(SHARED_OBJS) -lmpdec -lm ln -sf $(LIBSHARED_CXX) $(LIBNAME_CXX) ln -sf $(LIBSHARED_CXX) $(LIBSONAME_CXX) endif endif decimal.o:\ Makefile decimal.cc ../libmpdec/mpdecimal.h decimal.hh $(MPD_CXX) -I. -I../libmpdec $(MPD_CXXFLAGS) -c decimal.cc .objs/decimal.o:\ Makefile decimal.cc ../libmpdec/mpdecimal.h decimal.hh $(MPD_CXX) -I. -I../libmpdec $(MPD_CXXFLAGS_SHARED) -c decimal.cc -o .objs/decimal.o bench: Makefile bench.cc ../libmpdec/mpdecimal.h decimal.hh $(LIBSTATIC_CXX) $(MPD_CXX) -I. -I../libmpdec $(MPD_CXXFLAGS) -o bench bench.cc $(LINK_LIBSTATIC) -lm bench_full: Makefile bench_full.cc ../libmpdec/mpdecimal.h decimal.hh $(LIBSTATIC_CXX) $(MPD_CXX) -I. -I../libmpdec $(MPD_CXXFLAGS) -o bench_full bench_full.cc $(LINK_LIBSTATIC) -lm bench_shared: Makefile bench.cc ../libmpdec/mpdecimal.h decimal.hh $(LIBSHARED_CXX) $(MPD_CXX) -I. -I../libmpdec -L. -L../libmpdec $(MPD_CXXFLAGS_COMMON) -o bench_shared bench.cc -lm -lmpdec++ -lmpdec bench_full_shared: Makefile bench_full.cc ../libmpdec/mpdecimal.h decimal.hh $(LIBSHARED_CXX) $(MPD_CXX) -I. -I../libmpdec -L. -L../libmpdec $(MPD_CXXFLAGS_COMMON) -o bench_full_shared bench_full.cc -lm -lmpdec++ -lmpdec factorial: Makefile examples/factorial.cc $(LIBSTATIC_CXX) $(MPD_CXX) -I. -I../libmpdec $(MPD_CXXFLAGS) -o factorial examples/factorial.cc $(LINK_LIBSTATIC) -lm pi: Makefile examples/pi.cc $(LIBSTATIC_CXX) $(MPD_CXX) -I. -I../libmpdec $(MPD_CXXFLAGS) -o pi examples/pi.cc $(LINK_LIBSTATIC) -lm examples: factorial pi GEN_TARGETS = ifeq ($(ENABLE_STATIC), yes) GEN_TARGETS += bench_full endif ifeq ($(ENABLE_SHARED), yes) GEN_TARGETS += bench_shared endif profile_gen: $(GEN_TARGETS) ./.profile/train.sh $(MPD_PREC) profile_clean: rm -f *.o *.so *.gch rm -f bench bench_shared bench_full bench_full_shared factorial pi rm -f $(LIBSTATIC_CXX) $(LIBNAME_CXX) $(LIBSONAME_CXX) $(LIBSHARED_CXX) $(LIBIMPORT_CXX) cd .objs && rm -f *.o *.so *.gch profile_use: default profile: $(MAKE) clean $(MAKE) profile_gen $(MAKE) profile_clean $(MAKE) profile_use check: default cd ../tests++ && $(MAKE) && ./runshort.sh check_local: default cd ../tests++ && $(MAKE) && ./runshort.sh --local check_alloc: default cd ../tests++ && $(MAKE) && ./runshort_alloc.sh clean: rm -f *.o *.so *.gch *.gcda *.gcno *.gcov *.dyn *.dpi *.lock rm -f bench bench_shared bench_full bench_full_shared factorial pi rm -f $(LIBSTATIC_CXX) $(LIBNAME_CXX) $(LIBSONAME_CXX) $(LIBSHARED_CXX) $(LIBIMPORT_CXX) cd .objs && rm -f *.o *.so *.gch *.gcda *.gcno *.gcov *.dyn *.dpi *.lock distclean: clean rm -f Makefile .pc/libmpdec++.pc mpdecimal-4.0.1/libmpdec++/Makefile.vc0000644000000000000000000000531715005764474014373 0ustar00 # ====================================================================== # Visual C (nmake) Makefile for libmpdec++ # ====================================================================== SRCDIR = ..\libmpdec LIBSTATIC = libmpdec-4.0.1.lib LIBIMPORT = libmpdec-4.0.1.dll.lib LIBSHARED = libmpdec-4.0.1.dll LIBSTATIC_CXX = libmpdec++-4.0.1.lib LIBIMPORT_CXX = libmpdec++-4.0.1.dll.lib LIBSHARED_CXX = libmpdec++-4.0.1.dll !if "$(DEBUG)" == "1" OPT = /MTd /Od /Zi /EHsc OPT_SHARED = /MDd /Od /Zi /EHsc !else OPT = /MT /O2 /GS /EHsc /DNDEBUG OPT_SHARED = /MD /O2 /GS /EHsc /DNDEBUG !endif !if "$(CC)" == "clang-cl" WARN = /W4 -Wno-undefined-inline !else WARN = /W4 !endif MPD_CXXFLAGS = $(WARN) /nologo $(OPT) MPD_CXXFLAGS_SHARED = /DBUILD_LIBMPDECXX $(WARN) /nologo $(OPT_SHARED) $(PGOFLAGS) MPD_BIN_CXXFLAGS_SHARED = $(WARN) /nologo $(OPT_SHARED) $(PGOFLAGS) MPD_LDXXFLAGS= /DLL /MANIFEST $(LDXXFLAGS) default: $(LIBSTATIC_CXX) $(LIBSHARED_CXX) OBJS = decimal.obj SHARED_OBJS = .objs\decimal.obj $(LIBSTATIC_CXX): Makefile $(OBJS) -@if exist $@ del $(LIBSTATIC_CXX) lib /out:$(LIBSTATIC_CXX) $(OBJS) $(LIBSHARED_CXX): Makefile $(SHARED_OBJS) -@if exist $@ del $(LIBSHARED_CXX) link $(MPD_LDXXFLAGS) /out:$(LIBSHARED_CXX) /implib:$(LIBIMPORT_CXX) /LIBPATH:$(SRCDIR) $(SHARED_OBJS) $(LIBIMPORT) mt -manifest $(LIBSHARED_CXX).manifest -outputresource:$(LIBSHARED_CXX);2 decimal.obj:\ Makefile decimal.cc ..\libmpdec\mpdecimal.h decimal.hh $(CXX) "-I." "-I$(SRCDIR)" $(MPD_CXXFLAGS) -c decimal.cc .objs\decimal.obj:\ Makefile decimal.cc ..\libmpdec\mpdecimal.h decimal.hh $(CXX) "-I." "-I$(SRCDIR)" $(MPD_CXXFLAGS_SHARED) -c decimal.cc /Fo.objs\decimal.obj FORCE: bench: FORCE $(CXX) "-I." "-I$(SRCDIR)" $(MPD_CXXFLAGS) /O2 /EHsc /Fo:bench bench.cc $(LIBSTATIC_CXX) $(SRCDIR)\$(LIBSTATIC) bench_shared: FORCE $(CXX) "-I." "-I$(SRCDIR)" $(MPD_BIN_CXXFLAGS_SHARED) /O2 /EHsc /Fo:bench_shared bench.cc $(LIBIMPORT_CXX) $(SRCDIR)\$(LIBIMPORT) examples: FORCE $(CXX) "-I." "-I$(SRCDIR)" $(MPD_CXXFLAGS) /O2 /EHsc /Fo:factorial examples/factorial.cc $(LIBSTATIC_CXX) $(SRCDIR)\$(LIBSTATIC) $(CXX) "-I." "-I$(SRCDIR)" $(MPD_CXXFLAGS) /O2 /EHsc /Fo:pi examples/pi.cc $(LIBSTATIC_CXX) $(SRCDIR)\$(LIBSTATIC) clean: FORCE -@if exist *.obj del *.obj -@cd .objs -@if exist *.obj del *.obj -@cd .. -@if exist *.dll del *.dll -@if exist *.exp del *.exp -@if exist *.lib del *.lib -@if exist *.ilk del *.ilk -@if exist *.pdb del *.pdb -@if exist *.pgc del *.pgc -@if exist *.pgd del *.pgd -@if exist *.manifest del *.manifest -@if exist *.exe del *.exe -@cd ..\tests++ -@if exist Makefile nmake clean distclean: FORCE nmake clean -@if exist Makefile del Makefile -@cd ..\tests -@if exist Makefile nmake distclean mpdecimal-4.0.1/libmpdec++/bench.cc0000644000000000000000000000523615005764474013712 0ustar00/* * Copyright (c) 2020-2025 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 #include #include #include #include #include "mpdecimal.h" #include "decimal.hh" using decimal::Decimal; using decimal::Context; using decimal::context; /* Nonsense version of escape-time algorithm for calculating a Mandelbrot * set. Just for benchmarking. */ void color_point(Decimal& x0, const Decimal& y0, long maxiter) { Decimal x = 0; Decimal y = 0; Decimal sq_x = 0; Decimal sq_y = 0; Decimal two{2}; for (long i = 0; i < maxiter; i++) { y = x * y; y = y * two; y = y + y0; x = sq_x - sq_y; x = x + x0; sq_x = x * x; sq_y = y * y; } x0 = x; } int main(int argc, char **argv) { const double clocks_per_sec = CLOCKS_PER_SEC; clock_t start_clock, end_clock; uint32_t prec; long iter; assert(MPD_MINALLOC == 4); if (argc != 3) { fprintf(stderr, "usage: bench prec iter\n"); exit(1); } prec = strtoul(argv[1], NULL, 10); iter = strtol(argv[2], NULL, 10); context.prec(prec); Decimal x0{"0.222"}; Decimal y0{"0.333"}; start_clock = clock(); color_point(x0, y0, iter); end_clock = clock(); std::cout << x0 << std::endl; fprintf(stderr, "time: %f\n\n", (end_clock-start_clock)/clocks_per_sec); return 0; } mpdecimal-4.0.1/libmpdec++/bench_full.cc0000644000000000000000000000726315005764474014736 0ustar00/* * Copyright (c) 2020-2025 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 #include #include #include #include "mpdecimal.h" #include "decimal.hh" using decimal::Decimal; using decimal::Context; using decimal::context; /* * Example from: http://en.wikipedia.org/wiki/Mandelbrot_set * * Escape time algorithm for drawing the set: * * Point x0, y0 is deemed to be in the Mandelbrot set if the return * value is maxiter. Lower return values indicate how quickly points * escaped and can be used for coloring. */ int color_point(const Decimal& x0, const Decimal& y0, const int maxiter) { int i = 0; Decimal x = 0; Decimal y = 0; Decimal sq_x = 0; Decimal sq_y = 0; const Decimal two = 2; const Decimal four = 4; Decimal c = 0; for (i = 0; i < maxiter && c <= four; i++) { y = x * y; y *= two; y += y0; x = sq_x - sq_y; x += x0; sq_x = x * x; sq_y = y * y; c = sq_x + sq_y; } return i; } int main(int argc, char **argv) { const double clocks_per_sec = CLOCKS_PER_SEC; clock_t start_clock, end_clock; uint32_t prec = 19; int iter = 1000; int points[40][80]; int i, j; if (argc != 3) { fprintf(stderr, "usage: ./bench prec iter\n"); exit(1); } prec = strtoul(argv[1], NULL, 10); iter = strtol(argv[2], NULL, 10); context.prec(prec); Decimal x0; Decimal sqrt_2 = Decimal(2).sqrt(); Decimal xstep = sqrt_2 / 40; Decimal ystep = sqrt_2 / 20; start_clock = clock(); Decimal y0 = sqrt_2; for (i = 0; i < 40; i++) { x0 = -sqrt_2; for (j = 0; j < 80; j++) { points[i][j] = color_point(x0, y0, iter); x0 += xstep; } y0 -= ystep; } end_clock = clock(); #ifdef BENCH_VERBOSE for (i = 0; i < 40; i++) { for (j = 0; j < 80; j++) { if (points[i][j] == iter) { putchar('*'); } else if (points[i][j] >= 10) { putchar('+'); } else if (points[i][j] >= 5) { putchar('.'); } else { putchar(' '); } } putchar('\n'); } putchar('\n'); #else (void)points; /* suppress gcc warning */ #endif printf("time: %f\n\n", (end_clock-start_clock)/clocks_per_sec); return 0; } mpdecimal-4.0.1/libmpdec++/decimal.cc0000644000000000000000000002116315005764474014226 0ustar00/* * Copyright (c) 2020-2025 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 #include #include #include #include "mpdecimal.h" #include "decimal.hh" /*****************************************************************************/ /* Library init */ /*****************************************************************************/ namespace { class LibraryInit { public: LibraryInit() { mpd_setminalloc(decimal::MINALLOC); } }; const LibraryInit init; } // namespace /*****************************************************************************/ /* Context */ /*****************************************************************************/ namespace { typedef struct { const uint32_t flag; const char *name; const char *fqname; void (* const raise)(const std::string& msg); } cmap; template void raise(const std::string& msg) { throw T(msg); } const cmap signal_map[] = { { MPD_IEEE_Invalid_operation, "IEEEInvalidOperation", "decimal::IEEEInvalidOperation", raise }, { MPD_Division_by_zero, "DivisionByZero", "decimal::DivisionByZero", raise }, { MPD_Overflow, "Overflow", "decimal::Overflow", raise }, { MPD_Underflow, "Underflow", "decimal::Underflow", raise }, { MPD_Subnormal, "Subnormal", "decimal::Subnormal", raise }, { MPD_Inexact, "Inexact", "decimal::Inexact", raise }, { MPD_Rounded, "Rounded", "decimal::Rounded", raise }, { MPD_Clamped, "Clamped", "decimal::Clamped", raise }, { UINT32_MAX, nullptr, nullptr, nullptr } }; const cmap cond_map[] = { { MPD_Invalid_operation, "InvalidOperation", "decimal::InvalidOperation", raise }, { MPD_Conversion_syntax, "ConversionSyntax", "decimal::ConversionSyntax", raise }, { MPD_Division_impossible, "DivisionImpossible", "decimal::DivisionImpossible", raise }, { MPD_Division_undefined, "DivisionUndefined", "decimal::DivisionUndefined", raise }, { UINT32_MAX, nullptr, nullptr, nullptr } }; std::string signals(const uint32_t flags) { std::string s; s.reserve(MPD_MAX_SIGNAL_LIST); s += "["; for (const cmap *c = signal_map; c->flag != UINT32_MAX; c++) { if (flags & c->flag) { if (s != "[") { s += ", "; } s += c->name; } } s += "]"; return s; } std::string flags(const uint32_t flags) { std::string s; s.reserve(MPD_MAX_FLAG_LIST); s += "["; for (const cmap *c = cond_map; c->flag != UINT32_MAX; c++) { if (flags & c->flag) { if (s != "[") { s += ", "; } s += c->name; } } for (const cmap *c = signal_map+1; c->flag != UINT32_MAX; c++) { if (flags & c->flag) { if (s != "[") { s += ", "; } s += c->name; } } s += "]"; return s; } /* Context for exact calculations with (practically) unbounded precision. */ const decimal::Context maxcontext { MPD_MAX_PREC, MPD_MAX_EMAX, MPD_MIN_EMIN, MPD_ROUND_HALF_EVEN, MPD_IEEE_Invalid_operation, 0, 0 }; } // namespace /*****************************************************************************/ /* Context API */ /*****************************************************************************/ namespace decimal { /* Used for default initialization of new contexts such as TLS contexts. */ Context context_template { 16, /* prec */ 999999, /* emax */ -999999, /* emin */ MPD_ROUND_HALF_EVEN, /* rounding */ MPD_IEEE_Invalid_operation|MPD_Division_by_zero|MPD_Overflow, /* traps */ 0, /* clamp */ 1 /* allcr */ }; #if defined(__OpenBSD__) || defined(__sun) || defined(_MSC_VER) && defined(_DLL) Context& getcontext() { static thread_local Context _context{context_template}; return _context; } #else thread_local Context context{context_template}; #endif /* Factory function for creating a context for maximum unrounded arithmetic. */ Context MaxContext() { return Context(maxcontext); } /* Factory function for creating IEEE interchange format contexts. */ Context IEEEContext(int bits) { mpd_context_t ctx; if (mpd_ieee_context(&ctx, bits) < 0) { throw ValueError("argument must be a multiple of 32, with a maximum of " + std::to_string(MPD_IEEE_CONTEXT_MAX_BITS)); } return Context(ctx); } void Context::raiseit(const uint32_t status) { if (status & MPD_Malloc_error) { throw MallocError("out of memory"); } const std::string msg = flags(status); for (const cmap *c = cond_map; c->flag != UINT32_MAX; c++) { if (status & c->flag) { c->raise(msg); } } for (const cmap *c = signal_map+1; c->flag != UINT32_MAX; c++) { if (status & c->flag) { c->raise(msg); } } throw RuntimeError("internal_error: unknown status flag"); } std::string Context::repr() const { const int rounding = round(); std::ostringstream ss; if (rounding < 0 || rounding >= MPD_ROUND_GUARD) { throw RuntimeError("internal_error: invalid rounding mode"); } const char *round_str = mpd_round_string[rounding]; ss << "Context(prec=" << prec() << ", " << "emax=" << emax() << ", " << "emin=" << emin() << ", " << "round=" << round_str << ", " << "clamp=" << clamp() << ", " << "traps=" << signals(traps()) << ", " << "status=" << signals(status()) << ")"; return ss.str(); } std::ostream& operator<<(std::ostream& os, const Context& c) { os << c.repr(); return os; } /*****************************************************************************/ /* Decimal API */ /*****************************************************************************/ Decimal Decimal::exact(const char *const s, Context& c) { Decimal result; uint32_t status = 0; if (s == nullptr) { throw ValueError("Decimal::exact: string argument is NULL"); } mpd_qset_string_exact(result.get(), s, &status); c.raise(status); return result; } Decimal Decimal::exact(const std::string& s, Context& c) { return Decimal::exact(s.c_str(), c); } Decimal Decimal::ln10(int64_t n, Context& c) { Decimal result; uint32_t status = 0; if (n < 1 || n > MPD_MAX_PREC) { throw ValueError("Decimal::ln10: prec argument must in [1, MAX_PREC]"); } mpd_ssize_t nn = util::safe_downcast(n); mpd_qln10(result.get(), nn, &status); c.raise(status); return result; } int32_t Decimal::radix() { return 10; } std::string Decimal::repr(bool capitals) const { std::string s = to_sci(capitals); return "Decimal(\"" + s + "\")"; } std::ostream& operator<<(std::ostream& os, const Decimal& dec) { os << dec.to_sci(); return os; } } // namespace decimal mpdecimal-4.0.1/libmpdec++/decimal.hh0000644000000000000000000014140715005764474014244 0ustar00/* * Copyright (c) 2020-2025 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. */ #ifndef LIBMPDECXX_DECIMAL_HH_ #define LIBMPDECXX_DECIMAL_HH_ #include #include #include #include #include #include #include #include #include #include #include #include #include #undef iscanonical /* math.h */ #undef isfinite /* math.h */ #undef isinf /* math.h */ #undef isnan /* math.h */ #undef isnormal /* math.h */ #undef issubnormal /* math.h */ #undef iszero /* math.h */ #undef isspecial /* ctype.h */ #undef IMPORTEXPORT #ifdef _MSC_VER #if defined (BUILD_LIBMPDECXX) #define IMPORTEXPORT __declspec(dllexport) #elif defined(_DLL) #define IMPORTEXPORT __declspec(dllimport) #else #define IMPORTEXPORT #endif #define ALWAYS_INLINE __forceinline #else #define IMPORTEXPORT #define ALWAYS_INLINE inline #endif namespace decimal { /******************************************************************************/ /* Constants from libmpdec */ /******************************************************************************/ enum round { ROUND_UP = MPD_ROUND_UP, /* round away from 0 */ ROUND_DOWN = MPD_ROUND_DOWN, /* round toward 0 (truncate) */ ROUND_CEILING = MPD_ROUND_CEILING, /* round toward +infinity */ ROUND_FLOOR = MPD_ROUND_FLOOR, /* round toward -infinity */ ROUND_HALF_UP = MPD_ROUND_HALF_UP, /* 0.5 is rounded up */ ROUND_HALF_DOWN = MPD_ROUND_HALF_DOWN, /* 0.5 is rounded down */ ROUND_HALF_EVEN = MPD_ROUND_HALF_EVEN, /* 0.5 is rounded to even */ ROUND_05UP = MPD_ROUND_05UP, /* round zero or five away from 0 */ ROUND_TRUNC = MPD_ROUND_TRUNC, /* truncate, but set infinity */ ROUND_GUARD = MPD_ROUND_GUARD }; /* * Aliases for a spelling that is consistent with the exceptions below. * Use whichever form you prefer. */ constexpr uint32_t DecClamped = MPD_Clamped; constexpr uint32_t DecConversionSyntax = MPD_Conversion_syntax; constexpr uint32_t DecDivisionByZero = MPD_Division_by_zero; constexpr uint32_t DecDivisionImpossible = MPD_Division_impossible; constexpr uint32_t DecDivisionUndefined = MPD_Division_undefined; constexpr uint32_t DecFpuError = MPD_Fpu_error; /* unused */ constexpr uint32_t DecInexact = MPD_Inexact; constexpr uint32_t DecInvalidContext = MPD_Invalid_context; constexpr uint32_t DecInvalidOperation = MPD_Invalid_operation; constexpr uint32_t DecMallocError = MPD_Malloc_error; constexpr uint32_t DecNotImplemented = MPD_Not_implemented; /* unused */ constexpr uint32_t DecOverflow = MPD_Overflow; constexpr uint32_t DecRounded = MPD_Rounded; constexpr uint32_t DecSubnormal = MPD_Subnormal; constexpr uint32_t DecUnderflow = MPD_Underflow; /* Flag sets */ constexpr uint32_t DecIEEEInvalidOperation = MPD_IEEE_Invalid_operation; /* DecConversionSyntax */ /* DecDivisionImpossible */ /* DecDivisionUndefined */ /* DecFpuError */ /* DecInvalidContext */ /* DecInvalidOperation */ /* DecMallocError */ constexpr uint32_t DecErrors = MPD_Errors; /* DecIEEEInvalidOperation */ /* DecDivisionByZero */ constexpr uint32_t DecMaxStatus = MPD_Max_status; /* All flags */ /* IEEEContext(): common arguments */ constexpr int DECIMAL32 = MPD_DECIMAL32; constexpr int DECIMAL64 = MPD_DECIMAL64; constexpr int DECIMAL128 = MPD_DECIMAL128; /* IEEEContext(): maximum argument value */ constexpr int IEEE_CONTEXT_MAX_BITS = MPD_IEEE_CONTEXT_MAX_BITS; /******************************************************************************/ /* Decimal Exceptions */ /******************************************************************************/ class DecimalException : public std::runtime_error { using std::runtime_error::runtime_error; }; /* Signals */ class IEEEInvalidOperation : public DecimalException { using DecimalException::DecimalException; }; class DivisionByZero : public DecimalException { using DecimalException::DecimalException; }; class Overflow : public DecimalException { using DecimalException::DecimalException; }; class Underflow : public DecimalException { using DecimalException::DecimalException; }; class Subnormal : public DecimalException { using DecimalException::DecimalException; }; class Inexact : public DecimalException { using DecimalException::DecimalException; }; class Rounded : public DecimalException { using DecimalException::DecimalException; }; class Clamped : public DecimalException { using DecimalException::DecimalException; }; /* Conditions */ class InvalidOperation : public IEEEInvalidOperation { using IEEEInvalidOperation::IEEEInvalidOperation; }; class ConversionSyntax : public IEEEInvalidOperation { using IEEEInvalidOperation::IEEEInvalidOperation; }; class DivisionImpossible : public IEEEInvalidOperation { using IEEEInvalidOperation::IEEEInvalidOperation; }; class DivisionUndefined : public IEEEInvalidOperation { using IEEEInvalidOperation::IEEEInvalidOperation; }; /******************************************************************************/ /* Other Exceptions */ /******************************************************************************/ class MallocError : public DecimalException { using DecimalException::DecimalException; }; class RuntimeError : public DecimalException { using DecimalException::DecimalException; }; class ValueError : public DecimalException { using DecimalException::DecimalException; }; /******************************************************************************/ /* Context object */ /******************************************************************************/ class Context; IMPORTEXPORT extern Context context_template; #if defined(__OpenBSD__) || defined(__sun) || defined(_MSC_VER) && defined(_DLL) IMPORTEXPORT Context& getcontext(); static thread_local Context& context{getcontext()}; #else extern thread_local Context context; #endif class Context { private: mpd_context_t ctx; IMPORTEXPORT static void raiseit(uint32_t status); public: /***********************************************************************/ /* Constructors */ /***********************************************************************/ Context(const Context& c) = default; Context(Context&& c) = default; explicit Context(const mpd_context_t &m) noexcept : ctx(m) {} explicit Context(mpd_ssize_t prec=context_template.prec(), mpd_ssize_t emax=context_template.emax(), mpd_ssize_t emin=context_template.emin(), int round=context_template.round(), uint32_t traps=context_template.traps(), int clamp=context_template.clamp(), int allcr=context_template.allcr()) { this->prec(prec); this->emax(emax); this->emin(emin); this->traps(traps); this->round(round); this->clamp(clamp); this->allcr(allcr); this->ctx.status = 0; this->ctx.newtrap = 0; } /***********************************************************************/ /* Destructor */ /***********************************************************************/ ~Context() noexcept = default; /***********************************************************************/ /* Assignment operators */ /***********************************************************************/ Context& operator= (const Context& c) = default; Context& operator= (Context&& c) = default; /***********************************************************************/ /* Comparison operators */ /***********************************************************************/ bool operator== (const Context& other) const noexcept { return ctx.prec == other.ctx.prec && ctx.emax == other.ctx.emax && ctx.emin == other.ctx.emin && ctx.traps == other.ctx.traps && ctx.status == other.ctx.status && ctx.round == other.ctx.round && ctx.clamp == other.ctx.clamp && ctx.allcr == other.ctx.allcr && ctx.newtrap == other.ctx.newtrap; } bool operator!= (const Context& other) const noexcept { return !(*this == other); } /***********************************************************************/ /* Accessors */ /***********************************************************************/ /* Get pointers to the full context */ ALWAYS_INLINE mpd_context_t *get() { return &ctx; } ALWAYS_INLINE const mpd_context_t *getconst() const { return &ctx; } /* Get individual fields */ ALWAYS_INLINE mpd_ssize_t prec() const { return ctx.prec; } ALWAYS_INLINE mpd_ssize_t emax() const { return ctx.emax; } ALWAYS_INLINE mpd_ssize_t emin() const { return ctx.emin; } ALWAYS_INLINE int round() const { return ctx.round; } ALWAYS_INLINE uint32_t status() const { return ctx.status; } ALWAYS_INLINE uint32_t traps() const { return ctx.traps; } ALWAYS_INLINE int clamp() const { return ctx.clamp; } ALWAYS_INLINE int allcr() const { return ctx.allcr; } ALWAYS_INLINE int64_t etiny() const { return mpd_etiny(&ctx); } ALWAYS_INLINE int64_t etop() const { return mpd_etop(&ctx); } /* Set individual fields */ ALWAYS_INLINE void prec(mpd_ssize_t v) { if (!mpd_qsetprec(&ctx, v)) { throw ValueError("valid range for prec is [1, MAX_PREC]"); } } ALWAYS_INLINE void emax(mpd_ssize_t v) { if (!mpd_qsetemax(&ctx, v)) { throw ValueError("valid range for emax is [0, MAX_EMAX]"); } } ALWAYS_INLINE void emin(mpd_ssize_t v) { if (!mpd_qsetemin(&ctx, v)) { throw ValueError("valid range for emin is [MIN_EMIN, 0]"); } } ALWAYS_INLINE void round(int v) { if (!mpd_qsetround(&ctx, v)) { throw ValueError("valid values for rounding are:\n" " [ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN,\n" " ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN,\n" " ROUND_05UP]"); } } ALWAYS_INLINE void status(uint32_t v) { if (!mpd_qsetstatus(&ctx, v)) { throw ValueError("invalid status flag"); } } ALWAYS_INLINE void traps(uint32_t v) { if (!mpd_qsettraps(&ctx, v)) { throw ValueError("invalid status flag"); } } ALWAYS_INLINE void clamp(int v) { if (!mpd_qsetclamp(&ctx, v)) { throw ValueError("invalid value for clamp"); } } ALWAYS_INLINE void allcr(int v) { if (!mpd_qsetcr(&ctx, v)) { throw ValueError("invalid value for allcr"); } } /***********************************************************************/ /* Status and exception handling */ /***********************************************************************/ /* Add flags to status and raise an exception if a relevant trap is active */ ALWAYS_INLINE void raise(uint32_t flags) { ctx.status |= (flags & ~MPD_Malloc_error); const uint32_t active_traps = flags & (ctx.traps|MPD_Malloc_error); if (active_traps) { raiseit(active_traps); } } /* Same, but with cleanup for constructors */ ALWAYS_INLINE void raise(uint32_t flags, mpd_t *a, bool isstatic) { ctx.status |= (flags & ~MPD_Malloc_error); const uint32_t active_traps = flags & (ctx.traps|MPD_Malloc_error); if (active_traps) { if (!isstatic) { mpd_del(a); } raiseit(active_traps); } } /* Add selected status flags */ ALWAYS_INLINE void add_status(uint32_t flags) { if (flags > MPD_Max_status) { throw ValueError("invalid flags"); } ctx.status |= flags; } /* Clear all status flags */ ALWAYS_INLINE void clear_status() { ctx.status = 0; } /* Clear selected status flags */ ALWAYS_INLINE void clear_status(uint32_t flags) { if (flags > MPD_Max_status) { throw ValueError("invalid flags"); } ctx.status &= ~flags; } /* Add selected traps */ ALWAYS_INLINE void add_traps(uint32_t flags) { if (flags > MPD_Max_status) { throw ValueError("invalid flags"); } ctx.traps |= flags; } /* Clear all traps */ ALWAYS_INLINE void clear_traps() { ctx.traps = 0; } /* Clear selected traps */ ALWAYS_INLINE void clear_traps(uint32_t flags) { if (flags > MPD_Max_status) { throw ValueError("invalid flags"); } ctx.traps &= ~flags; } /***********************************************************************/ /* String conversion */ /***********************************************************************/ IMPORTEXPORT std::string repr() const; IMPORTEXPORT friend std::ostream& operator<<(std::ostream& os, const Context& c); }; IMPORTEXPORT Context MaxContext(); IMPORTEXPORT Context IEEEContext(int bits); /******************************************************************************/ /* Util */ /******************************************************************************/ namespace util { template inline dest_t safe_downcast(src_t v) { if (v < std::numeric_limits::min() || v > std::numeric_limits::max()) { throw ValueError("cast changes the original value"); } return static_cast(v); } inline std::shared_ptr shared_cp(const char *cp) { if (cp == nullptr) { throw RuntimeError("util::shared_cp: invalid nullptr argument"); } return std::shared_ptr(cp, [](const char *s){ mpd_free(const_cast(s)); }); } inline std::string string_from_cp(const char *cp) { const auto p = shared_cp(cp); return std::string(p.get()); } template struct int64_compat { #define INT64_SUBSET(T) \ (INT64_MIN <= std::numeric_limits::min() && std::numeric_limits::max() <= INT64_MAX) static const bool value = std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || (std::is_same::value && INT64_SUBSET(signed char)) || (std::is_same::value && INT64_SUBSET(short)) || (std::is_same::value && INT64_SUBSET(int)) || (std::is_same::value && INT64_SUBSET(long)) || (std::is_same::value && INT64_SUBSET(long long)); }; template struct uint64_compat { #define UINT64_SUBSET(T) (std::numeric_limits::max() <= UINT64_MAX) static const bool value = std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || (std::is_same::value && UINT64_SUBSET(unsigned char)) || (std::is_same::value && UINT64_SUBSET(unsigned short)) || (std::is_same::value && UINT64_SUBSET(unsigned int)) || (std::is_same::value && UINT64_SUBSET(unsigned long)) || (std::is_same::value && UINT64_SUBSET(unsigned long long)); }; #define ENABLE_IF_SIGNED(T) \ template::value>::type> #define ENABLE_IF_UNSIGNED(T) \ template::value>::type, typename = void> #define ENABLE_IF_INTEGRAL(T) \ template::value || util::uint64_compat::value>::type> #define ASSERT_SIGNED(T) \ static_assert(util::int64_compat::value, \ "internal error: selected type is not int64 compatible") #define ASSERT_UNSIGNED(T) \ static_assert(util::uint64_compat::value, \ "internal error: selected type is not uint64 compatible") #define ASSERT_INTEGRAL(T) \ static_assert(util::int64_compat::value || util::uint64_compat::value, \ "internal error: selected type is not a suitable integer type") } // namespace util /******************************************************************************/ /* Decimal object */ /******************************************************************************/ constexpr mpd_ssize_t MINALLOC = 4; class Decimal { private: mpd_uint_t data[MINALLOC] = {0}; mpd_t value { MPD_STATIC|MPD_STATIC_DATA|MPD_SNAN, /* flags */ 0, /* exp */ 0, /* digits */ 0, /* len */ MINALLOC, /* alloc */ data /* data */ }; /* mpd_t accessors */ ALWAYS_INLINE bool isstatic() const { return value.data == data; } /* Reset rhs to snan after moving data to lhs */ ALWAYS_INLINE void reset() { value = { MPD_STATIC|MPD_STATIC_DATA|MPD_SNAN, /* flags */ 0, /* exp */ 0, /* digits */ 0, /* len */ MINALLOC, /* alloc */ data /* data */ }; } /* Copy flags, preserving memory attributes of result */ ALWAYS_INLINE uint8_t copy_flags(const uint8_t rflags, const uint8_t aflags) { return (rflags & (MPD_STATIC|MPD_DATAFLAGS)) | (aflags & ~(MPD_STATIC|MPD_DATAFLAGS)); } ALWAYS_INLINE void copy_value(const mpd_t *const src, const bool fastcopy) { assert(mpd_isstatic(&value)); assert(mpd_isstatic(src)); assert(value.alloc >= MINALLOC); assert(src->alloc >= MINALLOC); assert(MPD_MINALLOC == MINALLOC); if (fastcopy) { value.data[0] = src->data[0]; value.data[1] = src->data[1]; value.data[2] = src->data[2]; value.data[3] = src->data[3]; value.flags = copy_flags(value.flags, src->flags); value.exp = src->exp; value.digits = src->digits; value.len = src->len; } else { if (!mpd_qcopy_cxx(&value, src)) { context.raise(MPD_Malloc_error); } } } ALWAYS_INLINE void move_value(const mpd_t *const src, const bool fastcopy) { assert(mpd_isstatic(&value)); assert(mpd_isstatic(src)); assert(value.alloc >= MINALLOC); assert(src->alloc >= MINALLOC); assert(MPD_MINALLOC == MINALLOC); if (fastcopy) { value.data[0] = src->data[0]; value.data[1] = src->data[1]; value.data[2] = src->data[2]; value.data[3] = src->data[3]; value.flags = copy_flags(value.flags, src->flags); value.exp = src->exp; value.digits = src->digits; value.len = src->len; } else { assert(mpd_isdynamic_data(src)); if (mpd_isdynamic_data(&value)) { mpd_free(value.data); } value = *src; assert(mpd_isstatic(&value)); assert(mpd_isdynamic_data(&value)); } } ALWAYS_INLINE Decimal unary_func_status( int (* func)(mpd_t *, const mpd_t *, uint32_t *)) const { Decimal result; uint32_t status = 0; if (!func(result.get(), getconst(), &status)) { throw MallocError("out of memory"); } return result; } ALWAYS_INLINE Decimal unary_func( void (* func)(mpd_t *, const mpd_t *, const mpd_context_t *, uint32_t *), Context& c=context) const { Decimal result; uint32_t status = 0; func(result.get(), getconst(), c.getconst(), &status); c.raise(status); return result; } ALWAYS_INLINE Decimal binary_func_noctx( int (* func)(mpd_t *, const mpd_t *, const mpd_t *), const Decimal& other) const { Decimal result; (void)func(result.get(), getconst(), other.getconst()); return result; } ALWAYS_INLINE Decimal int_binary_func( int (* func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_context_t *, uint32_t *), const Decimal& other, Context& c=context) const { Decimal result; uint32_t status = 0; (void)func(result.get(), getconst(), other.getconst(), c.getconst(), &status); c.raise(status); return result; } ALWAYS_INLINE Decimal binary_func( void (* func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_context_t *, uint32_t *), const Decimal& other, Context& c=context) const { Decimal result; uint32_t status = 0; func(result.get(), getconst(), other.getconst(), c.getconst(), &status); c.raise(status); return result; } ALWAYS_INLINE Decimal& inplace_binary_func( void (* func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_context_t *, uint32_t *), const Decimal& other, Context& c=context) { uint32_t status = 0; func(get(), getconst(), other.getconst(), c.getconst(), &status); c.raise(status); return *this; } ALWAYS_INLINE Decimal inplace_shiftl(const int64_t n, Context& c=context) { uint32_t status = 0; mpd_ssize_t nn = util::safe_downcast(n); mpd_qshiftl(get(), getconst(), nn, &status); c.raise(status); return *this; } ALWAYS_INLINE Decimal inplace_shiftr(const int64_t n, Context& c=context) { uint32_t status = 0; mpd_ssize_t nn = util::safe_downcast(n); mpd_qshiftr(get(), getconst(), nn, &status); c.raise(status); return *this; } public: /***********************************************************************/ /* Exact conversions regardless of context */ /***********************************************************************/ /* Implicit */ Decimal() noexcept = default; Decimal(const Decimal& other) { *this = other; } Decimal(Decimal&& other) noexcept { *this = std::move(other); } ENABLE_IF_SIGNED(T) Decimal(const T& other) { ASSERT_SIGNED(T); uint32_t status = 0; mpd_qset_i64_exact(&value, other, &status); context.raise(status, &value, isstatic()); } ENABLE_IF_UNSIGNED(T) Decimal(const T& other) { ASSERT_UNSIGNED(T); uint32_t status = 0; mpd_qset_u64_exact(&value, other, &status); context.raise(status, &value, isstatic()); } /* Explicit */ explicit Decimal(const char * const s) { uint32_t status = 0; if (s == nullptr) { throw ValueError("Decimal: string argument in constructor is NULL"); } mpd_qset_string_exact(&value, s, &status); context.raise(status, &value, isstatic()); } explicit Decimal(const std::string& s) { uint32_t status = 0; mpd_qset_string_exact(&value, s.c_str(), &status); context.raise(status, &value, isstatic()); } explicit Decimal(const mpd_uint128_triple_t& triple) { uint32_t status = 0; if (mpd_from_uint128_triple(&value, &triple, &status) < 0) { context.raise(status, &value, isstatic()); } } /***********************************************************************/ /* Inexact conversions that use a context */ /***********************************************************************/ explicit Decimal(const Decimal& other, Context& c) { const mpd_context_t *ctx = c.getconst(); *this = other; if (mpd_isnan(&value) && value.digits > ctx->prec - ctx->clamp) { /* Special case: too many NaN payload digits */ mpd_setspecial(&value, MPD_POS, MPD_NAN); c.raise(MPD_Conversion_syntax, &value, isstatic()); } else { uint32_t status = 0; mpd_qfinalize(&value, ctx, &status); c.raise(status, &value, isstatic()); } } ENABLE_IF_SIGNED(T) explicit Decimal(const T& other, Context& c) { ASSERT_SIGNED(T); uint32_t status = 0; mpd_qset_i64(&value, other, c.getconst(), &status); c.raise(status, &value, isstatic()); } ENABLE_IF_UNSIGNED(T) explicit Decimal(const T& other, Context& c) { ASSERT_UNSIGNED(T); uint32_t status = 0; mpd_qset_u64(&value, other, c.getconst(), &status); c.raise(status, &value, isstatic()); } explicit Decimal(const char * const s, Context& c) { uint32_t status = 0; if (s == nullptr) { throw ValueError("Decimal: string argument in constructor is NULL"); } mpd_qset_string(&value, s, c.getconst(), &status); c.raise(status, &value, isstatic()); } explicit Decimal(const std::string& s, Context& c) { uint32_t status = 0; mpd_qset_string(&value, s.c_str(), c.getconst(), &status); c.raise(status, &value, isstatic()); } /***********************************************************************/ /* Accessors */ /***********************************************************************/ ALWAYS_INLINE mpd_t *get() { return &value; } ALWAYS_INLINE const mpd_t *getconst() const { return &value; } ALWAYS_INLINE int sign() const { return mpd_isnegative(&value) ? -1 : 1; } ALWAYS_INLINE Decimal coeff() const { if (isspecial()) { throw ValueError("coefficient is undefined for special values"); } Decimal result = *this; mpd_set_positive(&result.value); result.value.exp = 0; return result; } ALWAYS_INLINE int64_t exponent() const { if (isspecial()) { throw ValueError("exponent is undefined for special values"); } return value.exp; } ALWAYS_INLINE Decimal payload() const { if (!isnan()) { throw ValueError("payload is only defined for NaNs"); } if (value.len == 0) { return Decimal(0); } Decimal result = *this; mpd_set_flags(&result.value, 0); result.value.exp = 0; return result; } /***********************************************************************/ /* Destructor */ /***********************************************************************/ ~Decimal() { if (value.data != data) mpd_del(&value); } /***********************************************************************/ /* Assignment operators */ /***********************************************************************/ ALWAYS_INLINE Decimal& operator= (const Decimal& other) { copy_value(other.getconst(), other.isstatic()); return *this; } ALWAYS_INLINE Decimal& operator= (Decimal&& other) noexcept { if (this != &other) { move_value(other.getconst(), other.isstatic()); other.reset(); } return *this; } ALWAYS_INLINE Decimal& operator+= (const Decimal& other) { return inplace_binary_func(mpd_qadd, other); } ALWAYS_INLINE Decimal& operator-= (const Decimal& other) { return inplace_binary_func(mpd_qsub, other); } ALWAYS_INLINE Decimal& operator*= (const Decimal& other) { return inplace_binary_func(mpd_qmul, other); } ALWAYS_INLINE Decimal& operator/= (const Decimal& other) { return inplace_binary_func(mpd_qdiv, other); } ALWAYS_INLINE Decimal& operator%= (const Decimal& other) { return inplace_binary_func(mpd_qrem, other); } /***********************************************************************/ /* Comparison operators */ /***********************************************************************/ ALWAYS_INLINE bool operator== (const Decimal& other) const { uint32_t status = 0; const int r = mpd_qcmp(getconst(), other.getconst(), &status); if (r == INT_MAX) { if (issnan() || other.issnan()) { context.raise(status); } return false; } return r == 0; } ALWAYS_INLINE bool operator!= (const Decimal& other) const { uint32_t status = 0; const int r = mpd_qcmp(getconst(), other.getconst(), &status); if (r == INT_MAX) { if (issnan() || other.issnan()) { context.raise(status); } return true; } return r != 0; } ALWAYS_INLINE bool operator< (const Decimal& other) const { uint32_t status = 0; const int r = mpd_qcmp(getconst(), other.getconst(), &status); if (r == INT_MAX) { context.raise(status); return false; } return r < 0; } ALWAYS_INLINE bool operator<= (const Decimal& other) const { uint32_t status = 0; const int r = mpd_qcmp(getconst(), other.getconst(), &status); if (r == INT_MAX) { context.raise(status); return false; } return r <= 0; } ALWAYS_INLINE bool operator>= (const Decimal& other) const { uint32_t status = 0; const int r = mpd_qcmp(getconst(), other.getconst(), &status); if (r == INT_MAX) { context.raise(status); return false; } return r >= 0; } ALWAYS_INLINE bool operator> (const Decimal& other) const { uint32_t status = 0; const int r = mpd_qcmp(getconst(), other.getconst(), &status); if (r == INT_MAX) { context.raise(status); return false; } return r > 0; } /***********************************************************************/ /* Unary arithmetic operators */ /***********************************************************************/ ALWAYS_INLINE Decimal operator- () const { return unary_func(mpd_qminus); } ALWAYS_INLINE Decimal operator+ () const { return unary_func(mpd_qplus); } /***********************************************************************/ /* Binary arithmetic operators */ /***********************************************************************/ ALWAYS_INLINE Decimal operator+ (const Decimal& other) const { return binary_func(mpd_qadd, other); } ALWAYS_INLINE Decimal operator- (const Decimal& other) const { return binary_func(mpd_qsub, other); } ALWAYS_INLINE Decimal operator* (const Decimal& other) const { return binary_func(mpd_qmul, other); } ALWAYS_INLINE Decimal operator/ (const Decimal& other) const { return binary_func(mpd_qdiv, other); } ALWAYS_INLINE Decimal operator% (const Decimal& other) const { return binary_func(mpd_qrem, other); } /***********************************************************************/ /* Predicates */ /***********************************************************************/ /* Predicates, no context arg */ ALWAYS_INLINE bool iscanonical() const { return mpd_iscanonical(getconst()); } ALWAYS_INLINE bool isfinite() const { return mpd_isfinite(getconst()); } ALWAYS_INLINE bool isinfinite() const { return mpd_isinfinite(getconst()); } ALWAYS_INLINE bool isspecial() const { return mpd_isspecial(getconst()); } ALWAYS_INLINE bool isnan() const { return mpd_isnan(getconst()); } ALWAYS_INLINE bool isqnan() const { return mpd_isqnan(getconst()); } ALWAYS_INLINE bool issnan() const { return mpd_issnan(getconst()); } ALWAYS_INLINE bool issigned() const { return mpd_issigned(getconst()); } ALWAYS_INLINE bool iszero() const { return mpd_iszero(getconst()); } ALWAYS_INLINE bool isinteger() const { return mpd_isinteger(getconst()); } /* Predicates, optional context arg */ ALWAYS_INLINE bool isnormal(const Context& c=context) const { return mpd_isnormal(getconst(), c.getconst()); } ALWAYS_INLINE bool issubnormal(const Context& c=context) const { return mpd_issubnormal(getconst(), c.getconst()); } /***********************************************************************/ /* Unary functions */ /***********************************************************************/ /* Unary functions, no context arg */ ALWAYS_INLINE int64_t adjexp() const { if (isspecial()) { throw ValueError("adjusted exponent undefined for special values"); } return mpd_adjexp(getconst()); } ALWAYS_INLINE Decimal canonical() const { return *this; } ALWAYS_INLINE Decimal copy() const { return unary_func_status(mpd_qcopy); } ALWAYS_INLINE Decimal copy_abs() const { return unary_func_status(mpd_qcopy_abs); } ALWAYS_INLINE Decimal copy_negate() const { return unary_func_status(mpd_qcopy_negate); } /* Unary functions, optional context arg */ ALWAYS_INLINE std::string number_class(Context& c=context) const { return mpd_class(getconst(), c.getconst()); } ALWAYS_INLINE Decimal abs(Context& c=context) const { return unary_func(mpd_qabs, c); } ALWAYS_INLINE Decimal ceil(Context& c=context) const { return unary_func(mpd_qceil, c); } ALWAYS_INLINE Decimal exp(Context& c=context) const { return unary_func(mpd_qexp, c); } ALWAYS_INLINE Decimal floor(Context& c=context) const { return unary_func(mpd_qfloor, c); } ALWAYS_INLINE Decimal invroot(Context& c=context) const { return unary_func(mpd_qinvroot, c); } ALWAYS_INLINE Decimal logical_invert(Context& c=context) const { return unary_func(mpd_qinvert, c); } ALWAYS_INLINE Decimal ln(Context& c=context) const { return unary_func(mpd_qln, c); } ALWAYS_INLINE Decimal log10(Context& c=context) const { return unary_func(mpd_qlog10, c); } ALWAYS_INLINE Decimal logb(Context& c=context) const { return unary_func(mpd_qlogb, c); } ALWAYS_INLINE Decimal minus(Context& c=context) const { return unary_func(mpd_qminus, c); } ALWAYS_INLINE Decimal next_minus(Context& c=context) const { return unary_func(mpd_qnext_minus, c); } ALWAYS_INLINE Decimal next_plus(Context& c=context) const { return unary_func(mpd_qnext_plus, c); } ALWAYS_INLINE Decimal plus(Context& c=context) const { return unary_func(mpd_qplus, c); } ALWAYS_INLINE Decimal reduce(Context& c=context) const { return unary_func(mpd_qreduce, c); } ALWAYS_INLINE Decimal to_integral(Context& c=context) const { return unary_func(mpd_qround_to_int, c); } ALWAYS_INLINE Decimal to_integral_exact(Context& c=context) const { return unary_func(mpd_qround_to_intx, c); } ALWAYS_INLINE Decimal sqrt(Context& c=context) const { return unary_func(mpd_qsqrt, c); } ALWAYS_INLINE Decimal trunc(Context& c=context) const { return unary_func(mpd_qtrunc, c); } /***********************************************************************/ /* Binary functions */ /***********************************************************************/ /* Binary functions, no context arg */ ALWAYS_INLINE Decimal compare_total(const Decimal& other) const { return binary_func_noctx(mpd_compare_total, other); } ALWAYS_INLINE Decimal compare_total_mag(const Decimal& other) const { return binary_func_noctx(mpd_compare_total_mag, other); } /* Binary arithmetic functions, optional context arg */ ALWAYS_INLINE Decimal add(const Decimal& other, Context& c=context) const { return binary_func(mpd_qadd, other, c); } ALWAYS_INLINE Decimal div(const Decimal& other, Context& c=context) const { return binary_func(mpd_qdiv, other, c); } ALWAYS_INLINE Decimal divint(const Decimal& other, Context& c=context) const { return binary_func(mpd_qdivint, other, c); } ALWAYS_INLINE Decimal compare(const Decimal& other, Context& c=context) const { return int_binary_func(mpd_qcompare, other, c); } ALWAYS_INLINE Decimal compare_signal(const Decimal& other, Context& c=context) const { return int_binary_func(mpd_qcompare_signal, other, c); } ALWAYS_INLINE Decimal logical_and(const Decimal& other, Context& c=context) const { return binary_func(mpd_qand, other, c); } ALWAYS_INLINE Decimal logical_or(const Decimal& other, Context& c=context) const { return binary_func(mpd_qor, other, c); } ALWAYS_INLINE Decimal logical_xor(const Decimal& other, Context& c=context) const { return binary_func(mpd_qxor, other, c); } ALWAYS_INLINE Decimal max(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmax, other, c); } ALWAYS_INLINE Decimal max_mag(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmax_mag, other, c); } ALWAYS_INLINE Decimal min(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmin, other, c); } ALWAYS_INLINE Decimal min_mag(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmin_mag, other, c); } ALWAYS_INLINE Decimal mul(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmul, other, c); } ALWAYS_INLINE Decimal next_toward(const Decimal& other, Context& c=context) const { return binary_func(mpd_qnext_toward, other, c); } ALWAYS_INLINE Decimal pow(const Decimal& other, Context& c=context) const { return binary_func(mpd_qpow, other, c); } ALWAYS_INLINE Decimal quantize(const Decimal& other, Context& c=context) const { return binary_func(mpd_qquantize, other, c); } ALWAYS_INLINE Decimal rem(const Decimal& other, Context& c=context) const { return binary_func(mpd_qrem, other, c); } ALWAYS_INLINE Decimal rem_near(const Decimal& other, Context& c=context) const { return binary_func(mpd_qrem_near, other, c); } ALWAYS_INLINE Decimal rotate(const Decimal& other, Context& c=context) const { return binary_func(mpd_qrotate, other, c); } ALWAYS_INLINE Decimal scaleb(const Decimal& other, Context& c=context) const { return binary_func(mpd_qscaleb, other, c); } ALWAYS_INLINE Decimal shift(const Decimal& other, Context& c=context) const { return binary_func(mpd_qshift, other, c); } ALWAYS_INLINE Decimal sub(const Decimal& other, Context& c=context) const { return binary_func(mpd_qsub, other, c); } /* Binary arithmetic function, two return values */ ALWAYS_INLINE std::pair divmod(const Decimal& other, Context& c=context) const { std::pair result; uint32_t status = 0; mpd_qdivmod(result.first.get(), result.second.get(), getconst(), other.getconst(), c.getconst(), &status); c.raise(status); return result; } /***********************************************************************/ /* Ternary functions */ /***********************************************************************/ ALWAYS_INLINE Decimal fma(const Decimal& other, const Decimal& third, Context& c=context) const { Decimal result; uint32_t status = 0; mpd_qfma(result.get(), getconst(), other.getconst(), third.getconst(), c.getconst(), &status); c.raise(status); return result; } ALWAYS_INLINE Decimal powmod(const Decimal& other, const Decimal& third, Context& c=context) const { Decimal result; uint32_t status = 0; mpd_qpowmod(result.get(), getconst(), other.getconst(), third.getconst(), c.getconst(), &status); c.raise(status); return result; } /***********************************************************************/ /* Irregular functions */ /***********************************************************************/ ALWAYS_INLINE Decimal apply(Context& c=context) const { Decimal result = *this; uint32_t status = 0; mpd_qfinalize(result.get(), c.getconst(), &status); c.raise(status); return result; } ALWAYS_INLINE int cmp(const Decimal& other) const { uint32_t status = 0; return mpd_qcmp(getconst(), other.getconst(), &status); } ALWAYS_INLINE int cmp_total(const Decimal& other) const { return mpd_cmp_total(getconst(), other.getconst()); } ALWAYS_INLINE int cmp_total_mag(const Decimal& other) const { return mpd_cmp_total_mag(getconst(), other.getconst()); } ALWAYS_INLINE Decimal copy_sign(const Decimal& other) const { Decimal result; uint32_t status = 0; if (!mpd_qcopy_sign(result.get(), getconst(), other.getconst(), &status)) { throw MallocError("out of memory"); } return result; } ALWAYS_INLINE Decimal rescale(const int64_t exp, Context& c=context) const { Decimal result; uint32_t status = 0; mpd_ssize_t xexp = util::safe_downcast(exp); mpd_qrescale(result.get(), getconst(), xexp, c.getconst(), &status); c.raise(status); return result; } ALWAYS_INLINE bool same_quantum(const Decimal& other) const { return mpd_same_quantum(getconst(), other.getconst()); } ALWAYS_INLINE Decimal shiftn(const int64_t n, Context& c=context) const { Decimal result; uint32_t status = 0; mpd_ssize_t nn = util::safe_downcast(n); mpd_qshiftn(result.get(), getconst(), nn, c.getconst(), &status); c.raise(status); return result; } ALWAYS_INLINE Decimal shiftl(const int64_t n, Context& c=context) const { Decimal result; uint32_t status = 0; if (isspecial()) { throw ValueError("shiftl: cannot handle special numbers"); } if (n < 0 || n > MPD_MAX_PREC - getconst()->digits) { throw ValueError("shiftl: shift is negative or too large"); } mpd_ssize_t nn = util::safe_downcast(n); mpd_qshiftl(result.get(), getconst(), nn, &status); c.raise(status); return result; } ALWAYS_INLINE Decimal shiftr(const int64_t n, Context& c=context) const { Decimal result; uint32_t status = 0; if (isspecial()) { throw ValueError("shiftr: cannot handle special numbers"); } if (n < 0) { throw ValueError("shiftr: shift is negative"); } mpd_ssize_t nn = util::safe_downcast(n); mpd_qshiftr(result.get(), getconst(), nn, &status); c.raise(status); return result; } IMPORTEXPORT static Decimal exact(const char *s, Context& c); IMPORTEXPORT static Decimal exact(const std::string& s, Context& c); IMPORTEXPORT static Decimal ln10(int64_t n, Context& c=context); IMPORTEXPORT static int32_t radix(); /***********************************************************************/ /* Integer conversion */ /***********************************************************************/ ALWAYS_INLINE int64_t i64() const { uint32_t status = 0; const int64_t result = mpd_qget_i64(getconst(), &status); if (status) { throw ValueError("cannot convert to int64_t"); } return result; } ALWAYS_INLINE int32_t i32() const { uint32_t status = 0; const int32_t result = mpd_qget_i32(getconst(), &status); if (status) { throw ValueError("cannot convert to int32_t"); } return result; } ALWAYS_INLINE uint64_t u64() const { uint32_t status = 0; const uint64_t result = mpd_qget_u64(getconst(), &status); if (status) { throw ValueError("cannot convert to uint64_t"); } return result; } ALWAYS_INLINE uint32_t u32() const { uint32_t status = 0; const uint32_t result = mpd_qget_u32(getconst(), &status); if (status) { throw ValueError("cannot convert to uint32_t"); } return result; } /***********************************************************************/ /* Triple conversion */ /***********************************************************************/ ALWAYS_INLINE mpd_uint128_triple_t as_uint128_triple() const { return mpd_as_uint128_triple(getconst()); } /***********************************************************************/ /* String conversion */ /***********************************************************************/ /* String representations */ IMPORTEXPORT std::string repr(bool capitals=true) const; inline std::string to_sci(bool capitals=true) const { const char *cp = mpd_to_sci(getconst(), capitals); if (cp == nullptr) { throw MallocError("out of memory"); } return util::string_from_cp(cp); } inline std::string to_eng(bool capitals=true) const { const char *cp = mpd_to_eng(getconst(), capitals); if (cp == nullptr) { throw MallocError("out of memory"); } return util::string_from_cp(cp); } inline std::string format(const char *fmt, const Context& c=context) const { uint32_t status = 0; mpd_context_t ctx; if (fmt == nullptr) { throw ValueError("Decimal.format: fmt argument is NULL"); } mpd_maxcontext(&ctx); ctx.round = c.getconst()->round; ctx.traps = 0; const char *cp = mpd_qformat(getconst(), fmt, &ctx, &status); if (cp == nullptr) { if (status & MPD_Malloc_error) { throw MallocError("out of memory"); } else if (status & MPD_Invalid_operation) { throw ValueError("invalid format string"); } else { throw RuntimeError("internal error: unexpected status"); } } return util::string_from_cp(cp); } inline std::string format(const std::string& s, const Context& c=context) const { return format(s.c_str(), c); } IMPORTEXPORT friend std::ostream& operator<< (std::ostream& os, const Decimal& dec); }; /***********************************************************************/ /* Reverse comparison operators */ /***********************************************************************/ ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator==(const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) == self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator!= (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) != self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator< (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) < self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator<= (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) <= self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator>= (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) >= self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator> (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) > self; } /***********************************************************************/ /* Reverse arithmetic operators */ /***********************************************************************/ ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator+ (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) + self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator- (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) - self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator* (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) * self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator/ (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) / self; } ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator% (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) % self; } #undef IMPORTEXPORT #undef ALWAYS_INLINE #undef INT64_SUBSET #undef UINT64_SUBSET #undef ENABLE_IF_SIGNED #undef ENABLE_IF_UNSIGNED #undef ENABLE_IF_INTEGRAL #undef ASSERT_SIGNED #undef ASSERT_UNSIGNED #undef ASSERT_INTEGRAL } // namespace decimal #endif // LIBMPDECXX_DECIMAL_HH_ mpdecimal-4.0.1/libmpdec++/examples/0000755000000000000000000000000015005764474014134 5ustar00mpdecimal-4.0.1/libmpdec++/examples/factorial.cc0000644000000000000000000000556415005764474016421 0ustar00/* * Copyright (c) 2020-2025 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 #include "decimal.hh" using decimal::Decimal; using decimal::MaxContext; using decimal::context; using decimal::ConversionSyntax; using decimal::InvalidOperation; using decimal::MallocError; using decimal::DecRounded; using decimal::DecInexact; Decimal f(const Decimal& n, const Decimal& m) { if (n > m) { return f(m, n); } else if (m == 0) { return 1; } else if (n == m) { return n; } else { return f(n, (n + m).divint(2)) * f((n + m).divint(2) + 1, m); } } Decimal factorial(const Decimal& n) { context = MaxContext(); // DecRounded can be skipped if integer results with non-zero // exponents are allowed. context.add_traps(DecInexact|DecRounded); return f(n, Decimal(0)); } void err_exit(const std::string& msg) { std::cerr << msg << std::endl; std::exit(1); } int main(int argc, char *argv[]) { Decimal n; if (argc != 2) { err_exit("usage: ./factorial n"); } try { n = Decimal(argv[1]); } catch (ConversionSyntax&) { err_exit("invalid decimal string"); } catch (InvalidOperation&) { err_exit("value exceeds internal limits"); } catch (MallocError&) { err_exit("out of memory"); } // The exponent could be nonzero, this is to avoid surprise at the result. if (!n.isinteger() || n.exponent() != 0 || n < 0) { err_exit("n must be a non-negative integer with exponent zero"); } std::cout << factorial(n) << std::endl; return 0; } mpdecimal-4.0.1/libmpdec++/examples/pi.cc0000644000000000000000000000525115005764474015056 0ustar00/* * Copyright (c) 2020-2025 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 #include #include #include #include #include "decimal.hh" using decimal::Decimal; using decimal::context; /* The algorithm is not optimized for bignum arithmetic */ Decimal pi(int prec) { assert(1 <= prec && prec <= INT_MAX-2); context.prec(prec + 2); Decimal lasts = 0; Decimal t = 3; Decimal s = 3; Decimal n = 1; Decimal na = 0; Decimal d = 0; Decimal da = 24; while (s != lasts) { lasts = s; n += na; na += 8; d += da; da += 32; t = (t * n) / d; s += t; } context.prec(prec); return +s; } void err_exit(const std::string& msg) { std::cerr << msg << std::endl; std::exit(1); } int main(int argc, char *argv[]) { size_t pos = 0; int prec = 0; if (argc != 2) { err_exit("usage: ./pi prec"); } std::string s = argv[1]; try { prec = std::stoi(s, &pos); } catch (const std::invalid_argument&) { err_exit("not a number"); } catch (const std::out_of_range &) { err_exit("out of range"); } if (pos < s.size()) { err_exit("trailing characters"); } if (prec <= 0 || prec > 999999) { err_exit("prec must be in [1, 999999]"); } std::cout << pi(prec) << std::endl; return 0; } mpdecimal-4.0.1/tests/0000755000000000000000000000000015005764474011553 5ustar00mpdecimal-4.0.1/tests/Makefile.in0000644000000000000000000000300715005764474013620 0ustar00 # ============================================================================== # Unix Makefile for libmpdec tests # ============================================================================== SRCDIR = ../libmpdec ENABLE_STATIC = @ENABLE_STATIC@ ENABLE_SHARED = @ENABLE_SHARED@ LIBSTATIC = @LIBSTATIC@ LIBSHARED = @LIBSHARED@ LINK_STATIC = @LINK_STATIC@ LINK_DYNAMIC = @LINK_DYNAMIC@ CC = @CC@ AR = @AR@ MPD_GNU99 = @MPD_GNU99@ FILTER_FOR_STATIC = @FILTER_FOR_STATIC@ CONFIGURE_CFLAGS = @CONFIGURE_CFLAGS@ MPD_CFLAGS_SHARED = $(strip $(filter-out $(CFLAGS),$(CONFIGURE_CFLAGS)) $(CFLAGS) $(MPD_GNU99)) MPD_CFLAGS = $(strip $(filter-out $(FILTER_FOR_STATIC),$(MPD_CFLAGS_SHARED))) LINK_LIBSTATIC = $(strip $(LINK_STATIC) $(SRCDIR)/$(LIBSTATIC) $(LINK_DYNAMIC)) MPD_TARGETS = ifeq ($(ENABLE_STATIC), yes) MPD_TARGETS += runtest endif ifeq ($(ENABLE_SHARED), yes) MPD_TARGETS += runtest_shared endif default: $(MPD_TARGETS) # Short test. runtest:\ Makefile runtest.c test.c $(SRCDIR)/$(LIBSTATIC) $(SRCDIR)/mpdecimal.h \ test.h vctest.h $(CC) -I$(SRCDIR) $(MPD_CFLAGS) -o runtest runtest.c test.c $(LINK_LIBSTATIC) -lm runtest_shared:\ Makefile runtest.c test.c $(SRCDIR)/$(LIBSHARED) $(SRCDIR)/mpdecimal.h \ test.h vctest.h $(CC) -I$(SRCDIR) $(MPD_CFLAGS_SHARED) -o runtest_shared runtest.c test.c -L$(SRCDIR) -lmpdec -lm FORCE: clean: FORCE rm -f *.o *.gch *.gcda *.gcno *.gcov *.dyn *.dpi *.lock rm -f runtest runtest_shared distclean: FORCE $(MAKE) clean rm -rf Makefile dectest.zip testdata mpdecimal-4.0.1/tests/Makefile.vc0000644000000000000000000000306115005764474013622 0ustar00 SRCDIR = ..\libmpdec LIBSTATIC = libmpdec-4.0.1.lib LIBSHARED = libmpdec-4.0.1.dll LIBIMPORT = libmpdec-4.0.1.dll.lib !if "$(DEBUG)" == "1" OPT = /MTd /Od /Zi /EHsc OPT_SHARED = /MDd /Od /Zi /EHsc !else OPT = /MT /O2 /GS /EHsc /DNDEBUG OPT_SHARED = /MD /O2 /GS /EHsc /DNDEBUG !endif !if "$(CC)" == "clang-cl" WARN = /W4 /wd4200 /wd4204 /wd4221 -Wno-undefined-inline /D_CRT_SECURE_NO_WARNINGS !else WARN = /W4 /wd4200 /wd4204 /wd4221 /D_CRT_SECURE_NO_WARNINGS !endif MPD_CFLAGS = $(WARN) /nologo $(OPT) MPD_CFLAGS_SHARED = $(WARN) /nologo $(OPT_SHARED) default: runtest runtest_shared copy_dll runtest:\ Makefile runtest.c test.c $(SRCDIR)\io.h $(SRCDIR)\mpdecimal.h $(SRCDIR)\mpalloc.h test.h vctest.h \ $(SRCDIR)\$(LIBSTATIC) $(CC) -I$(SRCDIR) $(MPD_CFLAGS) /Fe:runtest runtest.c test.c $(SRCDIR)\$(LIBSTATIC) runtest_shared:\ Makefile runtest.c test.c $(SRCDIR)/io.h $(SRCDIR)/mpdecimal.h $(SRCDIR)/mpalloc.h test.h vctest.h \ $(SRCDIR)/$(LIBSHARED) $(SRCDIR)/$(LIBIMPORT) $(CC) -I$(SRCDIR) $(MPD_CFLAGS_SHARED) /Fe:runtest_shared runtest.c test.c $(SRCDIR)\$(LIBIMPORT) FORCE: copy_dll: copy /y $(SRCDIR)\$(LIBSHARED) . clean: FORCE -@if exist *.obj del *.obj -@if exist *.dll del *.dll -@if exist *.exp del *.exp -@if exist *.lib del *.lib -@if exist *.ilk del *.ilk -@if exist *.pdb del *.pdb -@if exist *.pgc del *.pgc -@if exist *.pgd del *.pgd -@if exist *.manifest del *.manifest -@if exist *.exe del *.exe distclean: FORCE nmake clean -@if exist dectest.zip del dectest.zip -@if exist testdata rd /q /s testdata -@if exist Makefile del Makefile mpdecimal-4.0.1/tests/README.txt0000644000000000000000000000116315005764474013252 0ustar00 Download official tests and add the tests to the testdata directory: ==================================================================== # Unix: If wget is installed, just execute `make check` from # the top level directory. # Windows: See vcbuild directory. # # If gettests.sh or gettests.bat fails: # # mkdir testdata && cp testdata_dist/* testdata # # Get http://speleotrove.com/decimal/dectest.zip and extract the archive # so that the directory structure is testdata/*.decTest. # # Change into the top level directory, build the library, change back # to the test directory, run: # # make && ./runshort.sh # mpdecimal-4.0.1/tests/additional.decTest0000644000000000000000000000107315005764474015201 0ustar00 -- Additional Tests Dectest: ./testdata/baseconv.decTest Dectest: ./testdata/binop_eq.decTest Dectest: ./testdata/divmod.decTest Dectest: ./testdata/divmod_eq.decTest Dectest: ./testdata/fma_eq.decTest Dectest: ./testdata/format.decTest Dectest: ./testdata/invroot.decTest Dectest: ./testdata/largeint.decTest Dectest: ./testdata/powmod.decTest Dectest: ./testdata/powmod_eq.decTest Dectest: ./testdata/shiftlr.decTest Dectest: ./testdata/getint.decTest Dectest: ./testdata/cov.decTest Dectest: ./testdata/extra.decTest Dectest: ./testdata/maxprec.decTest mpdecimal-4.0.1/tests/gettests.bat0000755000000000000000000000066615005764474014120 0ustar00@ECHO OFF if not exist testdata mkdir testdata rem copy additional tests if not exist testdata\baseconv.decTest copy /y testdata_dist\* testdata if exist testdata\add.decTest goto OUT rem get official tests if exist dectest.zip goto UNZIP powershell -Command "wget http://speleotrove.com/decimal/dectest.zip -outfile dectest.zip" :UNZIP powershell -Command "Expand-Archive dectest.zip -DestinationPath testdata" :OUT mpdecimal-4.0.1/tests/gettests.sh0000755000000000000000000000137115005764474013756 0ustar00#!/bin/sh if [ ! -d testdata ]; then mkdir testdata fi if [ x"$1" != x"--local" -a ! -f testdata/add.decTest ]; then # The official tests are freely downloadable, but copyrighted. WGET=`which wget` if [ ! -f "$WGET" ]; then printf "\n*** gettests.sh: error: could not find wget. In order to run the tests, \n" printf " download http://speleotrove.com/decimal/dectest.zip and extract the \n" printf " archive into tests/testdata.\n\n" exit 1 fi printf "\nGetting official tests ... \n\n" $WGET -nv http://speleotrove.com/decimal/dectest.zip 2>&1 && cd testdata && unzip -qq ../dectest.zip && cd ../ fi if [ ! -f testdata/baseconv.decTest ]; then cp testdata_dist/* testdata fi mpdecimal-4.0.1/tests/official.decTest0000644000000000000000000001343615005764474014653 0ustar00 -- All tests from the dectest directory. Tests that are skipped are -- commented out. Dectest: ./testdata/abs.decTest Dectest: ./testdata/add.decTest Dectest: ./testdata/and.decTest Dectest: ./testdata/base.decTest Dectest: ./testdata/clamp.decTest Dectest: ./testdata/class.decTest Dectest: ./testdata/compare.decTest Dectest: ./testdata/comparetotal.decTest Dectest: ./testdata/comparetotmag.decTest Dectest: ./testdata/copyabs.decTest Dectest: ./testdata/copy.decTest Dectest: ./testdata/copynegate.decTest Dectest: ./testdata/copysign.decTest Dectest: ./testdata/ddAbs.decTest Dectest: ./testdata/ddAdd.decTest Dectest: ./testdata/ddAnd.decTest Dectest: ./testdata/ddBase.decTest -- Dectest: ./testdata/ddCanonical.decTest Dectest: ./testdata/ddClass.decTest Dectest: ./testdata/ddCompare.decTest Dectest: ./testdata/ddCompareSig.decTest Dectest: ./testdata/ddCompareTotal.decTest Dectest: ./testdata/ddCompareTotalMag.decTest Dectest: ./testdata/ddCopyAbs.decTest Dectest: ./testdata/ddCopy.decTest Dectest: ./testdata/ddCopyNegate.decTest Dectest: ./testdata/ddCopySign.decTest Dectest: ./testdata/ddDivide.decTest Dectest: ./testdata/ddDivideInt.decTest -- Dectest: ./testdata/ddEncode.decTest Dectest: ./testdata/ddFMA.decTest Dectest: ./testdata/ddInvert.decTest Dectest: ./testdata/ddLogB.decTest Dectest: ./testdata/ddMax.decTest Dectest: ./testdata/ddMaxMag.decTest Dectest: ./testdata/ddMin.decTest Dectest: ./testdata/ddMinMag.decTest Dectest: ./testdata/ddMinus.decTest Dectest: ./testdata/ddMultiply.decTest Dectest: ./testdata/ddNextMinus.decTest Dectest: ./testdata/ddNextPlus.decTest Dectest: ./testdata/ddNextToward.decTest Dectest: ./testdata/ddOr.decTest Dectest: ./testdata/ddPlus.decTest Dectest: ./testdata/ddQuantize.decTest Dectest: ./testdata/ddReduce.decTest Dectest: ./testdata/ddRemainder.decTest Dectest: ./testdata/ddRemainderNear.decTest Dectest: ./testdata/ddRotate.decTest Dectest: ./testdata/ddSameQuantum.decTest Dectest: ./testdata/ddScaleB.decTest Dectest: ./testdata/ddShift.decTest Dectest: ./testdata/ddSubtract.decTest Dectest: ./testdata/ddToIntegral.decTest Dectest: ./testdata/ddXor.decTest -- Dectest: ./testdata/decDouble.decTest -- Dectest: ./testdata/decQuad.decTest -- Dectest: ./testdata/decSingle.decTest Dectest: ./testdata/divide.decTest Dectest: ./testdata/divideint.decTest Dectest: ./testdata/dqAbs.decTest Dectest: ./testdata/dqAdd.decTest Dectest: ./testdata/dqAnd.decTest Dectest: ./testdata/dqBase.decTest -- Dectest: ./testdata/dqCanonical.decTest Dectest: ./testdata/dqClass.decTest Dectest: ./testdata/dqCompare.decTest Dectest: ./testdata/dqCompareSig.decTest Dectest: ./testdata/dqCompareTotal.decTest Dectest: ./testdata/dqCompareTotalMag.decTest Dectest: ./testdata/dqCopyAbs.decTest Dectest: ./testdata/dqCopy.decTest Dectest: ./testdata/dqCopyNegate.decTest Dectest: ./testdata/dqCopySign.decTest Dectest: ./testdata/dqDivide.decTest Dectest: ./testdata/dqDivideInt.decTest -- Dectest: ./testdata/dqEncode.decTest Dectest: ./testdata/dqFMA.decTest Dectest: ./testdata/dqInvert.decTest Dectest: ./testdata/dqLogB.decTest Dectest: ./testdata/dqMax.decTest Dectest: ./testdata/dqMaxMag.decTest Dectest: ./testdata/dqMin.decTest Dectest: ./testdata/dqMinMag.decTest Dectest: ./testdata/dqMinus.decTest Dectest: ./testdata/dqMultiply.decTest Dectest: ./testdata/dqNextMinus.decTest Dectest: ./testdata/dqNextPlus.decTest Dectest: ./testdata/dqNextToward.decTest Dectest: ./testdata/dqOr.decTest Dectest: ./testdata/dqPlus.decTest Dectest: ./testdata/dqQuantize.decTest Dectest: ./testdata/dqReduce.decTest Dectest: ./testdata/dqRemainder.decTest Dectest: ./testdata/dqRemainderNear.decTest Dectest: ./testdata/dqRotate.decTest Dectest: ./testdata/dqSameQuantum.decTest Dectest: ./testdata/dqScaleB.decTest Dectest: ./testdata/dqShift.decTest Dectest: ./testdata/dqSubtract.decTest Dectest: ./testdata/dqToIntegral.decTest Dectest: ./testdata/dqXor.decTest Dectest: ./testdata/dsBase.decTest -- Dectest: ./testdata/dsEncode.decTest Dectest: ./testdata/exp.decTest Dectest: ./testdata/fma.decTest Dectest: ./testdata/inexact.decTest Dectest: ./testdata/invert.decTest Dectest: ./testdata/ln.decTest Dectest: ./testdata/log10.decTest Dectest: ./testdata/logb.decTest Dectest: ./testdata/max.decTest Dectest: ./testdata/maxmag.decTest Dectest: ./testdata/min.decTest Dectest: ./testdata/minmag.decTest Dectest: ./testdata/minus.decTest Dectest: ./testdata/multiply.decTest Dectest: ./testdata/nextminus.decTest Dectest: ./testdata/nextplus.decTest Dectest: ./testdata/nexttoward.decTest Dectest: ./testdata/or.decTest Dectest: ./testdata/plus.decTest Dectest: ./testdata/power.decTest Dectest: ./testdata/powersqrt.decTest Dectest: ./testdata/quantize.decTest Dectest: ./testdata/randombound32.decTest Dectest: ./testdata/randoms.decTest Dectest: ./testdata/reduce.decTest Dectest: ./testdata/remainder.decTest Dectest: ./testdata/remaindernear.decTest Dectest: ./testdata/rescale.decTest Dectest: ./testdata/rotate.decTest Dectest: ./testdata/rounding.decTest Dectest: ./testdata/samequantum.decTest Dectest: ./testdata/scaleb.decTest Dectest: ./testdata/shift.decTest Dectest: ./testdata/squareroot.decTest Dectest: ./testdata/subtract.decTest -- Dectest: ./testdata/testall.decTest Dectest: ./testdata/tointegral.decTest Dectest: ./testdata/tointegralx.decTest -- Dectest: ./testdata/trim.decTest Dectest: ./testdata/xor.decTest -- Summary of functions that are not implemented or do not need testing: -- Dectest: ./testdata/ddCanonical.decTest ==> same as copy() -- Dectest: ./testdata/ddEncode.decTest -- Dectest: ./testdata/decDouble.decTest -- Dectest: ./testdata/decQuad.decTest -- Dectest: ./testdata/decSingle.decTest -- Dectest: ./testdata/dqCanonical.decTest ==> same as copy() -- Dectest: ./testdata/dqEncode.decTest -- Dectest: ./testdata/dsEncode.decTest -- Dectest: ./testdata/testall.decTest -- Dectest: ./testdata/trim.decTest mpdecimal-4.0.1/tests/runshort.sh0000755000000000000000000000431015005764474013774 0ustar00#!/bin/sh # malloc() on OS X does not conform to the C standard. SYSTEM=`uname -s` case $SYSTEM in darwin*|Darwin*) export MallocLogFile=/dev/null export MallocDebugReport=crash ;; *) ;; esac # Download the official test cases (text files). ./gettests.sh "$1" || exit 1 if [ ! -f ./runtest -a ! -f ./runtest_shared ]; then printf "\nERROR: ./runtest and ./runtest_shared not found\n\n\n"; exit 1; fi if [ -f ./runtest ]; then printf "\n# ========================================================================\n" printf "# libmpdec: static library\n" printf "# ========================================================================\n\n" if [ x"$1" != x"--local" ]; then printf "Running official tests ...\n\n" ./runtest official.decTest || { printf "\nFAIL\n\n\n"; exit 1; } fi printf "Running additional tests ...\n\n" ./runtest additional.decTest || { printf "\nFAIL\n\n\n"; exit 1; } fi if [ -f ./runtest_shared ]; then printf "\n# ========================================================================\n" printf "# libmpdec: shared library\n" printf "# ========================================================================\n\n" PORTABLE_PWD=`pwd` LD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$LD_LIBRARY_PATH" DYLD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$DYLD_LIBRARY_PATH" LD_64_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$LD_64_LIBRARY_PATH" LD_32_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$LD_32_LIBRARY_PATH" LD_LIBRARY_PATH_64="$PORTABLE_PWD/../libmpdec:$LD_LIBRARY_PATH_64" LD_LIBRARY_PATH_32="$PORTABLE_PWD/../libmpdec:$LD_LIBRARY_PATH_32" PATH="$LD_LIBRARY_PATH:$PATH" export LD_LIBRARY_PATH export DYLD_LIBRARY_PATH export LD_64_LIBRARY_PATH export LD_32_LIBRARY_PATH export LD_LIBRARY_PATH_64 export LD_LIBRARY_PATH_32 if [ x"$1" != x"--local" ]; then printf "Running official tests ...\n\n" ./runtest_shared official.decTest || { printf "\nFAIL\n\n\n"; exit 1; } fi printf "Running additional tests ...\n\n" ./runtest_shared additional.decTest || { printf "\nFAIL\n\n\n"; exit 1; } fi mpdecimal-4.0.1/tests/runshort_alloc.sh0000755000000000000000000000433715005764474015157 0ustar00#!/bin/sh # malloc() on OS X does not conform to the C standard. SYSTEM=`uname -s` case $SYSTEM in darwin*|Darwin*) export MallocLogFile=/dev/null export MallocDebugReport=crash ;; *) ;; esac # Download the official test cases (text files). ./gettests.sh || exit 1 if [ ! -f ./runtest -a ! -f ./runtest_shared ]; then printf "\nERROR: ./runtest and ./runtest_shared not found\n\n\n"; exit 1; fi if [ -f ./runtest ]; then printf "\n# ========================================================================\n" printf "# libmpdec: static library\n" printf "# ========================================================================\n\n" printf "Running official tests with allocation failures ...\n\n" ./runtest official.decTest --alloc || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running additional tests with allocation failures ...\n\n" ./runtest additional.decTest --alloc || { printf "\nFAIL\n\n\n"; exit 1; } fi if [ -f ./runtest_shared ]; then printf "\n# ========================================================================\n" printf "# libmpdec: shared library\n" printf "# ========================================================================\n\n" PORTABLE_PWD=`pwd` LD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$LD_LIBRARY_PATH" DYLD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$DYLD_LIBRARY_PATH" LD_64_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$LD_64_LIBRARY_PATH" LD_32_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$LD_32_LIBRARY_PATH" LD_LIBRARY_PATH_64="$PORTABLE_PWD/../libmpdec:$LD_LIBRARY_PATH_64" LD_LIBRARY_PATH_32="$PORTABLE_PWD/../libmpdec:$LD_LIBRARY_PATH_32" PATH="$LD_LIBRARY_PATH:$PATH" export LD_LIBRARY_PATH export DYLD_LIBRARY_PATH export LD_64_LIBRARY_PATH export LD_32_LIBRARY_PATH export LD_LIBRARY_PATH_64 export LD_LIBRARY_PATH_32 printf "Running official tests with allocation failures ...\n\n" ./runtest_shared official.decTest --alloc || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running additional tests with allocation failures ...\n\n" ./runtest_shared additional.decTest --alloc || { printf "\nFAIL\n\n\n"; exit 1; } fi mpdecimal-4.0.1/tests/runtest.c0000644000000000000000000045507515005764474013443 0ustar00/* * Copyright (c) 2008-2025 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. */ #if defined(__GNUC__) || defined(__COMPCERT__) #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include "mpdecimal.h" #include "test.h" #include "vctest.h" #define MAXLINE 400000 #define MAXTOKEN 32 #ifndef _MSC_VER #include #define ASSERT(p) if (!(p)) {abort();} #else #define ASSERT(p) if (!(p)) {mpd_err_fatal("assertion failed");} #endif static int extended = 1; static int global_failure = 0; static int file_failure = 0; static mpd_ssize_t strtossize(const char *s, char **end, int base) { int64_t retval; errno = 0; retval = _mpd_strtossize(s, end, base); if (errno == 0 && (retval > MPD_SSIZE_MAX || retval < MPD_SSIZE_MIN)) { errno = ERANGE; } if (errno == ERANGE) { return (retval < 0) ? MPD_SSIZE_MIN : MPD_SSIZE_MAX; } return (mpd_ssize_t)retval; } static void mpd_init_rand(mpd_t *x) { long r = random() % 100; uint8_t sign = random()%2; if (r >= 80) { mpd_minalloc(x); } else if (r >= 60) { mpd_minalloc(x); mpd_set_flags(x, sign); } else if (r >= 40) { mpd_setspecial(x, sign, MPD_NAN); } else if (r >= 20) { mpd_setspecial(x, sign, MPD_SNAN); } else { mpd_setspecial(x, sign, MPD_INF); } } /* These ranges are needed for the official test suite * and are generally not problematic at all. */ #if defined(MPD_CONFIG_64) #define MPD_READ_MAX_PREC 1070000000000000000LL #elif defined(MPD_CONFIG_32) #define MPD_READ_MAX_PREC 1070000000 #else #error "config not defined" #endif static void mpd_readcontext(mpd_context_t *ctx) { if (extended) { ctx->prec=MPD_READ_MAX_PREC; ctx->emax=MPD_READ_MAX_PREC; ctx->emin=-MPD_READ_MAX_PREC; } else { ctx->prec=MPD_MAX_PREC; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; } ctx->round=MPD_ROUND_HALF_UP; ctx->traps=MPD_Traps; ctx->status=0; ctx->newtrap=0; ctx->clamp=0; ctx->allcr=1; } static void mpd_testcontext(mpd_context_t *ctx) { if (extended) { #if defined(MPD_CONFIG_64) ctx->prec=MPD_MAX_PREC; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; #elif defined(MPD_CONFIG_32) /* These ranges are needed for the official test suite. */ ctx->prec=999999999; ctx->emax=999999999; ctx->emin=-999999999; #else #error "config not defined" #endif } else { ctx->prec=MPD_MAX_PREC; ctx->emax=MPD_MAX_EMAX; ctx->emin=MPD_MIN_EMIN; } ctx->round=MPD_ROUND_HALF_UP; ctx->traps=MPD_Traps; ctx->status=0; ctx->newtrap=0; ctx->clamp=0; ctx->allcr=1; } static void mpd_assert_context_ok(const mpd_context_t *ctx) { ASSERT(0 < ctx->prec && ctx->prec <= MPD_READ_MAX_PREC); ASSERT(0 <= ctx->emax && ctx->emax <= MPD_READ_MAX_PREC); ASSERT(-MPD_READ_MAX_PREC <= ctx->emin && ctx->emin <= 0); ASSERT(0 <= ctx->round && ctx->round < MPD_ROUND_GUARD); ASSERT(ctx->traps <= MPD_Max_status); ASSERT(ctx->status <= MPD_Max_status); ASSERT(ctx->clamp == 0 || ctx->clamp == 1); ASSERT(ctx->allcr == 0 || ctx->allcr == 1); } /* Known differences that are within the spec. */ struct result_diff { const char *id; const char *calc; const char *expected; }; struct status_diff { const char *id; uint32_t calc; uint32_t expected; }; static struct result_diff ulp_cases[] = { /* Cases where the result is allowed to differ by less than one ULP. * Only needed if ctx->allcr is 0. */ { "expx013", "1.001000", "1.001001" }, { "expx020", "1.000000", "1.000001" }, { "expx109", "0.999999910000004049999878", "0.999999910000004049999879" }, { "expx1036", "1.005088", "1.005087" }, { "expx350", "1.0000000", "1.0000001" }, { "expx351", "1.0000000", "1.0000001" }, { "expx352", "1.0000000", "1.0000001" }, {NULL, NULL, NULL} }; static struct status_diff status_cases[] = { /* With a reduced working precision in mpd_qpow() the status matches. */ { "pwsx803", MPD_Inexact|MPD_Rounded|MPD_Subnormal|MPD_Underflow, MPD_Inexact|MPD_Rounded }, {NULL, 0, 0} }; static const char *skipit[] = { /* NULL reference, decimal16, decimal32, or decimal128 */ "absx900", "addx9990", "addx9991", "clam090", "clam091", "clam092", "clam093", "clam094", "clam095", "clam096", "clam097", "clam098", "clam099", "clam189", "clam190", "clam191", "clam192", "clam193", "clam194", "clam195", "clam196", "clam197", "clam198", "clam199", "comx990", "comx991", "cotx9990", "cotx9991", "ctmx9990", "ctmx9991", "ddabs900", "ddadd9990", "ddadd9991", "ddcom9990", "ddcom9991", "ddcot9990", "ddcot9991", "ddctm9990", "ddctm9991", "dddiv9998", "dddiv9999", "dddvi900", "dddvi901", "ddfma2990", "ddfma2991", "ddfma39990", "ddfma39991", "ddlogb900", "ddmax900", "ddmax901", "ddmxg900", "ddmxg901", "ddmin900", "ddmin901", "ddmng900", "ddmng901", "ddmul9990", "ddmul9991", "ddnextm900", "ddnextm900", "ddnextp900", "ddnextp900", "ddnextt900", "ddnextt901", "ddqua998", "ddqua999", "ddred900", "ddrem1000", "ddrem1001", "ddrmn1000", "ddrmn1001", "ddsub9990", "ddsub9991", "ddintx074", "ddintx094", "divx9998", "divx9999", "dvix900", "dvix901", "dqabs900", "dqadd9990", "dqadd9991", "dqcom990", "dqcom991", "dqcot9990", "dqcot9991", "dqctm9990", "dqctm9991", "dqdiv9998", "dqdiv9999", "dqdvi900", "dqdvi901", "dqfma2990", "dqfma2991", "dqadd39990", "dqadd39991", "dqlogb900", "dqmax900", "dqmax901", "dqmxg900", "dqmxg901", "dqmin900", "dqmin901", "dqmng900", "dqmng901", "dqmul9990", "dqmul9991", "dqnextm900", "dqnextp900", "dqnextt900", "dqnextt901", "dqqua998", "dqqua999", "dqred900", "dqrem1000", "dqrem1001", "dqrmn1000", "dqrmn1001", "dqsub9990", "dqsub9991", "dqintx074", "dqintx094", "expx900", "fmax2990", "fmax2991", "fmax39990", "fmax39991", "lnx900", "logx900", "logbx900", "maxx900", "maxx901", "mxgx900", "mxgx901", "mnm900", "mnm901", "mng900", "mng901", "minx900", "mulx990", "mulx991", "nextm900", "nextp900", "nextt900", "nextt901", "plu900", "powx900", "powx901", "pwsx900", "quax1022", "quax1023", "quax1024", "quax1025", "quax1026", "quax1027", "quax1028", "quax1029", "quax0a2", "quax0a3", "quax998", "quax999", "redx900", "remx1000", "remx1001", "rmnx900", "rmnx901", "sqtx9900", "subx9990", "subx9991", /* operand range violations, invalid context */ "expx901", "expx902", "expx903", "expx905", "lnx901", "lnx902", "lnx903", "lnx905", "logx901", "logx902", "logx903", "logx905", "powx1183", "powx1184", "powx4001", "powx4002", "powx4003", "powx4005", "powx4008", "powx4010", "powx4012", "powx4014", "scbx164", "scbx165", "scbx166", #if defined(MPD_CONFIG_32) && MPD_MINALLOC_MAX <= 4 /* Under the allocation failure tests, the result is numerically correct (1 == 1.00000) but without zero padding. This is by design, since in case of MPD_Malloc_error mpd_qsqrt() retries the operation with a lower context precision and allows all exact results. The MPD_MINALLOC_MAX < 64 feature is is officially unsupported but works (if the little-endian mpd_ln10_data arrays are adjusted). */ "sqtx9045", #endif /* skipped for decNumber, too */ "powx4302", "powx4303", "powx4303", "powx4342", "powx4343", "pwsx805", /* disagreement for three arg power */ "pwmx325", "pwmx326", NULL }; static inline int startswith(const char *token, const char *s) { return token != NULL && strncasecmp(token, s, strlen(s)) == 0; } static inline int eqtoken(const char *token, const char *s) { return token != NULL && strcasecmp(token, s) == 0; } static int check_skip(char *id) { int i; for (i = 0; skipit[i] != NULL; i++) { if (eqtoken(id, skipit[i])) { #if defined(RT_VERBOSITY) && RT_VERBOSITY == 2 fprintf(stderr, "SKIP: %s\n", id); #endif return 1; } } return 0; } static char * nexttoken(char *cp) { static char *start = NULL; static char *end = NULL; if (cp == NULL) { assert(end != NULL); cp = end; } for (; *cp != '\0'; cp++) { if (isspace((unsigned char)*cp)) { /* empty */ } else if (*cp == '"') { start = end = cp+1; for (; *end != '\0'; end++) { if (*end == '"' && *(end+1) == '"') end += 1; else if (*end == '"') break; } if (*end == '\0') return NULL; *end++ = '\0'; return start; } else if (*cp == '\'') { start = end = cp+1; for (; *end != '\0'; end++) { if (*end == '\'' && *(end+1) == '\'') end += 1; else if (*end == '\'') break; } if (*end == '\0') return NULL; *end++ = '\0'; return start; } else { start = end = cp; for (; *end != '\0'; end++) if (isspace((unsigned char)*end)) break; if (*end == '\0') return NULL; *end++ = '\0'; return start; } } return NULL; } /* split a line into tokens */ static int split(char *token[], char line[]) { char *cp; size_t len; int n = 0; cp = nexttoken(line); while (n < MAXTOKEN && cp != NULL) { len = strlen(cp); if ((token[n] = malloc(len+1)) == NULL) { mpd_err_fatal("out of memory"); } strcpy(token[n], cp); cp = nexttoken(NULL); n++; } token[n] = NULL; return n; } static void freetoken(char **token) { while (*token != NULL) { free(*token++); } } /* returns all expected conditions in a status flag */ static uint32_t scan_conditions(char **token) { char *condition = *token; uint32_t status = 0; while (condition != NULL) { if (startswith(condition, "--")) break; else if (eqtoken(condition, "Clamped")) status |= MPD_Clamped; else if (eqtoken(condition, "Conversion_syntax")) status |= MPD_Conversion_syntax; else if (eqtoken(condition, "Division_by_zero")) status |= MPD_Division_by_zero; else if (eqtoken(condition, "Division_impossible")) status |= MPD_Division_impossible; else if (eqtoken(condition, "Division_undefined")) status |= MPD_Division_undefined; else if (eqtoken(condition, "Fpu_error")) status |= MPD_Fpu_error; else if (eqtoken(condition, "Inexact")) status |= MPD_Inexact; else if (eqtoken(condition, "Invalid_context")) status |= MPD_Invalid_context; else if (eqtoken(condition, "Invalid_operation")) status |= MPD_Invalid_operation; else if (eqtoken(condition, "Malloc_error")) status |= MPD_Malloc_error; else if (eqtoken(condition, "Not_implemented")) status |= MPD_Not_implemented; else if (eqtoken(condition, "Overflow")) status |= MPD_Overflow; else if (eqtoken(condition, "Rounded")) status |= MPD_Rounded; else if (eqtoken(condition, "Subnormal")) status |= MPD_Subnormal; else if (eqtoken(condition, "Underflow")) status |= MPD_Underflow; else mpd_err_fatal("unknown status: %s", condition); condition = *(++token); } return status; } static void compare_expected(const char *calc, const char *expected, uint32_t expected_status, char *id, mpd_context_t *ctx) { char ctxstatus[MPD_MAX_FLAG_STRING]; char expstatus[MPD_MAX_FLAG_STRING]; #ifndef RT_VERBOSITY /* Do not print known pseudo-failures. */ int i; /* known ULP diffs */ if (ctx->allcr == 0) { for (i = 0; ulp_cases[i].id != NULL; i++) { if (eqtoken(id, ulp_cases[i].id) && strcmp(expected, ulp_cases[i].expected) == 0 && strcmp(calc, ulp_cases[i].calc) == 0) { return; } } } /* known status diffs */ for (i = 0; status_cases[i].id != NULL; i++) { if (eqtoken(id, status_cases[i].id) && expected_status == status_cases[i].expected && ctx->status == status_cases[i].calc) { return; } } #endif if (strcmp(calc, expected) != 0) { if (file_failure == 0) { fputs("\n\n", stderr); } fprintf(stderr, "FAIL: %s calc: %s expected: %s\n", id, calc, expected); global_failure = file_failure = 1; } if (ctx->status != expected_status) { if (file_failure == 0) { fputs("\n\n", stderr); } mpd_snprint_flags(ctxstatus, MPD_MAX_FLAG_STRING, ctx->status); mpd_snprint_flags(expstatus, MPD_MAX_FLAG_STRING, expected_status); fprintf(stderr, "FAIL: %s: status: calc: %s expected: %s\n", id, ctxstatus, expstatus); global_failure = file_failure = 1; } } static int equalmem(const mpd_t *a, const mpd_t *b) { mpd_ssize_t i; if (a->flags != b->flags) return 0; if (a->exp != b->exp) return 0; if (a->len != b->len) return 0; if (a->digits != b->digits) return 0; for (i = 0; i < a->len; i++) if (a->data[i] != b->data[i]) return 0; return 1; } static void check_equalmem(const mpd_t *a, const mpd_t *b, const char *id) { if (!equalmem(a, b)) { fprintf(stderr, "FAIL: const arg changed: %s\n", id); } } static unsigned long get_testno(char *token) { char *number; number = strpbrk(token, "0123456789"); ASSERT(number != NULL); return strtoul(number, NULL, 10); } /* scan a single operand and the expected result */ static int scan_1op_result(mpd_t *op1, char **result, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } mpd_set_string(op1, token[2], ctx); /* discard "->" */ if (token[3] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } /* expected result */ if (token[4] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } *result = token[4]; return 5; } /* scan a single operand and two results */ static int scan_1op_2results(mpd_t *op1, char **result1, char **result2, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } mpd_set_string(op1, token[2], ctx); /* discard "->" */ if (token[3] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } /* expected result1 */ if (token[4] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } *result1 = token[4]; /* expected result2 */ if (token[5] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } *result2 = token[5]; return 6; } /* scan decimal operand, string operand and the expected result */ static int scan_1op_str_result(mpd_t *op1, char **op2, char **result, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op1, token[2], ctx); /* operand 2 */ if (token[3] == NULL) { mpd_err_fatal("%s", token[0]); } *op2 = token[3]; /* discard "->" */ if (token[4] == NULL) { mpd_err_fatal("%s", token[0]); } /* expected result */ if (token[5] == NULL) { mpd_err_fatal("%s", token[0]); } *result = token[5]; return 6; } /* scan two operands and the expected result */ static int scan_2ops_result(mpd_t *op1, mpd_t *op2, char **result, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op1, token[2], ctx); /* operand 2 */ if (token[3] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op2, token[3], ctx); /* discard "->" */ if (token[4] == NULL) { mpd_err_fatal("%s", token[0]); } /* expected result */ if (token[5] == NULL) { mpd_err_fatal("%s", token[0]); } *result = token[5]; return 6; } /* scan two operands and two results */ static int scan_2ops_2results(mpd_t *op1, mpd_t *op2, char **result1, char **result2, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op1, token[2], ctx); /* operand 2 */ if (token[3] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op2, token[3], ctx); /* discard "->" */ if (token[4] == NULL) { mpd_err_fatal("%s", token[0]); } /* expected result1 */ if (token[5] == NULL) { mpd_err_fatal("%s", token[0]); } *result1 = token[5]; /* expected result2 */ if (token[6] == NULL) { mpd_err_fatal("%s", token[0]); } *result2 = token[6]; return 7; } /* scan three operands and the expected result */ static int scan_3ops_result(mpd_t *op1, mpd_t *op2, mpd_t *op3, char **result, char *token[], mpd_context_t *ctx) { /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op1, token[2], ctx); /* operand 2 */ if (token[3] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op2, token[3], ctx); /* operand 2 */ if (token[4] == NULL) { mpd_err_fatal("%s", token[0]); } mpd_set_string(op3, token[4], ctx); /* discard "->" */ if (token[5] == NULL) { mpd_err_fatal("%s", token[0]); } /* expected result */ if (token[6] == NULL) { mpd_err_fatal("%s", token[0]); } *result = token[6]; return 7; } static mpd_t *op, *op1, *op2, *op3; static mpd_t *tmp, *tmp1, *tmp2, *tmp3; static mpd_t *result, *result1, *result2; /* Test triple conversion */ static void _TripleTest(const mpd_t *a, mpd_context_t *ctx, const char *testno) { mpd_uint128_triple_t triple; uint32_t status = 0; int ret = 0; #ifdef MPD_CONFIG_32 /* * 32-bit: as_triple() expects well-formed decimals. Skip test cases * that use the extended exponent, which is safe in the tests but not * in production. */ if (a->exp < MPD_MIN_ETINY || a->exp > MPD_MAX_EMAX) { return; } #endif triple = mpd_as_uint128_triple(a); switch (triple.tag) { case MPD_TRIPLE_QNAN: case MPD_TRIPLE_SNAN: ASSERT(triple.exp == 0) break; case MPD_TRIPLE_INF: ASSERT(triple.hi == 0 && triple.lo == 0 && triple.exp == 0) break; case MPD_TRIPLE_NORMAL: break; case MPD_TRIPLE_ERROR: ASSERT(triple.sign == 0 && triple.hi == 0 && triple.lo == 0 && triple.exp == 0) break; } /* Allocation failures in from_triple() */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(result); mpd_set_alloc_fail(ctx); status = 0; ret = mpd_from_uint128_triple(result, &triple, &status); mpd_set_alloc(ctx); if (!(status&MPD_Malloc_error)) { break; } ASSERT(ret == -1) ASSERT(mpd_isnan(result)) } if (triple.tag != MPD_TRIPLE_ERROR) { ASSERT(ret == 0) ASSERT(status == 0) check_equalmem(result, a, testno); } else { ASSERT(ret == -1) ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isnan(result)) } } /* Test both versions of mpd_to_sci. Do not use this if alloc_fail is set, since MPD_Malloc_error will only be triggered for one of the functions. */ static char * _mpd_to_sci(const mpd_t *dec, int fmt) { char *r, *s; mpd_ssize_t size; r = mpd_to_sci(dec, fmt); size = mpd_to_sci_size(&s, dec, fmt); if (r == NULL) { ASSERT(size == -1) ASSERT(s == NULL) } else { ASSERT(strcmp(r, s) == 0) ASSERT(size == (mpd_ssize_t)strlen(s)) } mpd_free(s); return r; } /* * Test a function returning pointer to char, accepting: * op1, context * * This function is used for "toSci", "toEng" and "apply" * and does not use a maxctx for the conversion of the operand. */ static void _cp_MpdCtx(char **token, char *(*func)(const mpd_t *, int), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected, *expected_fail = NULL; uint32_t expstatus; int n; mpd_readcontext(&maxctx); mpd_context_t *workctx = ctx; workctx->status = 0; n = scan_1op_result(op, &expected, token, workctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* Allocation failures for mpd_set_string */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); workctx->status = 0; mpd_set_alloc_fail(workctx); (void)scan_1op_result(tmp, &expected_fail, token, workctx); mpd_set_alloc(workctx); if (!(workctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } ASSERT(strcmp(expected, expected_fail) == 0) ASSERT(mpd_cmp_total(tmp, op) == 0) /* make a copy of the operand */ mpd_init_rand(tmp); mpd_copy(tmp, op, workctx); calc = func(tmp, 1); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], workctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, workctx); mpd_set_alloc_fail(workctx); calc = func(tmp, 1); mpd_set_alloc(workctx); if (calc != NULL) { break; } } compare_expected(calc, expected, expstatus, token[0], workctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); } /* Test mpd_to_sci_size() and mpd_to_eng_size(). */ static void sci_eng_size(char **token, mpd_ssize_t (*func)(char **, const mpd_t *, int), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected, *expected_fail = NULL; uint32_t expstatus; mpd_ssize_t size; int n; mpd_readcontext(&maxctx); mpd_context_t *workctx = ctx; workctx->status = 0; n = scan_1op_result(op, &expected, token, workctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* Allocation failures for mpd_set_string */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); workctx->status = 0; mpd_set_alloc_fail(workctx); (void)scan_1op_result(tmp, &expected_fail, token, workctx); mpd_set_alloc(workctx); if (!(workctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } ASSERT(strcmp(expected, expected_fail) == 0) ASSERT(mpd_cmp_total(tmp, op) == 0) /* make a copy of the operand */ mpd_init_rand(tmp); mpd_copy(tmp, op, workctx); size = func(&calc, tmp, 1); ASSERT(size == (mpd_ssize_t)strlen(calc)) /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], workctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, workctx); mpd_set_alloc_fail(workctx); size = func(&calc, tmp, 1); mpd_set_alloc(workctx); if (calc != NULL) { ASSERT(size == (mpd_ssize_t)strlen(calc)) break; } } compare_expected(calc, expected, expstatus, token[0], workctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); } /* Quick and dirty: parse hex escape sequences */ static char * parse_escapes(const char *s) { char hex[5]; char *res, *cp; unsigned int u; int n; cp = res = malloc(strlen(s)+1); if (res == NULL) { return NULL; } hex[0] = '0'; hex[1] = '\0'; while (*s) { if (*s == '\\' && *(s+1) == 'x') { for (n = 1; n < 4; n++) { if (!s[n]) { free(res); return NULL; } hex[n] = s[n]; } hex[n] = '\0'; sscanf(hex, "%x%n", &u, &n); *cp++ = (char)u; s += n; } else { *cp++ = *s++; } } *cp = '\0'; return res; } /* * Test a function returning pointer to char, accepting: * op1, fmt, context * * This function is used for "mpd_format". */ static void _cp_MpdFmtCtx(char **token, char *(*func)(const mpd_t *, const char *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *fmt; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_str_result(op1, &fmt, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); fmt = parse_escapes(fmt); expected = parse_escapes(expected); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op1, ctx); ctx->status = 0; calc = func(tmp, fmt, ctx); /* compare the calculated result to the expected result */ if (calc == NULL) { compare_expected("NULL", expected, expstatus, token[0], ctx); } else { compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } check_equalmem(tmp, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op1, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); calc = func(tmp, fmt, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(calc == NULL) } if (calc == NULL) { compare_expected("NULL", expected, expstatus, token[0], ctx); } else { compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } check_equalmem(tmp, op1, token[0]); free(fmt); free(expected); } /* * Test a function returning pointer to const char, accepting: * op1, context */ static void _ccp_MpdCtx(char **token, const char *(*func)(const mpd_t *, const mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; const char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc = func(tmp, ctx); compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); calc = func(tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(calc == NULL) } compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } /* Test a unary function */ static void _Res_Op_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* result and tmp are distinct decimals */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; mpd_set_alloc_count(ctx); func(result, tmp, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* result equals operand */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp, tmp, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } /* Test a unary function, quantize the operand before applying the actual function */ static void _Res_Op_CtxWithQuantize(char *token[], void (*func)(mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op, op1, &expected, token, &maxctx); mpd_quantize(op, op, op1, &maxctx); _TripleTest(op, ctx, token[0]); _TripleTest(op1, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* result and tmp are distinct decimals */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; mpd_set_alloc_count(ctx); func(result, tmp, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* result equals operand */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp, tmp, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } static void resolve_status_hack(uint32_t *expstatus, const uint32_t status) { /* hack #1 to resolve disagreement with results generated by decimal.py */ if ((*expstatus & MPD_Invalid_operation) && (status & MPD_Division_impossible)) { *expstatus = MPD_Division_impossible; } /* hack #2 to resolve disagreement with results generated by decimal.py */ if ((*expstatus & MPD_Invalid_operation) && (status & MPD_Division_undefined)) { *expstatus = MPD_Division_undefined; } } /* Test a binary function */ static void _Res_Binop_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* three distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; mpd_set_alloc_count(ctx); func(result, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); } /* Test a binary function where op1 == op2. */ static void _Res_EqualBinop_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands, distinct result */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp, tmp, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* all parameters equal */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; func(tmp, tmp, tmp, ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } /* Test a binary function with a binary result */ static void _Binres_Binop_Ctx(char *token[], void (*func)(mpd_t *, mpd_t*, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected1, *expected2; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_2results(op1, op2, &expected1, &expected2, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* four distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result1); mpd_init_rand(result2); ctx->status = 0; mpd_set_alloc_count(ctx); func(result1, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); resolve_status_hack(&expstatus, ctx->status); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result1); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(result2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result1 == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result2); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp1, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail <= INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) ASSERT(mpd_isnan(result2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result2 == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result1); ctx->status = 0; mpd_set_alloc_count(ctx); func(result1, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result1); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(tmp1)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result1 == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result2); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp2, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, result2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) ASSERT(mpd_isnan(result2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* result2 == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result1); ctx->status = 0; mpd_set_alloc_count(ctx); func(result1, tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result1); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(tmp2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* result1 == tmp1, result2 == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp1, tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) ASSERT(mpd_isnan(tmp2)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* result1 == tmp2, result2 == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp2, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) ASSERT(mpd_isnan(tmp1)) if (alloc_fail > 50) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); } /* Test a binary function with a binary result; equal operands */ static void _Binres_EqualBinop_Ctx(char *token[], void (*func)(mpd_t *, mpd_t*, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected1, *expected2; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_2results(op, &expected1, &expected2, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct results */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result1); mpd_init_rand(result2); ctx->status = 0; func(result1, result2, tmp, tmp, ctx); resolve_status_hack(&expstatus, ctx->status); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result1); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, result2, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(result2)) } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* result1 == tmp */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result2); ctx->status = 0; func(tmp, result2, tmp, tmp, ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result2); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, result2, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) ASSERT(mpd_isnan(result2)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(result2, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* result2 == tmp */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result1); ctx->status = 0; func(result1, tmp, tmp, tmp, ctx); calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result1); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result1, tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result1)) ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(result1, 1); compare_expected(calc, expected1, expstatus, token[0], ctx); mpd_free(calc); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected2, expstatus, token[0], ctx); mpd_free(calc); } /* Test a ternary function */ static void _Res_Ternop_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n, incr; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_3ops_result(op1, op2, op3, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); _TripleTest(op3, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* four distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); mpd_init_rand(result); ctx->status = 0; mpd_set_alloc_count(ctx); func(result, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); check_equalmem(tmp3, op3, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); check_equalmem(tmp3, op3, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp1, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); check_equalmem(tmp3, op3, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); check_equalmem(tmp3, op3, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp2, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp3, op3, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp3, op3, token[0]); /* result == tmp3 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_count(ctx); func(tmp3, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); calc = _mpd_to_sci(tmp3, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ incr = 1; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_copy(tmp3, op3, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp3, tmp1, tmp2, tmp3, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp3)) if (alloc_fail > 100) { incr = (int)(alloc_count*0.02) + 1; } } calc = _mpd_to_sci(tmp3, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); } /* Test a ternary function, first and second operand equal */ static void _Res_EqEqOp_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct result */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp1, tmp1, tmp2, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp1, tmp1, tmp1, tmp2, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp2, tmp1, tmp1, tmp2, ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); } /* Test a ternary function, first and third operand equal */ static void _Res_EqOpEq_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct result */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp1, tmp2, tmp1, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp2, tmp1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp1, tmp1, tmp2, tmp1, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp2, tmp1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp2, tmp1, tmp2, tmp1, ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp2, tmp1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); } /* Test a ternary function, second and third operand equal */ static void _Res_OpEqEq_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct result */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp1, tmp2, tmp2, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, tmp2, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp2, tmp1, tmp2, tmp2, ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp2, tmp1, tmp2, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; func(tmp1, tmp1, tmp2, tmp2, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, tmp2, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp2, op2, token[0]); } /* Test a ternary function, first, second and third operand equal */ static void _Res_EqEqEq_Ctx(char *token[], void (*func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* distinct result */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp, tmp, tmp, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp, op, token[0]); /* result == tmp */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; func(tmp, tmp, tmp, tmp, ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp, tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } /* * Test a binary function that returns an additional integer result. * Used for the comparison functions. */ static void _Int_Res_Binop_Ctx(char *token[], int (*func)(mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; int int_result; char buf[11]; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* three distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; int_result = func(result, tmp1, tmp2, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(result, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp1, tmp1, tmp2, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp1, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp2, tmp1, tmp2, ctx); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp2, tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); } /* * Test a binary function that returns an additional integer result. * Equal operands. * Used for the comparison functions. */ static void _Int_Res_EqualBinop_Ctx(char *token[], int (*func)(mpd_t *, const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; int int_result; char buf[11]; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; int_result = func(result, tmp, tmp, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(result, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* all parameters equal */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; int_result = func(tmp, tmp, tmp, ctx); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp, tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } } /* * Test a binary function that returns an additional integer result. * Function does not take a context argument. * Used for the comparison functions. */ static void _Int_Res_Binop(char *token[], int (*func)(mpd_t *, const mpd_t *, const mpd_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; int int_result; char buf[11]; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* three distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_init_rand(result); ctx->status = 0; int_result = func(result, tmp1, tmp2); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(result, tmp1, tmp2); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp1, tmp1, tmp2); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp1, tmp1, tmp2); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp2, op2, token[0]); /* result == tmp2 */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp2, tmp1, tmp2); calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp2, tmp1, tmp2); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp2)) } calc = _mpd_to_sci(tmp2, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); } /* * Test a binary function that returns an additional integer result. * Function does not take a context argument. * Equal operands. * Used for the comparison functions. */ static void _Int_Res_EqualBinop(char *token[], int (*func)(mpd_t *, const mpd_t *, const mpd_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; int int_result; char buf[11]; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_init_rand(result); ctx->status = 0; int_result = func(result, tmp, tmp); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(result, tmp, tmp); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* all parameters equal */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; int_result = func(tmp, tmp, tmp); calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp, tmp, tmp); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp)) } calc = _mpd_to_sci(tmp, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); snprintf(buf, 11, "%d", int_result); if (int_result != INT_MAX) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } } /* * Test a binary function that returns only an integer result. * Used for the cmp functions. */ enum {SKIP_NONE, SKIP_NAN, SKIP_NONINT}; static void _Int_Binop_Ctx(int skip, char *token[], int (*func)(const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int int_result; char buf[11]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* two distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp1, tmp2, ctx); snprintf(buf, 11, "%d", int_result); if (!(skip && int_result == INT_MAX)) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp1, tmp2, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(int_result== INT_MAX) } snprintf(buf, 11, "%d", int_result); if (!(skip && int_result == INT_MAX)) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); } /* * Test a binary function that returns only an integer result. * Equal operands. * Used for the cmp functions. */ static void _Int_EqualBinop_Ctx(int skip, char *token[], int (*func)(const mpd_t *, const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int int_result; char buf[11]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; int_result = func(tmp, tmp, ctx); snprintf(buf, 11, "%d", int_result); if (!(skip && int_result == INT_MAX)) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp, tmp, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(int_result== INT_MAX) } snprintf(buf, 11, "%d", int_result); if (!(skip && int_result == INT_MAX)) { /* NaN cases are skipped for the int_retval */ compare_expected(buf, expected, expstatus, token[0], ctx); } check_equalmem(tmp, op, token[0]); } /* * Test a binary function that returns an int. * The function does not take a context argument. */ static void _Int_Binop(char *token[], int (*func)(const mpd_t *, const mpd_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int int_result; char buf[11]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* two distinct decimals */ mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; int_result = func(tmp1, tmp2); snprintf(buf, 11, "%d", int_result); compare_expected(buf, expected, expstatus, token[0], ctx); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_copy(tmp1, op1, ctx); mpd_copy(tmp2, op2, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp1, tmp2); mpd_set_alloc(ctx); if (int_result != INT_MAX) { break; } } snprintf(buf, 11, "%d", int_result); compare_expected(buf, expected, expstatus, token[0], ctx); check_equalmem(tmp1, op1, token[0]); check_equalmem(tmp2, op2, token[0]); } /* * Test a binary function that returns an int. * Equal operands. * The function does not take a context argument. */ static void _Int_EqualBinop(char *token[], int (*func)(const mpd_t *, const mpd_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int int_result; char buf[11]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* equal operands */ mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; int_result = func(tmp, tmp); snprintf(buf, 11, "%d", int_result); compare_expected(buf, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); int_result = func(tmp, tmp); mpd_set_alloc(ctx); if (int_result != INT_MAX) { break; } } snprintf(buf, 11, "%d", int_result); compare_expected(buf, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } static mpd_ssize_t scan_ssize(char *token[]) { errno = 0; if (token[1] == NULL) { errno = 1; return MPD_SSIZE_MAX; } return strtossize(token[1], NULL, 10); } static void _mpd_shiftl(mpd_t *res, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx) { ASSERT(!mpd_isspecial(a)); mpd_shiftl(res, a, n, ctx); } static void _mpd_shiftr(mpd_t *res, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx) { ASSERT(!mpd_isspecial(a)); (void)mpd_shiftr(res, a, n, ctx); } /* * Test a function with an mpd_t and an mpd_ssize_t operand. * Used for the shift functions. */ static void _Res_Op_Lsize_Ctx(int skip, char *token[], void (*func)(mpd_t *, const mpd_t *, mpd_ssize_t, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; mpd_ssize_t ssize; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_2ops_result(op1, op2, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); _TripleTest(op2, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* only integers are allowed for ssize */ if (skip && (mpd_isspecial(op2) || op2->exp != 0)) { /* fprintf(stderr, "SKIP: %s\n", token[0]); */ return; } ssize = mpd_get_ssize(op2, &maxctx); if (maxctx.status&MPD_Invalid_operation) { return; } /* two distinct decimals */ mpd_init_rand(tmp1); mpd_copy(tmp1, op1, ctx); mpd_init_rand(result); ctx->status = 0; func(result, tmp1, ssize, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_copy(tmp1, op1, ctx); mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); func(result, tmp1, ssize, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); check_equalmem(tmp1, op1, token[0]); /* result == tmp1 */ mpd_init_rand(tmp1); mpd_copy(tmp1, op1, ctx); ctx->status = 0; func(tmp1, tmp1, ssize, ctx); calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_init_rand(tmp1); mpd_copy(tmp1, op1, ctx); ctx->status = 0; mpd_set_alloc_fail(ctx); func(tmp1, tmp1, ssize, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(tmp1)) } calc = _mpd_to_sci(tmp1, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } /* test mpd_qln10() */ static void _test_mpd_qln10(int skip, char *token[], mpd_context_t *ctx) { mpd_context_t maxctx; char *calc; char *expected; uint32_t expstatus; mpd_ssize_t ssize; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op1, &expected, token, &maxctx); _TripleTest(op1, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* only integers are allowed for ssize */ if (skip && (mpd_isspecial(op1) || op1->exp != 0)) { /* fprintf(stderr, "SKIP: %s\n", token[0]); */ return; } ssize = mpd_get_ssize(op1, &maxctx); if (maxctx.status&MPD_Invalid_operation) { return; } mpd_init_rand(result); ctx->status = 0; mpd_qln10(result, ssize, &ctx->status); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); /* Allocation failures */ for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_qln10(result, ssize, &ctx->status); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); } static void _Baseconv(char *token[], mpd_context_t *ctx) { mpd_context_t maxctx; uint32_t base; uint16_t *data16; uint32_t *data32; size_t len16, len32; size_t expected_len16, expected_len32; char *expected; uint32_t expstatus; char *calc; int n = 0; int i, iter = 0; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; n = scan_1op_result(op1, &expected, token, &maxctx); ASSERT(mpd_isinteger(op1)) _TripleTest(op1, ctx, token[0]); /* scan expected conditions */ expstatus = scan_conditions(token+n); /* * base := (1<<15) * data16 := NULL * Allocation and deallocation on error by mpd_export_u16(). */ base = (1<<15); data16 = NULL; expected_len16 = mpd_export_u16(&data16, 0, base, op1, ctx); if (expected_len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := (1<<15) * data16 := NULL * Test allocation failures. */ base = (1<<15); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; mpd_set_alloc_fail(ctx); data16 = NULL; expected_len16 = mpd_export_u16(&data16, 0, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } /* If data16 == NULL, it is deallocated on failure. */ ASSERT(expected_len16 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := (1<<15) * len(data16) := 1 * Simulate result from sizeinbase() that is too small. */ base = (1<<15); data16 = mpd_alloc(1, sizeof *data16); expected_len16 = mpd_export_u16(&data16, 1, base, op1, ctx); if (expected_len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := (1<<15) * len(data16) == 1 * Test allocation failures. */ base = (1<<15); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data16 = mpd_alloc(1, sizeof *data16); mpd_set_alloc_fail(ctx); expected_len16 = mpd_export_u16(&data16, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } /* Caller must free the memory that was passed in. */ mpd_free(data16); ASSERT(expected_len16 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := (1<<16) * len(data16) := mpd_sizeinbase() */ base = (1U<<16); len16 = mpd_sizeinbase(op1, base); data16 = mpd_alloc((mpd_size_t)len16, sizeof *data16); len16 = mpd_export_u16(&data16, len16, base, op1, ctx); if (len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := 9999 * len(data16) := mpd_sizeinbase() */ base = 9999; len16 = mpd_sizeinbase(op1, base); data16 = mpd_alloc((mpd_size_t)len16, sizeof *data16); expected_len16 = mpd_export_u16(&data16, len16, base, op1, ctx); if (expected_len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); /* * base := [2..16] * len(data16) := mpd_sizeinbase() */ iter = 16; for (i = 2; i <= iter; i++) { base = (uint32_t)i; len16 = mpd_sizeinbase(op1, base); data16 = mpd_alloc((mpd_size_t)len16, sizeof *data16); len16 = mpd_export_u16(&data16, len16, base, op1, ctx); if (len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); } /* * base := random(UINT_16_MAX) * len(data16) := mpd_sizeinbase() */ iter = 5; for (i = 0; i < iter; i++) { base = random() % UINT16_MAX; if (base < 2) base = 2; len16 = mpd_sizeinbase(op1, base); data16 = mpd_alloc((mpd_size_t)len16, sizeof *data16); len16 = mpd_export_u16(&data16, len16, base, op1, ctx); if (len16 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u16(result, data16, len16, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data16 = mpd_alloc(1, sizeof *data16); mpd_set_alloc_fail(ctx); expected_len16 = mpd_export_u16(&data16, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } /* Caller must free the memory that was passed in. */ mpd_free(data16); ASSERT(expected_len16 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data16 = mpd_alloc(1, sizeof *data16); mpd_set_alloc_fail(ctx); expected_len16 = mpd_export_u16(&data16, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } /* Caller must free the memory that was passed in. */ mpd_free(data16); ASSERT(expected_len16 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u16(result, data16, expected_len16, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data16); } /* ================================================================ */ /* uint32_t bases */ /* ================================================================ */ /* * base := (1<<30) * data32 := NULL */ base = (1<<30); data32 = NULL; expected_len32 = mpd_export_u32(&data32, 0, base, op1, ctx); if (expected_len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := (1<<30) * data32 := NULL * Test allocation failures. */ base = (1<<30); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; mpd_set_alloc_fail(ctx); data32 = NULL; expected_len32 = mpd_export_u32(&data32, 0, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := (1<<30) * len(data32) := 1 */ base = (1<<30); data32 = mpd_alloc(1, sizeof *data32); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); if (expected_len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := (1<<30) * len(data32) := 1 * Test allocation failures. */ base = (1<<30); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data32 = mpd_alloc(1, sizeof *data32); mpd_set_alloc_fail(ctx); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) mpd_free(data32); } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := 10**9 * len(data32) := mpd_sizeinbase() */ base = 1000000000; len32 = mpd_sizeinbase(op1, base); data32 = mpd_alloc((mpd_size_t)len32, sizeof *data32); expected_len32 = mpd_export_u32(&data32, len32, base, op1, ctx); if (len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := 10**9 * len(data32) := mpd_sizeinbase() * Test allocation failures. */ base = 1000000000; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; mpd_set_alloc_fail(ctx); data32 = NULL; expected_len32 = mpd_export_u32(&data32, 0, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); /* * base := 10**9 * len(data32) := 1 * Test allocation failures. */ base = 1000000000; for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data32 = mpd_alloc(1, sizeof *data32); mpd_set_alloc_fail(ctx); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) mpd_free(data32); } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); for (i = 2; i <= 16; i++) { base = (uint32_t)i; len32 = mpd_sizeinbase(op1, base); data32 = mpd_alloc((mpd_size_t)len32, sizeof *data32); expected_len32 = mpd_export_u32(&data32, len32, base, op1, ctx); if (len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); } for (i = 0; i < 5; i++) { base = random() % UINT32_MAX; if (base < 2) base = 2; len32 = mpd_sizeinbase(op1, base); data32 = mpd_alloc((mpd_size_t)len32, sizeof *data32); expected_len32 = mpd_export_u32(&data32, len32, base, op1, ctx); if (len32 == SIZE_MAX) { mpd_err_fatal("export_to_base failed"); } mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data32 = mpd_alloc(1, sizeof *data32); mpd_set_alloc_fail(ctx); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) mpd_free(data32); } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { ctx->status = 0; data32 = mpd_alloc(1, sizeof *data32); mpd_set_alloc_fail(ctx); expected_len32 = mpd_export_u32(&data32, 1, base, op1, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(expected_len32 == SIZE_MAX) mpd_free(data32); } for (alloc_fail = 1; alloc_fail < INT_MAX; alloc_fail++) { mpd_minalloc(result); ctx->status = 0; mpd_set_alloc_fail(ctx); mpd_import_u32(result, data32, expected_len32, MPD_POS, base, ctx); mpd_set_alloc(ctx); if (!(ctx->status&MPD_Malloc_error)) { break; } ASSERT(mpd_isnan(result)) } calc = _mpd_to_sci(result, 1); compare_expected(calc, expected, expstatus, token[0], ctx); mpd_free(calc); mpd_free(data32); } } /* * Test a function returning a uint64_t, accepting: * op, context * * This function is used for: * - mpd_get_uint (64 bit) * - mpd_abs_uint (64 bit) * - mpd_get_u64 */ #ifndef MPD_LEGACY_COMPILER static void _u64_MpdCtx(char **token, uint64_t (*func)(const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; uint64_t calc_uint; char calc[23]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc_uint = func(tmp, ctx); snprintf(calc, 23, "%" PRIu64, calc_uint); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } #endif /* * Test a function returning a uint64_t, accepting: * op, context * * This function is used for: * - mpd_get_uint (64 bit) * - mpd_abs_uint (64 bit) * - mpd_get_u64 */ static void _u32_MpdCtx(char **token, uint32_t (*func)(const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; uint32_t calc_uint; char calc[23]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc_uint = func(tmp, ctx); snprintf(calc, 23, "%" PRIu32, calc_uint); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } /* * Test a function returning an mpd_ssize_t, accepting: * op, fmt, context * * This function is used for: * - mpd_get_ssize * - mpd_get_i64 * - mpd_get_i32 */ #ifndef MPD_LEGACY_COMPILER static void _i64_MpdCtx(char **token, int64_t (*func)(const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int64_t calc_ssize; char calc[23]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc_ssize = func(tmp, ctx); snprintf(calc, 23, "%" PRIi64, calc_ssize); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } #endif /* * Test a function returning an mpd_ssize_t, accepting: * op, fmt, context * * This function is used for: * - mpd_get_ssize * - mpd_get_i64 * - mpd_get_i32 */ static void _i32_MpdCtx(char **token, int32_t (*func)(const mpd_t *, mpd_context_t *), mpd_context_t *ctx) { mpd_context_t maxctx; int32_t calc_ssize; char calc[23]; char *expected; uint32_t expstatus; int n; mpd_readcontext(&maxctx); maxctx.traps = MPD_Malloc_error; /* conversion should be done as if there were no limits */ n = scan_1op_result(op, &expected, token, &maxctx); _TripleTest(op, ctx, token[0]); expstatus = scan_conditions(token+n); mpd_init_rand(tmp); mpd_copy(tmp, op, ctx); ctx->status = 0; calc_ssize = func(tmp, ctx); snprintf(calc, 23, "%" PRIi32, calc_ssize); /* compare the calculated result to the expected result */ compare_expected(calc, expected, expstatus, token[0], ctx); check_equalmem(tmp, op, token[0]); } static void triple_cov(void) { mpd_uint128_triple_t triple = { MPD_TRIPLE_QNAN, 2, 0, 0, 0 }; uint32_t status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.sign = 0; triple.exp = 1; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_INF; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 2; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 0; triple.exp = INT64_MAX; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 0; triple.exp = INT64_MIN; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 0; triple.exp = MPD_SSIZE_MAX; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = MPD_TRIPLE_NORMAL; triple.sign = 0; triple.exp = MPD_SSIZE_MIN; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) triple.tag = (enum mpd_triple_class)10; triple.sign = 0; status = 0; mpd_from_uint128_triple(op, &triple, &status); ASSERT(status == MPD_Conversion_syntax) ASSERT(mpd_isqnan(op)) } /* process a file */ static void doit(const char *filename) { FILE *file; mpd_context_t ctx; char *line; char *tmpline; char *token[MAXTOKEN+1]; uint32_t testno; mpd_ssize_t l; mpd_testcontext(&ctx); ctx.traps = MPD_Malloc_error; file_failure = 0; if (strcmp(filename, "-") == 0) { file = stdin; } else { if ((file = fopen(filename, "r")) == NULL) { mpd_err_fatal("could not open %s", filename); } if (!startswith(filename, "official") && !startswith(filename, "additional")) { printf("%s ...", filename); fflush(stdout); } } if ((line = mpd_alloc(MAXLINE+1, sizeof *line)) == NULL) { mpd_err_fatal("out of memory"); } if ((tmpline = mpd_alloc(MAXLINE+1, sizeof *line)) == NULL) { mpd_err_fatal("out of memory"); } while (fgets(line, MAXLINE+1, file) != NULL) { /* split a line into tokens */ strcpy(tmpline, line); for (int i =0; i < MAXTOKEN+1; i++) { token[i] = NULL; } if (split(token, tmpline) == 0) { goto cleanup; } /* comments */ if (startswith(token[0], "--")) { goto cleanup; } /* end comments */ /* skip bool* tests in extra.decTest */ if (startswith(token[0], "bool")) { goto cleanup; } /* end skips */ /* directives */ if (startswith(token[0], "ExtendedRange")) { ASSERT(token[1] != NULL); if (strcmp(token[1], "1") == 0) { extended = 1; } else if (strcmp(token[1], "0") == 0) { extended = 0; } else { mpd_err_fatal("%s: %s", filename, line); } goto cleanup; } if (startswith(token[0], "Precision")) { ASSERT(token[1] != NULL); if (strcmp(token[1], "MAX_PREC") == 0) { l = MPD_MAX_PREC; } else { l = scan_ssize(token); if (errno != 0) { mpd_err_fatal("%s: %s", filename, line); } } ctx.prec = l; goto cleanup; } if (startswith(token[0], "Rounding")) { ASSERT(token[1] != NULL); if (eqtoken(token[1], "Ceiling")) ctx.round = MPD_ROUND_CEILING; else if (eqtoken(token[1], "Up")) ctx.round = MPD_ROUND_UP; else if (eqtoken(token[1], "Half_up")) ctx.round = MPD_ROUND_HALF_UP; else if (eqtoken(token[1], "Half_even")) ctx.round = MPD_ROUND_HALF_EVEN; else if (eqtoken(token[1], "Half_down")) ctx.round = MPD_ROUND_HALF_DOWN; else if (eqtoken(token[1], "Down")) ctx.round = MPD_ROUND_DOWN; else if (eqtoken(token[1], "Floor")) ctx.round = MPD_ROUND_FLOOR; else if (eqtoken(token[1], "05up")) ctx.round = MPD_ROUND_05UP; else mpd_err_fatal("%s: %s", filename, line); goto cleanup; } if (startswith(token[0], "MaxExponent")) { ASSERT(token[1] != NULL); if (strcmp(token[1], "MAX_EMAX") == 0) { l = MPD_MAX_EMAX; } else { l = scan_ssize(token); if (errno != 0) { mpd_err_fatal("%s: %s", filename, line); } } ctx.emax = l; goto cleanup; } if (startswith(token[0], "MinExponent")) { ASSERT(token[1] != NULL); if (strcmp(token[1], "MIN_EMIN") == 0) { l = MPD_MIN_EMIN; } else { l = scan_ssize(token); if (errno != 0) { mpd_err_fatal("%s: %s", filename, line); } } ctx.emin = l; goto cleanup; } if (startswith(token[0], "Dectest")) { ASSERT(token[1] != NULL); if (token[1] == NULL) { mpd_err_fatal("%s: %s", filename, line); } doit(token[1]); goto cleanup; } /* end directives */ /* optional directives */ if (startswith(token[0], "Version")) { goto cleanup; } if (startswith(token[0], "Extended")) { goto cleanup; } if (startswith(token[0], "Clamp")) { ASSERT(token[1] != NULL); l = scan_ssize(token); if (errno != 0) { mpd_err_fatal("%s: %s", filename, line); } if (!mpd_qsetclamp(&ctx, (int)l)) { mpd_err_fatal("%s: %s", filename, line); } goto cleanup; } if (startswith(token[0], "Locale")) { ASSERT(token[1] != NULL); if (token[1] == NULL) { mpd_err_fatal("%s: %s", filename, line); } if (extended) { printf("locale: %s\n", token[1]); fflush(stdout); } if (setlocale(LC_NUMERIC, token[1]) == NULL) { mpd_err_fatal("%s: %s", filename, line); } goto cleanup; } mpd_assert_context_ok(&ctx); /* end optional directives */ /* * Actual tests start here: * - token[0] is the id * - token[1] is the operation type * - testno can be used for setting a watchpoint in the debugger */ testno = (uint32_t)get_testno(token[0]); (void)testno; /* The id is in the skip list */ if (check_skip(token[0])) { goto cleanup; } #ifdef MPD_CONFIG_64 /* Skip 32-bit specific coverage tests. */ if (startswith(token[0], "cov32")) { goto cleanup; } #else /* Skip 64-bit specific coverage tests. */ if (startswith(token[0], "cov64")) { goto cleanup; } #endif /* Translate operation type for powmod */ if (startswith(token[0], "pwmx")) { free(token[1]); token[1] = malloc(sizeof("powmod")); strcpy(token[1], "powmod"); } /* end skips */ /* Unary functions with char * result */ if (eqtoken(token[1], "tosci") || eqtoken(token[1], "apply")) { _cp_MpdCtx(token, mpd_to_sci, &ctx); sci_eng_size(token, mpd_to_sci_size, &ctx); } else if (eqtoken(token[1], "toeng")) { _cp_MpdCtx(token, mpd_to_eng, &ctx); sci_eng_size(token, mpd_to_eng_size, &ctx); } else if (eqtoken(token[1], "format")) { _cp_MpdFmtCtx(token, mpd_format, &ctx); } /* Unary function with const char * result */ else if (eqtoken(token[1], "class")) { _ccp_MpdCtx(token, mpd_class, &ctx); } /* Unary functions with mpd_t * result */ else if (eqtoken(token[1], "abs")) { _Res_Op_Ctx(token, mpd_abs, &ctx); } else if (eqtoken(token[1], "copy")) { _Res_Op_Ctx(token, mpd_copy, &ctx); } else if (eqtoken(token[1], "copyabs")) { _Res_Op_Ctx(token, mpd_copy_abs, &ctx); } else if (eqtoken(token[1], "copynegate")) { _Res_Op_Ctx(token, mpd_copy_negate, &ctx); } else if (eqtoken(token[1], "exp")) { if (extended) { if (testno != 126) { ctx.allcr = 0; /* exp: err < 1ulp, but not correctly rounded */ _Res_Op_Ctx(token, mpd_exp, &ctx); ctx.allcr = 1; } } _Res_Op_Ctx(token, mpd_exp, &ctx); } else if (eqtoken(token[1], "invert")) { _Res_Op_Ctx(token, mpd_invert, &ctx); } else if (eqtoken(token[1], "invroot")) { _Res_Op_Ctx(token, mpd_invroot, &ctx); } else if (eqtoken(token[1], "ln")) { if (extended) { ctx.allcr = 0; _Res_Op_Ctx(token, mpd_ln, &ctx); ctx.allcr = 1; } _Res_Op_Ctx(token, mpd_ln, &ctx); } else if (eqtoken(token[1], "log10")) { if (extended) { ctx.allcr = 0; _Res_Op_Ctx(token, mpd_log10, &ctx); ctx.allcr = 1; } _Res_Op_Ctx(token, mpd_log10, &ctx); } else if (eqtoken(token[1], "logb")) { _Res_Op_Ctx(token, mpd_logb, &ctx); } else if (eqtoken(token[1], "minus")) { _Res_Op_Ctx(token, mpd_minus, &ctx); } else if (eqtoken(token[1], "nextminus")) { _Res_Op_Ctx(token, mpd_next_minus, &ctx); } else if (eqtoken(token[1], "nextplus")) { _Res_Op_Ctx(token, mpd_next_plus, &ctx); } else if (eqtoken(token[1], "plus")) { _Res_Op_Ctx(token, mpd_plus, &ctx); } else if (eqtoken(token[1], "reduce")) { _Res_Op_Ctx(token, mpd_reduce, &ctx); } else if (eqtoken(token[1], "squareroot")) { #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(16000000); #endif _Res_Op_Ctx(token, mpd_sqrt, &ctx); #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token[1], "quantize_squareroot")) { #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(16000000); #endif _Res_Op_CtxWithQuantize(token, mpd_sqrt, &ctx); #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token[1], "tointegral")) { _Res_Op_Ctx(token, mpd_round_to_int, &ctx); } else if (eqtoken(token[1], "tointegralx")) { _Res_Op_Ctx(token, mpd_round_to_intx, &ctx); } else if (eqtoken(token[1], "floor")) { _Res_Op_Ctx(token, mpd_floor, &ctx); } else if (eqtoken(token[1], "ceil")) { _Res_Op_Ctx(token, mpd_ceil, &ctx); } else if (eqtoken(token[1], "trunc")) { _Res_Op_Ctx(token, mpd_trunc, &ctx); } /* Binary function returning an int */ else if (eqtoken(token[1], "samequantum")) { _Int_Binop(token, mpd_same_quantum, &ctx); } /* Binary function returning an int, equal operands */ else if (eqtoken(token[1], "samequantum_eq")) { _Int_EqualBinop(token, mpd_same_quantum, &ctx); } /* Binary functions with mpd_t * result */ else if (eqtoken(token[1], "add")) { _Res_Binop_Ctx(token, mpd_add, &ctx); } else if (eqtoken(token[1], "and")) { _Res_Binop_Ctx(token, mpd_and, &ctx); } else if (eqtoken(token[1], "copysign")) { _Res_Binop_Ctx(token, mpd_copy_sign, &ctx); } else if (eqtoken(token[1], "divide")) { #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(16000000); #endif _Res_Binop_Ctx(token, mpd_div, &ctx); #ifdef MPD_CONFIG_32 if (ctx.prec == MPD_MAX_PREC) mpd_set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token[1], "divideint")) { _Res_Binop_Ctx(token, mpd_divint, &ctx); } else if (eqtoken(token[1], "max")) { _Res_Binop_Ctx(token, mpd_max, &ctx); } else if (eqtoken(token[1], "maxmag") || eqtoken(token[1], "max_mag")) { _Res_Binop_Ctx(token, mpd_max_mag, &ctx); } else if (eqtoken(token[1], "min")) { _Res_Binop_Ctx(token, mpd_min, &ctx); } else if (eqtoken(token[1], "minmag") || eqtoken(token[1], "min_mag")) { _Res_Binop_Ctx(token, mpd_min_mag, &ctx); } else if (eqtoken(token[1], "multiply")) { _Res_Binop_Ctx(token, mpd_mul, &ctx); } else if (eqtoken(token[1], "nexttoward")) { _Res_Binop_Ctx(token, mpd_next_toward, &ctx); } else if (eqtoken(token[1], "or")) { _Res_Binop_Ctx(token, mpd_or, &ctx); } else if (eqtoken(token[1], "power")) { if (extended) { ctx.allcr = 0; _Res_Binop_Ctx(token, mpd_pow, &ctx); ctx.allcr = 1; } _Res_Binop_Ctx(token, mpd_pow, &ctx); } else if (eqtoken(token[1], "quantize")) { _Res_Binop_Ctx(token, mpd_quantize, &ctx); } else if (eqtoken(token[1], "resc")) { _Res_Op_Lsize_Ctx(SKIP_NONINT, token, mpd_rescale, &ctx); } else if (eqtoken(token[1], "remainder")) { _Res_Binop_Ctx(token, mpd_rem, &ctx); } else if (eqtoken(token[1], "remaindernear")) { _Res_Binop_Ctx(token, mpd_rem_near, &ctx); } else if (eqtoken(token[1], "rotate")) { _Res_Binop_Ctx(token, mpd_rotate, &ctx); } else if (eqtoken(token[1], "scaleb")) { _Res_Binop_Ctx(token, mpd_scaleb, &ctx); } else if (eqtoken(token[1], "shift")) { _Res_Binop_Ctx(token, mpd_shift, &ctx); if (extended) { _Res_Op_Lsize_Ctx(SKIP_NONINT, token, mpd_shiftn, &ctx); } } else if (eqtoken(token[1], "subtract")) { _Res_Binop_Ctx(token, mpd_sub, &ctx); } else if (eqtoken(token[1], "xor")) { _Res_Binop_Ctx(token, mpd_xor, &ctx); } /* Binary functions with mpd_t result, equal operands */ else if (eqtoken(token[1], "add_eq")) { _Res_EqualBinop_Ctx(token, mpd_add, &ctx); } else if (eqtoken(token[1], "and_eq")) { _Res_EqualBinop_Ctx(token, mpd_and, &ctx); } else if (eqtoken(token[1], "copysign_eq")) { _Res_EqualBinop_Ctx(token, mpd_copy_sign, &ctx); } else if (eqtoken(token[1], "divide_eq")) { _Res_EqualBinop_Ctx(token, mpd_div, &ctx); } else if (eqtoken(token[1], "divideint_eq")) { _Res_EqualBinop_Ctx(token, mpd_divint, &ctx); } else if (eqtoken(token[1], "max_eq")) { _Res_EqualBinop_Ctx(token, mpd_max, &ctx); } else if (eqtoken(token[1], "maxmag_eq")) { _Res_EqualBinop_Ctx(token, mpd_max_mag, &ctx); } else if (eqtoken(token[1], "min_eq")) { _Res_EqualBinop_Ctx(token, mpd_min, &ctx); } else if (eqtoken(token[1], "minmag_eq")) { _Res_EqualBinop_Ctx(token, mpd_min_mag, &ctx); } else if (eqtoken(token[1], "multiply_eq")) { _Res_EqualBinop_Ctx(token, mpd_mul, &ctx); } else if (eqtoken(token[1], "nexttoward_eq")) { _Res_EqualBinop_Ctx(token, mpd_next_toward, &ctx); } else if (eqtoken(token[1], "or_eq")) { _Res_EqualBinop_Ctx(token, mpd_or, &ctx); } else if (eqtoken(token[1], "power_eq")) { if (extended) { ctx.allcr = 0; _Res_EqualBinop_Ctx(token, mpd_pow, &ctx); ctx.allcr = 1; } _Res_EqualBinop_Ctx(token, mpd_pow, &ctx); } else if (eqtoken(token[1], "quantize_eq")) { _Res_EqualBinop_Ctx(token, mpd_quantize, &ctx); } else if (eqtoken(token[1], "remainder_eq")) { _Res_EqualBinop_Ctx(token, mpd_rem, &ctx); } else if (eqtoken(token[1], "remaindernear_eq")) { _Res_EqualBinop_Ctx(token, mpd_rem_near, &ctx); } else if (eqtoken(token[1], "rotate_eq")) { _Res_EqualBinop_Ctx(token, mpd_rotate, &ctx); } else if (eqtoken(token[1], "scaleb_eq")) { _Res_EqualBinop_Ctx(token, mpd_scaleb, &ctx); } else if (eqtoken(token[1], "shift_eq")) { _Res_EqualBinop_Ctx(token, mpd_shift, &ctx); } else if (eqtoken(token[1], "subtract_eq")) { _Res_EqualBinop_Ctx(token, mpd_sub, &ctx); } else if (eqtoken(token[1], "xor_eq")) { _Res_EqualBinop_Ctx(token, mpd_xor, &ctx); } /* Binary function with binary result */ else if (eqtoken(token[1], "divmod")) { _Binres_Binop_Ctx(token, mpd_divmod, &ctx); } /* Binary function with binary result, equal operands */ else if (eqtoken(token[1], "divmod_eq")) { _Binres_EqualBinop_Ctx(token, mpd_divmod, &ctx); } /* Ternary functions with mpd_t result */ else if (eqtoken(token[1], "fma")) { _Res_Ternop_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod")) { _Res_Ternop_Ctx(token, mpd_powmod, &ctx); } /* Ternary functions with mpd_t result, eq_eq_op */ else if (eqtoken(token[1], "fma_eq_eq_op")) { _Res_EqEqOp_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod_eq_eq_op")) { _Res_EqEqOp_Ctx(token, mpd_powmod, &ctx); } /* Ternary functions with mpd_t result, eq_op_eq */ else if (eqtoken(token[1], "fma_eq_op_eq")) { _Res_EqOpEq_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod_eq_op_eq")) { _Res_EqOpEq_Ctx(token, mpd_powmod, &ctx); } /* Ternary functions with mpd_t result, op_eq_eq */ else if (eqtoken(token[1], "fma_op_eq_eq")) { _Res_OpEqEq_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod_op_eq_eq")) { _Res_OpEqEq_Ctx(token, mpd_powmod, &ctx); } /* Ternary functions with mpd_t result, eq_eq_eq */ else if (eqtoken(token[1], "fma_eq_eq_eq")) { _Res_EqEqEq_Ctx(token, mpd_fma, &ctx); } else if (eqtoken(token[1], "powmod_eq_eq_eq")) { _Res_EqEqEq_Ctx(token, mpd_powmod, &ctx); } /* Special cases for the comparison functions */ else if (eqtoken(token[1], "compare")) { _Int_Res_Binop_Ctx(token, mpd_compare, &ctx); _Int_Binop_Ctx(SKIP_NAN, token, mpd_cmp, &ctx); } else if (eqtoken(token[1], "comparesig")) { _Int_Res_Binop_Ctx(token, mpd_compare_signal, &ctx); } else if (eqtoken(token[1], "comparetotal")) { _Int_Res_Binop(token, mpd_compare_total, &ctx); _Int_Binop(token, mpd_cmp_total, &ctx); } else if (eqtoken(token[1], "comparetotmag")) { _Int_Res_Binop(token, mpd_compare_total_mag, &ctx); _Int_Binop(token, mpd_cmp_total_mag, &ctx); } /* Special cases for the comparison functions, equal operands */ else if (eqtoken(token[1], "compare_eq")) { _Int_Res_EqualBinop_Ctx(token, mpd_compare, &ctx); _Int_EqualBinop_Ctx(SKIP_NAN, token, mpd_cmp, &ctx); } else if (eqtoken(token[1], "comparesig_eq")) { _Int_Res_EqualBinop_Ctx(token, mpd_compare_signal, &ctx); } else if (eqtoken(token[1], "comparetotal_eq")) { _Int_Res_EqualBinop(token, mpd_compare_total, &ctx); _Int_EqualBinop(token, mpd_cmp_total, &ctx); } else if (eqtoken(token[1], "comparetotmag_eq")) { _Int_Res_EqualBinop(token, mpd_compare_total_mag, &ctx); _Int_EqualBinop(token, mpd_cmp_total_mag, &ctx); } /* Special cases for the shift functions */ else if (eqtoken(token[1], "shiftleft")) { _Res_Op_Lsize_Ctx(SKIP_NONINT, token, _mpd_shiftl, &ctx); } else if (eqtoken(token[1], "shiftright")) { _Res_Op_Lsize_Ctx(SKIP_NONINT, token, _mpd_shiftr, &ctx); } /* Special case for mpd_qln10() */ else if (eqtoken(token[1], "ln10")) { _test_mpd_qln10(SKIP_NONINT, token, &ctx); } /* Special case for the base conversion functions */ else if (eqtoken(token[1], "baseconv")) { _Baseconv(token, &ctx); } /* Special cases for the get_int functions */ #ifdef MPD_CONFIG_64 else if (eqtoken(token[1], "get_uint64")) { _u64_MpdCtx(token, mpd_get_uint, &ctx); } else if (eqtoken(token[1], "get_uint64_abs")) { _u64_MpdCtx(token, mpd_abs_uint, &ctx); } else if (eqtoken(token[1], "get_ssize64")) { _i64_MpdCtx(token, mpd_get_ssize, &ctx); } #else else if (eqtoken(token[1], "get_uint32")) { _u32_MpdCtx(token, mpd_get_uint, &ctx); } else if (eqtoken(token[1], "get_uint32_abs")) { _u32_MpdCtx(token, mpd_abs_uint, &ctx); } else if (eqtoken(token[1], "get_ssize32")) { _i32_MpdCtx(token, mpd_get_ssize, &ctx); } #endif #ifndef MPD_LEGACY_COMPILER else if (eqtoken(token[1], "get_u64")) { _u64_MpdCtx(token, mpd_get_u64, &ctx); } else if (eqtoken(token[1], "get_i64")) { _i64_MpdCtx(token, mpd_get_i64, &ctx); } #endif else if (eqtoken(token[1], "get_u32")) { _u32_MpdCtx(token, mpd_get_u32, &ctx); } else if (eqtoken(token[1], "get_i32")) { _i32_MpdCtx(token, mpd_get_i32, &ctx); } else if (startswith(token[1], "get_")) { /* empty */ } else if (eqtoken(token[1], "rescale")) { /* empty */ } /* unknown operation */ else { mpd_err_fatal("%s: unknown operation: %s", filename, line); } /* end tests */ cleanup: freetoken(token); } mpd_free(line); mpd_free(tmpline); if (file != stdin) { fclose(file); } if (!startswith(filename, "official") && !startswith(filename, "additional") && !file_failure) { printf(" PASS\n"); } else { printf("\n"); } fflush(stdout); } static void traphandler(mpd_context_t *ctx) { if (ctx->newtrap & MPD_Malloc_error) { fprintf(stderr, "\n\n\ runtest: out of memory:\n\ - bignum tests require 200MB heap and 300KB stack.\n\ - normal tests require 10MB heap and 50KB stack.\n\n"); } else { fprintf(stderr, "\n\nruntest: unexpected error: relevant traps: %u\n\n", ctx->newtrap); } exit(1); } static void usage(void) { fputs("runtest: usage: runtest testfile [--custom] [--alloc]\n", stderr); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { const char *filename = NULL; bool custom_alloc = false; bool check_alloc = false; for (int i = 1; i < argc; i++) { if (!filename && (strcmp(argv[i], "-") == 0 || !startswith(argv[i], "--"))) { filename = argv[i]; } else if (!custom_alloc && strcmp(argv[i], "--custom") == 0) { custom_alloc = true; } else if (!check_alloc && strcmp(argv[i], "--alloc") == 0) { check_alloc = true; } else { usage(); } } if (filename == NULL) { usage(); } /* Test version */ if (strcmp(mpd_version(), "4.0.1") != (0)) { fputs("runtest: error: mpd_version() != 4.0.1\n", stderr); exit(EXIT_FAILURE); } if (strcmp(MPD_VERSION, "4.0.1") != (0)) { fputs("runtest: error: MPD_VERSION != 4.0.1\n", stderr); exit(EXIT_FAILURE); } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4127) #endif if (MPD_MAJOR_VERSION != (4)) { fputs("runtest: error: MPD_MAJOR_VERSION != 4\n", stderr); exit(EXIT_FAILURE); } if (MPD_MINOR_VERSION != (0)) { fputs("runtest: error: MPD_MINOR_VERSION != 0\n", stderr); exit(EXIT_FAILURE); } if (MPD_MICRO_VERSION != (1)) { fputs("runtest: error: MPD_MICRO_VERSION != 1\n", stderr); exit(EXIT_FAILURE); } if (MPD_VERSION_HEX != (0x4000100)) { fputs("runtest: error: MPD_VERSION_HEX != 0x4000100\n", stderr); exit(EXIT_FAILURE); } #ifdef _MSC_VER #pragma warning(pop) #endif extended = strcmp(filename, "-") != 0; /* Initialize random number generator */ srandom((unsigned int)time(NULL)); /* Initialize custom allocation functions */ mpd_init_alloc(custom_alloc, check_alloc); /* Initialize MPD_MINALLOC (optional, default is 2) */ MPD_MINALLOC = 2; /* Initialize trap handler */ mpd_traphandler = traphandler; op = mpd_qnew(); op1 = mpd_qnew(); op2 = mpd_qnew(); op3 = mpd_qnew(); tmp = mpd_qnew(); tmp1 = mpd_qnew(); tmp2 = mpd_qnew(); tmp3 = mpd_qnew(); result = mpd_qnew(); result1 = mpd_qnew(); result2 = mpd_qnew(); triple_cov(); doit(filename); mpd_del(op); mpd_del(op1); mpd_del(op2); mpd_del(op3); mpd_del(tmp); mpd_del(tmp1); mpd_del(tmp2); mpd_del(tmp3); mpd_del(result); mpd_del(result1); mpd_del(result2); return global_failure; } mpdecimal-4.0.1/tests/test.c0000644000000000000000000001442415005764474012703 0ustar00/* * Copyright (c) 2008-2025 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 #include #include "mpdecimal.h" #include "test.h" /******************************************************************************/ /* Primary allocation functions (normal or offset) */ /******************************************************************************/ static const size_t OFFSET = 16; #ifdef MPD_CONFIG_64 static const size_t alloc_limit = 0x4000000000000ULL; #else static size_t alloc_limit = SIZE_MAX; #endif /* malloc with upper limits */ static void * malloc_ceil(size_t size) { if (size > alloc_limit) { return NULL; } return malloc(size); } static void * calloc_ceil(size_t nmemb, size_t size) { if (nmemb > alloc_limit / size) { return NULL; } return calloc(nmemb, size); } static void * realloc_ceil(void *ptr, size_t size) { if (size > alloc_limit) { return NULL; } return realloc(ptr, size); } static void free_ceil(void *ptr) { free(ptr); } /* custom malloc with an offset and upper limits */ static void * malloc_offset(size_t size) { if (size == 0 || size > SIZE_MAX - OFFSET) { return NULL; } char *ptr = malloc_ceil(OFFSET + size); return ptr ? ptr + OFFSET : NULL; } static void * calloc_offset(size_t nmemb, size_t size) { if (nmemb == 0 || size == 0 || size > SIZE_MAX - OFFSET) { return NULL; } char *ptr = calloc_ceil(nmemb, OFFSET + size); return ptr ? ptr + OFFSET : NULL; } static void * realloc_offset(void *ptr, size_t size) { if (size == 0 || size > SIZE_MAX - OFFSET) { return NULL; } char *c = (char *)ptr - OFFSET; char *p = realloc_ceil(c, OFFSET + size); return p ? p + OFFSET : NULL; } static void free_offset(void *ptr) { free((char *)ptr - OFFSET); } /* active set of primary allocation functions */ static void *(* test_mallocfunc)(size_t size) = malloc_ceil; static void *(* test_callocfunc)(size_t nmemb, size_t size) = calloc_ceil; static void *(* test_reallocfunc)(void *ptr, size_t size) = realloc_ceil; static void (* test_freefunc)(void *ptr) = free_ceil; /******************************************************************************/ /* Secondary allocation functions (count or failure mode) */ /******************************************************************************/ static bool enable_check_alloc = false; int alloc_count; int alloc_fail; int alloc_idx; static void * malloc_count(size_t size) { ++alloc_count; return test_mallocfunc(size); } static void * calloc_count(size_t nmemb, size_t size) { ++alloc_count; return test_callocfunc(nmemb, size); } static void * realloc_count(void *ptr, size_t size) { ++alloc_count; return test_reallocfunc(ptr, size); } static void * malloc_fail(size_t size) { if (++alloc_idx >= alloc_fail) { return NULL; } return test_mallocfunc(size); } static void * calloc_fail(size_t nmemb, size_t size) { if (++alloc_idx >= alloc_fail) { return NULL; } return test_callocfunc(nmemb, size); } static void * realloc_fail(void *ptr, size_t size) { if (++alloc_idx >= alloc_fail) { return NULL; } return test_reallocfunc(ptr, size); } /******************************************************************************/ /* Public API */ /******************************************************************************/ /* choose primary allocation functions at program start */ void mpd_init_alloc(bool custom_alloc, bool check_alloc) { static bool initialized = false; if (initialized) { fputs("mpd_init_alloc: error: cannot initialize twice\n", stderr); exit(EXIT_FAILURE); } initialized = true; enable_check_alloc = check_alloc; if (custom_alloc) { test_mallocfunc = malloc_offset; test_callocfunc = calloc_offset; test_reallocfunc = realloc_offset; test_freefunc = free_offset; } mpd_mallocfunc = test_mallocfunc; mpd_callocfunc = test_callocfunc; mpd_reallocfunc = test_reallocfunc; mpd_free = test_freefunc; } #ifdef MPD_CONFIG_32 void mpd_set_alloc_limit(size_t size) { alloc_limit = size; } #endif void mpd_set_alloc(mpd_context_t *ctx) { mpd_mallocfunc = test_mallocfunc; mpd_callocfunc = test_callocfunc; mpd_reallocfunc = test_reallocfunc; mpd_free = test_freefunc; ctx->traps = MPD_Malloc_error; } void mpd_set_alloc_count(mpd_context_t *ctx) { mpd_mallocfunc = malloc_count; mpd_callocfunc = calloc_count; mpd_reallocfunc = realloc_count; mpd_free = test_freefunc; ctx->traps = MPD_Malloc_error; alloc_count = 0; } void mpd_set_alloc_fail(mpd_context_t *ctx) { if (enable_check_alloc) { mpd_mallocfunc = malloc_fail; mpd_callocfunc = calloc_fail; mpd_reallocfunc = realloc_fail; mpd_free = test_freefunc; ctx->traps = 0; alloc_idx = 0; } } mpdecimal-4.0.1/tests/test.h0000644000000000000000000000342615005764474012710 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef TESTS_H_ #define TESTS_H_ #include #include #include "mpdecimal.h" extern int alloc_count; extern int alloc_fail; extern int alloc_idx; void mpd_init_alloc(bool custom_alloc, bool check_alloc); #ifdef MPD_CONFIG_32 void mpd_set_alloc_limit(size_t size); #endif void mpd_set_alloc(mpd_context_t *ctx); void mpd_set_alloc_count(mpd_context_t *ctx); void mpd_set_alloc_fail(mpd_context_t *ctx); #endif /* TESTS_H_ */ mpdecimal-4.0.1/tests/testdata_dist/0000755000000000000000000000000015005764474014407 5ustar00mpdecimal-4.0.1/tests/testdata_dist/baseconv.decTest0000644000000000000000000000655315005764474017535 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. Precision: 425000000 Maxexponent: 425000000 Minexponent: -425000000 bconv0 baseconv 0 -> 0 bconv1 baseconv 1 -> 1 bconv2 baseconv 2 -> 2 bconv3 baseconv 3 -> 3 bconv4 baseconv 4 -> 4 bconv5 baseconv 5 -> 5 bconv6 baseconv 6 -> 6 bconv7 baseconv 7 -> 7 bconv8 baseconv 8 -> 8 bconv9 baseconv 9 -> 9 bconv10 baseconv 10 -> 10 bconv0 baseconv 1 -> 1 bconv1 baseconv 10 -> 10 bconv2 baseconv 100 -> 100 bconv3 baseconv 1000 -> 1000 bconv4 baseconv 10000 -> 10000 bconv5 baseconv 100000 -> 100000 bconv6 baseconv 1000000 -> 1000000 bconv7 baseconv 10000000 -> 10000000 bconv8 baseconv 100000000 -> 100000000 bconv9 baseconv 1000000000 -> 1000000000 bconv10 baseconv 10000000000 -> 10000000000 bconv90 baseconv 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv91 baseconv 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv92 baseconv 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv93 baseconv 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv94 baseconv 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv95 baseconv 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv96 baseconv 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv97 baseconv 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv98 baseconv 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv99 baseconv 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bconv0 baseconv 1 -> 1 bconv1 baseconv 2 -> 2 bconv2 baseconv 4 -> 4 bconv3 baseconv 8 -> 8 bconv4 baseconv 16 -> 16 bconv5 baseconv 32 -> 32 bconv6 baseconv 64 -> 64 bconv7 baseconv 128 -> 128 bconv8 baseconv 256 -> 256 bconv9 baseconv 512 -> 512 mpdecimal-4.0.1/tests/testdata_dist/binop_eq.decTest0000644000000000000000000001154015005764474017521 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. rounding: half_even minExponent: -425000000 maxExponent: 425000000 precision: 27 add_eq1 add_eq +926069853 -> 1852139706 precision: 104 add_eq2 add_eq -Infinity -> -Infinity precision: 100 compare_eq1 compare_eq +5916794372888113130055019620156129327439018422817 -> 0 precision: 199 compare_eq2 compare_eq -6385564075788557361489053622233363254132221134310928544266570524036736301587945295E-378058779 -> 0 precision: 255 comparesig_eq1 comparesig_eq 37997421400698793468295234499258938258888893937595659697398091686412465480 -> 0 precision: 103 comparesig_eq2 comparesig_eq +Inf -> 0 precision: 112 comparetotal_eq0 comparetotal_eq +5246899448694934.76746583E7239466 -> 0 precision: 79 comparetotal_eq1 comparetotal_eq -461866196766787289755310460813711109452546567.23424500338922 -> 0 precision: 40 comparetotal_eq2 comparetotal_eq 40559967.8048E-198120324 -> 0 precision: 111 comparetotmag_eq1 comparetotmag_eq -.9680035 -> 0 precision: 280 comparetotmag_eq2 comparetotmag_eq -2978664146700401661050144467205502091778945285794943.5248293726490459289168834361170650892056840210562147124621253082638290597E+7322343 -> 0 precision: 241 copysign_eq0 copysign_eq +912849910816424783962776495925326137570904169012007696206741038734E-113244462 -> 9.12849910816424783962776495925326137570904169012007696206741038734E-113244397 precision: 120 copysign_eq2 copysign_eq -Inf -> -Infinity precision: 101 divide_eq0 divide_eq -Infinity -> NaN Invalid_operation precision: 245 divide_eq1 divide_eq Inf -> NaN Invalid_operation precision: 110 divide_eq2 divide_eq -.1476808094725729904095250393485863450763071588976156608004151488204454583149499119086353485308969531e-190874140 -> 1 precision: 146 divideint_eq1 divideint_eq -1256574716053067901997983102369440625154437304394877782 -> 1 precision: 48 divideint_eq2 divideint_eq -.548918 -> 1 precision: 107 max_eq1 max_eq -958729752001 -> -958729752001 precision: 125 maxmag_eq1 maxmag_eq .867049357676692568304662108070292464722909902766555830155 -> 0.867049357676692568304662108070292464722909902766555830155 precision: 135 maxmag_eq2 maxmag_eq NaN6070908532835254314072874 -> NaN6070908532835254314072874 precision: 16 min_eq0 min_eq 7097E334037297 -> 7.097E+334037300 precision: 41 min_eq1 min_eq .6441974486 -> 0.6441974486 precision: 90 minmag_eq0 minmag_eq +619334386544815.606216e+357209456 -> 6.19334386544815606216E+357209470 precision: 161 minmag_eq1 minmag_eq -25. -> -25 precision: 267 multiply_eq0 multiply_eq +16419229917556917718044035 -> 269591111085596147004142137735461565267426199081225 precision: 21 multiply_eq1 multiply_eq +5.27711105277744423e-348158313 -> 0E-425000020 Underflow Rounded Subnormal Clamped Inexact precision: 34 nexttoward_eq0 nexttoward_eq -78134744367691536194708531 -> -78134744367691536194708531 precision: 200 nexttoward_eq2 nexttoward_eq -.8537008685979470753640770866065301180915124288689 -> -0.8537008685979470753640770866065301180915124288689 precision: 36 power_eq0 power_eq -362429158631567479322670636751195 -> -0E-425000035 Underflow Rounded Subnormal Clamped Inexact precision: 182 power_eq1 power_eq Inf -> Infinity precision: 24 power_eq2 power_eq 336328251898.680440 -> Infinity Overflow Rounded Inexact precision: 91 quantize_eq0 quantize_eq 290548.8E-1423999 -> 2.905488E-1423994 precision: 44 quantize_eq1 quantize_eq +448658.9 -> 448658.9 precision: 172 quantize_eq2 quantize_eq -817350403193055 -> -817350403193055 precision: 110 remainder_eq0 remainder_eq -Inf -> NaN Invalid_operation precision: 57 remainder_eq2 remainder_eq -975534984681769723475932500908516678693056e-17495830 -> -0E-17495830 precision: 222 remaindernear_eq0 remaindernear_eq +606302560422303238839300023784949387340467879977016801015961108154411606509462813597451715049853691310868412854381471077355940382201615032 -> 0 precision: 70 remaindernear_eq1 remaindernear_eq -NaN -> -NaN precision: 125 remaindernear_eq2 remaindernear_eq -2353922789310.187 -> -0.000 precision: 33 shift_eq0 shift_eq +64 -> NaN Invalid_operation precision: 64 shift_eq2 shift_eq .1064629116843833794591007955659963903297906158674535586 -> NaN Invalid_operation precision: 259 subtract_eq0 subtract_eq -.784626254375705635359421742211628372073214972658015192255951E-322501478 -> 0E-322501538 precision: 43 subtract_eq1 subtract_eq +89690.7376661374 -> 0E-10 precision: 233 subtract_eq2 subtract_eq +Infinity -> NaN Invalid_operation precision: 116 samequantum_eq2 samequantum_eq +.956099822146866314870e+96185702 -> 1 mpdecimal-4.0.1/tests/testdata_dist/cov.decTest0000644000000000000000000002630615005764474016522 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. rounding: half_even precision: 28 maxexponent: 999999999 minexponent: -999999999 clamp: 0 covx5000 power 0 123456789123456789123456789 -> 0 covx5001 power 1 123456789123456789123456789 -> 1 covx5004 power 1.0000000000000 123456789123456789123456789 -> 1.000000000000000000000000000 Rounded covx5008 power 1.000000001 12345676891234567891 -> Infinity Rounded Inexact Overflow covx5010 power 1.000000001 -12345676891234567891 -> 0E-1000000026 Rounded Underflow Inexact Clamped Subnormal rounding: down covx5011 power 2.2 123456789123456789123456788 -> 9.999999999999999999999999999E+999999999 Rounded Inexact Overflow rounding: down covx5012 power 2.2 2921000000.891239129 -> 9.999999999999999999999999999E+999999999 Rounded Inexact Overflow rounding: half_even precision: 5000 covx5025 exp 1e20 -> Infinity Rounded Inexact Overflow rounding: half_even precision: 5000 covx5026 exp -1e20 -> 0E-1000004998 Rounded Subnormal Clamped Underflow Inexact rounding: down precision: 4 maxexponent: 4 minexponent: -4 covx5027 ln 1.000000000000000000001 -> 0E-7 Subnormal Inexact Clamped Underflow Rounded covx5028 ln 1e999999999 -> Infinity Inexact Overflow Rounded rounding: half_even precision: 1 maxexponent: 1 minexponent: -1 covx5029 log10 1.000000000000000000001 -> 0.0 Subnormal Inexact Clamped Underflow Rounded rounding: half_even covx5030 log10 12345e100 -> Infinity Inexact Overflow Rounded rounding: half_up precision: 28 maxexponent: 999999999 minexponent: -999999999 covx5031 log10 177.82794100389228012254211972400046751027254035861481049206983723942104337400734839183756638300367799 -> 2.250000000000000000000000001 Inexact Rounded rounding: half_even precision: 10000 covx5034 rotate 1234 12345678901234567890 -> NaN Invalid_operation rounding: half_up precision: 24 maxexponent: 999999999 minexponent: -999999999 covx5048 remaindernear 999999999999999999999999.5 1 -> NaN Division_impossible covx5051 remaindernear 999999999999999999999998.5 1 -> 0.5 rounding: half_even precision: 28 maxexponent: 99 minexponent: -99 covx5056 apply 9999999999999999999999999999E-127 -> 1.000000000000000000000000000E-99 Underflow Subnormal Rounded Inexact covx5057 quantize 9999999999999999999999999999e71 1e72 -> 1.000000000000000000000000000E+99 Rounded Inexact rounding: half_even precision: 58 maxexponent: 99 minexponent: -99 covx5058 apply 999999999999999999999999999999999999999999999999E-159 -> 1.000000000000000000000000000000000000000000000E-111 Underflow Subnormal Rounded Inexact covx5059 quantize 999999999999999999999999999999999999999999999999e51 1e52 -> 1.00000000000000000000000000000000000000000000000E+99 Rounded Inexact covx5060 tointegralx 999999999999999999999999999999999999999999999.9 -> 1000000000000000000000000000000000000000000000 Inexact Rounded covx5061 tointegralx 9999999999999999999999999999999999999999999999999999999999999999999999999999.9 -> 10000000000000000000000000000000000000000000000000000000000000000000000000000 Inexact Rounded rounding: half_even precision: 2000 maxexponent: 999999999 minexponent: -999999999 covx5071 quantize 9999999999999999999999999999999999999999999999999999999999 1e1 -> 1.000000000000000000000000000000000000000000000000000000000E+58 Rounded Inexact covx5072 and 100000010010011000000000000000000000000101001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000001000000000000 1081000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000010101000000000000000000000000000000000000000000000000000000000000000000000000000000100001010010100000100101010000101000100000100101000100100000010001010010000000000000000000000000000000000010101001010000000000000000000000000000000000000000001 -> NaN Invalid_operation covx5073 invert 1081000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000010101000000000000000000000000000000000000000000000000000000000000000000000000000000100001010010100000100101010000101000100000100101000100100000010001010010000000000000000000000000000000000010101001010000000000000000000000000000000000000000001 -> NaN Invalid_operation covx5074 or 100000010010011000000000000000000000000101001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000001000000000000 1081000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000010101000000000000000000000000000000000000000000000000000000000000000000000000000000100001010010100000100101010000101000100000100101000100100000010001010010000000000000000000000000000000000010101001010000000000000000000000000000000000000000001 -> NaN Invalid_operation covx5075 xor 100000010010011000000000000000000000000101001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000001000000000000 1081000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000010101000000000000000000000000000000000000000000000000000000000000000000000000000000100001010010100000100101010000101000100000100101000100100000010001010010000000000000000000000000000000000010101001010000000000000000000000000000000000000000001 -> NaN Invalid_operation rounding: half_even precision: 28 covx5076 shift 123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789 -20 -> 91234567 rounding: half_even precision: 80 covx5077 reduce 9892345673.0123456780000000000000000000000000000000000000000000000000000000000000000000000 -> 9892345673.012345678 Rounded rounding: down precision: 28 covx5078 resc Infinity 425000000 -> Infinity covx50780 resc NaN 425000000 -> NaN covx50782 resc sNaN 425000000 -> sNaN covx50783 resc 0 425000000 -> 0E+425000000 cov64x50784 resc 1e999999999999999999 -1000 -> NaN Invalid_operation cov32x50785 resc 1e425000000 -1000 -> NaN Invalid_operation rounding: half_even precision: 58 maxexponent: 99 minexponent: -99 covx5079 resc 999999999e200 100 -> 9.999999990000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+208 rounding: half_even covx5080 resc 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999e100 120 -> 1.0000000000000000000000000000000000000000000000000000000000000000000000E+190 Inexact Rounded rounding: half_even precision: 58 maxexponent: 999 minexponent: -999 covx5081 resc 1E-1000 -1005 -> 1.00000E-1000 Subnormal -- extreme cases for NaN payloads maxexponent: 1 minexponent: -1 precision: 1 clamp: 1 covx5082 plus NaN123 -> NaN covx5083 plus NaN0 -> NaN -- decapitating leads to NaN0 => NaN maxexponent: 999 minexponent: -999 precision: 6 covx5084 plus NaN123000000 -> NaN covx5085 plus NaN12300000 -> NaN covx5086 plus NaN1230000 -> NaN30000 clamp: 0 covx5087 plus NaN123000000 -> NaN covx5088 plus NaN12300000 -> NaN300000 covx5089 plus NaN1230000 -> NaN230000 -- floor, ceil, trunc rounding: half_even precision: 2000 maxexponent: 999 minexponent: -999 clamp: 0 floor10000 floor 0 -> 0 floor10001 floor 0.0 -> 0 floor10002 floor -0.0 -> -0 floor10003 floor 1e-200 -> 0 floor10004 floor -1e-200 -> -1 floor10005 floor 0.5 -> 0 floor10006 floor -0.5 -> -1 floor10007 floor 0.999999999999 -> 0 floor10008 floor -0.99999999999 -> -1 floor10009 floor -1.0 -> -1 floor10010 floor 1.0 -> 1 floor10011 floor 9.9 -> 9 floor10012 floor -9.9 -> -10 floor10013 floor 9.333e+80 -> 9.333E+80 floor10014 floor -9.333e+80 -> -9.333E+80 floor10015 floor 100.0 -> 100 floor10016 floor -100.0 -> -100 ceil10017 ceil 0 -> 0 ceil10018 ceil 0.0 -> 0 ceil10019 ceil -0.0 -> -0 ceil10020 ceil 1e-200 -> 1 ceil10021 ceil -1e-200 -> -0 ceil10022 ceil 0.5 -> 1 ceil10023 ceil -0.5 -> -0 ceil10024 ceil 0.999999999999 -> 1 ceil10025 ceil -0.99999999999 -> -0 ceil10026 ceil -1.0 -> -1 ceil10027 ceil 1.0 -> 1 ceil10028 ceil 9.9 -> 10 ceil10029 ceil -9.9 -> -9 ceil10030 ceil 9.333e+80 -> 9.333E+80 ceil10031 ceil -9.333e+80 -> -9.333E+80 ceil10032 ceil 100.0 -> 100 ceil10033 ceil -100.0 -> -100 trunc10034 trunc 0 -> 0 trunc10035 trunc 0.0 -> 0 trunc10036 trunc -0.0 -> -0 trunc10037 trunc 1e-200 -> 0 trunc10038 trunc -1e-200 -> -0 trunc10039 trunc 0.5 -> 0 trunc10040 trunc -0.5 -> -0 trunc10041 trunc 0.999999999999 -> 0 trunc10042 trunc -0.99999999999 -> -0 trunc10043 trunc -1.0 -> -1 trunc10044 trunc 1.0 -> 1 trunc10045 trunc 9.9 -> 9 trunc10046 trunc -9.9 -> -9 trunc10047 trunc 9.333e+80 -> 9.333E+80 trunc10048 trunc -9.333e+80 -> -9.333E+80 trunc10049 trunc 100.0 -> 100 trunc10050 trunc -100.0 -> -100 -- negative etop: trigger allocation failure in mpd_qshiftl. maxexponent: 50 minexponent: -50 precision: 100 clamp: 1 etop10051 apply 1e+50 -> 100000000000000000000000000000000000000000000000000.0000000000000000000000000000000000000000000000000 Clamped -- test mpd_qln10(). lnX10052 ln10 1 -> 2 Rounded Inexact lnX10053 ln10 51 -> 2.30258509299404568401799145468436420760110148862877 Rounded Inexact lnX10054 ln10 101 -> 2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983 Rounded Inexact precision: 4 rounding: floor maxExponent: 4 minExponent: -4 clamp: 0 covx10101 divide 99960 -8.4E+2 -> -119.0 -- ExtendedRange==0 disables the allcr=0 tests. ExtendedRange: 0 Precision: 119 MaxExponent: 425000000 MinExponent: -425000000 Rounding: Half_even Clamp: 0 gen14398 exp '-978598892.4783936221181690860' -> '1.0000000000000000000E-425000099' Inexact Rounded Subnormal Underflow precision: 21 MaxExponent: 2100 MinExponent: -2100 expx10001: exp -4835.428695287495936437782054837164835962313126120423249669988592031902480322440208495594130688156427 -> 1.00000000000000000000E-2100 Rounded Inexact Subnormal Underflow precision: 21 rounding: Up MaxExponent: 2100 MinExponent: -55 clamp: 0 lnx10001 ln 1.0000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000025 -> 1.00000000000000000000E-55 Rounded Inexact Subnormal Underflow precision: 43 rounding: Up MaxExponent: 784 MinExponent: -101 clamp: 1 lnx10002 ln 1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 -> 1.000000000000000000000000000000000000000000E-101 Rounded Inexact precision: 7 rounding: Up MaxExponent: 96 MinExponent: -95 clamp: 1 lnx10003 ln 1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005 -> 5E-101 Rounded Inexact Subnormal Underflow precision: 21 rounding: Up MaxExponent: 2100 MinExponent: -55 clamp: 0 log10x10001 log10 1.000000000000000000000000000000000000000000000000000000230258509299404568401799145468436420760110149 -> 1.00000000000000000000E-55 Rounded Inexact -- Restore ExtendedRange because it is a global variable in the C tests. ExtendedRange: 1 mpdecimal-4.0.1/tests/testdata_dist/divmod.decTest0000644000000000000000000000275415005764474017216 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. rounding: half_even minExponent: -999999999 maxExponent: 999999999 precision: 4 divmod0 divmod +.19e-911565689 3 -> 0 1.9E-911565690 precision: 134 divmod1 divmod -7511169757701755204403067994764250868266023726415875410280423917144182133410083809891399408586918959074 4246476766758966627011583811854662354887063790038443 -> -1768800389183453909698778567576755142065118498146502 -2797376381641405358930320502134014338018800092982688 precision: 262 divmod2 divmod -Inf +7.905442548849169790507598032704018880614786823147752534821712985326338770302489617E486798639 -> -Infinity NaN Invalid_operation precision: 216 divmod3 divmod -757719995173294752327540483701116946913961037738625667311193429926112129713646725612959034118065582310312494071362898125823373077706316701639971503.7061421 62623122235568293491576846461787522859478144460815517209962234575328066320595 -> -12099684080314501435119346718279324158329411218353503927245988982340212 -27825671910110331254919071614638382146665442212850800774501568154918287705363.7061421 precision: 264 divmod60 divmod .29710504707442803271433301062233400148972305067963266041512977334667175052716876430358025717559782571789385135307807427e+408570266 316018911136590957402752480309236024133069474131769799.16590 -> NaN NaN Invalid_operation mpdecimal-4.0.1/tests/testdata_dist/divmod_eq.decTest0000644000000000000000000000230015005764474017666 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. rounding: half_even minExponent: -999999999 maxExponent: 999999999 precision: 287 divmod_eq0 divmod_eq 53464363333374808283597687012581545556435043430877416069601812915742085729084642883631769946846145248101886580777706430843020189140428608578077608617960084403336009490995063314174483207370023308095611980240 -> 1 0 precision: 150 divmod_eq1 divmod_eq +60282411403474423437251944856221834213664804070443619110124159546725081821627.9520731524443948144720661450464724117304412956005906597494085920338030465 -> 1 0E-73 precision: 85 divmod_eq2 divmod_eq -63467629447618961271624908961051190267743022525700e648470929 -> 1 -0E+648470929 precision: 108 divmod_eq3 divmod_eq -762879944390665.371815875601 -> 1 -0E-12 precision: 288 divmod_eq4 divmod_eq +997594334066627951033394333915508375011722549244112196997015462663582982961809024613180076099282803800482019887107098847480355044678421823378359002130300510590127911433084709732427595232911169827362243916e+685827935 -> 1 0E+685827935 mpdecimal-4.0.1/tests/testdata_dist/extra.decTest0000644000000000000000000000064515005764474017054 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. precision: 28 maxexponent: 384 minexponent: -384 rounding: half_even mulx11337 multiply 88888444448888880000000000000000000000000000000000 0.0000000000000000000000000000000000000005 -> 44444222224.44444000000000000 Rounded mpdecimal-4.0.1/tests/testdata_dist/fma_eq.decTest0000644000000000000000000000324015005764474017153 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. rounding: half_even minExponent: -999999999 maxExponent: 999999999 precision: 90 fma_eq_eq_op0 fma_eq_eq_op 1171338855698368789056737337147116733764903254 6334341367673830006086235053199346622349828839 -> 1.37203471486876402097062945058787905483129562161521709249566934082907767436352197432961736E+90 Rounded Inexact precision: 159 fma_eq_eq_op1 fma_eq_eq_op 8846971720773377832118709116655976973169530112542418661239912443 6256181023698902965000946039667715131691025387162696107046936851 -> 78268908628163862019856367747135852723774224319783179476206001612701777270473207771109192335032068044416291512398851733353165100 precision: 255 fma_eq_eq_op2 fma_eq_eq_op 43160782777719481063272448014 49812293344537606155996723694 -> 1862853169985486563497651896052778055443061751840329267890 precision: 93 fma_eq_eq_op3 fma_eq_eq_op 2032071158752304061247812627062271522999803982027661360583876846812153089899539485250840 6360518457329636924305818275371080716215939771089431758009813661626572665849888335794576 -> 4.12931319423293173438185246065285707617873245447024136224145210538137905488220974932370465884E+174 Rounded Inexact precision: 227 fma_eq_eq_op4 fma_eq_eq_op 95019985613539095380134663979529421356656050721802478521977200303668310888 94197867895449893953505329706678321477778056838953868383808842326244093635 -> 9028797665997176656298151698503832425497797348392415467972558968046789558677401017404152498353487199247588110290399071760384180693759079897263442179 mpdecimal-4.0.1/tests/testdata_dist/format.decTest0000644000000000000000000001722615005764474017224 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. rounding: half_even xfmt1 format .12345 '\xe6\xae\x8d<50.23' -> '0.12345\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d\xe6\xae\x8d' xfmt4 format -2815980E0 ',' -> '-2,815,980' -- alignment of specials xfmt12201 format sNaN '+10.10' -> ' +sNaN' xfmt12202 format Inf ' 10.10' -> ' Infinity' xfmt12203 format Inf ' 10.10' -> ' Infinity' -- zero padding of specials xfmt12204 format NaN '010' -> ' NaN' -- zero padding conflicts with alignment specifier xfmt12205 format 999 '<010' -> NULL Invalid_operation -- zero minimum width xfmt12206 format 999 '00.10' -> NULL Invalid_operation -- excessive minimum width xfmt12207 format 999 '18446744073709551616.10' -> NULL Invalid_operation -- invalid fraction digits xfmt12207 format 999 '100.-10' -> NULL Invalid_operation -- excessive number of fraction digits xfmt12207 format 999 '100.18446744073709551616' -> NULL Invalid_operation -- trailing garbage xfmt12208 format 999 '10x' -> NULL Invalid_operation -- excess precision after rescale xfmt12209 format 999999999e20 '.7e' -> 1.0000000e+29 -- illegal UTF-8 sequences (see http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt) xfmt12211 format Inf '\xfe=10.10' -> NULL Invalid_operation xfmt12212 format Inf '\xff=10.10' -> NULL Invalid_operation xfmt12213 format Inf '\xfe\xfe\xff\xff=10.10' -> NULL Invalid_operation xfmt12214 format Inf '\xc0\xaf=10.10' -> NULL Invalid_operation xfmt12215 format Inf '\xe0\x80\xaf=10.10' -> NULL Invalid_operation xfmt12216 format Inf '\xf0\x80\x80\xaf<10.10' -> NULL Invalid_operation xfmt12217 format Inf '\xc1\xbf>10.10' -> NULL Invalid_operation xfmt12218 format Inf '\xe0\x9f\xbf^10.10' -> NULL Invalid_operation xfmt12219 format Inf '\xf0\x8f\xbf\xbf=10.10' -> NULL Invalid_operation xfmt12220 format Inf '\xed\xa0\x80=10.10' -> NULL Invalid_operation xfmt12221 format Inf '\xf4\x90\x80\x80=10.10' -> NULL Invalid_operation -- more illegal UTF-8 sequences xfmt12222 format Inf '\xf1\xf1\xf1\xf1=10.10' -> NULL Invalid_operation -- power of 10 boundaries xfmt12224 format 99999 'g' -> 99999 xfmt12225 format 99999 '.6g' -> 99999 xfmt12226 format 99999 '.5g' -> 99999 xfmt12227 format 99999 '.4g' -> 1.000e+5 xfmt12228 format 99999 '.3g' -> 1.00e+5 xfmt12229 format 99999 '.2g' -> 1.0e+5 xfmt12230 format 99999 '.1g' -> 1e+5 xfmt12231 format 99999 '.0g' -> 1e+5 xfmt12232 format 99999 'e' -> 9.9999e+4 xfmt12233 format 99999 '.6e' -> 9.999900e+4 xfmt12234 format 99999 '.5e' -> 9.99990e+4 xfmt12235 format 99999 '.4e' -> 9.9999e+4 xfmt12236 format 99999 '.3e' -> 1.000e+5 xfmt12237 format 99999 '.2e' -> 1.00e+5 xfmt12238 format 99999 '.1e' -> 1.0e+5 xfmt12239 format 99999 '.0e' -> 1e+5 xfmt12240 format 9.9999 'f' -> 9.9999 xfmt12241 format 9.9999 '.6f' -> 9.999900 xfmt12242 format 9.9999 '.5f' -> 9.99990 xfmt12243 format 9.9999 '.4f' -> 9.9999 xfmt12244 format 9.9999 '.3f' -> 10.000 xfmt12245 format 9.9999 '.2f' -> 10.00 xfmt12246 format 9.9999 '.1f' -> 10.0 xfmt12247 format 9.9999 '.0f' -> 10 xfmt12248 format 9.99e425000000 'g' -> 9.99e+425000000 xfmt12249 format 9.99e425000000 '.3g' -> 9.99e+425000000 xfmt12250 format 9.99e425000000 '.2g' -> 1.0e+425000001 xfmt12251 format 9.99e425000000 '.1g' -> 1e+425000001 xfmt12252 format 9.99e425000000 '.0g' -> 1e+425000001 xfmt12253 format 9.99e425000000 'e' -> 9.99e+425000000 xfmt12254 format 9.99e425000000 '.3e' -> 9.990e+425000000 xfmt12255 format 9.99e425000000 '.2e' -> 9.99e+425000000 xfmt12256 format 9.99e425000000 '.1e' -> 1.0e+425000001 xfmt12257 format 9.99e425000000 '.0e' -> 1e+425000001 -- target exponent less than min_etiny xfmt12258 format 1e-849999999 '.10e' -> 1.0000000000e-849999999 -- '%' formatting: add trailing percent sign for special values. xfmt12259 format NaN123 '%' -> 'NaN123%' xfmt12260 format sNaN '+10.10%' -> ' +sNaN%' xfmt12261 format Inf ' 10.10%' -> ' Infinity%' -- 'z' formatting: coerce to positive zero xfmt12300 format '-.508e+412' 'D=-z,.44%' -> '-508,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000.00000000000000000000000000000000000000000000%' xfmt12301 format '0.00000000000000000000E9227' 'Q>-z,.440%' -> '0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000%' xfmt12302 format '-0.00000000000000000000E9227' 'Q>-z,.440%' -> '0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000%' -- 64-bit only cov64x00001 format 9.99e999999999999999999 'g' -> 9.99e+999999999999999999 cov64x00002 format 9.99e999999999999999999 '.3g' -> 9.99e+999999999999999999 cov64x00003 format 9.99e999999999999999999 '.2g' -> 1.0e+1000000000000000000 cov64x00004 format 9.99e999999999999999999 '.1g' -> 1e+1000000000000000000 cov64x00005 format 9.99e999999999999999999 '.0g' -> 1e+1000000000000000000 cov64x00006 format 9.99e999999999999999999 'e' -> 9.99e+999999999999999999 cov64x00007 format 9.99e999999999999999999 '.3e' -> 9.990e+999999999999999999 cov64x00008 format 9.99e999999999999999999 '.2e' -> 9.99e+999999999999999999 cov64x00009 format 9.99e999999999999999999 '.1e' -> 1.0e+1000000000000000000 cov64x00010 format 9.99e999999999999999999 '.0e' -> 1e+1000000000000000000 -- target exponent less than min_etiny cov64x00011 format 1e-1999999999999999997 '.10e' -> 1.0000000000e-1999999999999999997 -- 32-bit only: result has too many digits for 'f' specifier. -- This test can legitimately fail with MPD_Malloc_error, thus it can produce -- a false positive. -- cov32x00012 format 1e-849999999 ',f' -> NULL Invalid_operation mpdecimal-4.0.1/tests/testdata_dist/getint.decTest0000644000000000000000000002613515005764474017225 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. precision: 16 rounding: half_up maxExponent: 384 minExponent: -383 -- get_uint64_abs intx001 get_uint64_abs 0 -> 0 intx002 get_uint64_abs -0 -> 0 intx003 get_uint64_abs 0e100 -> 0 intx004 get_uint64_abs -0e100 -> 0 intx007 get_uint64_abs 18446744073709551615 -> 18446744073709551615 intx008 get_uint64_abs 184467440737095516150e-1 -> 18446744073709551615 intx028 get_uint64_abs -18446744073709551615 -> 18446744073709551615 intx029 get_uint64_abs -184467440737095516150e-1 -> 18446744073709551615 intx049 get_uint64_abs 18446744073709551616 -> 18446744073709551615 Invalid_operation intx051 get_uint64_abs 1844674407370955161600000000000000000000e-20 -> 18446744073709551615 Invalid_operation intx053 get_uint64_abs -18446744073709551616 -> 18446744073709551615 Invalid_operation intx055 get_uint64_abs -1844674407370955161600000000000000000000e-20 -> 18446744073709551615 Invalid_operation -- get_uint64 intx127 get_uint64 0 -> 0 intx128 get_uint64 -0 -> 0 intx129 get_uint64 0e100 -> 0 intx130 get_uint64 -0e100 -> 0 intx133 get_uint64 18446744073709551615 -> 18446744073709551615 intx134 get_uint64 184467440737095516150e-1 -> 18446744073709551615 intx154 get_uint64 -18446744073709551615 -> 18446744073709551615 Invalid_operation intx175 get_uint64 18446744073709551616 -> 18446744073709551615 Invalid_operation intx177 get_uint64 1844674407370955161600000000000000000000e-20 -> 18446744073709551615 Invalid_operation intx179 get_uint64 -18446744073709551616 -> 18446744073709551615 Invalid_operation intx181 get_uint64 -1844674407370955161600000000000000000000e-20 -> 18446744073709551615 Invalid_operation intx183 get_uint64 1e0 -> 1 intx184 get_uint64 1e1 -> 10 intx202 get_uint64 1e19 -> 10000000000000000000 intx203 get_uint64 1e20 -> 18446744073709551615 Invalid_operation -- get_u64 intx253 get_u64 0 -> 0 intx254 get_u64 -0 -> 0 intx255 get_u64 0e100 -> 0 intx256 get_u64 -0e100 -> 0 intx259 get_u64 18446744073709551615 -> 18446744073709551615 intx260 get_u64 184467440737095516150e-1 -> 18446744073709551615 intx280 get_u64 -18446744073709551615 -> 18446744073709551615 Invalid_operation intx301 get_u64 18446744073709551616 -> 18446744073709551615 Invalid_operation intx303 get_u64 1844674407370955161600000000000000000000e-20 -> 18446744073709551615 Invalid_operation intx305 get_u64 -18446744073709551616 -> 18446744073709551615 Invalid_operation intx307 get_u64 -1844674407370955161600000000000000000000e-20 -> 18446744073709551615 Invalid_operation intx309 get_u64 1e0 -> 1 intx320 get_u64 1e11 -> 100000000000 intx328 get_u64 1e19 -> 10000000000000000000 intx329 get_u64 1e20 -> 18446744073709551615 Invalid_operation intx330 get_u64 -1e0 -> 18446744073709551615 Invalid_operation intx351 get_u64 1.0 -> 1 intx352 get_u64 1.2 -> 18446744073709551615 Invalid_operation intx375 get_u64 -0.1 -> 18446744073709551615 Invalid_operation intx377 get_u64 -191831e99999 -> 18446744073709551615 Invalid_operation -- get_ssize64 intx379 get_ssize64 0 -> 0 intx380 get_ssize64 -0 -> 0 intx383 get_ssize64 0e-1000 -> 0 intx384 get_ssize64 -0e-1000 -> 0 intx385 get_ssize64 9223372036854775807 -> 9223372036854775807 intx386 get_ssize64 92233720368547758070e-1 -> 9223372036854775807 intx405 get_ssize64 922337203685477580700000000000000000000e-20 -> 9223372036854775807 intx406 get_ssize64 -9223372036854775808 -> -9223372036854775808 intx417 get_ssize64 -922337203685477580800000000000e-11 -> -9223372036854775808 intx426 get_ssize64 -922337203685477580800000000000000000000e-20 -> -9223372036854775808 intx428 get_ssize64 9999999999999999999 -> 9223372036854775807 Invalid_operation intx430 get_ssize64 999999999999999999900000000000000000000e-20 -> 9223372036854775807 Invalid_operation intx431 get_ssize64 -9223372036854775809 -> 9223372036854775807 Invalid_operation intx434 get_ssize64 -999999999999999999900000000000000000000e-20 -> 9223372036854775807 Invalid_operation intx435 get_ssize64 1e0 -> 1 intx451 get_ssize64 1e16 -> 10000000000000000 intx454 get_ssize64 1e19 -> 9223372036854775807 Invalid_operation intx455 get_ssize64 -1e0 -> -1 intx466 get_ssize64 -1e11 -> -100000000000 intx474 get_ssize64 -1e19 -> 9223372036854775807 Invalid_operation intx475 get_ssize64 1.0 -> 1 intx477 get_ssize64 12.3 -> 9223372036854775807 Invalid_operation intx495 get_ssize64 0.1 -> 9223372036854775807 Invalid_operation intx499 get_ssize64 -0.1 -> 9223372036854775807 Invalid_operation -- get_i64 intx503 get_i64 0 -> 0 intx504 get_i64 -0 -> 0 intx507 get_i64 0e-1000 -> 0 intx508 get_i64 -0e-1000 -> 0 intx509 get_i64 9223372036854775807 -> 9223372036854775807 intx510 get_i64 92233720368547758070e-1 -> 9223372036854775807 intx529 get_i64 922337203685477580700000000000000000000e-20 -> 9223372036854775807 intx530 get_i64 -9223372036854775808 -> -9223372036854775808 intx550 get_i64 -922337203685477580800000000000000000000e-20 -> -9223372036854775808 intx551 get_i64 9223372036854775808 -> 9223372036854775807 Invalid_operation intx553 get_i64 922337203685477580800000000000000000000e-20 -> 9223372036854775807 Invalid_operation intx555 get_i64 -9223372036854775809 -> 9223372036854775807 Invalid_operation intx557 get_i64 -922337203685477580900000000000000000000e-20 -> 9223372036854775807 Invalid_operation intx559 get_i64 1e0 -> 1 intx577 get_i64 1e18 -> 1000000000000000000 intx578 get_i64 1e19 -> 9223372036854775807 Invalid_operation intx579 get_i64 -1e0 -> -1 intx597 get_i64 -1e18 -> -1000000000000000000 intx598 get_i64 -1e19 -> 9223372036854775807 Invalid_operation intx599 get_i64 1.0 -> 1 intx601 get_i64 12.3 -> 9223372036854775807 Invalid_operation intx625 get_i64 -191831e99999 -> 9223372036854775807 Invalid_operation -- get_uint32_abs intx627 get_uint32_abs 0 -> 0 intx628 get_uint32_abs -0 -> 0 intx629 get_uint32_abs 0e100 -> 0 intx630 get_uint32_abs -0e100 -> 0 intx631 get_uint32_abs 0e-1000 -> 0 intx632 get_uint32_abs -0e-1000 -> 0 intx633 get_uint32_abs 4294967295 -> 4294967295 intx653 get_uint32_abs 429496729500000000000000000000e-20 -> 4294967295 intx654 get_uint32_abs -4294967295 -> 4294967295 intx674 get_uint32_abs -429496729500000000000000000000e-20 -> 4294967295 intx675 get_uint32_abs 4294967296 -> 4294967295 Invalid_operation intx678 get_uint32_abs 999999999900000000000000000000e-20 -> 4294967295 Invalid_operation intx679 get_uint32_abs -4294967296 -> 4294967295 Invalid_operation intx682 get_uint32_abs -999999999900000000000000000000e-20 -> 4294967295 Invalid_operation intx683 get_uint32_abs 1e0 -> 1 intx684 get_uint32_abs 1e1 -> 10 intx692 get_uint32_abs 1e9 -> 1000000000 intx693 get_uint32_abs 1e10 -> 4294967295 Invalid_operation intx694 get_uint32_abs -1e0 -> 1 intx701 get_uint32_abs -1e7 -> 10000000 intx704 get_uint32_abs -1e10 -> 4294967295 Invalid_operation intx705 get_uint32_abs 1.0 -> 1 intx707 get_uint32_abs 12.3 -> 4294967295 Invalid_operation intx726 get_uint32_abs 0.01 -> 4294967295 Invalid_operation -- get_uint32 intx733 get_uint32 0 -> 0 intx734 get_uint32 -0 -> 0 intx737 get_uint32 0e-1000 -> 0 intx738 get_uint32 -0e-1000 -> 0 intx739 get_uint32 4294967295 -> 4294967295 intx740 get_uint32 42949672950e-1 -> 4294967295 intx741 get_uint32 429496729500e-2 -> 4294967295 intx760 get_uint32 -4294967295 -> 4294967295 Invalid_operation intx761 get_uint32 -42949672950e-1 -> 4294967295 Invalid_operation intx781 get_uint32 4294967296 -> 4294967295 Invalid_operation intx783 get_uint32 429496729600000000000000000000e-20 -> 4294967295 Invalid_operation intx785 get_uint32 -4294967296 -> 4294967295 Invalid_operation intx788 get_uint32 -999999999900000000000000000000e-20 -> 4294967295 Invalid_operation intx789 get_uint32 1e0 -> 1 intx798 get_uint32 1e9 -> 1000000000 intx799 get_uint32 1e10 -> 4294967295 Invalid_operation intx800 get_uint32 -1e0 -> 4294967295 Invalid_operation intx801 get_uint32 -1e1 -> 4294967295 Invalid_operation intx811 get_uint32 1.0 -> 1 intx812 get_uint32 1.2 -> 4294967295 Invalid_operation intx813 get_uint32 12.3 -> 4294967295 Invalid_operation intx831 get_uint32 0.1 -> 4294967295 Invalid_operation intx832 get_uint32 0.01 -> 4294967295 Invalid_operation -- get_u32 intx839 get_u32 0 -> 0 intx840 get_u32 -0 -> 0 intx843 get_u32 0e-1000 -> 0 intx844 get_u32 -0e-1000 -> 0 intx845 get_u32 4294967295 -> 4294967295 intx847 get_u32 429496729500e-2 -> 4294967295 intx866 get_u32 -4294967295 -> 4294967295 Invalid_operation intx868 get_u32 -429496729500e-2 -> 4294967295 Invalid_operation intx888 get_u32 9999999999 -> 4294967295 Invalid_operation intx890 get_u32 999999999900000000000000000000e-20 -> 4294967295 Invalid_operation intx891 get_u32 -4294967296 -> 4294967295 Invalid_operation intx894 get_u32 -999999999900000000000000000000e-20 -> 4294967295 Invalid_operation intx895 get_u32 1e0 -> 1 intx904 get_u32 1e9 -> 1000000000 intx905 get_u32 1e10 -> 4294967295 Invalid_operation intx906 get_u32 -1e0 -> 4294967295 Invalid_operation intx927 get_u32 1.0 -> 1 intx928 get_u32 1.2 -> 4294967295 Invalid_operation intx948 get_u32 0.01 -> 4294967295 Invalid_operation intx951 get_u32 -0.1 -> 4294967295 Invalid_operation -- get_ssize32 intx955 get_ssize32 0 -> 0 intx960 get_ssize32 -0e-1000 -> 0 intx961 get_ssize32 2147483647 -> 2147483647 intx981 get_ssize32 214748364700000000000000000000e-20 -> 2147483647 intx982 get_ssize32 -2147483648 -> -2147483648 intx983 get_ssize32 -21474836480e-1 -> -2147483648 intx1003 get_ssize32 2147483648 -> 2147483647 Invalid_operation intx1006 get_ssize32 999999999900000000000000000000e-20 -> 2147483647 Invalid_operation intx1007 get_ssize32 -2147483649 -> 2147483647 Invalid_operation intx1010 get_ssize32 -999999999900000000000000000000e-20 -> 2147483647 Invalid_operation intx1011 get_ssize32 1e0 -> 1 intx1021 get_ssize32 1e10 -> 2147483647 Invalid_operation intx1022 get_ssize32 -1e0 -> -1 intx1023 get_ssize32 -1e1 -> -10 intx1032 get_ssize32 -1e10 -> 2147483647 Invalid_operation intx1033 get_ssize32 1.0 -> 1 intx1035 get_ssize32 12.3 -> 2147483647 Invalid_operation intx1053 get_ssize32 0.1 -> 2147483647 Invalid_operation intx1054 get_ssize32 0.01 -> 2147483647 Invalid_operation -- get_i32 intx1061 get_i32 0 -> 0 intx1062 get_i32 -0 -> 0 intx1065 get_i32 0e-1000 -> 0 intx1066 get_i32 -0e-1000 -> 0 intx1087 get_i32 214748364700000000000000000000e-20 -> 2147483647 intx1088 get_i32 -2147483648 -> -2147483648 intx1107 get_i32 -21474836480000000000000000000e-19 -> -2147483648 intx1108 get_i32 -214748364800000000000000000000e-20 -> -2147483648 intx1109 get_i32 2147483648 -> 2147483647 Invalid_operation intx1112 get_i32 999999999900000000000000000000e-20 -> 2147483647 Invalid_operation intx1113 get_i32 -2147483649 -> 2147483647 Invalid_operation intx1116 get_i32 -999999999900000000000000000000e-20 -> 2147483647 Invalid_operation intx1117 get_i32 1e0 -> 1 intx1118 get_i32 1e1 -> 10 intx1127 get_i32 1e10 -> 2147483647 Invalid_operation intx1128 get_i32 -1e0 -> -1 intx1138 get_i32 -1e10 -> 2147483647 Invalid_operation intx1139 get_i32 1.0 -> 1 intx1140 get_i32 1.2 -> 2147483647 Invalid_operation intx1159 get_i32 0.1 -> 2147483647 Invalid_operation intx1166 get_i32 -192312e-99999 -> 2147483647 Invalid_operation mpdecimal-4.0.1/tests/testdata_dist/invroot.decTest0000644000000000000000000001056015005764474017426 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. precision: 300 rounding: half_even minExponent: -999999999 maxExponent: 999999999 invr0 invroot -Infinity -> NaN Invalid_operation invr2 invroot -3376565240538317615037767038165755236116203447734678670744153013395372825208152016626465050595503278853396341085504348076568638479251916469338156396026574105877198631284532958688897642411006633822625089845756964537796850154627554386765663430233408597155470339398891901177074562300320044771370817242748115757639488987096292 -> NaN Invalid_operation invr3 invroot +95557790255393130740393196310110154284984751359031309896398764952438051628915583632179283447391171528179135502526608913896698702181735323913607751130208974016914650039266324499752512639801785865733011946576983092213847146916959759670480 -> 1.02297954737445094825826091353591897908034078907362836953104996508129183034044873965399342835094488559981276170073085746439896855924382620964142769617650621159588395307098063232472761245685892549208662446992817391636726995669662784742850399639941776275468962154520979557600061978823233542390107411560E-118 Inexact Rounded invr4 invroot +8051652260715717610263596110901879049239.3440890507241630654113595115188390222902940530 -> 1.11444206152562569343119139170646814590687673654520947187475195773625010295109279239701370204558834676388207588338406433950233296077761519272905614305165226142108699992490893369385504606331664848177785618942682376871229067701973143985740722295023921892208001610719113184272379066174701404312597426825E-20 Inexact Rounded invr5 invroot -.36592197165789919876969283257371189200220402200002659961343068719568750580103064629288885229809757695723911672911158669042664271337478150632454244454960565234911315537252232074269938437761369352899081342085708843126846060396303945350939465545638101 -> NaN Invalid_operation invr6 invroot -44746722843951604605041558461383456959182507845890557497798391539993092079028123553869176194186087843018195092434490484241070467623257968572786647008622287052058689209189964425521897319959862625870991347425877073690538415750266535581321654559177420756494308462900355003716612396795433991910 -> NaN Invalid_operation invr7 invroot +948943248730899668078135699979058061509555547156272936842321883099986210361071671784923581065994346170593144382682672978251687228086752034258114675547822342248175243738443748555587177693108781764137437494362833726107839479656881344405669222835358836515928499629038518395413414623714986535354329243601061487796782578547555724171276979324853544047867997682662973927475596357370151608948634124805660835860927562392504753703385812781424464842992506914140686889577535698890662689110270312013809940854818331439242777832632044817511942491643768346925240287503557045420121622930380562123041337404040098906874134159081948444913584344609448236967767455043319958191959963868118208517350380776078952546003182041690777965037559329942566975282571898259137917930121840676845801080 -> 3.24623443149519044146774385327836533216464183727554392679254765473291522509121311915692833886535654787361124041696472280514828762946576638098283717652191479560502039986192618456351921133995783561356878919873169984960441104204131287360651888424979333021787801486657416363806384287256165526847351704137E-383 Inexact Rounded invr8 invroot -36239581670653731300376393991270825298462698702529251372002981419327268900757988734157481351979218060250537055351261009894843519440401788657349170163016901917917815994316715255465947532963406193334061 -> NaN Invalid_operation invr9 invroot -261991398311695734643807.1535693133488382941868280431130928308788012431642456251576173417538422878251082524398e746378140 -> NaN Invalid_operation invr10 invroot 5392994273424119957746641665203905176810793924546640338873763628068012901449347244884952406414806255774716519234359728634226215180798042381782514743562547260129885619190278005510661849262278265697792656530595774113949566960819294222315 -> 4.30610901552659999687939774182099552710011122859492366694590522944895625441106646296363694968075067418269832950495070518505429967811546889821795179881341981402317016586182144229577452648802459619383751681523643205218709146884421021314046308217102813588276744258032743878674683129154055178648878023013E-118 Inexact Rounded mpdecimal-4.0.1/tests/testdata_dist/largeint.decTest0000644000000000000000000030712715005764474017543 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. precision: 100000 maxExponent: 100000 minExponent: -100000 mulx0 multiply 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 mul1 multiply 259855745323357232745890712253887416451031208967471470449474019695124644498423062949885155972388210929667968254753295807982809714377324353571159505725644474734025502157155585162121635329432951408923118497245594490844554514688555440386816694997271623738290867169838195324237382194632207972711820382722740832983119604772185759970531438734329257155448968357111498209319084687169297453768970243030196461820663515402922337244484747253569092293427194166336182946357953738189838946454487067757988318473463822892516894441885092115954989959874205368851025381845599412924834920868072593660225597609244258738124962509946323212487548741489023120311051975685625748462237119934353872499936114406070315958956840973495535670511961892832193556457073257685605625038869932428148474509692594861627984867168885747718098146606498469714709293233799961423893668297419966348859667514469748340756070244851481677941290982124188310727641641215737140894530557581125699755018698874779084610381966724506193601294216140108254951242363356714276433163835876834854356143830424081928156290751569375844735768779812122430307924366071270887125661218641244215455122944686197251233356728185437618187079427307532495495832595571876935718576224244810857240710367454751592276668977385938028534736362962557198957763593864841497962998453853504348235154663122215720321585727302082383850532858453585633746127559597 73863586366471071858632272772171571272935882441964516479374616316149272931593790497343216682598208230224776373372289858589011895845763564288514706982417281174353896147435747340773086473590956777728516424099993058303195637730931246816961994176434648563358435712833022466985692450507790737511830353437274532276953535921289733142272811233542749431151059279796273214118559957111493674547797374997443368110838125677976123334032342972204555966867389436141847597922862854964356674996648632875172159206979572295769675037307124373351245570841619414034545940107746372155318810479842336964975170618299746010385749731941063722230682448974898102934297285843816406151446415582099214661179010342379946358425311724962127303486094389312195368597386112406237347969437188351448611030296883504086844741981641694501930815688732070767673167531230473192564030425685616736775846815557596331974775308588836372387674187342243425434228675144969498435611574942444923821533431932180908625605460555369824624841142089893798195849724937757744727434276628170171086696129315430721422534108489034832144794322738667021572750512730410451811850982989512402719741253389355857495331704986893830679335156490961079531990428859673483569862198614828674245341647345312962315369386725846320817518285927388297750444493304037629796793879360514545746440935946472907498712429499422511068519933128276728360864581286722884150272311031494871476635354176719503633173244981711292241173882729810570569719753358059828324518747025 -> 19193877287515508286922610371049921778857059399790795016581612265042228107039504913715562077646993848105094295745360224746342690227769637865395325054741273218852120791444484701577808145489223038641121091810835953960123579601712425560811948773117879756979041632553106934933927828572431116043611673648252222129526414558451393266089253556964502030814080526133007281638344837512909248966169241598912583666543979728947406461733476537623030840723596255571399454422191021577574497216814740257343138864353302036298370183927901489946670276962374132234245372086367484502901752759921343138247786992265406131790463163576372655961473522665719287194385674219337912544704475303747244853462352399551391208515967112189523400102442007932348001056607278667226016551106795065720547891247304320358379578467982727240933292848188246106056791639457448021498975095172772456008061185362921689912037993117573119576389658912157022859096202791974330434556764001719020733628375683269628942342299059624343656712407586638962328031818855718404137756326555989340923308009070679898401299791222925817471459571506420077885348082557102117200980861921626269397323351618499931175515323021634484247385932321752650794158161488681652287081234887060006512598587134524596079431648377891594334234750374058680256729237374126734415919703883234922909694379491328883400376499131702162663953855371652794487306696291617874462197750894210810261341153310763612641180443950763885334442094654068375086705889233388960066850559841402563705437199405343628681593636306975680894866452877680618993491977808097347579251107579990855925679412318567625492258074775822297971074909424039696321891452442339752171065707350308935339602163840909734389967240232715365727353571877037562705281178429717673679954106028776676185724842384861212016652890117745849230098420379322080637506306557272997704877330273099524084419452193442300656886415489998034315852044682744794216564005898325116882881751644948309769873399847689407670047198636502488995292902799331405539487324898049413613585321533210323210928357273291891338454743521825223648610395632991747277123345656468186334886809795340409030630923971743710850653786020433640822793357291602435995357704698262459357661905694938331044292051395489170358876685746070436343466749533202951673118720531719833945005384623228403561753675662770508079216486819521715969085722283895024359135657105876101964808028701642713726540675586225807178905557579017231762153608495826990622178813107795131391760592728467145079772257147110886349721383456740692525338708440950122667396532993356875780360895183526593289806895764791451982461776514277306618909930243786109292349495253115847233032713759586436561495251888930166306235346001549927398718788430181496686713646770904788146742951646660507514597372962237987772719514344420727695857036426972375086225127034356454338178195441902239453948925 mpdecimal-4.0.1/tests/testdata_dist/maxprec.decTest0000644000000000000000000004003015005764474017360 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. precision: MAX_PREC rounding: half_up maxExponent: MAX_EMAX minexponent: MIN_EMIN -- basics sqtx001 squareroot 1 -> 1 sqtx002 squareroot -1 -> NaN Invalid_operation sqtx003 squareroot 1.00 -> 1.0 sqtx004 squareroot -1.00 -> NaN Invalid_operation sqtx005 squareroot 0 -> 0 sqtx006 squareroot 00.0 -> 0.0 sqtx007 squareroot 0.00 -> 0.0 sqtx008 squareroot 00.00 -> 0.0 sqtx009 squareroot 00.000 -> 0.00 sqtx010 squareroot 00.0000 -> 0.00 sqtx012 squareroot -2 -> NaN Invalid_operation sqtx014 squareroot -2.00 -> NaN Invalid_operation sqtx016 squareroot -0 -> -0 sqtx017 squareroot -0.0 -> -0.0 sqtx018 squareroot -00.00 -> -0.0 sqtx019 squareroot -00.000 -> -0.00 sqtx020 squareroot -0.0000 -> -0.00 sqtx021 squareroot -0E+9 -> -0E+4 sqtx022 squareroot -0E+10 -> -0E+5 sqtx023 squareroot -0E+11 -> -0E+5 sqtx024 squareroot -0E+12 -> -0E+6 sqtx025 squareroot -00 -> -0 sqtx026 squareroot 0E+5 -> 0E+2 sqtx027 squareroot 4.0 -> 2.0 sqtx028 squareroot 4.00 -> 2.0 sqtx031 squareroot -0.1 -> NaN Invalid_operation sqtx032 squareroot +0.01 -> 0.1 sqtx033 squareroot -0.01 -> NaN Invalid_operation sqtx035 squareroot -0.001 -> NaN Invalid_operation sqtx036 squareroot +0.000001 -> 0.001 sqtx037 squareroot -0.000001 -> NaN Invalid_operation sqtx038 squareroot +0.000000000001 -> 0.000001 sqtx039 squareroot -0.000000000001 -> NaN Invalid_operation sqtx045 squareroot -1.1 -> NaN Invalid_operation sqtx046 squareroot -1.10 -> NaN Invalid_operation sqtx047 squareroot -1.100 -> NaN Invalid_operation sqtx048 squareroot -1.110 -> NaN Invalid_operation sqtx053 squareroot -9.9 -> NaN Invalid_operation sqtx054 squareroot -9.90 -> NaN Invalid_operation sqtx055 squareroot -9.900 -> NaN Invalid_operation sqtx056 squareroot -9.990 -> NaN Invalid_operation sqtx060 squareroot 1 -> 1 sqtx061 squareroot 1.0 -> 1.0 sqtx062 squareroot 1.00 -> 1.0 sqtx067 squareroot 100 -> 10 sqtx068 squareroot 100.0 -> 10.0 sqtx069 squareroot 100.00 -> 10.0 sqtx072 squareroot -10.0 -> NaN Invalid_operation sqtx073 squareroot -10.00 -> NaN Invalid_operation sqtx074 squareroot -100.0 -> NaN Invalid_operation sqtx075 squareroot -100.00 -> NaN Invalid_operation sqtx076 squareroot -1.1000E+3 -> NaN Invalid_operation sqtx077 squareroot -1.10000E+3 -> NaN Invalid_operation sqtx078 squareroot 1.000 -> 1.00 sqtx079 squareroot 1.0000 -> 1.00 ---- famous squares sqtx080 squareroot 1 -> 1 sqtx081 squareroot 4 -> 2 sqtx082 squareroot 9 -> 3 sqtx083 squareroot 16 -> 4 sqtx084 squareroot 25 -> 5 sqtx085 squareroot 36 -> 6 sqtx086 squareroot 49 -> 7 sqtx087 squareroot 64 -> 8 sqtx088 squareroot 81 -> 9 sqtx089 squareroot 100 -> 10 sqtx090 squareroot 121 -> 11 sqtx091 squareroot 144 -> 12 sqtx092 squareroot 169 -> 13 sqtx093 squareroot 256 -> 16 sqtx094 squareroot 1024 -> 32 sqtx095 squareroot 4096 -> 64 sqtx100 squareroot 0.01 -> 0.1 sqtx101 squareroot 0.04 -> 0.2 sqtx102 squareroot 0.09 -> 0.3 sqtx103 squareroot 0.16 -> 0.4 sqtx104 squareroot 0.25 -> 0.5 sqtx105 squareroot 0.36 -> 0.6 sqtx106 squareroot 0.49 -> 0.7 sqtx107 squareroot 0.64 -> 0.8 sqtx108 squareroot 0.81 -> 0.9 sqtx109 squareroot 1.00 -> 1.0 sqtx110 squareroot 1.21 -> 1.1 sqtx111 squareroot 1.44 -> 1.2 sqtx112 squareroot 1.69 -> 1.3 sqtx113 squareroot 2.56 -> 1.6 sqtx114 squareroot 10.24 -> 3.2 sqtx115 squareroot 40.96 -> 6.4 ---- Precision 1 squareroot tests [exhaustive, plus exponent adjusts] sqtx1202 squareroot 0.01 -> 0.1 sqtx1204 squareroot 1.00E-2 -> 0.10 sqtx1207 squareroot 1E+2 -> 1E+1 sqtx1226 squareroot 0.04 -> 0.2 sqtx1228 squareroot 4.00E-2 -> 0.20 sqtx1231 squareroot 4E+2 -> 2E+1 sqtx1266 squareroot 0.09 -> 0.3 sqtx1268 squareroot 9.00E-2 -> 0.30 sqtx1271 squareroot 9E+2 -> 3E+1 ---- Precision 2 squareroot tests [exhaustive, plus exponent adjusts] sqtx2202 squareroot 0.01 -> 0.1 sqtx2204 squareroot 1.00E-2 -> 0.10 sqtx2207 squareroot 1E+2 -> 1E+1 sqtx2226 squareroot 0.04 -> 0.2 sqtx2228 squareroot 4.00E-2 -> 0.20 --sqtx2231 squareroot 4E+2 -> 2E+1 sqtx2266 squareroot 0.09 -> 0.3 sqtx2268 squareroot 9.00E-2 -> 0.30 sqtx2271 squareroot 9E+2 -> 3E+1 sqtx2274 squareroot 0.010 -> 0.10 sqtx2275 squareroot 10.0E-1 -> 1.0 sqtx2277 squareroot 10E-3 -> 0.10 sqtx2278 squareroot 10E+1 -> 10 sqtx2280 squareroot 10E+3 -> 1.0E+2 sqtx2321 squareroot 0.16 -> 0.4 sqtx2324 squareroot 16.00E-2 -> 0.40 sqtx2327 squareroot 16E+2 -> 4E+1 sqtx2399 squareroot 25E+2 -> 5E+1 sqtx2484 squareroot 36.00E-2 -> 0.60 sqtx2487 squareroot 36E+2 -> 6E+1 sqtx2514 squareroot 0.040 -> 0.20 sqtx2515 squareroot 40.0E-1 -> 2.0 sqtx2517 squareroot 40E-3 -> 0.20 sqtx2518 squareroot 40E+1 -> 20 sqtx2520 squareroot 40E+3 -> 2.0E+2 sqtx2585 squareroot 0.49 -> 0.7 sqtx2588 squareroot 49.00E-2 -> 0.70 sqtx2591 squareroot 49E+2 -> 7E+1 sqtx2705 squareroot 0.64 -> 0.8 sqtx2708 squareroot 64.00E-2 -> 0.80 sqtx2711 squareroot 64E+2 -> 8E+1 sqtx2841 squareroot 0.81 -> 0.9 sqtx2844 squareroot 81.00E-2 -> 0.90 sqtx2847 squareroot 81E+2 -> 9E+1 sqtx2914 squareroot 0.090 -> 0.30 sqtx2915 squareroot 90.0E-1 -> 3.0 sqtx2917 squareroot 90E-3 -> 0.30 sqtx2918 squareroot 90E+1 -> 30 sqtx2920 squareroot 90E+3 -> 3.0E+2 sqtx3002 squareroot 0.01 -> 0.1 sqtx3008 squareroot 0.04 -> 0.2 precision: MAX_PREC rounding: half_up maxExponent: MAX_EMAX minexponent: MIN_EMIN divx001 divide 1 1 -> 1 divx002 divide 2 1 -> 2 divx003 divide 1 2 -> 0.5 divx004 divide 2 2 -> 1 divx005 divide 0 1 -> 0 divx006 divide 0 2 -> 0 divx009 divide 3 3 -> 1 divx010 divide 2.4 1 -> 2.4 divx011 divide 2.4 -1 -> -2.4 divx012 divide -2.4 1 -> -2.4 divx013 divide -2.4 -1 -> 2.4 divx014 divide 2.40 1 -> 2.40 divx015 divide 2.400 1 -> 2.400 divx016 divide 2.4 2 -> 1.2 divx017 divide 2.400 2 -> 1.200 divx018 divide 2. 2 -> 1 divx019 divide 20 20 -> 1 divx020 divide 187 187 -> 1 divx021 divide 5 2 -> 2.5 divx022 divide 50 20 -> 2.5 divx023 divide 500 200 -> 2.5 divx024 divide 50.0 20.0 -> 2.5 divx025 divide 5.00 2.00 -> 2.5 divx026 divide 5 2.0 -> 2.5 divx027 divide 5 2.000 -> 2.5 divx028 divide 5 0.20 -> 25 divx029 divide 5 0.200 -> 25 divx030 divide 10 1 -> 10 divx031 divide 100 1 -> 100 divx032 divide 1000 1 -> 1000 divx033 divide 1000 100 -> 10 divx035 divide 1 2 -> 0.5 divx036 divide 1 4 -> 0.25 divx037 divide 1 8 -> 0.125 divx038 divide 1 16 -> 0.0625 divx039 divide 1 32 -> 0.03125 divx040 divide 1 64 -> 0.015625 divx041 divide 1 -2 -> -0.5 divx042 divide 1 -4 -> -0.25 divx043 divide 1 -8 -> -0.125 divx044 divide 1 -16 -> -0.0625 divx045 divide 1 -32 -> -0.03125 divx046 divide 1 -64 -> -0.015625 divx047 divide -1 2 -> -0.5 divx048 divide -1 4 -> -0.25 divx049 divide -1 8 -> -0.125 divx050 divide -1 16 -> -0.0625 divx051 divide -1 32 -> -0.03125 divx052 divide -1 64 -> -0.015625 divx053 divide -1 -2 -> 0.5 divx054 divide -1 -4 -> 0.25 divx055 divide -1 -8 -> 0.125 divx056 divide -1 -16 -> 0.0625 divx057 divide -1 -32 -> 0.03125 divx058 divide -1 -64 -> 0.015625 divx070 divide 999999999 1 -> 999999999 divx083 divide 999999 1 -> 999999 divx084 divide 99999 1 -> 99999 divx085 divide 9999 1 -> 9999 divx086 divide 999 1 -> 999 divx087 divide 99 1 -> 99 divx088 divide 9 1 -> 9 divx090 divide 0. 1 -> 0 divx091 divide .0 1 -> 0.0 divx092 divide 0.00 1 -> 0.00 divx093 divide 0.00E+9 1 -> 0E+7 divx094 divide 0.0000E-50 1 -> 0E-54 divx095 divide 1 1E-8 -> 1E+8 divx096 divide 1 1E-9 -> 1E+9 divx097 divide 1 1E-10 -> 1E+10 divx098 divide 1 1E-11 -> 1E+11 divx099 divide 1 1E-12 -> 1E+12 divx100 divide 1 1 -> 1 divx101 divide 1 2 -> 0.5 divx103 divide 1 4 -> 0.25 divx104 divide 1 5 -> 0.2 divx107 divide 1 8 -> 0.125 divx109 divide 1 10 -> 0.1 divx110 divide 1 1 -> 1 divx111 divide 2 1 -> 2 divx112 divide 3 1 -> 3 divx113 divide 4 1 -> 4 divx114 divide 5 1 -> 5 divx115 divide 6 1 -> 6 divx116 divide 7 1 -> 7 divx117 divide 8 1 -> 8 divx118 divide 9 1 -> 9 divx119 divide 10 1 -> 10 divx120 divide 3E+1 0.001 -> 3E+4 divx121 divide 2.200 2 -> 1.100 divx133 divide 12345 5 -> 2469 divx301 divide 0 7 -> 0 divx302 divide 0 7E-5 -> 0E+5 divx303 divide 0 7E-1 -> 0E+1 divx304 divide 0 7E+1 -> 0.0 divx305 divide 0 7E+5 -> 0.00000 divx306 divide 0 7E+6 -> 0.000000 divx307 divide 0 7E+7 -> 0E-7 divx308 divide 0 70E-5 -> 0E+5 divx309 divide 0 70E-1 -> 0E+1 divx310 divide 0 70E+0 -> 0 divx311 divide 0 70E+1 -> 0.0 divx312 divide 0 70E+5 -> 0.00000 divx313 divide 0 70E+6 -> 0.000000 divx314 divide 0 70E+7 -> 0E-7 divx315 divide 0 700E-5 -> 0E+5 divx316 divide 0 700E-1 -> 0E+1 divx317 divide 0 700E+0 -> 0 divx318 divide 0 700E+1 -> 0.0 divx319 divide 0 700E+5 -> 0.00000 divx320 divide 0 700E+6 -> 0.000000 divx321 divide 0 700E+7 -> 0E-7 divx322 divide 0 700E+77 -> 0E-77 divx351 divide 0E-92 7E-1 -> 0E-91 divx352 divide 0E-92 7E+1 -> 0E-93 divx353 divide 0E-92 7E+5 -> 0E-97 divx354 divide 0E-92 7E+6 -> 0E-98 divx356 divide 0E-92 777E-1 -> 0E-91 divx357 divide 0E-92 777E+1 -> 0E-93 divx358 divide 0E-92 777E+3 -> 0E-95 divx359 divide 0E-92 777E+4 -> 0E-96 divx360 divide 0E-92 777E+5 -> 0E-97 divx361 divide 0E-92 777E+6 -> 0E-98 divx386 divide 0E+90 777E-2 -> 0E+92 divx391 divide 0E+90 700E+1 -> 0E+89 divx392 divide 0E+90 700E-1 -> 0E+91 divx393 divide 0E+90 700E-2 -> 0E+92 divx441 divide 12345678000 1 -> 12345678000 divx443 divide 1234567800 1 -> 1234567800 divx445 divide 1234567890 1 -> 1234567890 divx447 divide 1234567891 1 -> 1234567891 divx449 divide 12345678901 1 -> 12345678901 divx451 divide 1234567896 1 -> 1234567896 divx453 divide 1e+1 1 -> 1E+1 divx454 divide 1e+1 1.0 -> 1E+1 divx455 divide 1e+1 1.00 -> 1E+1 divx456 divide 1e+2 2 -> 5E+1 divx457 divide 1e+2 2.0 -> 5E+1 divx458 divide 1e+2 2.00 -> 5E+1 divx460 divide 3e0 2e0 -> 1.5 divx461 divide 30e-1 2e0 -> 1.5 divx462 divide 300e-2 2e0 -> 1.50 divx464 divide 3000e-3 2e0 -> 1.500 divx465 divide 3e0 20e-1 -> 1.5 divx466 divide 30e-1 20e-1 -> 1.5 divx467 divide 300e-2 20e-1 -> 1.5 divx468 divide 3000e-3 20e-1 -> 1.50 divx469 divide 3e0 200e-2 -> 1.5 divx470 divide 30e-1 200e-2 -> 1.5 divx471 divide 300e-2 200e-2 -> 1.5 divx472 divide 3000e-3 200e-2 -> 1.5 divx473 divide 3e0 2000e-3 -> 1.5 divx474 divide 30e-1 2000e-3 -> 1.5 divx475 divide 300e-2 2000e-3 -> 1.5 divx476 divide 3000e-3 2000e-3 -> 1.5 divx480 divide 1 1.0E+33 -> 1E-33 divx481 divide 1 10E+33 -> 1E-34 divx482 divide 1 1.0E-33 -> 1E+33 divx483 divide 1 10E-33 -> 1E+32 divx484 divide 0e5 1e3 -> 0E+2 divx485 divide 0e5 2e3 -> 0E+2 divx486 divide 0e5 10e2 -> 0E+3 divx487 divide 0e5 20e2 -> 0E+3 divx488 divide 0e5 100e1 -> 0E+4 divx489 divide 0e5 200e1 -> 0E+4 divx491 divide 1e5 1e3 -> 1E+2 divx492 divide 1e5 2e3 -> 5E+1 divx493 divide 1e5 10e2 -> 1E+2 divx494 divide 1e5 20e2 -> 5E+1 divx495 divide 1e5 100e1 -> 1E+2 divx496 divide 1e5 200e1 -> 5E+1 divx511 divide 1 2 -> 0.5 divx512 divide 1.0 2 -> 0.5 divx513 divide 1.00 2 -> 0.50 divx514 divide 1.000 2 -> 0.500 divx515 divide 1.0000 2 -> 0.5000 divx516 divide 1.00000 2 -> 0.50000 divx517 divide 1.000000 2 -> 0.500000 divx518 divide 1.0000000 2 -> 0.5000000 divx519 divide 1.00 2.00 -> 0.5 divx521 divide 2 1 -> 2 divx522 divide 2 1.0 -> 2 divx523 divide 2 1.00 -> 2 divx524 divide 2 1.000 -> 2 divx525 divide 2 1.0000 -> 2 divx526 divide 2 1.00000 -> 2 divx527 divide 2 1.000000 -> 2 divx528 divide 2 1.0000000 -> 2 divx529 divide 2.00 1.00 -> 2 divx530 divide 2.40 2 -> 1.20 divx531 divide 2.40 4 -> 0.60 divx532 divide 2.40 10 -> 0.24 divx533 divide 2.40 2.0 -> 1.2 divx534 divide 2.40 4.0 -> 0.6 divx535 divide 2.40 10.0 -> 0.24 divx536 divide 2.40 2.00 -> 1.2 divx537 divide 2.40 4.00 -> 0.6 divx538 divide 2.40 10.00 -> 0.24 divx539 divide 0.9 0.1 -> 9 divx540 divide 0.9 0.01 -> 9E+1 divx541 divide 0.9 0.001 -> 9E+2 divx542 divide 5 2 -> 2.5 divx543 divide 5 2.0 -> 2.5 divx544 divide 5 2.00 -> 2.5 divx545 divide 5 20 -> 0.25 divx546 divide 5 20.0 -> 0.25 divx547 divide 2.400 2 -> 1.200 divx548 divide 2.400 2.0 -> 1.20 divx549 divide 2.400 2.400 -> 1 divx550 divide 240 1 -> 240 divx551 divide 240 10 -> 24 divx552 divide 240 100 -> 2.4 divx553 divide 240 1000 -> 0.24 divx554 divide 2400 1 -> 2400 divx555 divide 2400 10 -> 240 divx556 divide 2400 100 -> 24 divx557 divide 2400 1000 -> 2.4 divx570 divide 2.4E+6 2 -> 1.2E+6 divx571 divide 2.40E+6 2 -> 1.20E+6 divx572 divide 2.400E+6 2 -> 1.200E+6 divx573 divide 2.4000E+6 2 -> 1.2000E+6 divx574 divide 24E+5 2 -> 1.2E+6 divx575 divide 240E+4 2 -> 1.20E+6 divx576 divide 2400E+3 2 -> 1.200E+6 divx577 divide 24000E+2 2 -> 1.2000E+6 divx580 divide 2.4E+6 2 -> 1.2E+6 divx581 divide 2.40E+6 2 -> 1.20E+6 divx582 divide 2.400E+6 2 -> 1.200E+6 divx583 divide 2.4000E+6 2 -> 1.2000E+6 divx584 divide 24E+5 2 -> 1.2E+6 divx585 divide 240E+4 2 -> 1.20E+6 divx586 divide 2400E+3 2 -> 1.200E+6 divx587 divide 24000E+2 2 -> 1.2000E+6 divx590 divide 2.4E+6 2 -> 1.2E+6 divx591 divide 2.40E+6 2 -> 1.20E+6 divx592 divide 2.400E+6 2 -> 1.200E+6 divx593 divide 2.4000E+6 2 -> 1.2000E+6 divx594 divide 24E+5 2 -> 1.2E+6 divx595 divide 240E+4 2 -> 1.20E+6 divx596 divide 2400E+3 2 -> 1.200E+6 divx597 divide 24000E+2 2 -> 1.2000E+6 divx600 divide 2.4E+9 2 -> 1.2E+9 divx601 divide 2.40E+9 2 -> 1.20E+9 divx602 divide 2.400E+9 2 -> 1.200E+9 divx603 divide 2.4000E+9 2 -> 1.2000E+9 divx604 divide 24E+8 2 -> 1.2E+9 divx605 divide 240E+7 2 -> 1.20E+9 divx606 divide 2400E+6 2 -> 1.200E+9 divx607 divide 24000E+5 2 -> 1.2000E+9 divx731 divide 5.00 1E-3 -> 5.00E+3 divx768 divide 1 -0.0 -> -Infinity Division_by_zero divx771 divide 0.0 -1.0 -> -0 divx772 divide -0.0 -1.0 -> 0 divx773 divide 0.0 1.0 -> 0 divx774 divide -0.0 1.0 -> -0 divx775 divide -1.0 0.0 -> -Infinity Division_by_zero divx776 divide -1.0 -0.0 -> Infinity Division_by_zero divx777 divide 1.0 0.0 -> Infinity Division_by_zero divx778 divide 1.0 -0.0 -> -Infinity Division_by_zero divx1021 divide 1E0 1E0 -> 1 divx1022 divide 1E0 2E0 -> 0.5 divx1024 divide 100E-2 1000E-3 -> 1 divx1025 divide 24E-1 2E0 -> 1.2 divx1026 divide 2400E-3 2E0 -> 1.200 divx1027 divide 5E0 2E0 -> 2.5 divx1028 divide 5E0 20E-1 -> 2.5 divx1029 divide 5E0 2000E-3 -> 2.5 divx1030 divide 5E0 2E-1 -> 25 divx1031 divide 5E0 20E-2 -> 25 divx1032 divide 480E-2 3E0 -> 1.60 divx1033 divide 47E-1 2E0 -> 2.35 precision: MAX_PREC rounding: floor maxExponent: MAX_EMAX minexponent: MIN_EMIN covx10101 divide 99960 -8.4E+2 -> -119.0 mpdecimal-4.0.1/tests/testdata_dist/powmod.decTest0000644000000000000000000000455415005764474017241 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. precision: 300 rounding: half_even minExponent: -999999999 maxExponent: 999999999 pmod0 powmod 7247904686162156268756641871543644042277623398853554468867975319666037255091265943032239093584347186840121801614360964715652905098992835894184096312341779376823207799350069002402412482877974177233546988057101295882961124291232141624373889565162488116166423046293656727734178579205421906196474298466264071397384981078088815708020547567692908284576079431039273026512391195375268504826615611695961562278978710576401808163854217637647917342787283928090945990324408427 72911381473307811290418643363695136875276855271908308737368782518679837994154352406227698386756871608461870214874280926511589848849509 31906341065580964484578663620717058806515367511816490829946418525273500969682346304935113670002560820475247356732823750538744195557414833644061144544241638354271446743426604392102101801937477784637031313407445437800551648717678380666928485445940200364432619268497489262492344529240796301572454958839525931754442716050812573815074211063046917762775052046523027021740926 -> NaN Invalid_operation pmod1 powmod 59816342012942315098970462658792059892275264984666990446685694836081374853969464705719653121102559161063448464450002818593554666036972 1808440009884288651308444897630656534698586825767821618301948133780421907801717966360865675146296117338393174811466066268142506120020368981269222935839579136181190608002826379175231653484083965817749509752489756776920528193757984279793894488949075815424261779157359579298699535689561175771493220024997103730141269778525271810651437708512930946335604586826191007094827137940404116546099548730264289007279419487949687312989144242506906630322687986264669543618191810165243349766739960425031531762481513737729696609184323341159543939333974610146195474375073717006915780114030367865416102826534713708505196953254429653890718217760115162556533325875262622658650892203751800063944733453791111519247757916131707317329186318624 5441234431046630110640268228481505590553050843321198167278506680894253863154515922871385873365865160472294826298674650 -> 1868917102694134207252102040168102130107084437203870633712404767805533972261967368751886815417341648241691466033330156 mpdecimal-4.0.1/tests/testdata_dist/powmod_eq.decTest0000644000000000000000000000112215005764474017712 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. rounding: half_even minExponent: -999999999 maxExponent: 999999999 precision: 241 powmod_eq_eq_op0 powmod_eq_eq_op 5172935023082998 61096828599662907 -> 39312309313006360 precision: 154 powmod_eq_eq_op1 powmod_eq_eq_op 501984777 951714845 -> 361293017 precision: 53 powmod_eq_eq_op2 powmod_eq_eq_op 271669153387921210695131 564448204364277556933406 -> 194556909709302006741699 mpdecimal-4.0.1/tests/testdata_dist/shiftlr.decTest0000644000000000000000000000136715005764474017406 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. shlx0 shiftleft 0 0 -> 0 shlx1 shiftleft 0 1 -> 0 shlx2 shiftleft 0 2 -> 0 shlx3 shiftleft 0 3 -> 0 shlx190 shiftleft 1 90 -> 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 shlx200 shiftleft 12 0 -> 12 shlx201 shiftleft 12 1 -> 120 shlx209 shiftleft 12 9 -> 12000000000 shlr4800 shiftright 12123456789 0 -> 12123456789 shlr4801 shiftright 12123456789 1 -> 1212345678 shlr4802 shiftright 12123456789 2 -> 121234567 shlr4810 shiftright 12123456789 10 -> 1 mpdecimal-4.0.1/tests/testdata_dist/testruntest.decTest0000644000000000000000000001127015005764474020331 0ustar00-- Selected test cases to reduce both the archive size and runtime. For the -- large test suite, download the separate mpdecimal-testdata distribution and -- replace the testdata_dist directory. -- Quis custodiet ipsos custodes? -- Small sanity check that failures are indeed reported. Precision: 100 maxExponent: 100000 minExponent: -100000 rt_should_fail000 tosci 918231.131 -> 8123813091.1 rt_should_fail001 apply 0.0391301 -> 10E+2387432 rt_should_fail002 toeng 1.1111e22 -> 433 rt_should_fail003 class NaN -> +Infinity rt_should_fail004 abs -99 -> -99 rt_should_fail005 copy 2 -> 3 rt_should_fail006 copyabs -2 -> -2 rt_should_fail007 copynegate -2 -> -2 rt_should_fail008 exp 5 -> 101 rt_should_fail009 invert 0101 -> 1111 rt_should_fail010 invroot 35 -> 47 rt_should_fail011 ln 101 -> 5 rt_should_fail012 log10 200 -> 137 rt_should_fail013 logb 1000 -> 440 rt_should_fail014 minus 22 -> 222 rt_should_fail015 nextminus 12838 -> 213123 rt_should_fail016 nextplus 23132 -> 3223 rt_should_fail017 plus 102 -> 110 rt_should_fail018 reduce 0.21321 -> 213213892 rt_should_fail019 squareroot 1281 -> 7 rt_should_fail020 tointegral 1281.444 -> 1781 rt_should_fail021 tointegralx 1281.444 -> 1783 rt_should_fail022 samequantum 88 99 -> -1 rt_should_fail023 samequantum_eq 88 -> -1 rt_should_fail024 add 0.111 0.222 -> -133.1381 rt_should_fail025 and 1010101 111 -> 100000000 rt_should_fail026 copysign -2 3 -> 1000 rt_should_fail027 divide 22 0.001 -> 27 rt_should_fail028 divideint 11 22 -> 11 rt_should_fail029 max 231 13221 -> 12312 rt_should_fail030 maxmag 320193 12312 -> 322 rt_should_fail031 min 1029 322323 -> 3322 rt_should_fail032 minmag 23232 1230921 -> 1232131 rt_should_fail033 multiply 25 25 -> 25 rt_should_fail034 nexttoward 3893792 0.2 -> 0.21 rt_should_fail035 or 1010101 111 -> 100000000 rt_should_fail036 power 0.444 0.554 -> 244 rt_should_fail037 quantize 234 22 -> 0.2342 rt_should_fail038 remainder 0 1 -> 2 rt_should_fail039 remaindernear 4 1 -> 774 rt_should_fail040 rotate 2 2 -> 1000 rt_should_fail041 scaleb 111 20 -> 22 rt_should_fail042 shift 10 -1 -> 100 rt_should_fail043 subtract 0.444 0.123 -> 0E-11 rt_should_fail044 xor 11111111111 0000011 -> 10101 rt_should_fail045 add_eq 0.111 -> -133.1381 rt_should_fail046 and_eq 1010101 -> 100000000 rt_should_fail047 copysign_eq -2 -> 1000 rt_should_fail048 divide_eq 22 -> 27 rt_should_fail049 divideint_eq 11 -> 11 rt_should_fail050 max_eq 231 -> 12312 rt_should_fail051 maxmag_eq 320193 -> 322 rt_should_fail052 min_eq 1029 -> 3322 rt_should_fail053 minmag_eq 23232 -> 1232131 rt_should_fail054 multiply_eq 25 -> 25 rt_should_fail055 nexttoward_eq 3893792 -> 0.21 rt_should_fail056 or_eq 1010101 -> 100000000 rt_should_fail057 power_eq 0.444 -> 244 rt_should_fail058 quantize_eq 234 -> 0.2342 rt_should_fail059 remainder_eq 5 -> 2 rt_should_fail060 remaindernear_eq 4 -> 774 rt_should_fail061 rotate_eq 2 -> 1000 rt_should_fail062 scaleb_eq 111 -> 22 rt_should_fail063 shift_eq 10 -> 100 rt_should_fail064 subtract_eq 0.444 -> 345 rt_should_fail065 xor_eq 11111111 -> 1111 rt_should_fail066 divmod 22 8 -> 27 28 rt_should_fail067 divmod_eq 22 -> 27 28 rt_should_fail068 fma 22 11 377 -> 551 rt_should_fail069 powmod 12 11 10 -> 27 rt_should_fail070 fma_eq_eq_op 11 377 -> 551 rt_should_fail071 powmod_eq_eq_op 11 10 -> 27 rt_should_fail072 fma_op_eq_eq 11 377 -> 551 rt_should_fail073 powmod_op_eq_eq 11 10 -> 27 rt_should_fail074 fma_eq_eq_eq 11 -> 551 rt_should_fail075 powmod_eq_eq_eq 11 -> 27 rt_should_fail076 compare 102938 012938 -> 0 rt_should_fail077 comparesig 102938 012938 -> 0 rt_should_fail078 comparetotal 1239210 -2103 -> -1 rt_should_fail079 comparetotmag 1239210 -2103 -> -1 rt_should_fail080 compare_eq 102938 -> 1 rt_should_fail081 comparesig_eq 102938 -> 1 rt_should_fail082 comparetotal_eq 1239210 -> -1 rt_should_fail083 comparetotmag_eq 1239210 -> -1 rt_should_fail084 shiftleft 10239 5 -> 129 rt_should_fail085 shiftright 1029 3 -> 32 rt_should_fail086 baseconv 2130 -> 3432 -- status test rt_should_fail087 divide 10 0 -> NaN rt_should_fail088 power 1E44 1E444444 -> Infinity rt_should_fail089 remaindernear 10 6 -> -2 Clamped Conversion_syntax Division_by_zero Division_impossible Division_undefined Fpu_error Inexact Invalid_context Invalid_operation Malloc_error Not_implemented Overflow Rounded Subnormal Underflow mpdecimal-4.0.1/tests/vctest.h0000644000000000000000000000344115005764474013236 0ustar00/* * Copyright (c) 2008-2025 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. */ #ifndef LIBMPDEC_VCTEST_H_ #define LIBMPDEC_VCTEST_H_ /* Visual C fixes */ #ifdef _MSC_VER #undef random #define random rand #undef srandom #define srandom srand #undef strncasecmp #define strncasecmp _strnicmp #undef strcasecmp #define strcasecmp _stricmp #define strdup _strdup #endif /* MinGW fixes */ #ifdef __MINGW32__ #undef random #define random rand #undef srandom #define srandom srand #endif #endif /* LIBMPDEC_VCTEST_H_ */ mpdecimal-4.0.1/tests++/0000755000000000000000000000000015005764474011701 5ustar00mpdecimal-4.0.1/tests++/Makefile.in0000644000000000000000000000527415005764474013756 0ustar00 # ============================================================================== # Unix Makefile for libmpdec++ tests # ============================================================================== SRCDIR = ../libmpdec ENABLE_STATIC = @ENABLE_STATIC@ ENABLE_SHARED = @ENABLE_SHARED@ LIBSTATIC = @LIBSTATIC@ LIBSHARED = @LIBSHARED@ LINK_STATIC = @LINK_STATIC@ LINK_DYNAMIC = @LINK_DYNAMIC@ SRCDIR_CXX = ../libmpdec++ LIBSTATIC_CXX = @LIBSTATIC_CXX@ LIBSHARED_CXX = @LIBSHARED_CXX@ LIBSHARED_USE_AR = @LIBSHARED_USE_AR@ CXX = @CXX@ MPD_PTHREAD = @MPD_PTHREAD@ MPD_CXX = $(strip $(CXX) $(MPD_PTHREAD)) FILTER_FOR_STATIC = @FILTER_FOR_STATIC@ CONFIGURE_CXXFLAGS = @CONFIGURE_CXXFLAGS@ MPD_CXXFLAGS_SHARED = $(strip $(filter-out $(CXXFLAGS),$(CONFIGURE_CXXFLAGS)) $(CXXFLAGS)) MPD_CXXFLAGS = $(strip $(filter-out $(FILTER_FOR_STATIC),$(MPD_CXXFLAGS_SHARED))) LINK_LIBSTATIC = $(strip $(LINK_STATIC) $(SRCDIR_CXX)/$(LIBSTATIC_CXX) $(SRCDIR)/$(LIBSTATIC) $(LINK_DYNAMIC)) TEST_LIBS = $(SRCDIR)/$(LIBSTATIC) $(SRCDIR_CXX)/$(LIBSTATIC_CXX) ifeq ($(LIBSHARED_USE_AR), yes) TEST_SHLIBS = $(SRCDIR)/$(LIBSHARED) $(SRCDIR_CXX)/$(LIBSTATIC_CXX) else TEST_SHLIBS = $(SRCDIR)/$(LIBSHARED) $(SRCDIR_CXX)/$(LIBSHARED_CXX) endif MPD_TARGETS = ifeq ($(ENABLE_STATIC), yes) MPD_TARGETS += runtest apitest endif ifeq ($(ENABLE_SHARED), yes) MPD_TARGETS += runtest_shared apitest_shared endif default: $(MPD_TARGETS) # Short test: RUNTEST_SOURCES = runtest.cc test.cc RUNTEST_HEADERS = test.hh vctest.hh ../config.h $(SRCDIR)/mpdecimal.h $(SRCDIR_CXX)/decimal.hh runtest:\ Makefile $(RUNTEST_SOURCES) $(RUNTEST_HEADERS) $(TEST_LIBS) $(MPD_CXX) -I.. -I$(SRCDIR) -I$(SRCDIR_CXX) $(MPD_CXXFLAGS) -o runtest runtest.cc test.cc $(LINK_LIBSTATIC) -lm runtest_shared:\ Makefile $(RUNTEST_SOURCES) $(RUNTEST_HEADERS) $(TEST_SHLIBS) $(MPD_CXX) -I.. -I$(SRCDIR) -I$(SRCDIR_CXX) $(MPD_CXXFLAGS_SHARED) -o runtest_shared runtest.cc test.cc -L$(SRCDIR) -L$(SRCDIR_CXX) -lmpdec++ -lmpdec -lm # API test: APITEST_SOURCES = apitest.cc test.cc APITEST_HEADERS = test.hh vctest.hh $(SRCDIR)/mpdecimal.h $(SRCDIR_CXX)/decimal.hh apitest:\ Makefile $(APITEST_SOURCES) $(APITEST_HEADERS) $(TEST_LIBS) $(MPD_CXX) -I$(SRCDIR) -I$(SRCDIR_CXX) $(MPD_CXXFLAGS) -o apitest apitest.cc test.cc $(LINK_LIBSTATIC) -lm apitest_shared:\ Makefile $(APITEST_SOURCES) $(APITEST_HEADERS) $(TEST_SHLIBS) $(MPD_CXX) -I$(SRCDIR) -I$(SRCDIR_CXX) $(MPD_CXXFLAGS_SHARED) -o apitest_shared apitest.cc test.cc -L$(SRCDIR) -L$(SRCDIR_CXX) -lmpdec++ -lmpdec -lm FORCE: clean: FORCE rm -f *.o *.gch *.gcda *.gcno *.gcov *.dyn *.dpi *.lock rm -f runtest runtest_shared apitest apitest_shared distclean: FORCE $(MAKE) clean rm -rf Makefile dectest.zip testdata mpdecimal-4.0.1/tests++/Makefile.vc0000644000000000000000000000503615005764474013754 0ustar00 SRCDIR = ..\libmpdec LIBSTATIC = libmpdec-4.0.1.lib LIBSHARED = libmpdec-4.0.1.dll LIBIMPORT = libmpdec-4.0.1.dll.lib SRCDIR_CXX = ..\libmpdec++ LIBSTATIC_CXX = libmpdec++-4.0.1.lib LIBSHARED_CXX = libmpdec++-4.0.1.dll LIBIMPORT_CXX = libmpdec++-4.0.1.dll.lib !if "$(DEBUG)" == "1" OPT = /MTd /Od /Zi /EHsc OPT_SHARED = /MDd /Od /Zi /EHsc !else OPT = /MT /O2 /GS /EHsc /DNDEBUG OPT_SHARED = /MD /O2 /GS /EHsc /DNDEBUG !endif !if "$(CC)" == "clang-cl" WARN = /W4 /wd4200 /wd4204 /wd4221 /wd4714 -Wno-undefined-inline /D_CRT_SECURE_NO_WARNINGS !else WARN = /W4 /wd4200 /wd4204 /wd4221 /wd4714 /D_CRT_SECURE_NO_WARNINGS !endif MPD_CXXFLAGS = $(WARN) /nologo $(OPT) MPD_CXXFLAGS_SHARED = $(WARN) /nologo $(OPT_SHARED) default: runtest runtest_shared apitest apitest_shared copy_dll runtest:\ Makefile runtest.cc test.cc $(SRCDIR)\mpdecimal.h $(SRCDIR_CXX)\decimal.hh test.hh vctest.hh \ $(SRCDIR)\$(LIBSTATIC) $(SRCDIR_CXX)\$(LIBSTATIC_CXX) $(CXX) -I$(SRCDIR) -I$(SRCDIR_CXX) $(MPD_CXXFLAGS) /Fe:runtest runtest.cc test.cc $(SRCDIR_CXX)\$(LIBSTATIC_CXX) $(SRCDIR)\$(LIBSTATIC) runtest_shared:\ Makefile runtest.cc test.cc $(SRCDIR)\mpdecimal.h $(SRCDIR_CXX)\decimal.hh test.hh vctest.hh \ $(SRCDIR_CXX)\$(LIBIMPORT_CXX) $(SRCDIR)\$(LIBIMPORT) $(CXX) -I$(SRCDIR) -I$(SRCDIR_CXX) $(MPD_CXXFLAGS_SHARED) /Fe:runtest_shared runtest.cc test.cc $(SRCDIR_CXX)\$(LIBIMPORT_CXX) $(SRCDIR)\$(LIBIMPORT) apitest:\ Makefile apitest.cc test.cc $(SRCDIR)\mpdecimal.h $(SRCDIR_CXX)\decimal.hh test.hh vctest.hh \ $(SRCDIR_CXX)\$(LIBSTATIC_CXX) $(SRCDIR)\$(LIBSTATIC) $(CXX) -I$(SRCDIR) -I$(SRCDIR_CXX) $(MPD_CXXFLAGS) /Fe:apitest apitest.cc test.cc $(SRCDIR_CXX)\$(LIBSTATIC_CXX) $(SRCDIR)\$(LIBSTATIC) apitest_shared:\ Makefile apitest.cc test.cc $(SRCDIR)\mpdecimal.h $(SRCDIR_CXX)\decimal.hh test.hh vctest.hh \ $(SRCDIR_CXX)\$(LIBIMPORT_CXX) $(SRCDIR)\$(LIBIMPORT) $(CXX) -I$(SRCDIR) -I$(SRCDIR_CXX) $(MPD_CXXFLAGS_SHARED) /Fe:apitest_shared apitest.cc test.cc $(SRCDIR_CXX)\$(LIBIMPORT_CXX) $(SRCDIR)\$(LIBIMPORT) FORCE: copy_dll: copy /y "$(SRCDIR)\$(LIBSHARED)" . copy /y "$(SRCDIR_CXX)\$(LIBSHARED_CXX)" . clean: FORCE -@if exist *.obj del *.obj -@if exist *.dll del *.dll -@if exist *.exp del *.exp -@if exist *.lib del *.lib -@if exist *.ilk del *.ilk -@if exist *.pdb del *.pdb -@if exist *.pgc del *.pgc -@if exist *.pgd del *.pgd -@if exist *.manifest del *.manifest -@if exist *.exe del *.exe -@if exist runtest del runtest -@if exist apitest del apitest distclean: FORCE nmake clean -@if exist testdata rd /q /s testdata -@if exist Makefile del Makefile mpdecimal-4.0.1/tests++/README.txt0000644000000000000000000000116315005764474013400 0ustar00 Download official tests and add the tests to the testdata directory: ==================================================================== # Unix: If wget is installed, just execute `make check` from # the top level directory. # Windows: See vcbuild directory. # # If gettests.sh or gettests.bat fails: # # mkdir testdata && cp testdata_dist/* testdata # # Get http://speleotrove.com/decimal/dectest.zip and extract the archive # so that the directory structure is testdata/*.decTest. # # Change into the top level directory, build the library, change back # to the test directory, run: # # make && ./runshort.sh # mpdecimal-4.0.1/tests++/additional.topTest0000644000000000000000000000107215005764474015375 0ustar00 -- Additional Tests Dectest: ./testdata/baseconv.decTest Dectest: ./testdata/binop_eq.decTest Dectest: ./testdata/divmod.decTest Dectest: ./testdata/divmod_eq.decTest Dectest: ./testdata/fma_eq.decTest Dectest: ./testdata/format.decTest Dectest: ./testdata/invroot.decTest Dectest: ./testdata/largeint.decTest Dectest: ./testdata/powmod.decTest Dectest: ./testdata/powmod_eq.decTest Dectest: ./testdata/shiftlr.decTest Dectest: ./testdata/getint.decTest Dectest: ./testdata/cov.decTest Dectest: ./testdata/extra.decTest Dectest: ./testdata/maxprec.decTest mpdecimal-4.0.1/tests++/apitest.cc0000644000000000000000000026707515005764474013702 0ustar00/* * Copyright (c) 2020-2025 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mpdecimal.h" #include "decimal.hh" #include "test.hh" #include "vctest.hh" using decimal::Context; using decimal::context_template; using decimal::context; using decimal::ROUND_UP; using decimal::ROUND_DOWN; using decimal::ROUND_CEILING; using decimal::ROUND_FLOOR; using decimal::ROUND_HALF_UP; using decimal::ROUND_HALF_DOWN; using decimal::ROUND_HALF_EVEN; using decimal::ROUND_05UP; using decimal::ROUND_TRUNC; using decimal::ROUND_GUARD; using decimal::DecIEEEInvalidOperation; using decimal::DecConversionSyntax; using decimal::DecInvalidOperation; using decimal::DecDivisionImpossible; using decimal::DecDivisionUndefined; using decimal::DecDivisionByZero; using decimal::DecOverflow; using decimal::DecUnderflow; using decimal::DecSubnormal; using decimal::DecInexact; using decimal::DecRounded; using decimal::DecClamped; using decimal::DecMaxStatus; using decimal::MaxContext; using decimal::IEEEContext; using decimal::DECIMAL32; using decimal::DECIMAL64; using decimal::DECIMAL128; using decimal::DecimalException; using decimal::IEEEInvalidOperation; using decimal::ConversionSyntax; using decimal::InvalidOperation; using decimal::DivisionImpossible; using decimal::DivisionUndefined; using decimal::DivisionByZero; using decimal::Overflow; using decimal::Underflow; using decimal::Subnormal; using decimal::Inexact; using decimal::Rounded; using decimal::Clamped; using decimal::ValueError; using decimal::RuntimeError; using decimal::MallocError; using decimal::Decimal; using decimal::util::safe_downcast; using test::Failure; /******************************************************************************/ /* Default context for some generated test cases */ /******************************************************************************/ static const Context pycontext{ 28, 999999, -999999, ROUND_HALF_EVEN, DecIEEEInvalidOperation | DecDivisionByZero | DecOverflow, 0, 0 }; /******************************************************************************/ /* Exception hierarchy */ /******************************************************************************/ static void ExceptionHierarchyTest() { assertEqual(context, context_template); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); assertTrue((std::is_base_of::value)); } /******************************************************************************/ /* IEEE interchange contexts */ /******************************************************************************/ static void IEEEContextTest() { assertEqual(context, context_template); Context c = IEEEContext(DECIMAL32); assertEqual(c.prec(), 7); assertEqual(c.emax(), 96); assertEqual(c.emin(), -95); assertEqual(c.round(), ROUND_HALF_EVEN); assertEqual(c.traps(), 0U); assertEqual(c.status(), 0U); assertEqual(c.clamp(), 1); assertEqual(c.allcr(), 1); assertEqual(c.etiny(), -101); assertEqual(c.etop(), 90); c = IEEEContext(DECIMAL64); assertEqual(c.prec(), 16); assertEqual(c.emax(), 384); assertEqual(c.emin(), -383); assertEqual(c.round(), ROUND_HALF_EVEN); assertEqual(c.traps(), 0U); assertEqual(c.status(), 0U); assertEqual(c.clamp(), 1); assertEqual(c.allcr(), 1); assertEqual(c.etiny(), -398); assertEqual(c.etop(), 369); c = IEEEContext(DECIMAL128); assertEqual(c.prec(), 34); assertEqual(c.emax(), 6144); assertEqual(c.emin(), -6143); assertEqual(c.round(), ROUND_HALF_EVEN); assertEqual(c.traps(), 0U); assertEqual(c.status(), 0U); assertEqual(c.clamp(), 1); assertEqual(c.allcr(), 1); assertEqual(c.etiny(), -6176); assertEqual(c.etop(), 6111); assertRaises(ValueError, [](){ IEEEContext(-1); }); assertRaises(ValueError, [](){ IEEEContext(0); }); assertRaises(ValueError, [](){ IEEEContext(16); }); assertRaises(ValueError, [](){ IEEEContext(1024); }); } /******************************************************************************/ /* Context get/set */ /******************************************************************************/ static void ContextGetSetTest() { assertEqual(context, context_template); Context c = context; c.prec(34); c.emax(3000); c.emin(-3000); c.round(ROUND_HALF_UP); c.traps(DecMaxStatus); c.status(DecMaxStatus); c.clamp(1); c.allcr(0); assertEqual(c.prec(), 34); assertEqual(c.emax(), 3000); assertEqual(c.emin(), -3000); assertEqual(c.round(), ROUND_HALF_UP); assertEqual(c.traps(), DecMaxStatus); assertEqual(c.status(), DecMaxStatus); assertEqual(c.clamp(), 1); assertEqual(c.allcr(), 0); assertEqual(c.etiny(), -3033); assertEqual(c.etop(), 2967); /* etop is the same, even though it is only relevant for clamp==1 */ c.clamp(0); assertEqual(c.etiny(), -3033); assertEqual(c.etop(), 2967); c.clear_status(DecDivisionByZero); assertEqual(c.status(), DecMaxStatus & ~DecDivisionByZero); c.clear_status(); assertEqual(c.status(), 0U); c.add_status(DecClamped|DecUnderflow); assertEqual(c.status(), DecClamped|DecUnderflow); c.add_status(DecInvalidOperation); assertEqual(c.status(), DecClamped|DecUnderflow|DecInvalidOperation); c.clear_traps(DecDivisionUndefined); assertEqual(c.traps(), DecMaxStatus & ~DecDivisionUndefined); c.clear_traps(); assertEqual(c.traps(), 0U); c.add_traps(DecClamped|DecUnderflow); assertEqual(c.traps(), DecClamped|DecUnderflow); c.add_traps(DecInvalidOperation); assertEqual(c.traps(), DecClamped|DecUnderflow|DecInvalidOperation); } /******************************************************************************/ /* Context input validation */ /******************************************************************************/ static void ContextInputValidationTest() { assertEqual(context, context_template); Context c = context; /* prec */ c.prec(1111); assertEqual(c.prec(), 1111); assertRaises(ValueError, [&](){ c.prec(-1); }); assertRaises(ValueError, [&](){ c.prec(MPD_SSIZE_MAX); }); /* emin */ c.emin(-1111); assertEqual(c.emin(), -1111); assertRaises(ValueError, [&](){ c.emin(1); }); assertRaises(ValueError, [&](){ c.emin(MPD_SSIZE_MIN); }); /* emax */ c.emax(1111); assertEqual(c.emax(), 1111); assertRaises(ValueError, [&](){ c.emax(-1); }); assertRaises(ValueError, [&](){ c.emax(MPD_SSIZE_MAX); }); /* round */ assertRaises(ValueError, [&](){ c.round(-1); }); assertRaises(ValueError, [&](){ c.round(ROUND_GUARD); }); /* traps */ assertRaises(ValueError, [&](){ c.traps(DecMaxStatus+1); }); assertRaises(ValueError, [&](){ c.traps(UINT32_MAX); }); /* clamp */ assertRaises(ValueError, [&](){ c.clamp(-1); }); assertRaises(ValueError, [&](){ c.clamp(2); }); assertRaises(ValueError, [&](){ c.clamp(INT_MAX); }); /* constructor */ assertRaises(ValueError, [&](){ Context(1, 1, -1, 999999); }); } /******************************************************************************/ /* Small context */ /******************************************************************************/ static void SmallContextTest() { assertEqual(context, context_template); Context &c = context; Context xc{pycontext}; xc.prec(1); xc.emax(1); xc.emin(-1); assertEqual(Decimal(9, xc), 9); xc.clear_status(); assertRaises(ConversionSyntax, [&](){ Decimal("xyz", xc); }); assertEqual(xc.status(), DecConversionSyntax); assertEqual(c.status(), 0U); xc.clear_status(); assertEqual(Decimal(2).exp(xc), 7); assertRaises(Overflow, [&](){ Decimal(8).exp(xc); }); assertTrue(xc.status() & DecOverflow); assertEqual(c.status(), 0U); xc.clear_status(); assertEqual(Decimal(2).ln(xc), Decimal("0.7")); assertRaises(InvalidOperation, [&](){ Decimal(-1).ln(xc); }); assertTrue(xc.status() & DecInvalidOperation); assertFalse(c.status() & DecInvalidOperation); assertEqual(Decimal(0).log10(xc), Decimal("-inf")); assertEqual(Decimal(-1).next_minus(xc), -2); assertEqual(Decimal(-1).next_plus(xc), Decimal("-0.9")); assertEqual(Decimal("9.73").reduce(xc), Decimal("1E+1")); assertEqual(Decimal("9999").to_integral(xc), 9999); assertEqual(Decimal("-2000").to_integral_exact(xc), -2000); assertEqual(Decimal("0.0625").sqrt(xc), Decimal("0.2")); assertEqual(Decimal("0.0625").compare(3, xc), -1); xc.clear_status(); assertRaises(InvalidOperation, [&](){ Decimal("0").compare_signal(Decimal("nan"), xc); }); assertTrue(xc.status() & DecInvalidOperation); assertFalse(c.status() & DecInvalidOperation); assertEqual(Decimal("0.01").max(Decimal("0.0101"), xc), Decimal("0.0")); assertEqual(Decimal("0.01").max(Decimal("0.0101"), xc), Decimal("0.0")); assertEqual(Decimal("0.2").max_mag(Decimal("-0.3"), xc), Decimal("-0.3")); assertEqual(Decimal("0.02").min(Decimal("-0.03"), xc), Decimal("-0.0")); assertEqual(Decimal("0.02").min_mag(Decimal("-0.03"), xc), Decimal("0.0")); assertEqual(Decimal("0.2").next_toward(Decimal("-1"), xc), Decimal("0.1")); xc.clear_status(); assertRaises(InvalidOperation, [&](){ Decimal("0.2").quantize(Decimal("1e10"), xc); }); assertTrue(xc.status() & DecInvalidOperation); assertFalse(c.status() & DecInvalidOperation); assertEqual(Decimal("9.99").rem_near(Decimal("1.5"), xc), Decimal("-0.5")); assertEqual(Decimal("9.9").fma(7, Decimal("0.9"), xc), Decimal("7E+1")); assertFalse(Decimal("0.01").isnormal(xc)); assertTrue(Decimal("0.01").issubnormal(xc)); assertEqual(Decimal(-111).logb(xc), 2); assertEqual(Decimal(0).logical_invert(xc), 1); assertEqual(Decimal("0.01").number_class(xc), std::string("+Subnormal")); assertEqual(Decimal("0.21").to_eng(), "0.21"); assertEqual(Decimal("9.99e10").to_eng(), "99.9E+9"); assertEqual(Decimal("11").logical_and(Decimal("10"), xc), 0); assertEqual(Decimal("11").logical_or(Decimal("10"), xc), 1); assertEqual(Decimal("01").logical_xor(Decimal("10"), xc), 1); assertEqual(Decimal("23").rotate(1, xc), 3); assertEqual(Decimal("23").rotate(1, xc), 3); xc.clear_status(); assertRaises(Overflow, [&](){ Decimal("23").scaleb(1, xc); }); assertTrue(xc.status() & DecOverflow); assertFalse(c.status() & DecOverflow); assertEqual(Decimal("23").shift(-1, xc), 0); assertEqual(Decimal(1).canonical(), 1); } /******************************************************************************/ /* Context representation */ /******************************************************************************/ static void ContextReprTest() { assertEqual(context, context_template); context.prec(425000000); context.emax(425000000); context.emin(-425000000); context.round(ROUND_HALF_UP); context.clamp(1); context.allcr(1); context.traps(DecMaxStatus); context.status(DecMaxStatus); const char *t = "Context(prec=425000000, emax=425000000, emin=-425000000, round=ROUND_HALF_UP, clamp=1, " "traps=[IEEEInvalidOperation, DivisionByZero, Overflow, Underflow, " "Subnormal, Inexact, Rounded, Clamped], " "status=[IEEEInvalidOperation, DivisionByZero, Overflow, Underflow, " "Subnormal, Inexact, Rounded, Clamped])"; auto s = context.repr(); assertEqualStr(s, t); s = test::str(context); assertEqualStr(s, t); } /******************************************************************************/ /* Exact conversions (default) */ /******************************************************************************/ static const char *large_prec[] = { /* int */ "12345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890", /* negative int */ "-12345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890", /* float */ "1.2345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890E+999999", /* negative float */ "-1.2345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890E+999999", /* tiny float */ "1.2345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890E-999999", /* negative tiny float */ "1.2345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890E-999999", /* nan */ "NaN12345678901234567890123456789012345678901234567890123456789012345678901234567890" "234567890123456789012345678901234567890", /* negative nan */ "-NaN12345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890", /* snan */ "sNaN12345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890", /* negative snan */ "-sNaN12345678901234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890", }; template static void signed_construction() { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); const std::vector values = {min, -1, 0, 1, max}; for (const T& v : values) { const Decimal d = {v}; const std::string ds = d.to_sci(); const std::string vs = std::to_string(v); assertEqual(d, v); assertEqual(v, d); assertEqual(ds, vs); assertEqual(vs, ds); } const std::vector signs = {-1, 1}; for (int n = 0; n < std::numeric_limits::digits; n++) { for (const T& sign : signs) { for (T x = -5; x < 5; x++) { const T i = static_cast(sign * ((static_cast(1) << n) + x)); const Decimal d = {i}; assertEqual(d, i); assertEqual(i, d); } } } } template static void unsigned_construction() { const T max = std::numeric_limits::max(); const std::vector values = {0, 1, max}; for (const T& v : values) { const Decimal d = {v}; const std::string ds = d.to_sci(); const std::string vs = std::to_string(v); assertEqual(d, v); assertEqual(v, d); assertEqual(ds, vs); assertEqual(vs, ds); } for (int n = 0; n < std::numeric_limits::digits; n++) { for (T x = 0; x < 5; x++) { const T i = static_cast((static_cast(1) << n) + x); const Decimal d = {i}; assertEqual(d, i); assertEqual(i, d); } } } static void ExactConstructionTest() { assertEqual(context, context_template); context.prec(1); context.emax(1); context.emin(-1); context.traps(DecMaxStatus); /*****************************************************************/ /* Implicit conversions */ /*****************************************************************/ /* from empty */ Decimal empty; assertTrue(empty.issnan()); /* from const Decimal& */ for (auto& s : {"-NaN", "-4096", "4096", "4.5E+3", "Infinity"}) { const Decimal init{Decimal(s)}; Decimal x = {init}; assertEqualStr(x, s); assertEqualStr(s, x); } for (auto& s : large_prec) { const Decimal init{Decimal(s)}; Decimal x = {init}; assertEqualStr(x, s); assertEqualStr(s, x); } /* from Decimal&& */ for (auto& s : {"-NaN", "-4096", "4096", "4.5E+3", "Infinity"}) { Decimal init{Decimal(s)}; Decimal x = {std::move(init)}; assertTrue(init.issnan()); assertEqualStr(x, s); assertEqualStr(s, x); } for (auto& s : large_prec) { Decimal init{Decimal(s)}; Decimal x = {std::move(init)}; assertEqualStr(x, s); assertEqualStr(s, x); } /* from integers */ signed_construction(); signed_construction(); signed_construction(); signed_construction(); signed_construction(); signed_construction(); signed_construction(); signed_construction(); signed_construction(); unsigned_construction(); unsigned_construction(); unsigned_construction(); unsigned_construction(); unsigned_construction(); unsigned_construction(); unsigned_construction(); unsigned_construction(); unsigned_construction(); /*****************************************************************/ /* Explicit conversions */ /*****************************************************************/ /* from string */ for (auto& s : {"-NaN", "-4096", "4096", "4.5E+3", "Infinity"}) { Decimal x{s}; assertEqualStr(x, s); assertEqualStr(s, x); } for (auto& s : large_prec) { Decimal x{s}; assertEqualStr(x, s); assertEqualStr(s, x); } /* from std::string */ for (auto& s : {"-sNaN", "123", "1E+999999", "1E-999999"}) { Decimal x{std::string(s)}; assertEqualStr(x, s); assertEqualStr(s, x); } for (auto& s : large_prec) { Decimal x{std::string(s)}; assertEqualStr(x, s); assertEqualStr(s, x); } assertEqual(context.status(), 0U); /* from string, out of bounds for exact conversion */ context.traps(DecInvalidOperation); std::string s = std::string("0E") + std::to_string(INT64_MAX); assertRaises(InvalidOperation, [&](){ Decimal x{s}; }); s = std::string("0E") + std::to_string(INT64_MIN); assertRaises(InvalidOperation, [&](){ Decimal x{s}; }); s = std::string("1E") + std::to_string(INT64_MAX); assertRaises(InvalidOperation, [&](){ Decimal x{s}; }); s = std::string("1E") + std::to_string(INT64_MIN); assertRaises(InvalidOperation, [&](){ Decimal x{s}; }); /* pass explicit context for error reporting */ Context c = Context(); c.clear_traps(); s = std::string("0E") + std::to_string(INT64_MAX); Decimal res = Decimal::exact(s, c); assertEqual(c.status(), DecInvalidOperation); /* large values */ const char *decstring = "9.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999e425000000"; const char *large_exp = "9.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999e99999999999999999999"; Decimal large{decstring}; c.traps(DecMaxStatus-1); c.prec(1); Decimal xlarge = Decimal(large); assertEqual(xlarge, large); xlarge = Decimal(std::move(large)); assertEqual(xlarge, Decimal(decstring)); assertTrue(large.issnan()); assertRaises(InvalidOperation, [&](){ Decimal x = Decimal(large_exp); }); s = std::string(large_exp); assertRaises(InvalidOperation, [&](){ Decimal x = Decimal(s); }); context.clear_status(); context.clear_traps(); } /******************************************************************************/ /* Conversions that respect the context */ /******************************************************************************/ template static void signed_construction_ctx(Context& ctx) { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); for (const T& v : {min, max}) { ctx.clear_traps(); ctx.clear_status(); const Decimal expected = Decimal(std::to_string(v), ctx); const uint32_t expected_status = ctx.status(); ctx.clear_status(); const Decimal calc = Decimal(v, ctx); const uint32_t calc_status = ctx.status(); assertEqual(calc, expected); assertEqual(calc_status, expected_status); ctx.traps(DecInexact); ctx.clear_status(); assertRaises(Inexact, [&](){ Decimal(v, ctx); }); assertEqual(ctx.status(), DecInexact|DecRounded); ctx.clear_traps(); } } template static void unsigned_construction_ctx(Context& ctx) { const T v = std::numeric_limits::max(); ctx.clear_traps(); ctx.clear_status(); const Decimal expected = Decimal(std::to_string(v), ctx); const uint32_t expected_status = ctx.status(); ctx.clear_status(); const Decimal calc = Decimal(v, ctx); const uint32_t calc_status = ctx.status(); assertEqual(calc, expected); assertEqual(calc_status, expected_status); ctx.traps(DecInexact); ctx.clear_status(); assertRaises(Inexact, [&](){ Decimal(v, ctx); }); assertEqual(ctx.status(), DecInexact|DecRounded); ctx.clear_traps(); } static void InexactConstructionTest() { assertEqual(context, context_template); context.traps(DecMaxStatus); Context ctx{context_template}; ctx.prec(1); ctx.emax(1); ctx.emin(-1); /*****************************************************************/ /* Explicit conversions */ /*****************************************************************/ /* from const Decimal& */ ctx.clear_traps(); ctx.clear_status(); Decimal nan = Decimal("-NaN123"); Decimal integer = Decimal("-4096"); Decimal floating = Decimal("4.5E+1"); Decimal x = Decimal(nan, ctx); assertEqualStr(x, "NaN"); assertEqual(ctx.status(), DecConversionSyntax); ctx.clear_status(); x = Decimal(integer, ctx); assertEqualStr(x, "-Infinity"); assertEqual(ctx.status(), (DecInexact | DecOverflow | DecRounded)); ctx.clear_status(); x = Decimal(floating, ctx); assertEqualStr(x, "4E+1"); assertEqual(ctx.status(), (DecInexact | DecRounded)); ctx.traps(DecMaxStatus); ctx.clear_status(); assertRaises(ConversionSyntax, [&](){ Decimal(nan, ctx); }); assertEqual(ctx.status(), DecConversionSyntax); ctx.clear_status(); assertRaises(Overflow, [&](){ Decimal(integer, ctx); }); assertEqual(ctx.status(), (DecInexact | DecOverflow | DecRounded)); ctx.clear_status(); assertRaises(Inexact, [&](){ Decimal(floating, ctx); }); assertEqual(ctx.status(), (DecInexact | DecRounded)); ctx.clear_traps(); /* from integers */ ctx.prec(1); ctx.emax(19); ctx.emin(-19); signed_construction_ctx(ctx); signed_construction_ctx(ctx); signed_construction_ctx(ctx); signed_construction_ctx(ctx); signed_construction_ctx(ctx); signed_construction_ctx(ctx); signed_construction_ctx(ctx); signed_construction_ctx(ctx); signed_construction_ctx(ctx); unsigned_construction_ctx(ctx); unsigned_construction_ctx(ctx); unsigned_construction_ctx(ctx); unsigned_construction_ctx(ctx); unsigned_construction_ctx(ctx); unsigned_construction_ctx(ctx); unsigned_construction_ctx(ctx); unsigned_construction_ctx(ctx); unsigned_construction_ctx(ctx); /* from string */ ctx.prec(3); ctx.clear_status(); ctx.clear_traps(); Decimal d = Decimal("456789"); assertEqualStr(d, "456789"); d = Decimal("456789", ctx); assertEqualStr(d, "4.57E+5"); ctx.traps(DecInexact); assertRaises(Inexact, [&](){ Decimal("456789", ctx); }); ctx.clear_status(); ctx.clear_traps(); ctx.traps(DecRounded); assertRaises(Rounded, [&](){ Decimal("456789", ctx); }); ctx.clear_status(); ctx.clear_traps(); ctx.traps(DecConversionSyntax); assertRaises(ConversionSyntax, [&](){ Decimal("NaN12345", ctx); }); ctx.clear_status(); ctx.clear_traps(); /* from std::string */ d = Decimal(std::string("456789")); assertEqualStr(d, "456789"); d = Decimal(std::string("456789"), ctx); assertEqualStr(d, "4.57E+5"); ctx.traps(DecInexact); assertRaises(Inexact, [&](){ Decimal(std::string("456789"), ctx); }); ctx.clear_status(); ctx.clear_traps(); ctx.traps(DecRounded); assertRaises(Rounded, [&](){ Decimal(std::string("456789"), ctx); }); ctx.clear_status(); ctx.clear_traps(); ctx.traps(DecConversionSyntax); assertRaises(ConversionSyntax, [&](){ Decimal(std::string("NaN12345"), ctx); }); #ifndef __mips__ /* miscompilation */ /* large values */ const char *decstring = "9.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999e425000000"; const char *large_exp = "9.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999e99999999999999999999"; Decimal large{decstring}; ctx.traps(DecMaxStatus-1); ctx.prec(100); ctx.emax(425000000); ctx.emin(-425000000); Decimal xlarge = Decimal(large, ctx); assertEqual(xlarge, large); ctx.prec(1); assertRaises(Overflow, [&](){ Decimal x = Decimal(large_exp, ctx); }); std::string s = std::string(large_exp); assertRaises(Overflow, [&](){ Decimal x = Decimal(s, ctx); }); #endif ctx.clear_status(); ctx.clear_traps(); } /******************************************************************************/ /* Exceptions during construction */ /******************************************************************************/ static void ConstructionExceptionTest() { assertEqual(context, context_template); /*** from string ***/ /* invalid syntax */ context.add_traps(DecConversionSyntax); assertRaises(ConversionSyntax, [](){ Decimal(""); }); assertRaises(ConversionSyntax, [](){ Decimal("xyz"); }); assertRaises(ConversionSyntax, [](){ Decimal("1 23"); }); assertRaises(ConversionSyntax, [](){ Decimal("123\n"); }); context.clear_traps(DecConversionSyntax); context.add_traps(DecIEEEInvalidOperation); assertRaises(IEEEInvalidOperation, [](){ Decimal("xyz"); }); assertRaises(IEEEInvalidOperation, [](){ Decimal("1 23"); }); assertRaises(IEEEInvalidOperation, [](){ Decimal("123\n"); }); context.clear_traps(DecIEEEInvalidOperation); /* too large for exact conversion */ context.add_traps(DecInvalidOperation); assertRaises(InvalidOperation, [](){ Decimal("1e9999999999999999999"); }); assertRaises(InvalidOperation, [](){ Decimal("-1e9999999999999999999"); }); assertRaises(InvalidOperation, [](){ Decimal("1e-9999999999999999999"); }); assertRaises(InvalidOperation, [](){ Decimal("-1e-9999999999999999999"); }); context.clear_traps(DecInvalidOperation); /*** from std::string ***/ /* invalid syntax */ context.add_traps(DecConversionSyntax); assertRaises(ConversionSyntax, [](){ Decimal(std::string("xyz")); }); assertRaises(ConversionSyntax, [](){ Decimal(std::string("1 23")); }); context.clear_traps(DecConversionSyntax); context.add_traps(DecIEEEInvalidOperation); assertRaises(IEEEInvalidOperation, [](){ Decimal(std::string("xyz")); }); assertRaises(IEEEInvalidOperation, [](){ Decimal(std::string("1 23")); }); context.clear_traps(DecIEEEInvalidOperation); /* too large for exact conversion */ context.add_traps(DecInvalidOperation); assertRaises(InvalidOperation, [](){ Decimal(std::string("1e9999999999999999999")); }); assertRaises(InvalidOperation, [](){ Decimal(std::string("-1e9999999999999999999")); }); assertRaises(InvalidOperation, [](){ Decimal(std::string("1e-9999999999999999999")); }); assertRaises(InvalidOperation, [](){ Decimal(std::string("-1e-9999999999999999999")); }); context.clear_traps(DecInvalidOperation); } /******************************************************************************/ /* Accessors */ /******************************************************************************/ static void AccessorTest() { assertEqual(context, context_template); Decimal d = Decimal("1.234E+200"); assertEqual(d.sign(), 1); assertEqual(d.exponent(), 197); assertEqual(d.coeff(), 1234); assertRaises(ValueError, [&](){ d.payload(); }); d = Decimal("-1.234E-20"); assertEqual(d.sign(), -1); assertEqual(d.exponent(), -23); assertEqual(d.coeff(), 1234); assertRaises(ValueError, [&](){ d.payload(); }); d = Decimal("inf"); assertEqual(d.sign(), 1); assertRaises(ValueError, [&](){ d.exponent(); }); assertRaises(ValueError, [&](){ d.coeff(); }); assertRaises(ValueError, [&](){ d.payload(); }); d = Decimal("-inf"); assertEqual(d.sign(), -1); assertRaises(ValueError, [&](){ d.exponent(); }); assertRaises(ValueError, [&](){ d.coeff(); }); assertRaises(ValueError, [&](){ d.payload(); }); d = Decimal("nan"); assertEqual(d.sign(), 1); assertEqual(d.payload(), 0); assertRaises(ValueError, [&](){ d.exponent(); }); assertRaises(ValueError, [&](){ d.coeff(); }); d = Decimal("-nan"); assertEqual(d.sign(), -1); assertEqual(d.payload(), 0); assertRaises(ValueError, [&](){ d.exponent(); }); assertRaises(ValueError, [&](){ d.coeff(); }); d = Decimal("snan"); assertEqual(d.payload(), 0); assertEqual(d.sign(), 1); assertRaises(ValueError, [&](){ d.exponent(); }); assertRaises(ValueError, [&](){ d.coeff(); }); d = Decimal("-snan"); assertEqual(d.payload(), 0); assertEqual(d.sign(), -1); assertRaises(ValueError, [&](){ d.exponent(); }); assertRaises(ValueError, [&](){ d.coeff(); }); d = Decimal("nan123"); assertEqual(d.sign(), 1); assertEqual(d.payload(), 123); assertRaises(ValueError, [&](){ d.exponent(); }); assertRaises(ValueError, [&](){ d.coeff(); }); std::string payload = "123456789123456789123456789123456789123456789123456789123456789123456789" "123456789123456789123456789123456789123456789123456789123456789123456789"; d = Decimal("-nan" + payload); assertEqual(d.sign(), -1); assertEqualStr(d.payload(), payload); assertRaises(ValueError, [&](){ d.exponent(); }); assertRaises(ValueError, [&](){ d.coeff(); }); } /******************************************************************************/ /* Assignment operators */ /******************************************************************************/ template static void signed_assignment() { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); const std::vector values = {min, -2, 2, max}; for (const T& v : values) { Decimal x = v; assertEqual(x, Decimal(v)); x = Decimal(-10000); x += v; assertEqual(x, Decimal(-10000) + v); x = Decimal(2122); x -= v; assertEqual(x, Decimal(2122) - v); x = Decimal("1.231e10"); x *= v; assertEqual(x, Decimal("1.231e10") * v); x = Decimal("225e-10"); x /= v; assertEqual(x, Decimal("225e-10") / v); x = Decimal("25"); x %= v; assertEqual(x, Decimal("25") % v); } } template static void unsigned_assignment() { const T max = std::numeric_limits::max(); const std::vector values = {2, max}; for (const T& v : values) { Decimal x = v; assertEqual(x, Decimal(v)); x = Decimal(-10000); x += v; assertEqual(x, Decimal(-10000) + v); x = Decimal(2122); x -= v; assertEqual(x, Decimal(2122) - v); x = Decimal("1.231e10"); x *= v; assertEqual(x, Decimal("1.231e10") * v); x = Decimal("225e-10"); x /= v; assertEqual(x, Decimal("225e-10") / v); x = Decimal("25"); x %= v; assertEqual(x, Decimal("25") % v); } } static void AssignmentOperatorTest() { assertEqual(context, context_template); /* Decimal */ context.prec(10000); Decimal x = Decimal(10).pow(1200); assertEqual(x, Decimal(10).pow(1200)); x = Decimal(10).pow(1200); x += Decimal("1.1127312"); assertEqual(x, Decimal(10).pow(1200) + Decimal("1.1127312")); x = Decimal(10).pow(1200); x -= Decimal("1.1127312"); assertEqual(x, Decimal(10).pow(1200) - Decimal("1.1127312")); x = -Decimal(10).pow(1200); x *= Decimal("1.1127312"); assertEqual(x, -Decimal(10).pow(1200) * Decimal("1.1127312")); x = -Decimal(10).pow(1200); x /= Decimal("1.1127312"); assertEqual(x, -Decimal(10).pow(1200) / Decimal("1.1127312")); x = Decimal(10).pow(1200); x %= Decimal("1.1127312"); assertEqual(x, Decimal(10).pow(1200) % Decimal("1.1127312")); /* integers */ context.prec(3); context.clear_status(); signed_assignment(); signed_assignment(); signed_assignment(); signed_assignment(); signed_assignment(); signed_assignment(); signed_assignment(); signed_assignment(); signed_assignment(); unsigned_assignment(); unsigned_assignment(); unsigned_assignment(); unsigned_assignment(); unsigned_assignment(); unsigned_assignment(); unsigned_assignment(); unsigned_assignment(); unsigned_assignment(); } static void PointerAssignmentOperatorTest() { assertEqual(context, context_template); const Decimal *d = new Decimal; assertTrue(d->issnan()); const Decimal *x = d; assertEqual(x, d); /* CheriBSD: the operator<< overload for uintptr_t is missing (purecap mode) */ #if !defined(__CHERI__) x += 10; assertEqual(reinterpret_cast(x), reinterpret_cast(d) + 10 * (sizeof *d)); x -= 10; assertEqual(reinterpret_cast(x), reinterpret_cast(d)); #endif delete x; } /******************************************************************************/ /* Comparison operators */ /******************************************************************************/ template static void signed_comparison() { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); const std::vector values = {min, -1, 0, 1, max}; const Decimal less = Decimal("-1000000000000000000000000000000000"); const Decimal less_equal = Decimal(min); const Decimal greater_equal = Decimal(max); const Decimal greater = Decimal("1000000000000000000000000000000000"); for (const T& v : values) { assertTrue(v == Decimal(v)); assertTrue(Decimal(v) == v); assertFalse(v != Decimal(v)); assertFalse(Decimal(v) != v); assertTrue(2 != Decimal(v)); assertTrue(Decimal(v) != 2); assertFalse(2 == Decimal(v)); assertFalse(Decimal(v) == 2); assertTrue(v < greater); assertTrue(less < v); assertTrue(v <= greater_equal); assertTrue(less_equal <= v); assertTrue(v >= less_equal); assertTrue(greater_equal >= v); assertTrue(v > less); assertTrue(greater > v); } } template static void unsigned_comparison() { const T max = std::numeric_limits::max(); const std::vector values = {0, 1, max}; Decimal less = Decimal("-1000000000000000000000000000000000"); Decimal less_equal = Decimal(0); Decimal greater_equal = Decimal(max); Decimal greater = Decimal("1000000000000000000000000000000000"); for (const T& v : values) { assertTrue(v == Decimal(v)); assertTrue(Decimal(v) == v); assertFalse(v != Decimal(v)); assertFalse(Decimal(v) != v); assertTrue(2 != Decimal(v)); assertTrue(Decimal(v) != 2); assertFalse(2 == Decimal(v)); assertFalse(Decimal(v) == 2); assertTrue(v < greater); assertTrue(less < v); assertTrue(v <= greater_equal); assertTrue(less_equal <= v); assertTrue(v >= less_equal); assertTrue(greater_equal >= v); assertTrue(v > less); assertTrue(greater > v); } } static void ComparisonOperatorTest() { assertEqual(context, context_template); context.emax(1); context.emin(-1); context.clear_status(); context.traps(DecMaxStatus); /* integer comparisons */ signed_comparison(); signed_comparison(); signed_comparison(); signed_comparison(); signed_comparison(); signed_comparison(); signed_comparison(); signed_comparison(); signed_comparison(); unsigned_comparison(); unsigned_comparison(); unsigned_comparison(); unsigned_comparison(); unsigned_comparison(); unsigned_comparison(); unsigned_comparison(); unsigned_comparison(); unsigned_comparison(); /* Decimal */ Context ctx = MaxContext(); ctx.traps(DecMaxStatus); assertTrue(Decimal(10).pow(1200, ctx) == Decimal(10).pow(1200, ctx)); assertTrue(Decimal(10).pow(1201, ctx) != Decimal(10).pow(1200, ctx)); assertTrue(Decimal(10).pow(1200, ctx) < Decimal(10).pow(1201, ctx)); assertTrue(Decimal(10).pow(1200, ctx) <= Decimal(10).pow(1200, ctx)); assertTrue(Decimal(10).pow(1200, ctx) >= Decimal(10).pow(1200, ctx)); assertTrue(Decimal(10).pow(1201, ctx) > Decimal(10).pow(1200, ctx)); assertEqual(ctx.status(), 0U); /* Decimal NaN */ context.clear_status(); context.traps(DecInvalidOperation); assertFalse(Decimal("NaN") == 2); assertFalse(2 == Decimal("NaN")); assertFalse(Decimal("NaN") == Decimal("NaN")); assertTrue(Decimal("NaN") != Decimal("NaN")); assertEqual(context.status(), 0U); assertRaises(InvalidOperation, [](){ void(Decimal("NaN") < 2); }); assertRaises(InvalidOperation, [](){ void(Decimal("NaN") <= 2); }); assertRaises(InvalidOperation, [](){ void(Decimal("NaN") >= 2); }); assertRaises(InvalidOperation, [](){ void(Decimal("NaN") > 2); }); assertEqual(context.status(), DecInvalidOperation); /* Decimal sNaN */ context.clear_status(); context.traps(DecInvalidOperation); assertRaises(InvalidOperation, [](){ void(Decimal("sNaN") == 2); }); assertRaises(InvalidOperation, [](){ void(Decimal("sNaN") != 2); }); assertRaises(InvalidOperation, [](){ void(Decimal("sNaN") < 2); }); assertRaises(InvalidOperation, [](){ void(Decimal("sNaN") <= 2); }); assertRaises(InvalidOperation, [](){ void(Decimal("sNaN") >= 2); }); assertRaises(InvalidOperation, [](){ void(Decimal("sNaN") > 2); }); assertEqual(context.status(), DecInvalidOperation); } static void PointerComparisonOperatorTest() { assertEqual(context, context_template); const Decimal *d = new Decimal; assertTrue(d->issnan()); const Decimal *x = d + 10; assertFalse(x == d); assertTrue(x != d); assertTrue(d < x); assertTrue(x <= x); assertTrue(x >= d); assertTrue(x > d); delete d; } /******************************************************************************/ /* Unary arithmetic operators */ /******************************************************************************/ static void UnaryOperatorTest() { assertEqual(context, context_template); context.prec(3); assertEqualStr(+Decimal(10000), "1.00E+4"); assertEqualStr(-Decimal(10000), "-1.00E+4"); } static void PointerUnaryOperatorTest() { assertEqual(context, context_template); context.prec(3); Decimal *d = new Decimal(10000); Decimal *x = +d; assertEqual(x, d); ++x; assertEqual(x-1, d); --x; assertEqual(x, d); x++; assertEqual(x-1, d); x--; assertEqual(x, d); bool b = !x; assertEqual(b, false); assertEqual(*x, 10000); assertEqual(**(&x), 10000); delete d; } /******************************************************************************/ /* Binary arithmetic operators */ /******************************************************************************/ template static void signed_arithmetic() { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); const std::vector values = {min, -2, 2, max}; for (const T& v : values) { assertEqual(Decimal(10) + v, Decimal(10) + Decimal(v)); assertEqual(v + Decimal(10), Decimal(v) + Decimal(10)); assertEqual(Decimal(27) - v, Decimal(27) - Decimal(v)); assertEqual(v - Decimal(27), Decimal(v) - Decimal(27)); assertEqual(Decimal(1729) * v, Decimal(1729) * Decimal(v)); assertEqual(v * Decimal(1729), Decimal(1729) * Decimal(v)); assertEqual(Decimal(225) / v, Decimal(225) / Decimal(v)); assertEqual(v / Decimal(225), Decimal(v) / Decimal(225)); assertEqual(Decimal(15222) % v, Decimal(15222) % Decimal(v)); assertEqual(v % Decimal(15222), Decimal(v) % Decimal(15222)); } } template static void unsigned_arithmetic() { const T max = std::numeric_limits::max(); const std::vector values = {2, max}; for (const T& v : values) { assertEqual(Decimal(10) + v, Decimal(10) + Decimal(v)); assertEqual(v + Decimal(10), Decimal(v) + Decimal(10)); assertEqual(Decimal(27) - v, Decimal(27) - Decimal(v)); assertEqual(v - Decimal(27), Decimal(v) - Decimal(27)); assertEqual(Decimal(1729) * v, Decimal(1729) * Decimal(v)); assertEqual(v * Decimal(1729), Decimal(1729) * Decimal(v)); assertEqual(Decimal(225) / v, Decimal(225) / Decimal(v)); assertEqual(v / Decimal(225), Decimal(v) / Decimal(225)); assertEqual(Decimal(15222) % v, Decimal(15222) % Decimal(v)); assertEqual(v % Decimal(15222), Decimal(v) % Decimal(15222)); } } static void ArithmeticOperatorTest() { assertEqual(context, context_template); /* Decimal */ context.prec(9); assertEqual(Decimal(20) + Decimal(2), 22); assertEqual(Decimal(5) + 123456789000, Decimal(123456789000)); assertEqual(Decimal(22) - Decimal(2), 20); assertEqual(Decimal(20) * Decimal(20), 400); assertEqual(Decimal(10) / Decimal(2), 5); assertEqual(Decimal(10) % Decimal(3), 1); /* integers */ context.prec(1000); signed_arithmetic(); signed_arithmetic(); signed_arithmetic(); signed_arithmetic(); signed_arithmetic(); signed_arithmetic(); signed_arithmetic(); signed_arithmetic(); signed_arithmetic(); unsigned_arithmetic(); unsigned_arithmetic(); unsigned_arithmetic(); unsigned_arithmetic(); unsigned_arithmetic(); unsigned_arithmetic(); unsigned_arithmetic(); unsigned_arithmetic(); unsigned_arithmetic(); } static void PointerArithmeticOperatorTest() { assertEqual(context, context_template); const Decimal *d = new Decimal; assertTrue(d->issnan()); /* CheriBSD: the operator<< overload for uintptr_t is missing (purecap mode) */ #if !defined(__CHERI__) const Decimal *x = d + 10; assertEqual(reinterpret_cast(x), reinterpret_cast(d) + 10 * (sizeof *d)); x = x - 10; assertEqual(reinterpret_cast(x), reinterpret_cast(d)); #endif delete d; } /******************************************************************************/ /* Predicates */ /******************************************************************************/ static void PredicateTest() { assertEqual(context, context_template); const Decimal finite("10.1"); const Decimal infinite("-inf"); const Decimal nan("nan"); const Decimal snan("-snan"); const Decimal zero("-0"); const Decimal integer("9.999E+100000"); const Decimal subnormal = Decimal(0).next_plus(); assertTrue(finite.iscanonical()); assertTrue(finite.isfinite()); assertFalse(finite.isinfinite()); assertFalse(finite.isspecial()); assertFalse(finite.isnan()); assertFalse(finite.isqnan()); assertFalse(finite.issnan()); assertFalse(finite.issigned()); assertFalse(finite.iszero()); assertFalse(finite.isinteger()); assertTrue(finite.isnormal()); assertFalse(finite.issubnormal()); assertTrue(infinite.iscanonical()); assertFalse(infinite.isfinite()); assertTrue(infinite.isinfinite()); assertTrue(infinite.isspecial()); assertFalse(infinite.isnan()); assertFalse(infinite.isqnan()); assertFalse(infinite.isqnan()); assertTrue(infinite.issigned()); assertFalse(infinite.iszero()); assertFalse(infinite.isinteger()); assertFalse(infinite.isnormal()); assertFalse(infinite.issubnormal()); assertTrue(nan.iscanonical()); assertFalse(nan.isfinite()); assertFalse(nan.isinfinite()); assertTrue(nan.isspecial()); assertTrue(nan.isnan()); assertTrue(nan.isqnan()); assertFalse(nan.issnan()); assertFalse(nan.issigned()); assertFalse(nan.iszero()); assertFalse(nan.isinteger()); assertFalse(nan.isnormal()); assertFalse(nan.issubnormal()); assertTrue(snan.iscanonical()); assertFalse(snan.isfinite()); assertFalse(snan.isinfinite()); assertTrue(snan.isspecial()); assertTrue(snan.isnan()); assertFalse(snan.isqnan()); assertTrue(snan.issnan()); assertTrue(snan.issigned()); assertFalse(snan.iszero()); assertFalse(snan.isinteger()); assertFalse(snan.isnormal()); assertFalse(snan.issubnormal()); assertTrue(zero.iscanonical()); assertTrue(zero.isfinite()); assertFalse(zero.isinfinite()); assertFalse(zero.isspecial()); assertFalse(zero.isnan()); assertFalse(zero.isqnan()); assertFalse(zero.issnan()); assertTrue(zero.issigned()); assertTrue(zero.iszero()); assertTrue(zero.isinteger()); assertFalse(zero.isnormal()); assertFalse(zero.issubnormal()); assertTrue(integer.iscanonical()); assertTrue(integer.isfinite()); assertFalse(integer.isinfinite()); assertFalse(integer.isspecial()); assertFalse(integer.isnan()); assertFalse(integer.isqnan()); assertFalse(integer.issnan()); assertFalse(integer.issigned()); assertFalse(integer.iszero()); assertTrue(integer.isinteger()); assertTrue(integer.isnormal()); assertFalse(integer.issubnormal()); assertTrue(subnormal.iscanonical()); assertTrue(subnormal.isfinite()); assertFalse(subnormal.isinfinite()); assertFalse(subnormal.isspecial()); assertFalse(subnormal.isnan()); assertFalse(subnormal.isqnan()); assertFalse(subnormal.issnan()); assertFalse(subnormal.issigned()); assertFalse(subnormal.iszero()); assertFalse(subnormal.isinteger()); assertFalse(subnormal.isnormal()); assertTrue(subnormal.issubnormal()); Context ctx{1, 1, -1}; Decimal sub = Decimal("0.00000001"); assertFalse(sub.isnormal(ctx)); assertTrue(sub.issubnormal(ctx)); } /******************************************************************************/ /* Unary functions */ /******************************************************************************/ static void UnaryFunctionTest() { assertEqual(context, context_template); /* Unary functions, no context arg */ Decimal x = Decimal("-123.113E+25100"); assertEqual(x.adjexp(), 25102); assertEqual(Decimal("1234e9999").adjexp(), 10002); assertRaises(ValueError, [](){ Decimal("nan").adjexp(); }); assertRaises(ValueError, [](){ Decimal("inf").adjexp(); }); assertEqual(Decimal::radix(), 10); assertEqual(x.canonical(), x); x = Decimal(123456789); assertEqual(x.copy(), x); for (const auto& s : large_prec) { x = Decimal(s); assertEqualStr(x.copy(), x); } x = Decimal(-123456789); assertEqual(x.copy_abs(), 123456789); x = Decimal(123456789); assertEqual(x.copy_negate(), -123456789); context.prec(10000); auto large = -Decimal(1172).pow(1712); assertEqual(large.copy_abs(), -large); assertEqual(large.copy_negate(), -large); assertEqual(large.copy_sign(1), -large); context.prec(9); /* Unary functions, optional context arg */ Context ctx{1, 1, -1}; assertEqualStr(Decimal("-0.00001").number_class(), "-Normal"); assertEqualStr(Decimal("-0.00001").number_class(ctx), "-Subnormal"); assertEqual(Decimal(-123456789).abs(), 123456789); assertEqual(Decimal(-15).abs(ctx), Decimal("2E+1")); assertEqual(Decimal(-1123).exp(), Decimal("1.93774588E-488")); assertEqual(Decimal(2).exp(ctx), 7); assertEqual(Decimal(1123).invroot(), Decimal("0.0298407766")); assertEqual(Decimal(7).invroot(ctx), Decimal("0.4")); assertEqual(Decimal(0).logical_invert(), Decimal("111111111")); assertEqual(Decimal(0).logical_invert(ctx), Decimal("1")); assertEqual(Decimal(10).ln(), Decimal("2.30258509")); assertEqual(Decimal(10).ln(ctx), Decimal("2")); assertEqual(Decimal(20).log10(), Decimal("1.30103000")); assertEqual(Decimal(20).log10(ctx), Decimal("1")); assertEqual(Decimal("2250000000000000000000000000").logb(), Decimal("27")); assertEqual(Decimal("2250000000000000000000000000").logb(ctx), Decimal("3E+1")); assertEqual(Decimal("2250000000000000000000000000").minus(), Decimal("-2.25000000E+27")); assertEqual(Decimal("25").minus(ctx), Decimal("-2E+1")); assertEqual(Decimal("2250000000000000000000000000").next_minus(), Decimal("2.24999999E+27")); assertEqual(Decimal("2250000000000000000000000000").next_minus(ctx), Decimal("9E+1")); assertEqual(Decimal("2250000000000000000000000000").plus(), Decimal("2.25000000E+27")); assertEqual(Decimal("28").plus(ctx), Decimal("3E+1")); assertEqual(Decimal("2250000000000000000000000000").reduce(), Decimal("2.25E+27")); assertEqual(Decimal("-28").reduce(ctx), Decimal("-3E+1")); assertEqual(Decimal("22500000.12").to_integral(), Decimal("22500000")); assertEqual(Decimal("22500000.12").to_integral(ctx), Decimal("22500000")); assertEqual(Decimal("22500000.12").to_integral_exact(), Decimal("22500000")); assertEqual(Decimal("22500000.12").to_integral_exact(ctx), Decimal("22500000")); assertEqual(Decimal("90025").sqrt(), Decimal("300.041664")); assertEqual(Decimal("99").sqrt(ctx), Decimal("1E+1")); ctx.round(ROUND_UP); x = Decimal("99999999999999999999999999.9").to_integral(ctx); assertEqual(x, Decimal("100000000000000000000000000")); x = Decimal("99999999999999999999999999.9").to_integral_exact(ctx); assertEqual(x, Decimal("100000000000000000000000000")); ctx.add_traps(DecInexact); assertRaises(Inexact, [&](){ Decimal("999.9").to_integral_exact(ctx); }); } static void CeilTest() { assertEqual(context, context_template); context.traps(DecMaxStatus); const std::vector> pairs = { {"123.00", 123}, {"3.2", 4}, {"3.54", 4}, {"3.899", 4}, {"-2.3", -2}, {"-11.0", -11}, {"0.0", 0}, {"-0E3", 0}, {"898211712379812736.1", 898211712379812737LL}, }; for (auto& p : pairs) { const char *s = p.first; long long i = p.second; assertEqual(Decimal(s).ceil(), i); } context.status(0); assertRaises(InvalidOperation, [](){ Decimal("NaN").ceil(); }); assertRaises(InvalidOperation, [](){ Decimal("NaN123").ceil(); }); assertRaises(InvalidOperation, [](){ Decimal("Inf").ceil(); }); assertRaises(InvalidOperation, [](){ Decimal("-Inf").ceil(); }); assertRaises(InvalidOperation, [](){ Decimal("sNaN").ceil(); }); assertEqual(context.status(), DecInvalidOperation); } static void FloorTest() { assertEqual(context, context_template); context.traps(DecMaxStatus); const std::vector> pairs = { {"123.00", 123}, {"3.2", 3}, {"3.54", 3}, {"3.899", 3}, {"-2.3", -3}, {"-11.0", -11}, {"0.0", 0}, {"-0E3", 0}, {"898211712379812736.1", 898211712379812736LL}, }; for (auto& p : pairs) { const char *s = p.first; long long i = p.second; assertEqual(Decimal(s).floor(), i); } context.status(0); assertRaises(InvalidOperation, [](){ Decimal("NaN").floor(); }); assertRaises(InvalidOperation, [](){ Decimal("NaN123").floor(); }); assertRaises(InvalidOperation, [](){ Decimal("Inf").floor(); }); assertRaises(InvalidOperation, [](){ Decimal("-Inf").floor(); }); assertRaises(InvalidOperation, [](){ Decimal("sNaN").floor(); }); assertEqual(context.status(), DecInvalidOperation); } static void TruncTest() { assertEqual(context, context_template); char buf[10]; context.traps(DecMaxStatus); const std::vector> pairs = { {"123.00", 123}, {"3.2", 3}, {"3.54", 3}, {"3.899", 3}, {"-2.3", -2}, {"-11.0", -11}, {"-11.8", -11}, {"0.0", 0}, {"-0E3", 0}, {"898211712379812736.1", 898211712379812736LL}, }; for (auto& p : pairs) { const char *s = p.first; long long i = p.second; assertEqual(Decimal(s).trunc(), i); } context.round(ROUND_DOWN); for (int i = -250; i < 250; i++) { int n = snprintf(buf, sizeof buf, "%0.2f", i / 100.0); assertTrue(n >= 0 && n < 10); Decimal d = Decimal(static_cast(buf)); Decimal r = d.to_integral(); assertEqual(d.trunc(), r); } context.status(0); assertRaises(InvalidOperation, [](){ Decimal("NaN").trunc(); }); assertRaises(InvalidOperation, [](){ Decimal("NaN123").trunc(); }); assertRaises(InvalidOperation, [](){ Decimal("Inf").trunc(); }); assertRaises(InvalidOperation, [](){ Decimal("-Inf").trunc(); }); assertRaises(InvalidOperation, [](){ Decimal("sNaN").trunc(); }); assertEqual(context.status(), DecInvalidOperation); } /******************************************************************************/ /* Binary functions */ /******************************************************************************/ static void BinaryFunctionTest() { assertEqual(context, context_template); /* Binary functions, no context arg */ assertEqual(Decimal("123").compare_total(Decimal("sNaN")), Decimal("-1")); assertEqual(Decimal("-123").compare_total_mag(Decimal("10")), Decimal("1")); /* Binary functions */ Context ctx{3, 100, -100}; ctx.round(ROUND_UP); ctx.clamp(1); ctx.traps(DecIEEEInvalidOperation); assertEqualStr(Decimal(1234567890).add(Decimal("-9988888.23")), "1.22457900E+9"); assertEqualStr(Decimal(1234567890).add(Decimal("-9988888.23"), ctx), "1.23E+9"); assertEqualStr(Decimal(1234567890).div(Decimal("-9988888.23")), "-123.594124"); assertEqualStr(Decimal(1234567890).div(Decimal("-9988888.23"), ctx), "-124"); assertEqualStr(Decimal(1234567890).divint(Decimal("-9988888.23")), "-123"); assertEqualStr(Decimal(1234567890).divint(Decimal("-9988888.23"), ctx), "-123"); assertEqualStr(Decimal(1234567890).compare(Decimal("-9988888.23")), 1); assertEqualStr(Decimal(1234567890).compare(Decimal("-9988888.23"), ctx), 1); assertEqualStr(Decimal(1234567890).compare_signal(Decimal("-9988888.23")), 1); assertEqualStr(Decimal(1234567890).compare_signal(Decimal("-9988888.23"), ctx), 1); assertEqualStr(Decimal("101111").logical_and(Decimal("110001101")), "1101"); assertEqualStr(Decimal("101111").logical_and(Decimal("110001101"), ctx), "101"); assertEqualStr(Decimal("101111").logical_or(Decimal("110001101")), "110101111"); assertEqualStr(Decimal("101111").logical_or(Decimal("110001101"), ctx), "111"); assertEqualStr(Decimal("101111").logical_xor(Decimal("110001101")), "110100010"); assertEqualStr(Decimal("101111").logical_xor(Decimal("110001101"), ctx), "10"); assertEqualStr(Decimal(1234567890).max(Decimal("-9988888.23")), "1.23456789E+9"); assertEqualStr(Decimal(1234567890).max(Decimal("-9988888.23"), ctx), "1.24E+9"); assertEqualStr(Decimal(1234567890).max_mag(Decimal("-9988888.23")), "1.23456789E+9"); assertEqualStr(Decimal(1234567890).max_mag(Decimal("-9988888.23"), ctx), "1.24E+9"); assertEqualStr(Decimal(1234567890).min(Decimal("-9988888.23")), "-9988888.23"); assertEqualStr(Decimal(1234567890).min(Decimal("-9988888.23"), ctx), "-9.99E+6"); assertEqualStr(Decimal(1234567890).min_mag(Decimal("-9988888.23")), "-9988888.23"); assertEqualStr(Decimal(1234567890).min_mag(Decimal("-9988888.23"), ctx), "-9.99E+6"); assertEqualStr(Decimal(1234567890).mul(Decimal("-9988888.23")), "-1.23319607E+16"); assertEqualStr(Decimal(1234567890).mul(Decimal("-9988888.23"), ctx), "-1.24E+16"); assertEqualStr(Decimal(1234567890).next_toward(Decimal("-9988888.23")), "1.23456788E+9"); assertEqualStr(Decimal(1234567890).next_toward(Decimal("-9988888.23"), ctx), "1.23E+9"); assertEqualStr(Decimal(1234567890).pow(Decimal("-9988888.23")), "0E-1000007"); assertEqualStr(Decimal(1234567890).pow(Decimal("-9988888.23"), ctx), "1E-102"); ctx.clear_status(); assertEqual(Decimal("1.0").pow(100, ctx), Decimal("1.00")); assertTrue(ctx.status() & DecRounded); ctx.clear_status(); ctx.emax(1); ctx.emin(-1); assertEqual(Decimal(10000).pow(Decimal("0.5"), ctx), Decimal("inf")); assertTrue(ctx.status() & DecOverflow); ctx.emax(100); ctx.emin(-100); assertEqualStr(Decimal(1234567890).rem(Decimal("-9988888.23")), "5934637.71"); assertEqualStr(Decimal(1234567890).rem(Decimal("-9988888.23"), ctx), "5.94E+6"); assertEqualStr(Decimal(1234567890).rem_near(Decimal("-9988888.23")), "-4054250.52"); assertEqualStr(Decimal(1234567890).rem_near(Decimal("-9988888.23"), ctx), "-4.06E+6"); assertEqualStr(Decimal(1234567890).rotate(2), "456789023"); assertEqualStr(Decimal(1234567890).rotate(2, ctx), "89"); assertEqualStr(Decimal(20).quantize(Decimal("1E-2")), "20.00"); assertRaises(InvalidOperation, [&](){ Decimal(20).quantize(Decimal("1E-2"), ctx); }); assertEqualStr(Decimal(20).quantize(Decimal("1E-1"), ctx), "20.0"); assertEqualStr(Decimal(20).scaleb(Decimal("100")), "2.0E+101"); ctx.add_traps(DecOverflow); assertRaises(Overflow, [&](){ Decimal(20).scaleb(Decimal("100"), ctx); }); assertEqualStr(Decimal(20).scaleb(Decimal("10"), ctx), "2.0E+11"); assertEqualStr(Decimal(1).shift(8), Decimal("100000000")); assertRaises(InvalidOperation, [&](){ Decimal(1).shift(8, ctx); }); assertEqualStr(Decimal(1).shift(2, ctx), 100); assertEqualStr(Decimal(1234567890).sub(Decimal("-9988888.23")), "1.24455678E+9"); assertEqualStr(Decimal(1234567890).sub(Decimal("-9988888.23"), ctx), "1.25E+9"); } /******************************************************************************/ /* Divmod */ /******************************************************************************/ static void DivmodTest() { assertEqual(context, context_template); /* Binary functions */ Context ctx{3, 100, -100}; ctx.round(ROUND_UP); ctx.clamp(1); ctx.traps(DecIEEEInvalidOperation); auto result = Decimal("1234567890").divmod(12716); assertEqual(result.first, 97087); assertEqual(result.second, 9598); assertRaises(DivisionImpossible, [&](){ Decimal("1234567890").divmod(12716, ctx); }); result = Decimal("1234567890").divmod(12716172); assertEqualStr(result.first, "97"); assertEqualStr(result.second, "1099206"); result = Decimal("10912837129").divmod(1001); assertEqual(result.first, Decimal("10901935")); assertEqual(result.second, Decimal("194")); result = Decimal("NaN").divmod(7); assertTrue(result.first.isqnan()); assertTrue(result.second.isqnan()); context.clear_traps(); context.clear_status(); result = Decimal("inf").divmod(Decimal("inf")); assertTrue(result.first.isqnan()); assertTrue(result.second.isqnan()); assertTrue(context.status() & DecInvalidOperation); context.clear_status(); result = Decimal("inf").divmod(Decimal("101")); assertTrue(result.first.isinfinite()); assertTrue(result.second.isqnan()); assertTrue(context.status() & DecInvalidOperation); context.clear_status(); result = Decimal("0").divmod(Decimal("0")); assertTrue(result.first.isqnan()); assertTrue(result.second.isqnan()); assertTrue(context.status() & DecDivisionUndefined); context.clear_status(); result = Decimal("11").divmod(Decimal("0")); assertTrue(result.first.isinfinite()); assertTrue(result.second.isqnan()); assertTrue(context.status() & DecInvalidOperation); assertTrue(context.status() & DecDivisionByZero); } /******************************************************************************/ /* Quantize */ /******************************************************************************/ static void QuantizeTest() { assertEqual(context, context_template); context.clear_status(); Context c = Context(9, 99999, -99999, ROUND_DOWN); assertEqual(Decimal("7.335").quantize(Decimal(".01")), Decimal("7.34")); assertEqual(Decimal("7.335").quantize(Decimal(".01"), c), Decimal("7.33")); c = Context(28, 99999, -99999); c.traps(DecInvalidOperation); assertRaises(InvalidOperation, [&](){ Decimal("10e99999").quantize(Decimal("1e100000"), c); }); c = Context(); c.round(ROUND_DOWN); Decimal d = Decimal("0.871831e800"); Decimal x = d.quantize(Decimal("1e797"), c); assertEqual(x, Decimal("8.71E+799")); } /******************************************************************************/ /* Ternary functions */ /******************************************************************************/ static void TernaryFunctionTest() { assertEqual(context, context_template); Context ctx{3, 100, -100}; ctx.round(ROUND_UP); ctx.clamp(1); ctx.traps(DecIEEEInvalidOperation); assertEqual(Decimal("1234").fma(919, Decimal("3.2507355")), Decimal("1134049.25")); assertEqual(Decimal("1234").fma(919, Decimal("3.2507355"), ctx), Decimal("1.14E+6")); assertEqual(Decimal("1234").powmod(919, Decimal("123456789")), Decimal("119347714")); assertRaises(InvalidOperation, [&](){ Decimal("1234").powmod(919, Decimal("123456789"), ctx); }); assertEqual(Decimal("1234").powmod(919, Decimal("996")), Decimal("892")); ctx.prec(2); assertRaises(InvalidOperation, [&](){ Decimal("1000").powmod(1, Decimal("501"), ctx); }); } /******************************************************************************/ /* Irregular functions */ /******************************************************************************/ static void IrregularFunctionTest() { assertEqual(context, context_template); Context ctx{3, 100, -100}; ctx.round(ROUND_UP); ctx.clamp(1); ctx.traps(DecIEEEInvalidOperation); assertEqual(Decimal("1").cmp(10), -1); assertEqual(Decimal("10").cmp(10), 0); assertEqual(Decimal("10").cmp(1), 1); assertEqual(Decimal("1").cmp(Decimal("inf")), -1); assertEqual(Decimal("1").cmp(Decimal("-inf")), 1); assertEqual(Decimal("inf").cmp(Decimal("1")), 1); assertEqual(Decimal("-inf").cmp(Decimal("1")), -1); assertEqual(Decimal("-inf").cmp(Decimal("inf")), -1); assertEqual(Decimal("inf").cmp(Decimal("-inf")), 1); assertEqual(Decimal("10").cmp(Decimal("nan")), INT_MAX); assertEqual(Decimal("inf").cmp(Decimal("nan")), INT_MAX); assertEqual(Decimal("nan").cmp(Decimal("nan")), INT_MAX); assertEqual(Decimal("nan").cmp(Decimal("snan")), INT_MAX); assertEqual(Decimal("snan").cmp(Decimal("snan")), INT_MAX); assertEqual(Decimal("1").cmp_total(10), -1); assertEqual(Decimal("10").cmp_total(10), 0); assertEqual(Decimal("10").cmp_total(1), 1); assertEqual(Decimal("1").cmp_total(Decimal("inf")), -1); assertEqual(Decimal("1").cmp_total(Decimal("-inf")), 1); assertEqual(Decimal("inf").cmp_total(Decimal("1")), 1); assertEqual(Decimal("-inf").cmp_total(Decimal("1")), -1); assertEqual(Decimal("-inf").cmp_total(Decimal("inf")), -1); assertEqual(Decimal("inf").cmp_total(Decimal("-inf")), 1); assertEqual(Decimal("10").cmp_total(Decimal("nan")), -1); assertEqual(Decimal("inf").cmp_total(Decimal("nan")), -1); assertEqual(Decimal("nan").cmp_total(Decimal("inf")), 1); assertEqual(Decimal("nan").cmp_total(Decimal("nan")), 0); assertEqual(Decimal("nan").cmp_total(Decimal("snan")), 1); assertEqual(Decimal("snan").cmp_total(Decimal("snan")), 0); assertEqual(Decimal("1").compare_total_mag(10), -1); assertEqual(Decimal("-10").compare_total_mag(1), 1); assertEqual(Decimal("10").compare_total_mag(1), 1); assertEqual(Decimal("1").compare_total_mag(Decimal("inf")), -1); assertEqual(Decimal("1").compare_total_mag(Decimal("-inf")), -1); assertEqual(Decimal("inf").compare_total_mag(Decimal("1")), 1); assertEqual(Decimal("-inf").compare_total_mag(Decimal("1")), 1); assertEqual(Decimal("-inf").compare_total_mag(Decimal("inf")), 0); assertEqual(Decimal("inf").compare_total_mag(Decimal("-inf")), 0); assertEqual(Decimal("10").compare_total_mag(Decimal("nan")), -1); assertEqual(Decimal("inf").compare_total_mag(Decimal("nan")), -1); assertEqual(Decimal("nan").compare_total_mag(Decimal("inf")), 1); assertEqual(Decimal("nan").compare_total_mag(Decimal("nan")), 0); assertEqual(Decimal("nan").compare_total_mag(Decimal("snan")), 1); assertEqual(Decimal("snan").compare_total_mag(Decimal("snan")), 0); assertEqual(Decimal("10").copy_sign(-1), -10); ctx.round(ROUND_DOWN); assertEqual(Decimal("123456785").rescale(1, ctx), Decimal("1.2345678E+8")); ctx.round(ROUND_UP); assertEqual(Decimal("123456785").rescale(1, ctx), Decimal("1.2345679E+8")); assertTrue(Decimal("123456785").same_quantum(10)); assertFalse(Decimal("123456785").same_quantum(Decimal("1E+1"))); assertEqual(Decimal("1").shiftn(8), Decimal("1E+8")); assertRaises(InvalidOperation, [&](){ Decimal("1").shiftn(8, ctx); }); assertEqual(Decimal("1000").shiftn(-1), Decimal("100")); assertEqual(Decimal("1").shiftl(100), Decimal("1E+100")); assertEqual(Decimal("1").shiftl(100, ctx), Decimal("1E+100")); assertRaises(ValueError, [](){ Decimal("NaN").shiftl(100); }); assertRaises(ValueError, [](){ Decimal("sNaN").shiftl(100); }); assertRaises(ValueError, [](){ Decimal("Infinity").shiftl(100); }); assertEqual(Decimal("1000000000000").shiftr(1), Decimal("100000000000")); assertEqual(Decimal("1000000000000").shiftr(1, ctx), Decimal("100000000000")); assertRaises(ValueError, [](){ Decimal("NaN").shiftl(100); }); assertRaises(ValueError, [](){ Decimal("sNaN").shiftl(100); }); assertRaises(ValueError, [](){ Decimal("Infinity").shiftl(100); }); assertEqual(Decimal::ln10(9), Decimal("2.30258509")); } /******************************************************************************/ /* Apply */ /******************************************************************************/ static void ApplyTest() { assertEqual(context, context_template); context.prec(2); Decimal d = Decimal("1.234E+200"); assertEqual(+d, Decimal("1.2E+200")); assertEqual(d.apply(context), Decimal("1.2E+200")); assertEqual(Decimal("1.2E+200", context), Decimal("1.2E+200")); d = Decimal("-0"); assertEqualStr(+d, "0"); assertEqualStr(d.apply(context), "-0"); assertEqualStr(Decimal("-0", context), "-0"); d = Decimal("NaN0123456789"); assertEqualStr(+d, "NaN89"); assertEqualStr(d.apply(context), "NaN89"); assertEqualStr(Decimal(d, context), "NaN"); context.add_traps(DecIEEEInvalidOperation); assertRaises(ConversionSyntax, [&](){ Decimal(d, context); }); } /******************************************************************************/ /* Integer conversion */ /******************************************************************************/ static void IntegerConversionTest() { assertEqual(context, context_template); assertEqual(Decimal(INT64_MIN).i64(), INT64_MIN); assertEqual(Decimal(INT64_MAX).i64(), INT64_MAX); assertEqual(Decimal("1E+3").i64(), 1000); assertRaises(ValueError, [](){ Decimal("1E+20").i64(); }); assertRaises(ValueError, [](){ Decimal("-1E+20").i64(); }); assertRaises(ValueError, [](){ Decimal("1E-20").i64(); }); assertRaises(ValueError, [](){ Decimal("nan").i64(); }); assertRaises(ValueError, [](){ Decimal("inf").i64(); }); assertEqual(Decimal(INT32_MIN).i32(), INT32_MIN); assertEqual(Decimal(INT32_MAX).i32(), INT32_MAX); assertEqual(Decimal("1E+3").i32(), 1000); assertRaises(ValueError, [](){ Decimal("1E+11").i32(); }); assertRaises(ValueError, [](){ Decimal("-1E+11").i32(); }); assertRaises(ValueError, [](){ Decimal("1E-11").i32(); }); assertRaises(ValueError, [](){ Decimal("nan").i32(); }); assertRaises(ValueError, [](){ Decimal("inf").i32(); }); assertEqual(Decimal(UINT64_MAX).u64(), UINT64_MAX); assertEqual(Decimal("1E+3").u64(), 1000U); assertRaises(ValueError, [](){ Decimal("-1").u64(); }); assertRaises(ValueError, [](){ Decimal("1E+20").u64(); }); assertRaises(ValueError, [](){ Decimal("-1E+20").u64(); }); assertRaises(ValueError, [](){ Decimal("1E-20").u64(); }); assertRaises(ValueError, [](){ Decimal("nan").u64(); }); assertRaises(ValueError, [](){ Decimal("inf").u64(); }); assertEqual(Decimal(UINT32_MAX).u32(), UINT32_MAX); assertEqual(Decimal("1E+3").u32(), 1000U); assertRaises(ValueError, [](){ Decimal("-1").u32(); }); assertRaises(ValueError, [](){ Decimal("1E+11").u32(); }); assertRaises(ValueError, [](){ Decimal("-1E+11").u32(); }); assertRaises(ValueError, [](){ Decimal("1E-11").u32(); }); assertRaises(ValueError, [](){ Decimal("nan").u32(); }); assertRaises(ValueError, [](){ Decimal("inf").u32(); }); } /******************************************************************************/ /* Exact arithmetic */ /******************************************************************************/ static void ExactArithTest() { assertEqual(context, context_template); context = MaxContext(); assertEqual(Decimal(0).exp(), 1); assertEqual(Decimal(1).ln(), 0); assertEqual(Decimal(1).log10(), 0); assertEqual(Decimal(100).log10(), 2); assertEqual(Decimal("1E+223").log10(), 223); assertEqual(Decimal("1E+19").logb(), 19); assertEqual(Decimal(4).sqrt(), 2); assertEqual(Decimal("40E+9").sqrt(), Decimal("2.0E+5")); assertEqual(Decimal(10).divint(3), 3); assertEqual(Decimal(4) / 2, 2); assertEqual(Decimal(400).pow(-1), Decimal("0.0025")); } /******************************************************************************/ /* Containers and data structures */ /******************************************************************************/ static void DataStructuresTest(void) { assertEqual(context, context_template); /* array */ Decimal *x = new Decimal[10](); for (size_t i = 0; i < 10; i++) { assertTrue(x[i].issnan()); x[i] = i; } for (size_t i = 0; i < 10; i++) { assertEqual(x[i], i); } delete[] x; /* array of pointers */ Decimal **y = new Decimal *[10]; for (size_t i = 0; i < 10; i++) { y[i] = new Decimal(); assertTrue((*y[i]).issnan()); *y[i] = i; } for (size_t i = 0; i < 10; i++) { assertEqual(*y[i], i); } for (size_t i = 0; i < 10; i++) { delete y[i]; } delete[] y; /* linked list */ std::list lst; for (size_t i = 0; i < 10; i++) { lst.push_front(Decimal(i)); } lst.sort(); size_t n = 0; for (const Decimal& d : lst) { assertEqual(d, n++); } /* map */ std::map map1; std::vector keys = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; for (auto& k : keys) { map1[k] = Decimal(k); } for (auto& k : keys) { assertEqual(map1.at(k), Decimal(k)); } /* map */ std::map map2; std::vector values = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; for (auto& v : values) { map2[Decimal(v)] = v; } for (auto& v : values) { assertEqual(map2.at(Decimal(v)), v); } } static void LargeDataStructuresTest(void) { assertEqual(context, context_template); std::vector powers(10); context.prec(10000); context.traps(DecMaxStatus); for (size_t i = 0; i < 10; i++) { powers[i] = Decimal(i).pow(2100); } /* array */ Decimal *x = new Decimal[10](); for (size_t i = 0; i < 10; i++) { assertTrue(x[i].issnan()); x[i] = powers[i]; } for (size_t i = 0; i < 10; i++) { assertEqual(x[i], powers[i]); } delete[] x; /* array of pointers */ Decimal **y = new Decimal *[10]; for (size_t i = 0; i < 10; i++) { y[i] = new Decimal(); assertTrue((*y[i]).issnan()); *y[i] = powers[i]; } for (size_t i = 0; i < 10; i++) { assertEqual(*y[i], powers[i]); } for (size_t i = 0; i < 10; i++) { delete y[i]; } delete[] y; /* linked list */ std::list lst; for (size_t i = 0; i < 10; i++) { lst.push_front(powers[i]); } lst.sort(); size_t n = 0; for (const Decimal& d : lst) { assertEqual(d, powers[n++]); } /* map */ std::map map1; std::vector keys = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; for (size_t i = 0; i < 10; i++) { map1[keys[i]] = powers[i]; } for (size_t i = 0; i < 10; i++) { assertEqual(map1.at(keys[i]), powers[i]); } std::map map2; std::vector values = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; for (size_t i = 0; i < 10; i++) { map2[Decimal(values[i])] = powers[i]; } for (size_t i = 0; i < 10; i++) { assertEqual(map2.at(Decimal(values[i])), powers[i]); } } /******************************************************************************/ /* String and repr */ /******************************************************************************/ static void StringReprTest() { assertEqual(context, context_template); context.traps(DecMaxStatus); std::stringstream ss; Decimal d = Decimal("225E+1000"); ss << d; assertEqual(ss.str(), "2.25E+1002"); assertEqual(d.repr(), "Decimal(\"2.25E+1002\")"); assertEqual(d.repr(true), "Decimal(\"2.25E+1002\")"); assertEqual(d.repr(false), "Decimal(\"2.25e+1002\")"); assertEqual(context.status(), 0U); } /******************************************************************************/ /* Format */ /******************************************************************************/ static void FormatTest() { assertEqual(context, context_template); const std::vector> test_cases = { {"e", "0E-15", "0e-15"}, {"e", "2.3E-15", "2.3e-15"}, {"e", "2.30E+2", "2.30e+2"}, {"e", "2.30000E-15", "2.30000e-15"}, {"e", "1.23456789123456789e40", "1.23456789123456789e+40"}, {"e", "1.5", "1.5e+0"}, {"e", "0.15", "1.5e-1"}, {"e", "0.015", "1.5e-2"}, {"e", "0.0000000000015", "1.5e-12"}, {"e", "15.0", "1.50e+1"}, {"e", "-15", "-1.5e+1"}, {"e", "0", "0e+0"}, {"e", "0E1", "0e+1"}, {"e", "0.0", "0e-1"}, {"e", "0.00", "0e-2"}, {".6e", "0E-15", "0.000000e-9"}, {".6e", "0", "0.000000e+6"}, {".6e", "9.999999", "9.999999e+0"}, {".6e", "9.9999999", "1.000000e+1"}, {".6e", "-1.23e5", "-1.230000e+5"}, {".6e", "1.23456789e-3", "1.234568e-3"}, {"f", "0", "0"}, {"f", "0.0", "0.0"}, {"f", "0E-2", "0.00"}, {"f", "0.00E-8", "0.0000000000"}, {"f", "0E1", "0"}, {"f", "3.2E1", "32"}, {"f", "3.2E2", "320"}, {"f", "3.20E2", "320"}, {"f", "3.200E2", "320.0"}, {"f", "3.2E-6", "0.0000032"}, {".6f", "0E-15", "0.000000"}, {".6f", "0E1", "0.000000"}, {".6f", "0", "0.000000"}, {".0f", "0", "0"}, {".0f", "0e-2", "0"}, {".0f", "3.14159265", "3"}, {".1f", "3.14159265", "3.1"}, {".4f", "3.14159265", "3.1416"}, {".6f", "3.14159265", "3.141593"}, {".7f", "3.14159265", "3.1415926"}, {".8f", "3.14159265", "3.14159265"}, {".9f", "3.14159265", "3.141592650"}, {"g", "0", "0"}, {"g", "0.0", "0.0"}, {"g", "0E1", "0e+1"}, {"G", "0E1", "0E+1"}, {"g", "0E-5", "0.00000"}, {"g", "0E-6", "0.000000"}, {"g", "0E-7", "0e-7"}, {"g", "-0E2", "-0e+2"}, {".0g", "3.14159265", "3"}, {".0n", "3.14159265", "3"}, {".1g", "3.14159265", "3"}, {".2g", "3.14159265", "3.1"}, {".5g", "3.14159265", "3.1416"}, {".7g", "3.14159265", "3.141593"}, {".8g", "3.14159265", "3.1415926"}, {".9g", "3.14159265", "3.14159265"}, {".10g", "3.14159265", "3.14159265"}, {"%", "0E1", "0%"}, {"%", "0E0", "0%"}, {"%", "0E-1", "0%"}, {"%", "0E-2", "0%"}, {"%", "0E-3", "0.0%"}, {"%", "0E-4", "0.00%"}, {".3%", "0", "0.000%"}, {".3%", "0E10", "0.000%"}, {".3%", "0E-10", "0.000%"}, {".3%", "2.34", "234.000%"}, {".3%", "1.234567", "123.457%"}, {".0%", "1.23", "123%"}, {"e", "NaN", "NaN"}, {"f", "-NaN123", "-NaN123"}, {"+g", "NaN456", "+NaN456"}, {".3e", "Inf", "Infinity"}, {".16f", "-Inf", "-Infinity"}, {".0g", "-sNaN", "-sNaN"}, {"", "1.00", "1.00"}, {"6", "123", " 123"}, {"<6", "123", "123 "}, {">6", "123", " 123"}, {"^6", "123", " 123 "}, {"=+6", "123", "+ 123"}, {"#<10", "NaN", "NaN#######"}, {"#<10", "-4.3", "-4.3######"}, {"#<+10", "0.0130", "+0.0130###"}, {"#< 10", "0.0130", " 0.0130###"}, {"@>10", "-Inf", "@-Infinity"}, {"#>5", "-Inf", "-Infinity"}, {"?^5", "123", "?123?"}, {"%^6", "123", "%123%%"}, {" ^6", "-45.6", "-45.6 "}, {"/=10", "-45.6", "-/////45.6"}, {"/=+10", "45.6", "+/////45.6"}, {"/= 10", "45.6", " /////45.6"}, {",", "1234567", "1,234,567"}, {",", "123456", "123,456"}, {",", "12345", "12,345"}, {",", "1234", "1,234"}, {",", "123", "123"}, {",", "12", "12"}, {",", "1", "1"}, {",", "0", "0"}, {",", "-1234567", "-1,234,567"}, {",", "-123456", "-123,456"}, {"7,", "123456", "123,456"}, {"8,", "123456", " 123,456"}, {"08,", "123456", "0,123,456"}, {"+08,", "123456", "+123,456"}, {" 08,", "123456", " 123,456"}, {"08,", "-123456", "-123,456"}, {"+09,", "123456", "+0,123,456"}, {"07,", "1234.56", "1,234.56"}, {"08,", "1234.56", "1,234.56"}, {"09,", "1234.56", "01,234.56"}, {"010,", "1234.56", "001,234.56"}, {"011,", "1234.56", "0,001,234.56"}, {"012,", "1234.56", "0,001,234.56"}, {"08,.1f", "1234.5", "01,234.5"}, {",", "1.23456789", "1.23456789"}, {",%", "123.456789", "12,345.6789%"}, {",e", "123456", "1.23456e+5"}, {",E", "123456", "1.23456E+5"}, {"a=-7.0", "0.12345", "aaaa0.1"}, {"<^+15.20%", "inf", "<<+Infinity%<<<"}, {"\x07>,%", "sNaN1234567", "sNaN1234567%"}, {"=10.10%", "NaN123", " NaN123%"}, }; for (const std::vector& v : test_cases) { const char *fmt = v.at(0); const char *d = v.at(1); const char *result = v.at(2); assertEqual(Decimal(d).format(fmt), result); assertEqual(Decimal(std::string(d)).format(std::string(fmt)), result); } assertRaises(ValueError, [](){ Decimal(1).format("<>=10.10"); }); const std::string fmt = "=" + std::to_string(MPD_SSIZE_MAX) + ".1"; assertRaises(ValueError, [&](){ Decimal("1.23456789").format(fmt); }); } /******************************************************************************/ /* Run tests */ /******************************************************************************/ struct test_case { const char *name; void (*f)(void); }; static const size_t NUM_TESTS = 35; static const std::array test_cases { { /* Context tests */ { "ExceptionHierarchyTest", ExceptionHierarchyTest }, { "IEEEContextTest", IEEEContextTest }, { "ContextGetSetTest", ContextGetSetTest }, { "ContextInputValidationTest", ContextInputValidationTest }, { "SmallContextTest", SmallContextTest }, { "ContextReprTest", ContextReprTest }, /* Decimal tests */ { "ExactConstructionTest", ExactConstructionTest }, { "InexactConstructionTest", InexactConstructionTest }, { "ConstructionExceptionTest", ConstructionExceptionTest }, { "AccessorTest", AccessorTest }, { "UnaryOperatorTest", UnaryOperatorTest }, { "PointerUnaryOperatorTest", PointerUnaryOperatorTest }, { "ComparisonOperatorTest", ComparisonOperatorTest }, { "PointerComparisonOperatorTest", PointerComparisonOperatorTest }, { "AssignmentOperatorTest", AssignmentOperatorTest }, { "PointerAssignmentOperatorTest", PointerAssignmentOperatorTest }, { "ArithmeticOperatorTest", ArithmeticOperatorTest }, { "PointerArithmeticOperatorTest", PointerArithmeticOperatorTest }, { "PredicateTest", PredicateTest }, { "UnaryFunctionTest", UnaryFunctionTest }, { "CeilTest", CeilTest }, { "FloorTest", FloorTest }, { "TruncTest", TruncTest }, { "BinaryFunctionTest", BinaryFunctionTest }, { "DivmodTest", DivmodTest }, { "QuantizeTest", QuantizeTest }, { "TernaryFunctionTest", TernaryFunctionTest }, { "IrregularFunctionTest", IrregularFunctionTest }, { "ApplyTest", ApplyTest }, { "IntegerConversionTest", IntegerConversionTest }, { "ExactArithTest", ExactArithTest }, { "DataStructuresTest", DataStructuresTest }, { "LargeDataStructuresTest", LargeDataStructuresTest }, { "StringReprTest", StringReprTest }, { "FormatTest", FormatTest }, } }; static int exit_status(const std::vector& status) { for (auto p : status) { if (p != "PASS") { return EXIT_FAILURE; } } return EXIT_SUCCESS; } /* run a single function */ static void do_test(const struct test_case& t, std::vector& status, size_t i) { try { assertEqual(context, context_template); t.f(); } catch (Failure& e) { status[i] = e.what(); } } /* process a function list */ static int do_tests(const std::array& tests) { const size_t n = tests.size(); std::vector status(n, "PASS"); for (size_t i = 0; i < n; i++) { std::cout << tests[i].name << " ... " << std::flush; do_test(tests[i], status, i); context = context_template; std::cout << status[i] << "\n" << std::flush; } std::cout << "\n" << std::flush; return exit_status(status); } /* process a file list, threaded */ static int do_tests_threaded(const std::array& tests) { const size_t n = tests.size(); std::vector status(n, "PASS"); std::vector t(n); for (size_t i = 0; i < n; i++) { t[i] = std::thread(do_test, tests[i], std::ref(status), i); } for (size_t i = 0; i < n; i++) { t[i].join(); } for (size_t i = 0; i < n; i++) { std::cout << tests[i].name << " ... " << status[i] << "\n" << std::flush; } std::cout << "\n" << std::flush; return exit_status(status); } /* repeatedly process a randomized function list */ static int do_tests_repeat(const std::array& tests) { const size_t n = tests.size(); std::vector status(n, "PASS"); std::random_device rd; std::mt19937 g(rd()); std::vector a(n); for (size_t i = 0; i < n; i++) { a[i] = i; } for (int64_t i = 0; i < 100; i++) { std::shuffle(a.begin(), a.end(), g); for (size_t k = 0; k < n; k++) { do_test(tests[a[k]], status, a[k]); context = context_template; } if (exit_status(status) != EXIT_SUCCESS) { exit(EXIT_FAILURE); } } return EXIT_SUCCESS; } /* process a file list, threaded */ static int do_tests_threaded_repeat(const std::array& tests) { const size_t n = tests.size(); std::vector status(n, "PASS"); std::vector t(n); std::random_device rd; std::mt19937 g(rd()); std::vector a(n); for (size_t i = 0; i < n; i++) { a[i] = i; } for (int64_t i = 0; i < 100; i++) { std::shuffle(a.begin(), a.end(), g); for (size_t k = 0; k < n; k++) { t[k] = std::thread(do_test, tests[a[k]], std::ref(status), a[k]); } for (size_t k = 0; k < n; k++) { t[k].join(); } if (exit_status(status) != EXIT_SUCCESS) { exit(EXIT_FAILURE); } } return EXIT_SUCCESS; } /* * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77704 * * valgrind --tool=helgrind shows a data race in libstdc++. The race * disappears when streams are used before calling any threads. */ static void init_libc(void) { std::ostringstream ss; ss << 1; } static void usage(void) { std::cerr << "apitest: usage: apitest [--custom] [--thread] [--repeat]" << std::endl; exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { std::vector args(argv + (argc!=0), argv + argc); bool custom_alloc = false; bool thread = false; bool repeat = false; for (auto arg : args) { if (!custom_alloc && arg == "--custom") { custom_alloc = true; } else if (!thread && arg == "--thread") { thread = true; } else if (!repeat && arg == "--repeat") { repeat = true; } else { usage(); } } /* Initialize streams (see above) */ init_libc(); /* Initialize custom allocation functions */ test::init_alloc(custom_alloc, /*check_alloc=*/false); /* Initialize context template */ context_template = Context(9, 999999, -999999, ROUND_HALF_EVEN, 0, 0, 0); /* Initialize context for the main thread */ context = context_template; /* Check version numbers */ static_assert(MPD_MAJOR_VERSION == 4, "MPD_MAJOR_VERSION must be 4"); static_assert(MPD_MINOR_VERSION == 0, "MPD_MINOR_VERSION must be 0"); static_assert(MPD_MICRO_VERSION == 1, "MPD_MICRO_VERSION must be 1"); if (mpd_version() != std::string("4.0.1")) { err_exit("mpd_version() != 4.0.1"); } if (MPD_VERSION != std::string("4.0.1")) { err_exit("MPD_VERSION != 4.0.1"); } /* Check fundamental libmpdec++ invariant */ assertEqual(MPD_MINALLOC, decimal::MINALLOC); if (thread) { if (repeat) { return do_tests_threaded_repeat(test_cases); } else { return do_tests_threaded(test_cases); } } else { if (repeat) { return do_tests_repeat(test_cases); } else { return do_tests(test_cases); } } } mpdecimal-4.0.1/tests++/gettests.bat0000644000000000000000000000037615005764474014241 0ustar00@ECHO OFF cd ..\tests call gettests.bat cd ..\tests++ if not exist testdata mkdir testdata if not exist testdata\baseconv.decTest copy /y ..\tests\testdata_dist\* testdata if not exist testdata\add.decTest copy /y ..\tests\testdata\* testdata mpdecimal-4.0.1/tests++/gettests.sh0000755000000000000000000000015615005764474014104 0ustar00#!/bin/sh cd ../tests && ./gettests.sh "$1" || exit 1 cd ../tests++ && cp -Rp ../tests/testdata . || exit 1 mpdecimal-4.0.1/tests++/official.topTest0000644000000000000000000001343615005764474015050 0ustar00 -- All tests from the dectest directory. Tests that are skipped are -- commented out. Dectest: ./testdata/abs.decTest Dectest: ./testdata/add.decTest Dectest: ./testdata/and.decTest Dectest: ./testdata/base.decTest Dectest: ./testdata/clamp.decTest Dectest: ./testdata/class.decTest Dectest: ./testdata/compare.decTest Dectest: ./testdata/comparetotal.decTest Dectest: ./testdata/comparetotmag.decTest Dectest: ./testdata/copyabs.decTest Dectest: ./testdata/copy.decTest Dectest: ./testdata/copynegate.decTest Dectest: ./testdata/copysign.decTest Dectest: ./testdata/ddAbs.decTest Dectest: ./testdata/ddAdd.decTest Dectest: ./testdata/ddAnd.decTest Dectest: ./testdata/ddBase.decTest -- Dectest: ./testdata/ddCanonical.decTest Dectest: ./testdata/ddClass.decTest Dectest: ./testdata/ddCompare.decTest Dectest: ./testdata/ddCompareSig.decTest Dectest: ./testdata/ddCompareTotal.decTest Dectest: ./testdata/ddCompareTotalMag.decTest Dectest: ./testdata/ddCopyAbs.decTest Dectest: ./testdata/ddCopy.decTest Dectest: ./testdata/ddCopyNegate.decTest Dectest: ./testdata/ddCopySign.decTest Dectest: ./testdata/ddDivide.decTest Dectest: ./testdata/ddDivideInt.decTest -- Dectest: ./testdata/ddEncode.decTest Dectest: ./testdata/ddFMA.decTest Dectest: ./testdata/ddInvert.decTest Dectest: ./testdata/ddLogB.decTest Dectest: ./testdata/ddMax.decTest Dectest: ./testdata/ddMaxMag.decTest Dectest: ./testdata/ddMin.decTest Dectest: ./testdata/ddMinMag.decTest Dectest: ./testdata/ddMinus.decTest Dectest: ./testdata/ddMultiply.decTest Dectest: ./testdata/ddNextMinus.decTest Dectest: ./testdata/ddNextPlus.decTest Dectest: ./testdata/ddNextToward.decTest Dectest: ./testdata/ddOr.decTest Dectest: ./testdata/ddPlus.decTest Dectest: ./testdata/ddQuantize.decTest Dectest: ./testdata/ddReduce.decTest Dectest: ./testdata/ddRemainder.decTest Dectest: ./testdata/ddRemainderNear.decTest Dectest: ./testdata/ddRotate.decTest Dectest: ./testdata/ddSameQuantum.decTest Dectest: ./testdata/ddScaleB.decTest Dectest: ./testdata/ddShift.decTest Dectest: ./testdata/ddSubtract.decTest Dectest: ./testdata/ddToIntegral.decTest Dectest: ./testdata/ddXor.decTest -- Dectest: ./testdata/decDouble.decTest -- Dectest: ./testdata/decQuad.decTest -- Dectest: ./testdata/decSingle.decTest Dectest: ./testdata/divide.decTest Dectest: ./testdata/divideint.decTest Dectest: ./testdata/dqAbs.decTest Dectest: ./testdata/dqAdd.decTest Dectest: ./testdata/dqAnd.decTest Dectest: ./testdata/dqBase.decTest -- Dectest: ./testdata/dqCanonical.decTest Dectest: ./testdata/dqClass.decTest Dectest: ./testdata/dqCompare.decTest Dectest: ./testdata/dqCompareSig.decTest Dectest: ./testdata/dqCompareTotal.decTest Dectest: ./testdata/dqCompareTotalMag.decTest Dectest: ./testdata/dqCopyAbs.decTest Dectest: ./testdata/dqCopy.decTest Dectest: ./testdata/dqCopyNegate.decTest Dectest: ./testdata/dqCopySign.decTest Dectest: ./testdata/dqDivide.decTest Dectest: ./testdata/dqDivideInt.decTest -- Dectest: ./testdata/dqEncode.decTest Dectest: ./testdata/dqFMA.decTest Dectest: ./testdata/dqInvert.decTest Dectest: ./testdata/dqLogB.decTest Dectest: ./testdata/dqMax.decTest Dectest: ./testdata/dqMaxMag.decTest Dectest: ./testdata/dqMin.decTest Dectest: ./testdata/dqMinMag.decTest Dectest: ./testdata/dqMinus.decTest Dectest: ./testdata/dqMultiply.decTest Dectest: ./testdata/dqNextMinus.decTest Dectest: ./testdata/dqNextPlus.decTest Dectest: ./testdata/dqNextToward.decTest Dectest: ./testdata/dqOr.decTest Dectest: ./testdata/dqPlus.decTest Dectest: ./testdata/dqQuantize.decTest Dectest: ./testdata/dqReduce.decTest Dectest: ./testdata/dqRemainder.decTest Dectest: ./testdata/dqRemainderNear.decTest Dectest: ./testdata/dqRotate.decTest Dectest: ./testdata/dqSameQuantum.decTest Dectest: ./testdata/dqScaleB.decTest Dectest: ./testdata/dqShift.decTest Dectest: ./testdata/dqSubtract.decTest Dectest: ./testdata/dqToIntegral.decTest Dectest: ./testdata/dqXor.decTest Dectest: ./testdata/dsBase.decTest -- Dectest: ./testdata/dsEncode.decTest Dectest: ./testdata/exp.decTest Dectest: ./testdata/fma.decTest Dectest: ./testdata/inexact.decTest Dectest: ./testdata/invert.decTest Dectest: ./testdata/ln.decTest Dectest: ./testdata/log10.decTest Dectest: ./testdata/logb.decTest Dectest: ./testdata/max.decTest Dectest: ./testdata/maxmag.decTest Dectest: ./testdata/min.decTest Dectest: ./testdata/minmag.decTest Dectest: ./testdata/minus.decTest Dectest: ./testdata/multiply.decTest Dectest: ./testdata/nextminus.decTest Dectest: ./testdata/nextplus.decTest Dectest: ./testdata/nexttoward.decTest Dectest: ./testdata/or.decTest Dectest: ./testdata/plus.decTest Dectest: ./testdata/power.decTest Dectest: ./testdata/powersqrt.decTest Dectest: ./testdata/quantize.decTest Dectest: ./testdata/randombound32.decTest Dectest: ./testdata/randoms.decTest Dectest: ./testdata/reduce.decTest Dectest: ./testdata/remainder.decTest Dectest: ./testdata/remaindernear.decTest Dectest: ./testdata/rescale.decTest Dectest: ./testdata/rotate.decTest Dectest: ./testdata/rounding.decTest Dectest: ./testdata/samequantum.decTest Dectest: ./testdata/scaleb.decTest Dectest: ./testdata/shift.decTest Dectest: ./testdata/squareroot.decTest Dectest: ./testdata/subtract.decTest -- Dectest: ./testdata/testall.decTest Dectest: ./testdata/tointegral.decTest Dectest: ./testdata/tointegralx.decTest -- Dectest: ./testdata/trim.decTest Dectest: ./testdata/xor.decTest -- Summary of functions that are not implemented or do not need testing: -- Dectest: ./testdata/ddCanonical.decTest ==> same as copy() -- Dectest: ./testdata/ddEncode.decTest -- Dectest: ./testdata/decDouble.decTest -- Dectest: ./testdata/decQuad.decTest -- Dectest: ./testdata/decSingle.decTest -- Dectest: ./testdata/dqCanonical.decTest ==> same as copy() -- Dectest: ./testdata/dqEncode.decTest -- Dectest: ./testdata/dsEncode.decTest -- Dectest: ./testdata/testall.decTest -- Dectest: ./testdata/trim.decTest mpdecimal-4.0.1/tests++/runshort.sh0000755000000000000000000000556115005764474014133 0ustar00#!/bin/sh SYSTEM=`uname -s` case $SYSTEM in darwin*|Darwin*) # malloc() on OS X does not conform to the C standard. export MallocLogFile=/dev/null export MallocDebugReport=crash ;; *) ;; esac # Download or copy the official test cases (text files). ./gettests.sh "$1" || exit 1 if [ ! -f ./runtest -a ! -f ./runtest_shared ]; then printf "\nERROR: ./runtest and ./runtest_shared not found\n\n\n"; exit 1; fi if [ -f ./runtest ]; then printf "\n# ========================================================================\n" printf "# libmpdec++: static library\n" printf "# ========================================================================\n\n" if [ x"$1" != x"--local" ]; then printf "Running official tests ...\n\n" ./runtest official.topTest --thread || { printf "\nFAIL\n\n\n"; exit 1; } fi printf "Running additional tests ...\n\n" ./runtest additional.topTest --thread || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running API tests (single thread) ... \n\n" ./apitest || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running API tests (threaded) ... \n\n" ./apitest --thread || { printf "\nFAIL\n\n\n"; exit 1; } fi if [ -f ./runtest_shared ]; then printf "\n# ========================================================================\n" printf "# libmpdec++: shared library\n" printf "# ========================================================================\n\n" PORTABLE_PWD=`pwd` LD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_LIBRARY_PATH" DYLD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$DYLD_LIBRARY_PATH" LD_64_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_64_LIBRARY_PATH" LD_32_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_32_LIBRARY_PATH" LD_LIBRARY_PATH_64="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_LIBRARY_PATH_64" LD_LIBRARY_PATH_32="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_LIBRARY_PATH_32" PATH="$LD_LIBRARY_PATH:$PATH" export LD_LIBRARY_PATH export DYLD_LIBRARY_PATH export LD_64_LIBRARY_PATH export LD_32_LIBRARY_PATH export LD_LIBRARY_PATH_64 export LD_LIBRARY_PATH_32 if [ x"$1" != x"--local" ]; then printf "Running official tests ...\n\n" ./runtest_shared official.topTest --thread || { printf "\nFAIL\n\n\n"; exit 1; } fi printf "Running additional tests ...\n\n" ./runtest_shared additional.topTest --thread || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running API tests (single thread) ... \n\n" ./apitest_shared || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running API tests (threaded) ... \n\n" ./apitest_shared --thread || { printf "\nFAIL\n\n\n"; exit 1; } fi mpdecimal-4.0.1/tests++/runshort_alloc.sh0000755000000000000000000000561115005764474015301 0ustar00#!/bin/sh SYSTEM=`uname -s` case $SYSTEM in darwin*|Darwin*) # malloc() on OS X does not conform to the C standard. export MallocLogFile=/dev/null export MallocDebugReport=crash ;; *) ;; esac # Download or copy the official test cases (text files). ./gettests.sh || exit 1 if [ ! -f ./runtest -a ! -f ./runtest_shared ]; then printf "\nERROR: ./runtest and ./runtest_shared not found\n\n\n"; exit 1; fi if [ -f ./runtest ]; then printf "\n# ========================================================================\n" printf "# libmpdec++: static library\n" printf "# ========================================================================\n\n" printf "Running official tests with allocation failures ...\n\n" ./runtest official.topTest --thread --alloc || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running additional tests with allocation failures ...\n\n" ./runtest additional.topTest --thread --alloc || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running API tests (single thread) ... \n\n" ./apitest || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running API tests (threaded) ... \n\n" ./apitest --thread || { printf "\nFAIL\n\n\n"; exit 1; } fi if [ -f ./runtest_shared ]; then printf "\n# ========================================================================\n" printf "# libmpdec++: shared library\n" printf "# ========================================================================\n\n" PORTABLE_PWD=`pwd` LD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_LIBRARY_PATH" DYLD_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$DYLD_LIBRARY_PATH" LD_64_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_64_LIBRARY_PATH" LD_32_LIBRARY_PATH="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_32_LIBRARY_PATH" LD_LIBRARY_PATH_64="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_LIBRARY_PATH_64" LD_LIBRARY_PATH_32="$PORTABLE_PWD/../libmpdec:$PORTABLE_PWD/../libmpdec++:$LD_LIBRARY_PATH_32" PATH="$LD_LIBRARY_PATH:$PATH" export LD_LIBRARY_PATH export DYLD_LIBRARY_PATH export LD_64_LIBRARY_PATH export LD_32_LIBRARY_PATH export LD_LIBRARY_PATH_64 export LD_LIBRARY_PATH_32 printf "Running official tests with allocation failures ...\n\n" ./runtest_shared official.topTest --thread --alloc || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running additional tests with allocation failures ...\n\n" ./runtest_shared additional.topTest --thread --alloc || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running API tests (single thread) ... \n\n" ./apitest_shared || { printf "\nFAIL\n\n\n"; exit 1; } printf "Running API tests (threaded) ... \n\n" ./apitest_shared --thread || { printf "\nFAIL\n\n\n"; exit 1; } fi mpdecimal-4.0.1/tests++/runtest.cc0000644000000000000000000030157415005764474013726 0ustar00/* * Copyright (c) 2020-2025 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. */ #ifdef _AIX #define __STDC_FORMAT_MACROS #endif #ifndef _MSC_VER #include "config.h" #ifdef HAVE_PTHREAD_H #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mpdecimal.h" #include "decimal.hh" #include "test.hh" #include "vctest.hh" using decimal::ValueError; using decimal::MallocError; using decimal::RuntimeError; using decimal::InvalidOperation; using decimal::Decimal; using decimal::Context; using decimal::context_template; using decimal::context; using decimal::util::safe_downcast; #if defined(MPD_CONFIG_32) using test::set_alloc_limit; #endif using test::set_alloc; using test::set_alloc_fail; enum skip_cmp {SKIP_NONE, SKIP_NAN, SKIP_NONINT}; /* * These extended ranges are required for the official test suite and are * not problematic for its specific test cases. However, they should not * be used in production code. * * The use of the directive "ExtendedRange" is not related to the "Extended" * directive that is briefly referred to in the official tests. */ #if defined(MPD_CONFIG_64) #define MPD_READ_MAX_PREC 1070000000000000000LL #elif defined(MPD_CONFIG_32) #define MPD_READ_MAX_PREC 1070000000 #else #error "config not defined" #endif static mpd_context_t readcontext(const bool extended) { mpd_context_t c; if (extended) { c.prec = MPD_READ_MAX_PREC; c.emax = MPD_READ_MAX_PREC; c.emin = -MPD_READ_MAX_PREC; } else { c.prec = MPD_MAX_PREC; c.emax = MPD_MAX_EMAX; c.emin = MPD_MIN_EMIN; } c.traps = MPD_Malloc_error; c.status = 0; c.newtrap = 0; c.round = MPD_ROUND_HALF_UP; c.clamp = 0; c.allcr = 1; return c; } static mpd_context_t testcontext(const bool extended) { mpd_context_t c; if (extended) { #if defined(MPD_CONFIG_64) c.prec = MPD_MAX_PREC; c.emax = MPD_MAX_EMAX; c.emin = MPD_MIN_EMIN; #elif defined(MPD_CONFIG_32) c.prec = 999999999; c.emax = 999999999; c.emin = -999999999; #else #error "config not defined" #endif } else { c.prec = MPD_MAX_PREC; c.emax = MPD_MAX_EMAX; c.emin = MPD_MIN_EMIN; } c.traps = MPD_Malloc_error; c.status = 0; c.newtrap = 0; c.round = MPD_ROUND_HALF_UP; c.clamp = 0; c.allcr = 1; return c; } static void mpd_assert_context_ok(const Context& c, const std::vector& token) { const mpd_context_t *ctx = c.getconst(); DECIMAL_ASSERT(0 < ctx->prec && ctx->prec <= MPD_READ_MAX_PREC, token); DECIMAL_ASSERT(0 <= ctx->emax && ctx->emax <= MPD_READ_MAX_PREC, token); DECIMAL_ASSERT(-MPD_READ_MAX_PREC <= ctx->emin && ctx->emin <= 0, token); DECIMAL_ASSERT(0 <= ctx->round && ctx->round < MPD_ROUND_GUARD, token); DECIMAL_ASSERT(ctx->traps <= MPD_Max_status, token); DECIMAL_ASSERT(ctx->status <= MPD_Max_status, token); DECIMAL_ASSERT(ctx->clamp == 0 || ctx->clamp == 1, token); DECIMAL_ASSERT(ctx->allcr == 0 || ctx->allcr == 1, token); } /* Known differences that are within the spec */ struct result_diff { const char *id; const char *calc; const char *expected; }; struct status_diff { const char *id; uint32_t calc; uint32_t expected; }; static const struct result_diff ulp_cases[] { /* Cases where the result is allowed to differ by less than one ULP. * Only needed if ctx->allcr is 0. */ { "expx013", "1.001000", "1.001001" }, { "expx020", "1.000000", "1.000001" }, { "expx109", "0.999999910000004049999878", "0.999999910000004049999879" }, { "expx1036", "1.005088", "1.005087" }, { "expx350", "1.0000000", "1.0000001" }, { "expx351", "1.0000000", "1.0000001" }, { "expx352", "1.0000000", "1.0000001" }, }; static const struct status_diff status_cases[] { /* With a reduced working precision in mpd_qpow() the status matches. */ { "pwsx803", MPD_Inexact|MPD_Rounded|MPD_Subnormal|MPD_Underflow, MPD_Inexact|MPD_Rounded }, }; static const char *skipit[] { /* NULL reference, decimal16, decimal32, or decimal128 */ "absx900", "addx9990", "addx9991", "clam090", "clam091", "clam092", "clam093", "clam094", "clam095", "clam096", "clam097", "clam098", "clam099", "clam189", "clam190", "clam191", "clam192", "clam193", "clam194", "clam195", "clam196", "clam197", "clam198", "clam199", "comx990", "comx991", "cotx9990", "cotx9991", "ctmx9990", "ctmx9991", "ddabs900", "ddadd9990", "ddadd9991", "ddcom9990", "ddcom9991", "ddcot9990", "ddcot9991", "ddctm9990", "ddctm9991", "dddiv9998", "dddiv9999", "dddvi900", "dddvi901", "ddfma2990", "ddfma2991", "ddfma39990", "ddfma39991", "ddlogb900", "ddmax900", "ddmax901", "ddmxg900", "ddmxg901", "ddmin900", "ddmin901", "ddmng900", "ddmng901", "ddmul9990", "ddmul9991", "ddnextm900", "ddnextm900", "ddnextp900", "ddnextp900", "ddnextt900", "ddnextt901", "ddqua998", "ddqua999", "ddred900", "ddrem1000", "ddrem1001", "ddrmn1000", "ddrmn1001", "ddsub9990", "ddsub9991", "ddintx074", "ddintx094", "divx9998", "divx9999", "dvix900", "dvix901", "dqabs900", "dqadd9990", "dqadd9991", "dqcom990", "dqcom991", "dqcot9990", "dqcot9991", "dqctm9990", "dqctm9991", "dqdiv9998", "dqdiv9999", "dqdvi900", "dqdvi901", "dqfma2990", "dqfma2991", "dqadd39990", "dqadd39991", "dqlogb900", "dqmax900", "dqmax901", "dqmxg900", "dqmxg901", "dqmin900", "dqmin901", "dqmng900", "dqmng901", "dqmul9990", "dqmul9991", "dqnextm900", "dqnextp900", "dqnextt900", "dqnextt901", "dqqua998", "dqqua999", "dqred900", "dqrem1000", "dqrem1001", "dqrmn1000", "dqrmn1001", "dqsub9990", "dqsub9991", "dqintx074", "dqintx094", "expx900", "fmax2990", "fmax2991", "fmax39990", "fmax39991", "lnx900", "logx900", "logbx900", "maxx900", "maxx901", "mxgx900", "mxgx901", "mnm900", "mnm901", "mng900", "mng901", "minx900", "mulx990", "mulx991", "nextm900", "nextp900", "nextt900", "nextt901", "plu900", "powx900", "powx901", "pwsx900", "quax1022", "quax1023", "quax1024", "quax1025", "quax1026", "quax1027", "quax1028", "quax1029", "quax0a2", "quax0a3", "quax998", "quax999", "redx900", "remx1000", "remx1001", "rmnx900", "rmnx901", "sqtx9900", "subx9990", "subx9991", /* operand range violations, invalid context */ "expx901", "expx902", "expx903", "expx905", "lnx901", "lnx902", "lnx903", "lnx905", "logx901", "logx902", "logx903", "logx905", "powx1183", "powx1184", "powx4001", "powx4002", "powx4003", "powx4005", "powx4008", "powx4010", "powx4012", "powx4014", "scbx164", "scbx165", "scbx166", #if defined(MPD_CONFIG_32) && MPD_MINALLOC_MAX <= 4 /* Under the allocation failure tests, the result is numerically correct (1 == 1.00000) but without zero padding. This is by design, since in case of MPD_Malloc_error mpd_qsqrt() retries the operation with a lower context precision and allows all exact results. The MPD_MINALLOC_MAX < 64 feature is is officially unsupported but works (if the little-endian mpd_ln10_data arrays are adjusted). */ "sqtx9045", #endif /* skipped for decNumber, too */ "powx4302", "powx4303", "powx4303", "powx4342", "powx4343", "pwsx805", /* disagreement for three arg power */ "pwmx325", "pwmx326", }; static mpd_ssize_t strtossize(const char *s, char **end, int base) { int64_t retval; errno = 0; retval = _mpd_strtossize(s, end, base); if (errno == 0 && (retval > MPD_SSIZE_MAX || retval < MPD_SSIZE_MIN)) { errno = ERANGE; } if (errno == ERANGE) { return (retval < 0) ? MPD_SSIZE_MIN : MPD_SSIZE_MAX; } return static_cast(retval); } static uint64_t rnd(void) { static thread_local std::mt19937_64 r(time(nullptr)); return r(); } static void mpd_init_rand(Decimal &x) { Context maxcontext{readcontext(false)}; uint64_t r = rnd() % 100; uint8_t sign = rnd() % 2; if (r >= 80) { x = Decimal("-1111111111e20200", maxcontext); } else if (r >= 60) { x = Decimal("-1111111111222222222233333333334444444444555555555566666666667777777777" "888888888899999999990000000000e-1201", maxcontext); } else if (r >= 40) { x = sign ? Decimal("-nan") : Decimal("nan"); } else if (r >= 20) { x = sign ? Decimal("-snan") : Decimal("snan"); } else { x = sign ? Decimal("-inf") : Decimal("inf"); } } static bool skip_test(const std::string& id) { const auto& loc = std::find(std::begin(skipit), std::end(skipit), id); if (loc != std::end(skipit)) { return true; } return false; } static bool startswith(const std::string& s, const char *prefix) { return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0; } static bool endswith(const std::string& s, const char *suffix) { std::string rs(s); std::string prefix(suffix); std::reverse(rs.begin(), rs.end()); std::reverse(prefix.begin(), prefix.end()); return startswith(rs, prefix.c_str()); } static bool eqtoken(const std::string& tok, const char *s) { return strcasecmp(tok.c_str(), s) == 0; } static bool istokchar(unsigned char c) { return std::isalnum(c) || (std::ispunct(c) && c != '"' && c != '\''); } static int nexttoken(std::string::const_iterator& start, std::string::const_iterator& end, std::string::const_iterator& next_start, const std::string::const_iterator& nul) { end = next_start; for (; end != nul; end++) { if (isspace(static_cast(*end))) { /* empty */ } else if (*end == '-' && (end+1) != nul && *(end+1) == '-') { start = end = next_start = nul; return 0; } else if (*end == '"') { start = ++end; for (; end != nul; end++) { if (*end == '"') { if ((end+1) != nul && *(end+1) == '"') { end++; /* official test cases: "1""1" is parsed as a single string. */ } else { next_start = end+1; return 0; } } } return -1; } else if (*end == '\'') { start = ++end; for (; end != nul; end++) { if (*end == '\'') { if ((end+1) != nul && *(end+1) == '\'') { end++; /* official test cases: '1''1' is parsed as a single string. */ } else { next_start = end+1; return 0; } } } return -1; } else { start = end; for (; end != nul; end++) { if (std::isspace(static_cast(*end))) { break; } if (!istokchar(static_cast(*end))) { return -1; } } next_start = end; return 0; } } start = next_start = end; return 0; } /* split a line into tokens */ static std::vector split(const std::string& line) { std::string::const_iterator start = line.begin(); std::string::const_iterator end = start; std::string::const_iterator next_start = start; const std::string::const_iterator nul = line.end(); std::vector token; while (true) { const int r = nexttoken(start, end, next_start, nul); if (r < 0) { std::cerr << "parse_error: " << line << std::endl; std::exit(EXIT_FAILURE); } if (end == start && end == next_start) { break; } std::string tok{start, end}; token.push_back(tok); } return token; } /* returns all expected conditions in a status flag */ static uint32_t scan_conditions(const std::vector& token, const size_t n) { uint32_t status = 0; for (size_t i = n; i < token.size(); i++) { const std::string condition = token[i]; if (eqtoken(condition, "Clamped")) { status |= MPD_Clamped; } else if (eqtoken(condition, "Conversion_syntax")) { status |= MPD_Conversion_syntax; } else if (eqtoken(condition, "Division_by_zero")) { status |= MPD_Division_by_zero; } else if (eqtoken(condition, "Division_impossible")) { status |= MPD_Division_impossible; } else if (eqtoken(condition, "Division_undefined")) { status |= MPD_Division_undefined; } else if (eqtoken(condition, "Fpu_error")) { status |= MPD_Fpu_error; } else if (eqtoken(condition, "Inexact")) { status |= MPD_Inexact; } else if (eqtoken(condition, "Invalid_context")) { status |= MPD_Invalid_context; } else if (eqtoken(condition, "Invalid_operation")) { status |= MPD_Invalid_operation; } else if (eqtoken(condition, "Malloc_error")) { status |= MPD_Malloc_error; } else if (eqtoken(condition, "Not_implemented")) { status |= MPD_Not_implemented; } else if (eqtoken(condition, "Overflow")) { status |= MPD_Overflow; } else if (eqtoken(condition, "Rounded")) { status |= MPD_Rounded; } else if (eqtoken(condition, "Subnormal")) { status |= MPD_Subnormal; } else if (eqtoken(condition, "Underflow")) { status |= MPD_Underflow; } else { err_token(token, "scan_conditions: unknown status"); } } return status; } static void compare_expected(const std::vector& token, const std::string& calc, const std::string& expected, uint32_t expected_status, const Context& ctx) { const std::string id = token.at(0); /* known ULP diffs */ if (ctx.allcr() == 0) { for (const auto& c : ulp_cases) { if (id == c.id && expected == c.expected && calc == c.calc) { return; } } } /* known status diffs */ for (const auto& c : status_cases) { if (id == c.id && expected_status == c.expected && ctx.status() == c.calc) { return; } } if (calc != expected) { err_token(token, "calc: ", calc, " expected: ", expected); } if (ctx.status() != expected_status) { char ctxstatus[MPD_MAX_FLAG_STRING]; char expstatus[MPD_MAX_FLAG_STRING]; mpd_snprint_flags(ctxstatus, MPD_MAX_FLAG_STRING, ctx.status()); mpd_snprint_flags(expstatus, MPD_MAX_FLAG_STRING, expected_status); err_token(token, "calc: [", ctxstatus, "] expected: [", expstatus, "]"); } } static bool equalmem(const Decimal& x, const Decimal& y) { const mpd_t *a = x.getconst(); const mpd_t *b = y.getconst(); if ((a->flags & ~MPD_DATAFLAGS) != (b->flags & ~MPD_DATAFLAGS) || a->exp != b->exp || a->len != b->len || a->digits != b->digits) { return false; } for (mpd_ssize_t i = 0; i < a->len; i++) { if (a->data[i] != b->data[i]) { return false; } } return true; } static void check_equalmem(const std::vector& token, const Decimal& a, const Decimal& b) { if (!equalmem(a, b)) { err_token(token, "const arg changed"); } } static unsigned long get_testno(const std::vector& token) { const char *number = strpbrk(token.at(0).c_str(), "0123456789"); if (number == nullptr) { err_token(token, "invalid test id: ", token.at(0)); } return strtoul(number, nullptr, 10); } /* scan a single operand and the expected result */ static size_t scan_op_expected(Decimal& op, std::string& expected, const std::vector& token, Context& ctx) { op = Decimal(token.at(2), ctx); if (token.at(3) != "->") { err_token(token, "expected '->' token"); } expected = token.at(4); return 5; } /* scan decimal operand, string operand and the expected result */ static size_t scan_op_string_expected(Decimal& op1, std::string& op2, std::string& result, const std::vector& token, Context& ctx) { op1 = Decimal(token.at(2), ctx); op2 = token.at(3); if (token.at(4) != "->") { err_token(token, "expected '->' token"); } result = token.at(5); return 6; } /* scan two operands and the expected result */ static size_t scan_op_op_expected(Decimal& op1, Decimal& op2, std::string& result, const std::vector& token, Context& ctx) { op1 = Decimal(token.at(2), ctx); op2 = Decimal(token.at(3), ctx); if (token.at(4) != "->") { err_token(token, "expected '->' token"); } result = token.at(5); return 6; } /* scan one operands and two results */ static size_t scan_op_expected_expected(Decimal& op1, std::string& result1, std::string& result2, const std::vector& token, Context& ctx) { op1 = Decimal(token.at(2), ctx); if (token.at(3) != "->") { err_token(token, "expected '->' token"); } result1 = token.at(4); result2 = token.at(5); return 6; } /* scan two operands and two results */ static size_t scan_op_op_expected_expected(Decimal& op1, Decimal& op2, std::string& result1, std::string& result2, const std::vector& token, Context& ctx) { op1 = Decimal(token.at(2), ctx); op2 = Decimal(token.at(3), ctx); if (token.at(4) != "->") { err_token(token, "expected '->' token"); } result1 = token.at(5); result2 = token.at(6); return 7; } /* scan three operands and the expected result */ static size_t scan_op_op_op_expected(Decimal& op1, Decimal& op2, Decimal& op3, std::string& result, const std::vector& token, Context& ctx) { op1 = Decimal(token.at(2), ctx); op2 = Decimal(token.at(3), ctx); op3 = Decimal(token.at(4), ctx); if (token.at(5) != "->") { err_token(token, "expected '->' token"); } result = token.at(6); return 7; } /* Triple tests */ static void Triple(const std::vector& token, const Decimal &dec, Context &ctx) { #ifdef MPD_CONFIG_32 /* * 32-bit: as_triple() expects well-formed decimals. Skip test cases * that use the extended exponent, which is safe in the tests but not * in production. */ if (!dec.isspecial()) { if (dec.exponent() < MPD_MIN_ETINY || dec.exponent() > MPD_MAX_EMAX) { return; } } #endif mpd_uint128_triple_t triple = dec.as_uint128_triple(); switch (triple.tag) { case MPD_TRIPLE_QNAN: case MPD_TRIPLE_SNAN: DECIMAL_ASSERT(triple.exp == 0, token); break; case MPD_TRIPLE_INF: DECIMAL_ASSERT(triple.hi == 0 && triple.lo == 0 && triple.exp == 0, token); break; case MPD_TRIPLE_NORMAL: break; case MPD_TRIPLE_ERROR: DECIMAL_ASSERT(triple.sign == 0 && triple.hi == 0 && triple.lo == 0 && triple.exp == 0, token); return; } /* Allocation failures in Decimal(triple) */ Decimal d = 10; for (uint64_t n = 1; n < UINT64_MAX-1; n++) { set_alloc_fail(ctx, n); try { d = Decimal(triple); } catch (MallocError&) { set_alloc(ctx); DECIMAL_ASSERT(d == 10, token); continue; } set_alloc(ctx); break; } check_equalmem(token, d, dec); DECIMAL_ASSERT(d.cmp_total(dec) == 0, token); } /* * This function is used for "toSci", "toEng" and "apply" and does not use * a maxcontext for the conversion of the operand. */ typedef std::string (Decimal::*String_DecimalContext)(bool) const; static void Str_DecCtx(String_DecimalContext func, const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op; Decimal tmp; std::string expected; std::string expected_fail; std::string calc; Context& workctx = context; workctx.status(0); const size_t i = scan_op_expected(op, expected, token, workctx); const uint32_t expstatus = scan_conditions(token, i); if (expstatus != workctx.status()) { err_token(token, "op: ", op, " expstatus: ", expstatus, " got: ", workctx.status()); } Triple(token, op, workctx); /* Allocation failures for Decimal() */ for (uint64_t n = 1; n < UINT64_MAX-1; n++) { mpd_init_rand(tmp); const Decimal save_tmp = tmp; workctx.status(0); set_alloc_fail(workctx, n); try { (void)scan_op_expected(tmp, expected_fail, token, workctx); } catch (MallocError&) { set_alloc(workctx); check_equalmem(token, tmp, save_tmp); continue; } set_alloc(workctx); break; } /* internal sanity checks */ DECIMAL_ASSERT(expected == expected_fail, token); DECIMAL_ASSERT(tmp.cmp_total(op) == 0, token); /* make a copy of the operand */ mpd_init_rand(tmp); tmp = op; workctx.status(0); calc = (tmp.*func)(true); /* compare the calculated result with the expected result */ compare_expected(token, calc, expected, 0, workctx); check_equalmem(token, tmp, op); /* Allocation failures */ for (uint64_t n = 1; n < UINT64_MAX-1; n++) { mpd_init_rand(tmp); tmp = op; workctx.status(0); set_alloc_fail(workctx, n); try { calc = (tmp.*func)(true); } catch (MallocError&) { set_alloc(context); check_equalmem(token, tmp, op); continue; } set_alloc(workctx); break; } compare_expected(token, calc, expected, 0, workctx); check_equalmem(token, tmp, op); } #ifdef __INTEL_COMPILER #pragma warning(disable : 186) #endif /* Quick and dirty: parse hex escape sequences */ static std::string parse_escapes_backslash(const char *s) { char hex[5]; char *result, *cp; unsigned int u; unsigned char b; int n; std::shared_ptr ptr(new char[strlen(s)+1], std::default_delete()); cp = result = ptr.get(); hex[0] = '0'; hex[1] = '\0'; while (*s) { if (*s == '\\' && *(s+1) == 'x') { for (n = 1; n < 4; n++) { if (!s[n]) { err_raise("parse hex escapes: invalid escape sequence"); } hex[n] = s[n]; } hex[n] = '\0'; sscanf(hex, "%x%n", &u, &n); b = safe_downcast(u); *cp++ = static_cast(b); s += n; } else { *cp++ = *s++; } } *cp = '\0'; return std::string(result); } static std::string parse_escapes_hexstring(const char *s) { const std::string hex{s}; const size_t len = hex.size(); std::vector bytes; if (len % 2 != 0) { err_raise("parse hex escapes: invalid escape sequence"); } for (size_t i = 0; i < len; i += 2) { std::string twodigits = hex.substr(i, 2); const unsigned long ul = strtoul(twodigits.c_str(), nullptr, 16); const unsigned char b = safe_downcast(ul); bytes.push_back(static_cast(b)); } return std::string(bytes.data(), bytes.size()); } static std::string parse_escapes(const char *s) { if (startswith(s, "HEX")) { return parse_escapes_hexstring(s+3); } else { return parse_escapes_backslash(s); } } /* This function is used for Decimal::format. */ static void Fmt(const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op, tmp; std::string fmt, expected; std::string calc; const size_t i = scan_op_string_expected(op, fmt, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, i); Triple(token, op, maxcontext); fmt = parse_escapes(fmt.c_str()); expected = parse_escapes(expected.c_str()); mpd_init_rand(tmp); tmp = op; context.status(0); try { calc = tmp.format(fmt); } catch (ValueError&) { DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token); DECIMAL_ASSERT(context.status() == 0, token); check_equalmem(token, tmp, op); #ifdef __mips__ return; #endif } DECIMAL_ASSERT(expstatus == 0 || expstatus == MPD_Invalid_operation, token); if (expstatus == 0) { compare_expected(token, calc, expected, expstatus, context); check_equalmem(token, tmp, op); } for (uint64_t n = 1; n < UINT64_MAX-1; n++) { mpd_init_rand(tmp); tmp = op; context.status(0); set_alloc_fail(context, n); try { calc = tmp.format(fmt); } catch (MallocError&) { set_alloc(context); continue; } #ifndef __mips__ /* miscompilation */ catch (ValueError&) { DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token); DECIMAL_ASSERT(context.status() == 0, token); } #endif set_alloc(context); break; } DECIMAL_ASSERT(expstatus == 0 || expstatus == MPD_Invalid_operation, token); if (expstatus == 0) { compare_expected(token, calc, expected, expstatus, context); check_equalmem(token, tmp, op); } } /* test number class */ static void Class(const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op, tmp; std::string expected; const size_t n = scan_op_expected(op, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); mpd_init_rand(tmp); tmp = op; context.status(0); std::string calc = tmp.number_class(context); compare_expected(token, calc, expected, expstatus, context); check_equalmem(token, tmp, op); } /* test a unary function */ typedef Decimal (Decimal::*Decimal_Decimal)() const; static void Dec_Dec_RunSingle(Decimal& result, Decimal& tmp, const std::vector& token, const Decimal_Decimal func, const Decimal& op, const std::string& expected, const uint32_t expstatus) { uint64_t incr = 1; for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) { mpd_init_rand(result); mpd_init_rand(tmp); tmp = op; const Decimal save_result = result; context.status(0); set_alloc_fail(context, n); try { result = (tmp.*func)(); } catch (MallocError&) { set_alloc(context); check_equalmem(token, result, save_result); check_equalmem(token, tmp, op); if (n > 50) { incr = rnd() % 100 + 1; } continue; } set_alloc(context); break; } const std::string calc = result.to_sci(); compare_expected(token, calc, expected, expstatus, context); if (&tmp != &result) { check_equalmem(token, tmp, op); } } static void Dec_Dec(Decimal_Decimal func, const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op, result, tmp; std::string expected; const size_t n = scan_op_expected(op, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); Dec_Dec_RunSingle(result, tmp, token, func, op, expected, expstatus); Dec_Dec_RunSingle(tmp, tmp, token, func, op, expected, expstatus); } /* test a unary function with an optional context argument */ typedef Decimal (Decimal::*Decimal_DecimalContext)(Context&) const; static void Dec_DecCtx_RunSingle(Decimal& result, Decimal& tmp, const std::vector& token, const Decimal_DecimalContext func, const Decimal& op, const std::string& expected, const uint32_t expstatus) { uint64_t incr = 1; for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) { mpd_init_rand(result); mpd_init_rand(tmp); tmp = op; const Decimal save_result = result; context.status(0); set_alloc_fail(context, n); try { result = (tmp.*func)(context); } catch (MallocError&) { set_alloc(context); check_equalmem(token, result, save_result); check_equalmem(token, tmp, op); if (n > 50) { incr = rnd() % 100 + 1; } continue; } set_alloc(context); break; } const std::string calc = result.to_sci(); compare_expected(token, calc, expected, expstatus, context); if (&tmp != &result) { check_equalmem(token, tmp, op); } } static void Dec_DecCtx(Decimal_DecimalContext func, const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op, result, tmp; std::string expected; const size_t n = scan_op_expected(op, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); Dec_DecCtx_RunSingle(result, tmp, token, func, op, expected, expstatus); Dec_DecCtx_RunSingle(tmp, tmp, token, func, op, expected, expstatus); } /* Same as Dec_DecCtx, but quantize the operand before applying the actual function */ static void Dec_DecCtxWithQuantize(Decimal_DecimalContext func, const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op, scale, result, tmp; std::string expected; const size_t n = scan_op_op_expected(op, scale, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); Triple(token, scale, maxcontext); op = op.quantize(scale, maxcontext); Dec_DecCtx_RunSingle(result, tmp, token, func, op, expected, expstatus); Dec_DecCtx_RunSingle(tmp, tmp, token, func, op, expected, expstatus); } /* Test a binary function */ typedef Decimal (Decimal::*Decimal_DecimalDecimalContext)(const Decimal&, Context&) const; static void resolve_status_hack(uint32_t& expstatus, const uint32_t status) { /* hack #1 to resolve disagreement with results generated by decimal.py */ if ((expstatus & MPD_Invalid_operation) && (status & MPD_Division_impossible)) { expstatus = MPD_Division_impossible; } /* hack #2 to resolve disagreement with results generated by decimal.py */ if ((expstatus & MPD_Invalid_operation) && (status & MPD_Division_undefined)) { expstatus = MPD_Division_undefined; } } static void Dec_DecDecCtx_RunSingle(Decimal& result, Decimal& tmp1, Decimal& tmp2, const std::vector& token, const Decimal_DecimalDecimalContext func, const Decimal& op1, const Decimal &op2, const std::string& expected, const uint32_t expstatus) { uint64_t incr = 1; for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); tmp1 = op1; tmp2 = op2; const Decimal save_result = result; context.status(0); set_alloc_fail(context, n); try { result = (tmp1.*func)(tmp2, context); } catch (MallocError&) { set_alloc(context); check_equalmem(token, result, save_result); check_equalmem(token, tmp1, op1); check_equalmem(token, tmp2, op2); if (n > 50) { incr = rnd() % 100 + 1; } continue; } set_alloc(context); break; } const std::string calc = result.to_sci(); compare_expected(token, calc, expected, expstatus, context); if (&tmp1 != &result) { check_equalmem(token, tmp1, op1); } if (&tmp2 != &result) { check_equalmem(token, tmp2, op2); } } static void Dec_DecDecCtx(const Decimal_DecimalDecimalContext func, const std::vector& token, const bool scan_equal, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal result, tmp1, tmp2; Decimal op1, op2; std::string expected; uint32_t expstatus; size_t n; if (scan_equal) { n = scan_op_expected(op1, expected, token, maxcontext); op2 = op1; } else { n = scan_op_op_expected(op1, op2, expected, token, maxcontext); } expstatus = scan_conditions(token, n); Triple(token, op1, maxcontext); Triple(token, op2, maxcontext); context.status(0); result = (op1.*func)(op2, context); Dec_DecDecCtx_RunSingle(result, tmp1, tmp2, token, func, op1, op2, expected, expstatus); Dec_DecDecCtx_RunSingle(tmp1, tmp1, tmp2, token, func, op1, op2, expected, expstatus); Dec_DecDecCtx_RunSingle(tmp2, tmp1, tmp2, token, func, op1, op2, expected, expstatus); if (equalmem(op1, op2)) { Dec_DecDecCtx_RunSingle(result, tmp1, tmp1, token, func, op1, op2, expected, expstatus); Dec_DecDecCtx_RunSingle(tmp1, tmp1, tmp1, token, func, op1, op2, expected, expstatus); } } /* Test a binary function with a binary result */ typedef std::pair (Decimal::*DecimalPair_DecimalDecimalContext)(const Decimal&, Context&) const; static void DecPair_DecDecCtx_RunSingle(std::pair& result, Decimal& tmp1, Decimal& tmp2, const std::vector& token, const DecimalPair_DecimalDecimalContext func, const Decimal& op1, const Decimal &op2, const std::string& expected1, const std::string& expected2, const uint32_t expstatus) { uint64_t incr = 1; for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); tmp1 = op1; tmp2 = op2; const Decimal first = result.first; const Decimal second = result.second; context.status(0); set_alloc_fail(context, n); try { result = (tmp1.*func)(tmp2, context); } catch (MallocError&) { set_alloc(context); check_equalmem(token, result.first, first); check_equalmem(token, result.second, second); check_equalmem(token, tmp1, op1); check_equalmem(token, tmp2, op2); if (n > 50) { incr = rnd() % 100 + 1; } continue; } set_alloc(context); break; } std::string calc = result.first.to_sci(); compare_expected(token, calc, expected1, expstatus, context); calc = result.second.to_sci(); compare_expected(token, calc, expected2, expstatus, context); if (&tmp1 != &result.first && &tmp1 != &result.second) { check_equalmem(token, tmp1, op1); } if (&tmp2 != &result.first && &tmp2 != &result.second) { check_equalmem(token, tmp2, op2); } } static void DecPair_DecDecCtx(const DecimalPair_DecimalDecimalContext func, const std::vector& token, const bool scan_equal, const bool extended) { Context maxcontext{readcontext(extended)}; std::pair result; Decimal tmp1, tmp2; Decimal op1, op2; std::string expected1, expected2; uint32_t expstatus; size_t n; if (scan_equal) { n = scan_op_expected_expected(op1, expected1, expected2, token, maxcontext); op2 = op1; } else { n = scan_op_op_expected_expected(op1, op2, expected1, expected2, token, maxcontext); } expstatus = scan_conditions(token, n); Triple(token, op1, maxcontext); Triple(token, op2, maxcontext); context.status(0); result = (op1.*func)(op2, context); resolve_status_hack(expstatus, context.status()); DecPair_DecDecCtx_RunSingle(result, tmp1, tmp2, token, func, op1, op2, expected1, expected2, expstatus); DecPair_DecDecCtx_RunSingle(result, result.first, tmp2, token, func, op1, op2, expected1, expected2, expstatus); DecPair_DecDecCtx_RunSingle(result, tmp1, result.first, token, func, op1, op2, expected1, expected2, expstatus); DecPair_DecDecCtx_RunSingle(result, result.second, tmp2, token, func, op1, op2, expected1, expected2, expstatus); DecPair_DecDecCtx_RunSingle(result, tmp1, result.second, token, func, op1, op2, expected1, expected2, expstatus); if (equalmem(op1, op2)) { DecPair_DecDecCtx_RunSingle(result, tmp1, tmp1, token, func, op1, op2, expected1, expected2, expstatus); DecPair_DecDecCtx_RunSingle(result, result.first, result.first, token, func, op1, op2, expected1, expected2, expstatus); DecPair_DecDecCtx_RunSingle(result, result.second, result.second, token, func, op1, op2, expected1, expected2, expstatus); } } /* Test a ternary function */ typedef Decimal (Decimal::*Decimal_DecimalDecimalDecimalContext)(const Decimal&, const Decimal&, Context&) const; static void Dec_DecDecDecCtx_RunSingle(Decimal& result, Decimal& tmp1, Decimal& tmp2, Decimal& tmp3, const std::vector& token, const Decimal_DecimalDecimalDecimalContext func, const Decimal& op1, const Decimal &op2, const Decimal &op3, const std::string& expected, const uint32_t expstatus) { uint64_t incr = 1; for (uint64_t n = 1; n < UINT64_MAX-100; n += incr) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); mpd_init_rand(tmp3); tmp1 = op1; tmp2 = op2; tmp3 = op3; const Decimal save_result = result; context.status(0); set_alloc_fail(context, n); try { result = (tmp1.*func)(tmp2, tmp3, context); } catch (MallocError&) { set_alloc(context); check_equalmem(token, result, save_result); check_equalmem(token, tmp1, op1); check_equalmem(token, tmp2, op2); check_equalmem(token, tmp3, op3); if (n > 100) { incr = rnd() % 100 + 1; } continue; } set_alloc(context); break; } const std::string calc = result.to_sci(); compare_expected(token, calc, expected, expstatus, context); if (&tmp1 != &result) { check_equalmem(token, tmp1, op1); } if (&tmp2 != &result) { check_equalmem(token, tmp2, op2); } if (&tmp3 != &result) { check_equalmem(token, tmp3, op3); } } enum ternary_equal { OpOpOp, EqEqOp, EqOpEq, OpEqEq, EqEqEq }; static void Dec_DecDecDecCtx(const Decimal_DecimalDecimalDecimalContext func, enum ternary_equal scan_equal, const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal result, tmp1, tmp2, tmp3; Decimal op1, op2, op3; std::string expected; uint32_t expstatus; size_t n; switch (scan_equal) { case OpOpOp: n = scan_op_op_op_expected(op1, op2, op3, expected, token, maxcontext); break; case EqEqOp: n = scan_op_op_expected(op1, op3, expected, token, maxcontext); op2 = op1; break; case EqOpEq: n = scan_op_op_expected(op1, op2, expected, token, maxcontext); op3 = op1; break; case OpEqEq: n = scan_op_op_expected(op1, op2, expected, token, maxcontext); op3 = op2; break; case EqEqEq: n = scan_op_expected(op1, expected, token, maxcontext); op3 = op2 = op1; break; default: err_raise("internal error: unexpected tag"); break; } expstatus = scan_conditions(token, n); Triple(token, op1, maxcontext); Triple(token, op2, maxcontext); Triple(token, op3, maxcontext); Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp2, tmp3, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, result, tmp2, tmp3, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, tmp1, result, tmp3, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp2, result, token, func, op1, op2, op3, expected, expstatus); if (equalmem(op1, op2)) { Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp1, tmp3, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, result, result, tmp3, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp1, result, token, func, op1, op2, op3, expected, expstatus); } if (equalmem(op1, op3)) { Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp2, tmp1, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, result, tmp2, result, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, tmp1, result, tmp1, token, func, op1, op2, op3, expected, expstatus); } if (equalmem(op2, op3)) { Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp2, tmp2, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, result, tmp2, tmp2, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, tmp1, result, result, token, func, op1, op2, op3, expected, expstatus); } if (equalmem(op1, op2) && equalmem(op1, op3)) { Dec_DecDecDecCtx_RunSingle(result, tmp1, tmp1, tmp1, token, func, op1, op2, op3, expected, expstatus); Dec_DecDecDecCtx_RunSingle(result, result, result, result, token, func, op1, op2, op3, expected, expstatus); } } /* Test a binary function with no context argument */ typedef Decimal (Decimal::*Decimal_DecimalDecimal)(const Decimal&) const; static void Dec_DecDec_RunSingle(Decimal& result, Decimal& tmp1, Decimal& tmp2, const std::vector& token, const Decimal_DecimalDecimal func, const Decimal& op1, const Decimal &op2, const std::string& expected, const uint32_t expstatus) { for (uint64_t n = 1; n < UINT64_MAX-1; n++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); tmp1 = op1; tmp2 = op2; const Decimal save_result = result; context.status(0); set_alloc_fail(context, n); try { result = (tmp1.*func)(tmp2); } catch (MallocError&) { set_alloc(context); check_equalmem(token, result, save_result); check_equalmem(token, tmp1, op1); check_equalmem(token, tmp2, op2); continue; } set_alloc(context); break; } const std::string calc = result.to_sci(); compare_expected(token, calc, expected, expstatus, context); if (&tmp1 != &result) { check_equalmem(token, tmp1, op1); } if (&tmp2 != &result) { check_equalmem(token, tmp2, op2); } } static void Dec_DecDec(const Decimal_DecimalDecimal func, const std::vector& token, const bool scan_equal, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal result, tmp1, tmp2; Decimal op1, op2; std::string expected; uint32_t expstatus; size_t n; if (scan_equal) { n = scan_op_expected(op1, expected, token, maxcontext); op2 = op1; } else { n = scan_op_op_expected(op1, op2, expected, token, maxcontext); } expstatus = scan_conditions(token, n); Triple(token, op1, maxcontext); Triple(token, op2, maxcontext); Dec_DecDec_RunSingle(result, tmp1, tmp2, token, func, op1, op2, expected, expstatus); Dec_DecDec_RunSingle(tmp1, tmp1, tmp2, token, func, op1, op2, expected, expstatus); Dec_DecDec_RunSingle(tmp2, tmp1, tmp2, token, func, op1, op2, expected, expstatus); if (equalmem(op1, op2)) { Dec_DecDec_RunSingle(result, tmp1, tmp1, token, func, op1, op2, expected, expstatus); Dec_DecDec_RunSingle(tmp1, tmp1, tmp1, token, func, op1, op2, expected, expstatus); } } /* Test a binary function that returns an integer result */ typedef int (Decimal::*Int_DecimalDecimal)(const Decimal&) const; static void Int_DecDec_RunSingle(Decimal& tmp1, Decimal& tmp2, const enum skip_cmp skip, const std::vector& token, const Int_DecimalDecimal func, const Decimal& op1, const Decimal &op2, const std::string& expected, const uint32_t expstatus) { int int_result = -101; for (uint64_t n = 1; n < UINT64_MAX-1; n++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); tmp1 = op1; tmp2 = op2; context.status(0); set_alloc_fail(context, n); try { int_result = (tmp1.*func)(tmp2); } catch (MallocError&) { set_alloc(context); check_equalmem(token, tmp1, op1); check_equalmem(token, tmp2, op2); continue; } set_alloc(context); break; } char buf[11]; snprintf(buf, sizeof buf, "%d", int_result); if (skip == SKIP_NONE || int_result != INT_MAX) { compare_expected(token, buf, expected, expstatus, context); } check_equalmem(token, tmp1, op1); check_equalmem(token, tmp2, op2); } static void Int_DecDec(const Int_DecimalDecimal func, const std::vector& token, const enum skip_cmp skip, const bool scan_equal, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal tmp1, tmp2; Decimal op1, op2; std::string expected; uint32_t expstatus; size_t n; if (scan_equal) { n = scan_op_expected(op1, expected, token, maxcontext); op2 = op1; } else { n = scan_op_op_expected(op1, op2, expected, token, maxcontext); } expstatus = scan_conditions(token, n); Triple(token, op1, maxcontext); Triple(token, op2, maxcontext); Int_DecDec_RunSingle(tmp1, tmp2, skip, token, func, op1, op2, expected, expstatus); if (equalmem(op1, op2)) { Int_DecDec_RunSingle(tmp1, tmp1, skip, token, func, op1, op2, expected, expstatus); } } /* Test a binary function that returns a bool result */ typedef bool (Decimal::*Bool_DecimalDecimal)(const Decimal&) const; static void Bool_DecDec_RunSingle(Decimal& tmp1, Decimal& tmp2, const enum skip_cmp skip, const std::vector& token, const Bool_DecimalDecimal func, const Decimal& op1, const Decimal &op2, const std::string& expected, const uint32_t expstatus) { int int_result = -101; for (uint64_t n = 1; n < UINT64_MAX-1; n++) { mpd_init_rand(tmp1); mpd_init_rand(tmp2); tmp1 = op1; tmp2 = op2; context.status(0); set_alloc_fail(context, n); try { int_result = (tmp1.*func)(tmp2); } catch (MallocError&) { set_alloc(context); DECIMAL_ASSERT(int_result== INT_MAX, token); check_equalmem(token, tmp1, op1); check_equalmem(token, tmp2, op2); continue; } set_alloc(context); break; } char buf[11]; snprintf(buf, 11, "%d", int_result); if (skip == SKIP_NONE || int_result != INT_MAX) { compare_expected(token, buf, expected, expstatus, context); } check_equalmem(token, tmp1, op1); check_equalmem(token, tmp2, op2); } static void Bool_DecDec(const Bool_DecimalDecimal func, const std::vector& token, const enum skip_cmp skip, const bool scan_equal, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal tmp1, tmp2; Decimal op1, op2; std::string expected; uint32_t expstatus; size_t n; if (scan_equal) { n = scan_op_expected(op1, expected, token, maxcontext); op2 = op1; } else { n = scan_op_op_expected(op1, op2, expected, token, maxcontext); } expstatus = scan_conditions(token, n); Triple(token, op1, maxcontext); Triple(token, op2, maxcontext); Bool_DecDec_RunSingle(tmp1, tmp2, skip, token, func, op1, op2, expected, expstatus); if (equalmem(op1, op2)) { Bool_DecDec_RunSingle(tmp1, tmp1, skip, token, func, op1, op2, expected, expstatus); } } static mpd_ssize_t scan_ssize(const std::string& tok) { errno = 0; mpd_ssize_t x = strtossize(tok.c_str(), nullptr, 10); if (errno != 0) { err_raise("invalid conversion to ssize_t"); } return x; } /* Test a function with a Decimal and an int64_t operand */ typedef Decimal (Decimal::*Decimal_DecimalInt64Context)(int64_t, Context&) const; static void Dec_DecInt64_RunSingle(Decimal& result, Decimal& tmp, const std::vector& token, const Decimal_DecimalInt64Context func, const Decimal& op, const int64_t i64, const std::string& expected, const uint32_t expstatus) { /* Allocation failures */ for (uint64_t n = 1; n < UINT64_MAX-1; n++) { mpd_init_rand(tmp); tmp = op; context.status(0); set_alloc_fail(context, n); try { result = (tmp.*func)(i64, context); } catch (MallocError&) { check_equalmem(token, tmp, op); set_alloc(context); continue; } set_alloc(context); break; } const std::string calc = result.to_sci(); compare_expected(token, calc, expected, expstatus, context); if (&tmp != &result) { check_equalmem(token, tmp, op); } } static void Dec_DecInt64Ctx(const Decimal_DecimalInt64Context func, const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal result, tmp; Decimal op1, op2; std::string expected; const size_t n = scan_op_op_expected(op1, op2, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op1, maxcontext); Triple(token, op2, maxcontext); if (op2.isspecial() || op2.exponent() != 0) { return; } const int64_t i64 = mpd_get_ssize(op2.getconst(), maxcontext.get()); if (maxcontext.status() & MPD_Invalid_operation) { return; } Dec_DecInt64_RunSingle(result, tmp, token, func, op1, i64, expected, expstatus); Dec_DecInt64_RunSingle(tmp, tmp, token, func, op1, i64, expected, expstatus); } /* Test decimal::ln10 */ static void ln10(const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal result; Decimal op; std::string expected; const size_t n = scan_op_expected(op, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); if (op.isspecial() || op.exponent() != 0) { return; } const int64_t i64 = mpd_get_ssize(op.getconst(), maxcontext.get()); if (maxcontext.status() & MPD_Invalid_operation) { return; } for (uint64_t i = 1; i < UINT64_MAX-1; i++) { const Decimal save_result = result; context.status(0); set_alloc_fail(context, i); try { result = Decimal::ln10(i64, context); } catch (MallocError&) { set_alloc(context); check_equalmem(token, result, save_result); continue; } set_alloc(context); break; } const std::string calc = result.to_sci(); compare_expected(token, calc, expected, expstatus, context); } /* Test u64() */ static void u64_DecCtx(const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op; uint64_t u64; char calc[23]; std::string expected; const size_t n = scan_op_expected(op, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); context.status(0); try { u64 = op.u64(); } catch (ValueError&) { DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token); return; } snprintf(calc, 23, "%" PRIu64, u64); compare_expected(token, calc, expected, expstatus, context); } /* Test u32() */ static void u32_DecCtx(const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op; std::string expected; uint32_t u32; char calc[23]; const size_t n = scan_op_expected(op, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); context.status(0); try { u32 = op.u32(); } catch (ValueError&) { DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token); return; } snprintf(calc, sizeof calc, "%" PRIu32, u32); compare_expected(token, calc, expected, 0, context); } /* Test a function returning an int64_t */ static void i64_DecCtx(const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op; std::string expected; int64_t i64; char calc[23]; const size_t n = scan_op_expected(op, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); context.status(0); try { i64 = op.i64(); } catch (ValueError&) { DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token); return; } snprintf(calc, sizeof calc, "%" PRIi64, i64); compare_expected(token, calc, expected, 0, context); } /* Test a function returning an int64_t */ static void i32_DecCtx(const std::vector& token, const bool extended) { Context maxcontext{readcontext(extended)}; Decimal op; std::string expected; int32_t i32; char calc[23]; const size_t n = scan_op_expected(op, expected, token, maxcontext); const uint32_t expstatus = scan_conditions(token, n); Triple(token, op, maxcontext); context.status(0); try { i32 = op.i32(); } catch (ValueError&) { DECIMAL_ASSERT(expstatus == MPD_Invalid_operation, token); return; } snprintf(calc, sizeof calc, "%" PRIi32, i32); compare_expected(token, calc, expected, 0, context); } static void test_copy_constructor(void) { const std::vector token{"copy_constr"}; Decimal a = Decimal(1).shiftl((decimal::MINALLOC*MPD_RDIGITS)); Decimal b = Decimal(1).shiftl((2*decimal::MINALLOC*MPD_RDIGITS)); Decimal c = 2025; Context ctx; /* static ==> dynamic */ for (uint64_t n = 1; n < UINT64_MAX-1; n++) { set_alloc_fail(ctx, n); try { c = a; } catch (MallocError&) { set_alloc(ctx); DECIMAL_ASSERT(c == 2025, token); continue; } set_alloc(ctx); break; } DECIMAL_ASSERT(c == a, token); /* static ==> larger dynamic */ for (uint64_t n = 1; n < UINT64_MAX-1; n++) { set_alloc_fail(ctx, n); try { c = b; } catch (MallocError&) { set_alloc(ctx); DECIMAL_ASSERT(c == a, token); continue; } set_alloc(ctx); break; } DECIMAL_ASSERT(c == b, token); } /* process an input stream of test cases */ static bool skip_bignum = false; static std::atomic bignum_counter{0}; static void do_stream(std::istream& in, bool extended=true) { std::string line; context = Context(testcontext(extended)); while (std::getline(in, line)) { std::vector token = split(line); if (token.size() == 0) { continue; } if (skip_bignum) { /* small thread stack */ bool cont = false; for (const std::string &s : token) { /* This is a simple heuristic, which works for the test cases in additional.topTest. */ if (s.size() > 4096) { cont = true; bignum_counter++; break; } } if (cont) { continue; } } if (startswith(token.at(0), "ExtendedRange")) { if (token.at(1) == "1") { extended = true; } else if (token.at(1) == "0") { extended = false; } else { err_token(token, "value must be 1 or 0"); } continue; } if (startswith(token.at(0), "Precision")) { if (token.at(1) == "MAX_PREC") { context.prec(MPD_MAX_PREC); } else { mpd_context_t ctx = *context.getconst(); const mpd_ssize_t l = scan_ssize(token.at(1)); ctx.prec = l; context = Context(ctx); } continue; } if (startswith(token.at(0), "MinExponent")) { if (token.at(1) == "MIN_EMIN") { context.emin(MPD_MIN_EMIN); } else { mpd_context_t ctx = *context.getconst(); const mpd_ssize_t l = scan_ssize(token.at(1)); ctx.emin = l; context = Context(ctx); } continue; } if (startswith(token.at(0), "MaxExponent")) { if (token.at(1) == "MAX_EMAX") { context.emax(MPD_MAX_EMAX); } else { mpd_context_t ctx = *context.getconst(); const mpd_ssize_t l = scan_ssize(token.at(1)); ctx.emax = l; context = Context(ctx); } continue; } if (startswith(token.at(0), "Rounding")) { if (eqtoken(token.at(1), "Up")) { context.round(MPD_ROUND_UP); } else if (eqtoken(token.at(1), "Down")) { context.round(MPD_ROUND_DOWN); } else if (eqtoken(token.at(1), "Ceiling")) { context.round(MPD_ROUND_CEILING); } else if (eqtoken(token.at(1), "Floor")) { context.round(MPD_ROUND_FLOOR); } else if (eqtoken(token.at(1), "Half_up")) { context.round(MPD_ROUND_HALF_UP); } else if (eqtoken(token.at(1), "Half_down")) { context.round(MPD_ROUND_HALF_DOWN); } else if (eqtoken(token.at(1), "Half_even")) { context.round(MPD_ROUND_HALF_EVEN); } else if (eqtoken(token.at(1), "05up")) { context.round(MPD_ROUND_05UP); } else { err_token(token, "invalid rounding mode"); } continue; } if (startswith(token.at(0), "Clamp")) { const int l = static_cast(scan_ssize(token.at(1))); context.clamp(l); continue; } if (startswith(token.at(0), "Locale")) { if (setlocale(LC_NUMERIC, token.at(1).c_str()) == nullptr) { err_token(token, "invalid or missing locale"); } continue; } if (startswith(token.at(0), "Version")) { continue; /* optional directive */ } if (startswith(token.at(0), "Extended")) { continue; /* optional directive */ } mpd_assert_context_ok(context, token); /* * Actual tests start here: * - token.at(0) is the id * - token.at(1) is the operation type * - testno can be used for setting a watchpoint in the debugger */ const unsigned long testno = get_testno(token); (void)testno; if (skip_test(token.at(0))) { continue; /* id is in the skip list */ } #ifdef MPD_CONFIG_64 if (startswith(token.at(0), "cov32")) { continue; /* skip 32-bit specific coverage tests */ } #else if (startswith(token.at(0), "cov64")) { continue; /* skip 64-bit specific coverage tests */ } #endif if (startswith(token.at(0), "pwmx")) { token.at(1) = std::string("powmod"); } /* Unary functions with std::string result */ if (eqtoken(token.at(1), "tosci") || eqtoken(token.at(1), "apply")) { Str_DecCtx(&Decimal::to_sci, token, extended); } else if (eqtoken(token.at(1), "toeng")) { Str_DecCtx(&Decimal::to_eng, token, extended); } else if (eqtoken(token.at(1), "format")) { Fmt(token, extended); } /* Unary function with const char * result */ else if (eqtoken(token.at(1), "class")) { Class(token, extended); } /* Unary functions with Decimal result */ else if (eqtoken(token.at(1), "abs")) { Dec_DecCtx(&Decimal::abs, token, extended); } else if (eqtoken(token.at(1), "copy")) { Dec_Dec(&Decimal::copy, token, extended); } else if (eqtoken(token.at(1), "copyabs")) { Dec_Dec(&Decimal::copy_abs, token, extended); } else if (eqtoken(token.at(1), "copynegate")) { Dec_Dec(&Decimal::copy_negate, token, extended); } else if (eqtoken(token.at(1), "exp")) { if (extended) { if (testno != 126) { /* Almost all test cases in the official tests are correctly rounded even when context.allcr is not set. */ context.allcr(0); Dec_DecCtx(&Decimal::exp, token, extended); context.allcr(1); } } Dec_DecCtx(&Decimal::exp, token, extended); } else if (eqtoken(token.at(1), "invert")) { Dec_DecCtx(&Decimal::logical_invert, token, extended); } else if (eqtoken(token.at(1), "invroot")) { Dec_DecCtx(&Decimal::invroot, token, extended); } else if (eqtoken(token.at(1), "ln")) { if (extended) { /* All test cases in the official tests are correctly rounded even when context.allcr is not set. */ context.allcr(0); Dec_DecCtx(&Decimal::ln, token, extended); context.allcr(1); } Dec_DecCtx(&Decimal::ln, token, extended); } else if (eqtoken(token.at(1), "log10")) { if (extended) { /* All test cases in the official tests are correctly rounded even when context.allcr is not set. */ context.allcr(0); Dec_DecCtx(&Decimal::log10, token, extended); context.allcr(1); } Dec_DecCtx(&Decimal::log10, token, extended); } else if (eqtoken(token.at(1), "logb")) { Dec_DecCtx(&Decimal::logb, token, extended); } else if (eqtoken(token.at(1), "minus")) { Dec_DecCtx(&Decimal::minus, token, extended); } else if (eqtoken(token.at(1), "nextminus")) { Dec_DecCtx(&Decimal::next_minus, token, extended); } else if (eqtoken(token.at(1), "nextplus")) { Dec_DecCtx(&Decimal::next_plus, token, extended); } else if (eqtoken(token.at(1), "plus")) { Dec_DecCtx(&Decimal::plus, token, extended); } else if (eqtoken(token.at(1), "reduce")) { Dec_DecCtx(&Decimal::reduce, token, extended); } else if (eqtoken(token.at(1), "squareroot")) { #ifdef MPD_CONFIG_32 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(16000000); #endif Dec_DecCtx(&Decimal::sqrt, token, extended); #ifdef MPD_CONFIG_32 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token.at(1), "quantize_squareroot")) { #ifdef MPD_CONFIG_32 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(16000000); #endif Dec_DecCtxWithQuantize(&Decimal::sqrt, token, extended); #ifdef MPD_CONFIG_32 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token.at(1), "tointegral")) { Dec_DecCtx(&Decimal::to_integral, token, extended); } else if (eqtoken(token.at(1), "tointegralx")) { Dec_DecCtx(&Decimal::to_integral_exact, token, extended); } else if (eqtoken(token.at(1), "floor")) { Dec_DecCtx(&Decimal::floor, token, extended); } else if (eqtoken(token.at(1), "ceil")) { Dec_DecCtx(&Decimal::ceil, token, extended); } else if (eqtoken(token.at(1), "trunc")) { Dec_DecCtx(&Decimal::trunc, token, extended); } /* Binary function returning an int */ else if (eqtoken(token.at(1), "samequantum")) { Bool_DecDec(&Decimal::same_quantum, token, SKIP_NONE, false, extended); } /* Binary function returning an int, equal operands */ else if (eqtoken(token.at(1), "samequantum_eq")) { Bool_DecDec(&Decimal::same_quantum, token, SKIP_NONE, true, extended); } /* Binary functions with Decimal result */ else if (eqtoken(token.at(1), "add")) { Dec_DecDecCtx(&Decimal::add, token, false, extended); Dec_DecDec(&Decimal::operator+, token, false, extended); } else if (eqtoken(token.at(1), "and")) { Dec_DecDecCtx(&Decimal::logical_and, token, false, extended); } else if (eqtoken(token.at(1), "copysign")) { Dec_DecDec(&Decimal::copy_sign, token, false, extended); } else if (eqtoken(token.at(1), "divide")) { #ifdef MPD_CONFIG_32 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(16000000); #endif Dec_DecDecCtx(&Decimal::div, token, false, extended); Dec_DecDec(&Decimal::operator/, token, false, extended); #ifdef MPD_CONFIG_32 if (context.prec() == MPD_MAX_PREC) set_alloc_limit(SIZE_MAX); #endif } else if (eqtoken(token.at(1), "divideint")) { Dec_DecDecCtx(&Decimal::divint, token, false, extended); } else if (eqtoken(token.at(1), "max")) { Dec_DecDecCtx(&Decimal::max, token, false, extended); } else if (eqtoken(token.at(1), "maxmag") || eqtoken(token.at(1), "max_mag")) { Dec_DecDecCtx(&Decimal::max_mag, token, false, extended); } else if (eqtoken(token.at(1), "min")) { Dec_DecDecCtx(&Decimal::min, token, false, extended); } else if (eqtoken(token.at(1), "minmag") || eqtoken(token.at(1), "min_mag")) { Dec_DecDecCtx(&Decimal::min_mag, token, false, extended); } else if (eqtoken(token.at(1), "multiply")) { Dec_DecDecCtx(&Decimal::mul, token, false, extended); Dec_DecDec(&Decimal::operator*, token, false, extended); } else if (eqtoken(token.at(1), "nexttoward")) { Dec_DecDecCtx(&Decimal::next_toward, token, false, extended); } else if (eqtoken(token.at(1), "or")) { Dec_DecDecCtx(&Decimal::logical_or, token, false, extended); } else if (eqtoken(token.at(1), "power")) { if (extended) { /* All test cases in the official tests are correctly rounded even when context.allcr is not set. */ context.allcr(0); Dec_DecDecCtx(&Decimal::pow, token, false, extended); context.allcr(1); } Dec_DecDecCtx(&Decimal::pow, token, false, extended); } else if (eqtoken(token.at(1), "quantize")) { Dec_DecDecCtx(&Decimal::quantize, token, false, extended); } else if (eqtoken(token.at(1), "resc")) { Dec_DecInt64Ctx(&Decimal::rescale, token, extended); } else if (eqtoken(token.at(1), "remainder")) { Dec_DecDecCtx(&Decimal::rem, token, false, extended); Dec_DecDec(&Decimal::operator%, token, false, extended); } else if (eqtoken(token.at(1), "remaindernear")) { Dec_DecDecCtx(&Decimal::rem_near, token, false, extended); } else if (eqtoken(token.at(1), "rotate")) { Dec_DecDecCtx(&Decimal::rotate, token, false, extended); } else if (eqtoken(token.at(1), "scaleb")) { Dec_DecDecCtx(&Decimal::scaleb, token, false, extended); } else if (eqtoken(token.at(1), "shift")) { Dec_DecDecCtx(&Decimal::shift, token, false, extended); if (extended) { Dec_DecInt64Ctx(&Decimal::shiftn, token, extended); } } else if (eqtoken(token.at(1), "subtract")) { Dec_DecDecCtx(&Decimal::sub, token, false, extended); Dec_DecDec(&Decimal::operator-, token, false, extended); } else if (eqtoken(token.at(1), "xor")) { Dec_DecDecCtx(&Decimal::logical_xor, token, false, extended); } /* Binary functions with Decimal result, equal operands */ else if (eqtoken(token.at(1), "add_eq")) { Dec_DecDecCtx(&Decimal::add, token, true, extended); Dec_DecDec(&Decimal::operator+, token, true, extended); } else if (eqtoken(token.at(1), "and_eq")) { Dec_DecDecCtx(&Decimal::logical_and, token, true, extended); } else if (eqtoken(token.at(1), "copysign_eq")) { Dec_DecDec(&Decimal::copy_sign, token, true, extended); } else if (eqtoken(token.at(1), "divide_eq")) { Dec_DecDecCtx(&Decimal::div, token, true, extended); Dec_DecDec(&Decimal::operator/, token, true, extended); } else if (eqtoken(token.at(1), "divideint_eq")) { Dec_DecDecCtx(&Decimal::divint, token, true, extended); } else if (eqtoken(token.at(1), "max_eq")) { Dec_DecDecCtx(&Decimal::max, token, true, extended); } else if (eqtoken(token.at(1), "maxmag_eq")) { Dec_DecDecCtx(&Decimal::max_mag, token, true, extended); } else if (eqtoken(token.at(1), "min_eq")) { Dec_DecDecCtx(&Decimal::min, token, true, extended); } else if (eqtoken(token.at(1), "minmag_eq")) { Dec_DecDecCtx(&Decimal::min_mag, token, true, extended); } else if (eqtoken(token.at(1), "multiply_eq")) { Dec_DecDecCtx(&Decimal::mul, token, true, extended); Dec_DecDec(&Decimal::operator*, token, true, extended); } else if (eqtoken(token.at(1), "nexttoward_eq")) { Dec_DecDecCtx(&Decimal::next_toward, token, true, extended); } else if (eqtoken(token.at(1), "or_eq")) { Dec_DecDecCtx(&Decimal::logical_or, token, true, extended); } else if (eqtoken(token.at(1), "power_eq")) { if (extended) { /* see power */ context.allcr(0); Dec_DecDecCtx(&Decimal::pow, token, true, extended); context.allcr(1); } Dec_DecDecCtx(&Decimal::pow, token, true, extended); } else if (eqtoken(token.at(1), "quantize_eq")) { Dec_DecDecCtx(&Decimal::quantize, token, true, extended); } else if (eqtoken(token.at(1), "remainder_eq")) { Dec_DecDecCtx(&Decimal::rem, token, true, extended); Dec_DecDec(&Decimal::operator%, token, true, extended); } else if (eqtoken(token.at(1), "remaindernear_eq")) { Dec_DecDecCtx(&Decimal::rem_near, token, true, extended); } else if (eqtoken(token.at(1), "rotate_eq")) { Dec_DecDecCtx(&Decimal::rotate, token, true, extended); } else if (eqtoken(token.at(1), "scaleb_eq")) { Dec_DecDecCtx(&Decimal::scaleb, token, true, extended); } else if (eqtoken(token.at(1), "shift_eq")) { Dec_DecDecCtx(&Decimal::shift, token, true, extended); } else if (eqtoken(token.at(1), "subtract_eq")) { Dec_DecDecCtx(&Decimal::sub, token, true, extended); Dec_DecDec(&Decimal::operator-, token, true, extended); } else if (eqtoken(token.at(1), "xor_eq")) { Dec_DecDecCtx(&Decimal::logical_xor, token, true, extended); } /* Binary function with Decimal pair result */ else if (eqtoken(token.at(1), "divmod")) { DecPair_DecDecCtx(&Decimal::divmod, token, false, extended); } /* Binary function with Decimal pair result, equal operands */ else if (eqtoken(token.at(1), "divmod_eq")) { DecPair_DecDecCtx(&Decimal::divmod, token, true, extended); } /* Ternary functions with Decimal result */ else if (eqtoken(token.at(1), "fma")) { Dec_DecDecDecCtx(&Decimal::fma, OpOpOp, token, extended); } else if (eqtoken(token.at(1), "powmod")) { Dec_DecDecDecCtx(&Decimal::powmod, OpOpOp, token, extended); } /* Ternary functions with Decimal result, eq_eq_op */ else if (eqtoken(token.at(1), "fma_eq_eq_op")) { Dec_DecDecDecCtx(&Decimal::fma, EqEqOp, token, extended); } else if (eqtoken(token.at(1), "powmod_eq_eq_op")) { Dec_DecDecDecCtx(&Decimal::powmod, EqEqOp, token, extended); } /* Ternary functions with Decimal result, eq_op_eq */ else if (eqtoken(token.at(1), "fma_eq_op_eq")) { Dec_DecDecDecCtx(&Decimal::fma, EqOpEq, token, extended); } else if (eqtoken(token.at(1), "powmod_eq_op_eq")) { Dec_DecDecDecCtx(&Decimal::powmod, EqOpEq, token, extended); } /* Ternary functions with Decimal result, op_eq_eq */ else if (eqtoken(token.at(1), "fma_op_eq_eq")) { Dec_DecDecDecCtx(&Decimal::fma, OpEqEq, token, extended); } else if (eqtoken(token.at(1), "powmod_op_eq_eq")) { Dec_DecDecDecCtx(&Decimal::powmod, OpEqEq, token, extended); } /* Ternary functions with Decimal result, eq_eq_eq */ else if (eqtoken(token.at(1), "fma_eq_eq_eq")) { Dec_DecDecDecCtx(&Decimal::fma, EqEqEq, token, extended); } else if (eqtoken(token.at(1), "powmod_eq_eq_eq")) { Dec_DecDecDecCtx(&Decimal::powmod, EqEqEq, token, extended); } /* Special cases for the comparison functions */ else if (eqtoken(token.at(1), "compare")) { Dec_DecDecCtx(&Decimal::compare, token, false, extended); Int_DecDec(&Decimal::cmp, token, SKIP_NAN, false, extended); } else if (eqtoken(token.at(1), "comparesig")) { Dec_DecDecCtx(&Decimal::compare_signal, token, false, extended); } else if (eqtoken(token.at(1), "comparetotal")) { Dec_DecDec(&Decimal::compare_total, token, false, extended); Int_DecDec(&Decimal::cmp_total, token, SKIP_NONE, false, extended); } else if (eqtoken(token.at(1), "comparetotmag")) { Dec_DecDec(&Decimal::compare_total_mag, token, false, extended); Int_DecDec(&Decimal::cmp_total_mag, token, SKIP_NONE, false, extended); } /* Special cases for the comparison functions, equal operands */ else if (eqtoken(token.at(1), "compare_eq")) { Dec_DecDecCtx(&Decimal::compare, token, true, extended); Int_DecDec(&Decimal::cmp, token, SKIP_NAN, true, extended); } else if (eqtoken(token.at(1), "comparesig_eq")) { Dec_DecDecCtx(&Decimal::compare_signal, token, true, extended); } else if (eqtoken(token.at(1), "comparetotal_eq")) { Dec_DecDec(&Decimal::compare_total, token, true, extended); Int_DecDec(&Decimal::cmp_total, token, SKIP_NAN, true, extended); } else if (eqtoken(token.at(1), "comparetotmag_eq")) { Dec_DecDec(&Decimal::compare_total_mag, token, true, extended); Int_DecDec(&Decimal::cmp_total_mag, token, SKIP_NAN, true, extended); } /* Special cases for the shift functions */ else if (eqtoken(token.at(1), "shiftleft")) { Dec_DecInt64Ctx(&Decimal::shiftl, token, extended); } else if (eqtoken(token.at(1), "shiftright")) { Dec_DecInt64Ctx(&Decimal::shiftr, token, extended); } /* Special case for Decimal::ln10() */ else if (eqtoken(token.at(1), "ln10")) { ln10(token, extended); } /* Special cases for the get_int functions */ else if (eqtoken(token.at(1), "get_u64") || eqtoken(token.at(1), "get_uint64")) { u64_DecCtx(token, extended); } else if (eqtoken(token.at(1), "get_u32") || eqtoken(token.at(1), "get_uint32")) { u32_DecCtx(token, extended); } else if (eqtoken(token.at(1), "get_i64") || eqtoken(token.at(1), "get_int64")) { i64_DecCtx(token, extended); } else if (eqtoken(token.at(1), "get_i32") || eqtoken(token.at(1), "get_int32")) { i32_DecCtx(token, extended); } else if (startswith(token.at(0), "bool")) { /* skip: not implemented: bool tests in extra.decTest */ continue; } else if (eqtoken(token.at(1), "get_uint64_abs") || eqtoken(token.at(1), "get_ssize64") || eqtoken(token.at(1), "get_uint32_abs") || eqtoken(token.at(1), "get_ssize32")) { /* skip: not implemented */ } else if (eqtoken(token.at(1), "rescale")) { /* * skip: 'rescale' is obsolete in the standard and Decimal::rescale() * is not equivalent to the obsolete version. */ } else if (eqtoken(token.at(1), "baseconv")) { /* skip: not implemented */ } else { err_token(token, "unknown operation"); } } } static int exit_status(const std::vector& status) { for (auto p : status) { if (p != "PASS") { return EXIT_FAILURE; } } return EXIT_SUCCESS; } static void do_file(const std::string& filename, std::vector& status, size_t i, bool threaded) { try { if (threaded) { /* Thread local context is initialized on first access. */ if (context.prec() != 1) { err_raise("automatic context initialization from template failed"); } } std::ifstream in{filename}; if (!in.is_open()) { err_raise("could not open ", filename); } do_stream(in); if (in.bad()) { err_raise("iterating over lines failed in ", filename); } } catch (test::Failure& e) { status[i] = e.what(); } } /* process a file list */ static int do_files(const std::vector& files) { const size_t n = files.size(); std::vector status(n, "PASS"); for (size_t i = 0; i < n; i++) { std::cout << files[i] << " ... " << std::flush; do_file(files[i], status, i, false); std::cout << status[i] << "\n" << std::flush; } std::cout << "\n" << std::flush; return exit_status(status); } /* process a file list, using std::thread */ static int do_files_thread(const std::vector& files) { const size_t n = files.size(); std::vector status(n, "PASS"); std::vector t(n); for (size_t i = 0; i < n; i++) { t[i] = std::thread(do_file, files[i], std::ref(status), i, true); } for (size_t i = 0; i < n; i++) { t[i].join(); } for (size_t i = 0; i < n; i++) { std::cout << files[i] << " ... " << status[i] << "\n" << std::flush; } std::cout << "\n" << std::flush; if (skip_bignum) { std::cout << "NOTE: std::thread stack size < 512K: skipped " << bignum_counter << " bignum test case" << (bignum_counter == 1 ? "\n\n" : "s\n\n") << std::flush; } return exit_status(status); } #ifdef HAVE_PTHREAD_H /* * The pthread section is for systems like AIX, which have a std::thread stack * size that is too small for the bignum tests. std::thread does not allow to * set the stack size. */ #define THREAD_STACK_SIZE 1048576 struct thread_info { size_t index; pthread_t tid; const std::string *filename; std::vector *status; }; static bool thread_stack_too_small_for_bignum() { pthread_attr_t tattr; size_t size; int ret; ret = pthread_attr_init(&tattr); if (ret != 0) { err_raise("thread attribute initialization failed"); } ret = pthread_attr_getstacksize(&tattr, &size); pthread_attr_destroy(&tattr); if (ret != 0) { err_raise("getting thread stack size failed"); } return size < 524288; } static void * do_file_pthread(void *arg) { struct thread_info *tinfo = static_cast(arg); try { if (context.prec() != 1) { err_raise("automatic context initialization from template failed"); } std::ifstream in{*tinfo->filename}; if (!in.is_open()) { err_raise("could not open ", *tinfo->filename); } do_stream(in); if (in.bad()) { err_raise("iterating over lines failed in ", *tinfo->filename); } } catch (test::Failure& e) { (*tinfo->status)[tinfo->index] = e.what(); } return nullptr; } /* process a file list, using pthread */ static int do_files_pthread(const std::vector& files) { const size_t n = files.size(); std::vector status(n, "PASS"); std::vector tinfo(n); pthread_attr_t tattr; int ret; ret = pthread_attr_init(&tattr); if (ret != 0) { err_raise("thread attribute initialization failed"); } ret = pthread_attr_setstacksize(&tattr, THREAD_STACK_SIZE); if (ret != 0) { pthread_attr_destroy(&tattr); err_raise("setting thread stack size failed"); } for (size_t i = 0; i < n; i++) { tinfo[i].index = i; tinfo[i].filename = &files[i]; tinfo[i].status = &status; ret = pthread_create(&tinfo[i].tid, &tattr, &do_file_pthread, &tinfo[i]); if (ret != 0) { pthread_attr_destroy(&tattr); err_raise("could not create thread"); } } for (size_t i = 0; i < n; i++) { ret = pthread_join(tinfo[i].tid, nullptr); if (ret != 0) { pthread_attr_destroy(&tattr); err_raise("error in thread execution"); } } for (size_t i = 0; i < n; i++) { std::cout << files[i] << " ... " << status[i] << "\n" << std::flush; } std::cout << "\n" << std::flush; pthread_attr_destroy(&tattr); return exit_status(status); } #endif /* HAVE_PTHREAD_H */ static const int32_t int32_cases[] = { INT32_MIN, INT32_MIN+1, INT32_MIN+2, INT32_MAX-2, INT32_MAX-1, INT32_MAX, -10, -5, -1, 0, 5, 10, -999999999, -99999999, -9999999, -999999, -99999, -9999, -999, -99, -9, -1000500001, -100050001, -10050001, -1005001, -105001, -10501, -1501, -151, -1000000001, -100000001, -10000001, -1000001, -100001, -10001, -1001, -101, -1000000000, -100000000, -10000000, -1000000, -100000, -10000, -1000, -100, 999999999, 99999999, 9999999, 999999, 99999, 9999, 999, 99, 9, 1000500001, 100050001, 10050001, 1005001, 105001, 10501, 1501, 151, 1000000001, 100000001, 10000001, 1000001, 100001, 10001, 1001, 101, 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, -(1<<30), -(1<<29), -(1<<28), -(1<<27), -(1<<26), -(1<<25), -(1<<24), -(1<<23), -(1<<22), -(1<<21), -(1<<20), -(1<<19), -(1<<18), -(1<<17), -(1<<16), -(1<<15), -(1<<14), -(1<<13), -(1<<12), -(1<<11), -(1<<10), -(1<<9), -(1<<8), -(1<<7), -(1<<6), -(1<<5), -(1<<4), -(1<<3), -(1<<2), -(1<<1), -(1<<0), (1<<30), (1<<29), (1<<28), (1<<27), (1<<26), (1<<25), (1<<24), (1<<23), (1<<22), (1<<21), (1<<20), (1<<19), (1<<18), (1<<17), (1<<16), (1<<15), (1<<14), (1<<13), (1<<12), (1<<11), (1<<10), (1<<9), (1<<8), (1<<7), (1<<6), (1<<5), (1<<4), (1<<3), (1<<2), (1<<1), (1<<0) }; static const int64_t int64_cases[] = { INT64_MIN, INT64_MIN+1, INT64_MIN+2, -10, -5, -1, 0, 5, 10, INT64_MAX-2, INT64_MAX-1, INT64_MAX, -999999999999999999LL, -99999999999999999LL, -9999999999999999LL, -999999999999999LL, -99999999999999LL, -9999999999999LL, -999999999999LL, -99999999999LL, -9999999999LL, -999999999LL, -99999999LL, -9999999LL, -999999LL, -99999LL, -9999LL, -999LL, -99LL, -9LL, -1000000000000000000LL, -100000000000000000LL, -10000000000000000LL, -1000000000000000LL, -100000000000000LL, -10000000000000LL, -1000000000000LL, -100000000000LL, -10000000000LL, -1000000000LL, -100000000LL, -10000000LL, -1000000LL, -100000LL, -10000LL, -1000LL, -100LL, -10LL, -1000000005000000000LL, -100000005000000000LL, -10000005000000000LL, -1000005000000000LL, -100000005000000LL, -10000005000000LL, -1000005000000LL, -100005000000LL, -10000005000LL, -1000005000LL, -100005000LL, -10005000LL, -1005000LL, -100050LL, -10050LL, -1050LL, -150LL, -15LL, -1000000005000000001LL, -100000005000000001LL, -10000005000000001LL, -1000005000000001LL, -100000005000001LL, -10000005000001LL, -1000005000001LL, -100005000001LL, -10000005001LL, -1000005001LL, -100005001LL, -10005001LL, -1005001LL, -100051LL, -10051LL, -1051LL, -151LL, -15LL, 999999999999999999LL, 99999999999999999LL, 9999999999999999LL, 999999999999999LL, 99999999999999LL, 9999999999999LL, 999999999999LL, 99999999999LL, 9999999999LL, 999999999LL, 99999999LL, 9999999LL, 999999LL, 99999LL, 9999LL, 999LL, 99LL, 9LL, 1000000000000000000LL, 100000000000000000LL, 10000000000000000LL, 1000000000000000LL, 100000000000000LL, 10000000000000LL, 1000000000000LL, 100000000000LL, 10000000000LL, 1000000000LL, 100000000LL, 10000000LL, 1000000LL, 100000LL, 10000LL, 1000LL, 100LL, 10LL, 1000000005000000000LL, 100000005000000000LL, 10000005000000000LL, 1000005000000000LL, 100000005000000LL, 10000005000000LL, 1000005000000LL, 100005000000LL, 10000005000LL, 1000005000LL, 100005000LL, 10005000LL, 1005000LL, 100050LL, 10050LL, 1050LL, 150LL, 15LL, 1000000005000000001LL, 100000005000000001LL, 10000005000000001LL, 1000005000000001LL, 100000005000001LL, 10000005000001LL, 1000005000001LL, 100005000001LL, 10000005001LL, 1000005001LL, 100005001LL, 10005001LL, 1005001LL, 100051LL, 10051LL, 1051LL, 151LL, 15LL, -(1LL<<62), -(1LL<<61), -(1LL<<60), -(1LL<<59), -(1LL<<58), -(1LL<<57), -(1LL<<56), -(1LL<<55), -(1LL<<54), -(1LL<<53), -(1LL<<52), -(1LL<<51), -(1LL<<50), -(1LL<<39), -(1LL<<38), -(1LL<<37), -(1LL<<36), -(1LL<<35), -(1LL<<34), -(1LL<<33), -(1LL<<32), -(1LL<<31), -(1LL<<30), -(1LL<<29), -(1LL<<28), -(1LL<<27), -(1LL<<26), -(1LL<<25), -(1LL<<24), -(1LL<<23), -(1LL<<22), -(1LL<<21), -(1LL<<20), -(1LL<<19), -(1LL<<18), -(1LL<<17), -(1LL<<16), -(1LL<<15), -(1LL<<14), -(1LL<<13), -(1LL<<12), -(1LL<<11), -(1LL<<10), -(1LL<<9), -(1LL<<8), -(1LL<<7), -(1LL<<6), -(1LL<<5), -(1LL<<4), -(1LL<<3), -(1LL<<2), -(1LL<<1), -(1LL<<0), -(1LL<<62), -(1LL<<61), -(1LL<<60), (1LL<<59), (1LL<<58), (1LL<<57), (1LL<<56), (1LL<<55), (1LL<<54), (1LL<<53), (1LL<<52), (1LL<<51), (1LL<<50), (1LL<<39), (1LL<<38), (1LL<<37), (1LL<<36), (1LL<<35), (1LL<<34), (1LL<<33), (1LL<<32), (1LL<<31), (1LL<<30), (1LL<<29), (1LL<<28), (1LL<<27), (1LL<<26), (1LL<<25), (1LL<<24), (1LL<<23), (1LL<<22), (1LL<<21), (1LL<<20), (1LL<<19), (1LL<<18), (1LL<<17), (1LL<<16), (1LL<<15), (1LL<<14), (1LL<<13), (1LL<<12), (1LL<<11), (1LL<<10), (1LL<<9), (1LL<<8), (1LL<<7), (1LL<<6), (1LL<<5), (1LL<<4), (1LL<<3), (1LL<<2), (1LL<<1), (1LL<<0), }; static const char *init_cases[] = { "sNaN", "sNaN19", "sNaN1982612612300000002000000000050000000000000000101111111111111112111111111111111111111111111111111111111111111111" "111111111111111111111111111111111111111111111111111111111111111", "-sNaN", "-sNaN19", "-sNaN198261261230000000200000000005000000000000000010111111111111111211111111111111111111111111111111111111111111111" "1111111111111111111111111111111111111111111111111111111111111111", "NaN", "NaN19", "NaN19826126123000000020000000000500000000000000001011111111111111121111111111111111111111111111111111111111111111111" "11111111111111111111111111111111111111111111111111111111111111", "-NaN", "-NaN19", "-NaN1982612612300000002000000000050000000000000000101111111111111112111111111111111111111111111111111111111111111111" "111111111111111111111111111111111111111111111111111111111111111", "inf", "-inf", "-1", "-0", "0", "1", "1e10", "-1e10", "1.21019218731291112376416152e10", "-1.21019218731291112376416152e10", "0.0000000000000000000000000000000000000000000000000001e-999999", "-0.0000000000000000000000000000000000000000000000000001e-999999" }; static void test_set_i32(void) { const Context savecontext = context; context.status(0); for (const char *s : init_cases) { for (const int32_t& x : int32_cases) { Decimal v{s}; v = x; assertEqual(context.status(), 0U); assertEqualStr(v, std::to_string(x)); } } context = savecontext; } static void test_set_i64(void) { const Context savecontext = context; context.status(0); for (const char *s : init_cases) { for (const int64_t& x : int64_cases) { Decimal v{s}; v = x; assertEqual(context.status(), 0U); assertEqualStr(v, std::to_string(x)); } } context = savecontext; } /* process a single test file */ static void usage(void) { std::cerr << "runtest: usage: runtest testfile [--custom] [--alloc] [--thread|--pthread]" << std::endl; exit(EXIT_FAILURE); } static std::vector collect_files(const std::string& topfile) { std::vector files; std::string line; std::ifstream in{topfile}; if (!in.is_open()) { err_exit("could not open file"); } while (std::getline(in, line)) { std::vector token = split(line); if (token.size() == 0) { continue; } if (startswith(token.at(0), "Dectest")) { files.push_back(token.at(1)); continue; } else { err_exit("parse error"); } } if (in.bad()) { err_exit("iterating over lines failed"); } return files; } int main(int argc, char *argv[]) { std::vector args(argv + (argc!=0), argv + argc); std::string filename = ""; bool custom_alloc = false; bool check_alloc = false; bool thread = false; bool pthread = false; for (auto arg : args) { if (filename == "" && (arg == "-" || !startswith(arg, "--"))) { filename = arg; } else if (!custom_alloc && arg == "--custom") { custom_alloc = true; } else if (!check_alloc && arg == "--alloc") { check_alloc = true; } else if (!thread && arg == "--thread") { thread = true; } else if (!pthread && arg == "--pthread") { pthread = true; } else { usage(); } } if (filename == "") { usage(); } /* std::thread needs 300K stack size for the bignum tests. */ #ifdef HAVE_PTHREAD_H if (thread && thread_stack_too_small_for_bignum()) { skip_bignum = true; } #endif /* Initialize custom allocation functions */ test::init_alloc(custom_alloc, check_alloc); /* Initialize the context template */ context_template = Context(1, 1, -1); /* Initialize main thread context */ context = context_template; /* Initial tests */ test_set_i32(); test_set_i64(); test_copy_constructor(); /* Read test cases from stdin */ if (filename == "-") { try { do_stream(std::cin, /*extended=*/false); } catch (test::Failure& e) { std::cerr << " ... " << e.what() << "\n" << std::flush; return EXIT_FAILURE; } std::cout << " ... PASS\n\n" << std::flush; return EXIT_SUCCESS; } /* Collect test files */ std::vector files; if (endswith(filename, ".decTest")) { files.push_back(filename); } else if (endswith(filename, ".topTest")) { std::ifstream in{filename}; if (!in.is_open()) { err_exit("could not open file"); } files = collect_files(filename); if (in.bad()) { err_exit("iterating over lines failed"); } } else { err_exit("unrecognized file extension: expect .decTest or .topTest"); } /* Run all tests */ if (thread) { return do_files_thread(files); } else if (pthread) { #ifdef HAVE_PTHREAD_H return do_files_pthread(files); #else err_exit("pthread not found on this system: use --thread"); #endif } else { return do_files(files); } } mpdecimal-4.0.1/tests++/test.cc0000644000000000000000000001476115005764474013200 0ustar00/* * Copyright (c) 2020-2025 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 #include #include #include "mpdecimal.h" #include "decimal.hh" #include "test.hh" /******************************************************************************/ /* Exceptions */ /******************************************************************************/ namespace test { const char *Failure::what() const noexcept { return m.what(); } } // namespace test /******************************************************************************/ /* Functions */ /******************************************************************************/ namespace test { void assert_true(const char *file, const int64_t line, const bool p) { if (!(p)) { raise(file, line, "assertion failed (expected true, got false)"); } } void assert_false(const char *file, const int64_t line, const bool p) { if (p) { raise(file, line, "assertion failed (expected false, got true)"); } } } // namespace test /******************************************************************************/ /* Primary allocation functions (normal or offset) */ /******************************************************************************/ static const size_t OFFSET = 16; #ifdef MPD_CONFIG_64 static const size_t alloc_limit = 0x4000000000000ULL; #else static thread_local size_t alloc_limit = SIZE_MAX; #endif /* malloc with upper limits */ static void * malloc_ceil(size_t size) { if (size > alloc_limit) { return nullptr; } return malloc(size); } static void * calloc_ceil(size_t nmemb, size_t size) { if (nmemb > alloc_limit / size) { return nullptr; } return calloc(nmemb, size); } static void * realloc_ceil(void *ptr, size_t size) { if (size > alloc_limit) { return nullptr; } return realloc(ptr, size); } static void free_ceil(void *ptr) { free(ptr); } /* custom malloc with an offset and upper limits */ static void * malloc_offset(size_t size) { if (size == 0 || size > SIZE_MAX - OFFSET) { return nullptr; } char *ptr = (char *)malloc_ceil(OFFSET + size); return ptr ? ptr + OFFSET : nullptr; } static void * calloc_offset(size_t nmemb, size_t size) { if (nmemb == 0 || size == 0 || size > SIZE_MAX - OFFSET) { return nullptr; } char *ptr = (char *)calloc_ceil(nmemb, OFFSET + size); return ptr ? ptr + OFFSET : nullptr; } static void * realloc_offset(void *ptr, size_t size) { if (size == 0 || size > SIZE_MAX - OFFSET) { return nullptr; } char *c = (char *)ptr - OFFSET; char *p = (char *)realloc_ceil(c, OFFSET + size); return p ? p + OFFSET : nullptr; } static void free_offset(void *ptr) { free((char *)ptr - OFFSET); } /* active set of primary allocation functions */ static void *(* test_mallocfunc)(size_t size) = malloc_ceil; static void *(* test_callocfunc)(size_t nmemb, size_t size) = calloc_ceil; static void *(* test_reallocfunc)(void *ptr, size_t size) = realloc_ceil; static void (* test_freefunc)(void *ptr) = free_ceil; /******************************************************************************/ /* Secondary allocation functions (count or failure mode) */ /******************************************************************************/ static bool enable_check_alloc = false; static thread_local uint64_t alloc_fail = UINT64_MAX; static thread_local uint64_t alloc_idx = 0; static void * malloc_fail(size_t size) { if (++alloc_idx >= alloc_fail) { return nullptr; } return test_mallocfunc(size); } static void * calloc_fail(size_t nmemb, size_t size) { if (++alloc_idx >= alloc_fail) { return nullptr; } return test_callocfunc(nmemb, size); } static void * realloc_fail(void *ptr, size_t size) { if (++alloc_idx >= alloc_fail) { return nullptr; } return test_reallocfunc(ptr, size); } namespace test { void init_alloc(bool custom_alloc, bool check_alloc) { static bool initialized = false; if (initialized) { fputs("mpd_init_alloc: error: cannot initialize twice\n", stderr); exit(EXIT_FAILURE); } initialized = true; /* initialization for the main thread */ #ifdef MPD_CONFIG_32 alloc_limit = SIZE_MAX; #endif alloc_fail = UINT64_MAX; alloc_idx = 0; enable_check_alloc = check_alloc; if (custom_alloc) { test_mallocfunc = malloc_offset; test_callocfunc = calloc_offset; test_reallocfunc = realloc_offset; test_freefunc = free_offset; } mpd_mallocfunc = malloc_fail; mpd_callocfunc = calloc_fail; mpd_reallocfunc = realloc_fail; mpd_free = test_freefunc; } #ifdef MPD_CONFIG_32 void set_alloc_limit(size_t size) { alloc_limit = size; } #endif void set_alloc(decimal::Context &ctx) { ctx.traps(MPD_Malloc_error); alloc_idx = 0; alloc_fail = UINT64_MAX; } void set_alloc_fail(decimal::Context &ctx, uint64_t n) { if (enable_check_alloc) { ctx.traps(MPD_Malloc_error); alloc_idx = 0; alloc_fail = n; } } } /* namespace test */ mpdecimal-4.0.1/tests++/test.hh0000644000000000000000000001274115005764474013206 0ustar00/* * Copyright (c) 2020-2025 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. */ #ifndef TESTS_HH_ #define TESTS_HH_ #include #include #include #include namespace test { /******************************************************************************/ /* Util */ /******************************************************************************/ template static inline const std::string str(const T& t) { std::stringstream ss; ss << t; return ss.str(); } static inline const std::string stringize() { return std::string(); } template static inline const std::string stringize(const T& t, Args... args) { return str(t) + stringize(args...); } /******************************************************************************/ /* Exceptions */ /******************************************************************************/ class Failure: public std::exception { private: std::runtime_error m; public: template explicit Failure(Args... args) : m(stringize(args...)) {} virtual const char* what() const noexcept; }; template static void raise(const char *file, const int64_t line, Args... args) { throw Failure("error: ", args..., " [", file, ":", line, "]"); } /******************************************************************************/ /* Test support */ /******************************************************************************/ void assert_true(const char *file, const int64_t line, const bool p); void assert_false(const char *file, const int64_t line, const bool p); template void assert_equal(const char *file, const int64_t line, const T& calc, const U& expected) { if (calc != expected) { raise(file, line, "values not equal: ", "expected: ", test::str(expected), " got: ", test::str(calc)); } } template void assert_equal_str(const char *file, int64_t line, const T& calc, const U& expected) { if (str(calc) != str(expected)) { raise(file, line, "string representations not equal: expected: ", test::str(expected), " got: ", test::str(calc)); } } template void assert_raises(const char *file, const int64_t line, const F& f) { try { f(); raise(file, line, "exception not raised"); } catch (Exc& e) { (void)e; return; } catch (std::exception& e) { raise(file, line, "unexpected exception: ", e.what()); } } #define assertTrue(p) test::assert_true(__FILE__, __LINE__, p) #define assertFalse(p) test::assert_false(__FILE__, __LINE__, p) #define assertEqual(calc, expected) test::assert_equal(__FILE__, __LINE__, calc, expected) #define assertEqualStr(calc, expected) test::assert_equal_str(__FILE__, __LINE__, calc, expected) #define assertRaises(ex, func) test::assert_raises(__FILE__, __LINE__, func) #define err_exit(msg) \ do {std::cerr << __FILE__ << ":" << __LINE__ << ": error: "; \ std::cerr << msg << std::endl; \ std::exit(EXIT_FAILURE); \ } while (0) #define err_raise(...) \ do { throw test::Failure( "error: ", __VA_ARGS__, " [", __FILE__, ":", __LINE__, "]"); } while (0) #define err_token(token, ...) \ do { throw test::Failure(token.at(0), ": ", __VA_ARGS__, " [", __FILE__, ":", __LINE__, "]"); } while (0) #define DECIMAL_ASSERT(p, token) \ do { if (!(p)) { err_token(token, "assertion failure"); } } while (0) /******************************************************************************/ /* API for testing allocation failures */ /******************************************************************************/ void init_alloc(bool custom_alloc, bool check_alloc); #ifdef MPD_CONFIG_32 void set_alloc_limit(size_t size); #endif void set_alloc_fail(decimal::Context &ctx, uint64_t n); void set_alloc(decimal::Context &ctx); } // namespace test #endif // TESTS_HH_ mpdecimal-4.0.1/tests++/vctest.hh0000644000000000000000000000353115005764474013534 0ustar00/* * Copyright (c) 2020-2025 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. */ #ifndef TESTSXX_VCTEST_H_ #define TESTSXX_VCTEST_H_ /* Visual C fixes */ #ifdef _MSC_VER /* workaround for broken headers */ #undef INT8_MIN #define INT8_MIN ((int8_t)SCHAR_MIN) #undef INT8_MAX #define INT8_MAX ((int8_t)SCHAR_MAX) /* missing functions */ #undef random #define random rand #undef srandom #define srandom srand #undef strncasecmp #define strncasecmp _strnicmp #undef strcasecmp #define strcasecmp _stricmp #endif #endif /* TESTSXX_VCTEST_H_ */ mpdecimal-4.0.1/vcbuild/0000755000000000000000000000000015005764474012041 5ustar00mpdecimal-4.0.1/vcbuild/README.txt0000644000000000000000000000312015005764474013533 0ustar00 libmpdec and libmpdec++ build instructions for Visual Studio ============================================================ For all builds: After a successful build, the static libraries, the dynamic libraries and the header files should be in the dist64 or dist32 directory. The unit tests attempt to download the official IBM test cases (text files). No executables are downloaded. 64-bit release build -------------------- # Clean the build directory if files from a previous build are present. vcdistclean.bat # Build the libraries. Optionally use pgobuild64.bat instead of vcbuild64.bat # for a profile-guided optimization build. vcbuild64.bat # Run the unit tests. runshort.bat 64-bit debug build ------------------ # Clean the build directory if files from a previous build are present. vcdistclean.bat # Build the libraries. vcbuild64.bat /d # Run the unit tests. runshort.bat /d 32-bit release build -------------------- # Clean the build directory if files from a previous build are present. vcdistclean.bat # Build the libraries. Optionally use pgobuild32.bat instead of vcbuild32.bat # for a profile-guided optimization build. vcbuild32.bat # Run the unit tests. runshort.bat 32-bit debug build -------------------- # Clean the build directory if files from a previous build are present. vcdistclean.bat # Build the libraries. vcbuild32.bat /d # Run the unit tests. runshort.bat /d mpdecimal-4.0.1/vcbuild/pgobuild32.bat0000755000000000000000000000172115005764474014507 0ustar00@ECHO off "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt set /p vcpath= vcpath.txt set /p vcpath= vcpath.txt set /p vcpath= vcpath.txt set /p vcpath= vcpath.txt set /p vcpath= vcpath.txt set /p vcpath= vcpath.txt set /p vcpath= vcpath.txt set /p vcpath=