--- /dev/null
+
+
+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 <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 <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.
+
+
+
--- /dev/null
+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.
--- /dev/null
+
+# ==============================================================================
+# 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.
+
+
+
--- /dev/null
+
+# ==============================================================================
+# 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
--- /dev/null
+
+
+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 <skrah@bytereef.org>
+
+
--- /dev/null
+#! /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 <https://www.gnu.org/licenses/>.
+#
+# 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 <config-patches@gnu.org>.
+
+
+# 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 <config-patches@gnu.org>."
+
+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 <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #elif defined(__GLIBC__)
+ LIBC=gnu
+ #elif defined(__LLVM_LIBC__)
+ LIBC=llvm
+ #else
+ #include <stdarg.h>
+ /* 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 <stdio.h> /* 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 <sys/systemcfg.h>
+
+ 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 <stdlib.h>
+ #include <unistd.h>
+
+ 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 <unistd.h>
+ 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' </usr/options/cb.name`
+ GUESS=$UNAME_MACHINE-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/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 <Richard.M.Bartel@ccMail.Census.GOV>
+ GUESS=i586-unisys-sysv4
+ ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # 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" <<EOF
+#ifdef _SEQUENT_
+#include <sys/types.h>
+#include <sys/utsname.h>
+#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 <signal.h>
+#if defined(_SIZE_T_) || defined(SIGLOST)
+#include <sys/utsname.h>
+#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 <sys/param.h>
+ 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 <sys/param.h>
+#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 <<EOF
+
+NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize
+the system type. Please install a C compiler and try again.
+EOF
+ ;;
+esac
+
+cat >&2 <<EOF
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite *all*
+copies of config.guess and config.sub with the latest versions from:
+
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
+and
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
+EOF
+
+our_year=`echo $timestamp | sed 's,-.*,,'`
+thisyear=`date +%Y`
+# shellcheck disable=SC2003
+script_age=`expr "$thisyear" - "$our_year"`
+if test "$script_age" -lt 3 ; then
+ cat >&2 <<EOF
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
+
+config.guess timestamp = $timestamp
+
+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`
+/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:
--- /dev/null
+/* 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 <inttypes.h> 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 <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> 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 <unistd.h> 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 <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> 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 <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> 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 <sys/types.h> 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
--- /dev/null
+#! /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 <https://www.gnu.org/licenses/>.
+#
+# 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 <config-patches@gnu.org>.
+#
+# 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 <config-patches@gnu.org>."
+
+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 <<EOF
+$1
+EOF
+IFS=$saved_IFS
+
+# Separate into logical components for further validation
+case $1 in
+ *-*-*-*-*)
+ echo "Invalid configuration '$1': more than four components" >&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 <<EOF
+$basic_machine
+EOF
+ IFS=$saved_IFS
+ ;;
+ # We use 'pc' rather than 'unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ cpu=$basic_machine
+ vendor=pc
+ ;;
+ # These rules are duplicated from below for sake of the special case above;
+ # i.e. things that normalized to x86 arches should also default to "pc"
+ pc98)
+ cpu=i386
+ vendor=pc
+ ;;
+ x64 | amd64)
+ cpu=x86_64
+ vendor=pc
+ ;;
+ # Recognize the basic CPU types without company name.
+ *)
+ cpu=$basic_machine
+ vendor=unknown
+ ;;
+esac
+
+unset -v basic_machine
+
+# Decode basic machines in the full and proper CPU-Company form.
+case $cpu-$vendor in
+ # Here we handle the default manufacturer of certain CPU types in canonical form.
+ # It is in some cases the only manufacturer, in others, it is the most popular.
+ c[12]-convex | c[12]-unknown | c3[248]-convex | c3[248]-unknown)
+ vendor=convex
+ basic_os=${basic_os:-bsd}
+ ;;
+ craynv-unknown)
+ vendor=cray
+ basic_os=${basic_os:-unicosmp}
+ ;;
+ c90-unknown | c90-cray)
+ vendor=cray
+ basic_os=${basic_os:-unicos}
+ ;;
+ fx80-unknown)
+ vendor=alliant
+ ;;
+ romp-unknown)
+ vendor=ibm
+ ;;
+ mmix-unknown)
+ vendor=knuth
+ ;;
+ microblaze-unknown | microblazeel-unknown)
+ vendor=xilinx
+ ;;
+ rs6000-unknown)
+ vendor=ibm
+ ;;
+ vax-unknown)
+ vendor=dec
+ ;;
+ pdp11-unknown)
+ vendor=dec
+ ;;
+ we32k-unknown)
+ vendor=att
+ ;;
+ cydra-unknown)
+ vendor=cydrome
+ ;;
+ i370-ibm*)
+ vendor=ibm
+ ;;
+ orion-unknown)
+ vendor=highlevel
+ ;;
+ xps-unknown | xps100-unknown)
+ cpu=xps100
+ vendor=honeywell
+ ;;
+
+ # Here we normalize CPU types with a missing or matching vendor
+ armh-unknown | armh-alt)
+ cpu=armv7l
+ vendor=alt
+ basic_os=${basic_os:-linux-gnueabihf}
+ ;;
+
+ # Normalized CPU+vendor pairs that imply an OS, if not otherwise specified
+ m68k-isi)
+ basic_os=${basic_os:-sysv}
+ ;;
+ m68k-sony)
+ basic_os=${basic_os:-newsos}
+ ;;
+ m68k-tektronix)
+ basic_os=${basic_os:-bsd}
+ ;;
+ m88k-harris)
+ basic_os=${basic_os:-sysv3}
+ ;;
+ i386-bull | m68k-bull)
+ basic_os=${basic_os:-sysv3}
+ ;;
+ rs6000-bull)
+ basic_os=${basic_os:-bosx}
+ ;;
+ mips-sni)
+ basic_os=${basic_os:-sysv4}
+ ;;
+
+ # Here we normalize CPU types irrespective of the vendor
+ amd64-*)
+ cpu=x86_64
+ ;;
+ blackfin-*)
+ cpu=bfin
+ basic_os=${basic_os:-linux}
+ ;;
+ c54x-*)
+ cpu=tic54x
+ ;;
+ c55x-*)
+ cpu=tic55x
+ ;;
+ c6x-*)
+ cpu=tic6x
+ ;;
+ e500v[12]-*)
+ cpu=powerpc
+ basic_os=${basic_os}"spe"
+ ;;
+ mips3*-*)
+ cpu=mips64
+ ;;
+ ms1-*)
+ cpu=mt
+ ;;
+ m68knommu-*)
+ cpu=m68k
+ basic_os=${basic_os:-linux}
+ ;;
+ m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+ cpu=s12z
+ ;;
+ openrisc-*)
+ cpu=or32
+ ;;
+ parisc-*)
+ cpu=hppa
+ basic_os=${basic_os:-linux}
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ cpu=i586
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
+ cpu=i686
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ cpu=i686
+ ;;
+ pentium4-*)
+ cpu=i786
+ ;;
+ ppc-* | ppcbe-*)
+ cpu=powerpc
+ ;;
+ ppcle-* | powerpclittle-*)
+ cpu=powerpcle
+ ;;
+ ppc64-*)
+ cpu=powerpc64
+ ;;
+ ppc64le-* | powerpc64little-*)
+ cpu=powerpc64le
+ ;;
+ sb1-*)
+ cpu=mipsisa64sb1
+ ;;
+ sb1el-*)
+ cpu=mipsisa64sb1el
+ ;;
+ sh5e[lb]-*)
+ cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
+ ;;
+ spur-*)
+ cpu=spur
+ ;;
+ strongarm-* | thumb-*)
+ cpu=arm
+ ;;
+ tx39-*)
+ cpu=mipstx39
+ ;;
+ tx39el-*)
+ cpu=mipstx39el
+ ;;
+ xscale-* | xscalee[bl]-*)
+ cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
+ ;;
+ arm64-* | aarch64le-*)
+ cpu=aarch64
+ ;;
+
+ # Recognize the canonical CPU Types that limit and/or modify the
+ # company names they are paired with.
+ cr16-*)
+ basic_os=${basic_os:-elf}
+ ;;
+ crisv32-* | etraxfs*-*)
+ cpu=crisv32
+ vendor=axis
+ ;;
+ cris-* | etrax*-*)
+ cpu=cris
+ vendor=axis
+ ;;
+ crx-*)
+ basic_os=${basic_os:-elf}
+ ;;
+ neo-tandem)
+ cpu=neo
+ vendor=tandem
+ ;;
+ nse-tandem)
+ cpu=nse
+ vendor=tandem
+ ;;
+ nsr-tandem)
+ cpu=nsr
+ vendor=tandem
+ ;;
+ nsv-tandem)
+ cpu=nsv
+ vendor=tandem
+ ;;
+ nsx-tandem)
+ cpu=nsx
+ vendor=tandem
+ ;;
+ mipsallegrexel-sony)
+ cpu=mipsallegrexel
+ vendor=sony
+ ;;
+ tile*-*)
+ basic_os=${basic_os:-linux-gnu}
+ ;;
+
+ *)
+ # Recognize the canonical CPU types that are allowed with any
+ # company name.
+ case $cpu in
+ 1750a \
+ | 580 \
+ | [cjt]90 \
+ | a29k \
+ | aarch64 \
+ | aarch64_be \
+ | aarch64c \
+ | abacus \
+ | alpha \
+ | alpha64 \
+ | alpha64ev56 \
+ | alpha64ev6[78] \
+ | alpha64ev[4-8] \
+ | alpha64pca5[67] \
+ | alphaev56 \
+ | alphaev6[78] \
+ | alphaev[4-8] \
+ | alphapca5[67] \
+ | am33_2.0 \
+ | amdgcn \
+ | arc \
+ | arc32 \
+ | arc64 \
+ | arceb \
+ | arm \
+ | arm64e \
+ | arm64ec \
+ | arm[lb]e \
+ | arme[lb] \
+ | armv* \
+ | asmjs \
+ | avr \
+ | avr32 \
+ | ba \
+ | be32 \
+ | be64 \
+ | bfin \
+ | bpf \
+ | bs2000 \
+ | c30 \
+ | c4x \
+ | c8051 \
+ | c[123]* \
+ | clipper \
+ | craynv \
+ | csky \
+ | cydra \
+ | d10v \
+ | d30v \
+ | dlx \
+ | dsp16xx \
+ | e2k \
+ | elxsi \
+ | epiphany \
+ | f30[01] \
+ | f700 \
+ | fido \
+ | fr30 \
+ | frv \
+ | ft32 \
+ | fx80 \
+ | h8300 \
+ | h8500 \
+ | hexagon \
+ | hppa \
+ | hppa1.[01] \
+ | hppa2.0 \
+ | hppa2.0[nw] \
+ | hppa64 \
+ | i*86 \
+ | i370 \
+ | i860 \
+ | i960 \
+ | ia16 \
+ | ia64 \
+ | ip2k \
+ | iq2000 \
+ | javascript \
+ | k1om \
+ | kvx \
+ | le32 \
+ | le64 \
+ | lm32 \
+ | loongarch32 \
+ | loongarch64 \
+ | m32c \
+ | m32r \
+ | m32rle \
+ | m5200 \
+ | m68000 \
+ | m680[012346]0 \
+ | m6811 \
+ | m6812 \
+ | m68360 \
+ | m683?2 \
+ | m68hc11 \
+ | m68hc12 \
+ | m68hcs12x \
+ | m68k \
+ | m88110 \
+ | m88k \
+ | maxq \
+ | mb \
+ | mcore \
+ | mep \
+ | metag \
+ | microblaze \
+ | microblazeel \
+ | mips* \
+ | mmix \
+ | mn10200 \
+ | mn10300 \
+ | moxie \
+ | msp430 \
+ | mt \
+ | nanomips* \
+ | nds32 \
+ | nds32be \
+ | nds32le \
+ | nfp \
+ | nios \
+ | nios2 \
+ | nios2eb \
+ | nios2el \
+ | none \
+ | np1 \
+ | ns16k \
+ | ns32k \
+ | nvptx \
+ | open8 \
+ | or1k* \
+ | or32 \
+ | orion \
+ | pdp10 \
+ | pdp11 \
+ | picochip \
+ | pj \
+ | pjl \
+ | pn \
+ | power \
+ | powerpc \
+ | powerpc64 \
+ | powerpc64le \
+ | powerpcle \
+ | powerpcspe \
+ | pru \
+ | pyramid \
+ | riscv \
+ | riscv32 \
+ | riscv32be \
+ | riscv64 \
+ | riscv64be \
+ | rl78 \
+ | romp \
+ | rs6000 \
+ | rx \
+ | s390 \
+ | s390x \
+ | score \
+ | sh \
+ | sh64 \
+ | sh64le \
+ | sh[12345][lb]e \
+ | sh[1234] \
+ | sh[1234]e[lb] \
+ | sh[23]e \
+ | sh[23]ele \
+ | sh[24]a \
+ | sh[24]ae[lb] \
+ | sh[lb]e \
+ | she[lb] \
+ | shl \
+ | sparc \
+ | sparc64 \
+ | sparc64b \
+ | sparc64v \
+ | sparc86x \
+ | sparclet \
+ | sparclite \
+ | sparcv8 \
+ | sparcv9 \
+ | sparcv9b \
+ | sparcv9v \
+ | spu \
+ | sv1 \
+ | sx* \
+ | tahoe \
+ | thumbv7* \
+ | tic30 \
+ | tic4x \
+ | tic54x \
+ | tic55x \
+ | tic6x \
+ | tic80 \
+ | tron \
+ | ubicom32 \
+ | v70 \
+ | v810 \
+ | v850 \
+ | v850e \
+ | v850e1 \
+ | v850e2 \
+ | v850e2v3 \
+ | v850es \
+ | vax \
+ | vc4 \
+ | visium \
+ | w65 \
+ | wasm32 \
+ | wasm64 \
+ | we32k \
+ | x86 \
+ | x86_64 \
+ | xc16x \
+ | xgate \
+ | xps100 \
+ | xstormy16 \
+ | xtensa* \
+ | ymp \
+ | z80 \
+ | z8k)
+ ;;
+
+ *)
+ echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&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 <<EOF
+$basic_os
+EOF
+ IFS=$saved_IFS
+ ;;
+ # Default OS when just kernel was specified
+ nto*)
+ kernel=nto
+ os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
+ ;;
+ linux*)
+ kernel=linux
+ os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
+ ;;
+ managarm*)
+ kernel=managarm
+ os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
+ ;;
+ *)
+ kernel=
+ os=$basic_os
+ ;;
+esac
+
+# Now, normalize the OS (knowing we just have one component, it's not a kernel,
+# etc.)
+case $os in
+ # First match some system type aliases that might get confused
+ # with valid system types.
+ # solaris* is a basic system type, with this one exception.
+ auroraux)
+ os=auroraux
+ ;;
+ bluegene*)
+ os=cnk
+ ;;
+ solaris1 | solaris1.*)
+ os=`echo "$os" | sed -e 's|solaris1|sunos4|'`
+ ;;
+ solaris)
+ os=solaris2
+ ;;
+ unixware*)
+ os=sysv4.2uw
+ ;;
+ # The marketing names for NeXT's operating systems were
+ # NeXTSTEP, NeXTSTEP 2, OpenSTEP 3, OpenSTEP 4. 'openstep' is
+ # mapped to 'openstep3', but 'openstep1' and 'openstep2' are
+ # mapped to 'nextstep' and 'nextstep2', consistent with the
+ # treatment of SunOS/Solaris.
+ ns | ns1 | nextstep | nextstep1 | openstep1)
+ os=nextstep
+ ;;
+ ns2 | nextstep2 | openstep2)
+ os=nextstep2
+ ;;
+ ns3 | nextstep3 | openstep | openstep3)
+ os=openstep3
+ ;;
+ ns4 | nextstep4 | openstep4)
+ os=openstep4
+ ;;
+ # es1800 is here to avoid being matched by es* (a different OS)
+ es1800*)
+ os=ose
+ ;;
+ # Some version numbers need modification
+ chorusos*)
+ os=chorusos
+ ;;
+ isc)
+ os=isc2.2
+ ;;
+ sco6)
+ os=sco5v6
+ ;;
+ sco5)
+ os=sco3.2v5
+ ;;
+ sco4)
+ os=sco3.2v4
+ ;;
+ sco3.2.[4-9]*)
+ os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'`
+ ;;
+ sco*v* | scout)
+ # Don't match below
+ ;;
+ sco*)
+ os=sco3.2v2
+ ;;
+ psos*)
+ os=psos
+ ;;
+ qnx*)
+ os=qnx
+ ;;
+ hiux*)
+ os=hiuxwe2
+ ;;
+ lynx*178)
+ os=lynxos178
+ ;;
+ lynx*5)
+ os=lynxos5
+ ;;
+ lynxos*)
+ # don't get caught up in next wildcard
+ ;;
+ lynx*)
+ os=lynxos
+ ;;
+ mac[0-9]*)
+ os=`echo "$os" | sed -e 's|mac|macos|'`
+ ;;
+ opened*)
+ os=openedition
+ ;;
+ os400*)
+ os=os400
+ ;;
+ sunos5*)
+ os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+ ;;
+ sunos6*)
+ os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+ ;;
+ wince*)
+ os=wince
+ ;;
+ utek*)
+ os=bsd
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|tektronix|'`
+ ;;
+ dynix*)
+ os=bsd
+ ;;
+ acis*)
+ os=aos
+ ;;
+ atheos*)
+ os=atheos
+ ;;
+ syllable*)
+ os=syllable
+ ;;
+ 386bsd)
+ os=bsd
+ ;;
+ ctix*)
+ os=sysv
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|convergent|'`
+ ;;
+ uts*)
+ os=sysv
+ ;;
+ nova*)
+ kernel=rtmk
+ os=nova
+ ;;
+ # Preserve the version number of sinix5.
+ sinix5.*)
+ os=`echo "$os" | sed -e 's|sinix|sysv|'`
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
+ ;;
+ sinix*)
+ os=sysv4
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
+ ;;
+ tpf*)
+ os=tpf
+ ;;
+ triton*)
+ os=sysv3
+ ;;
+ oss*)
+ os=sysv3
+ ;;
+ svr4*)
+ os=sysv4
+ ;;
+ svr3)
+ os=sysv3
+ ;;
+ sysvr4)
+ os=sysv4
+ ;;
+ ose*)
+ os=ose
+ ;;
+ *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+ os=mint
+ ;;
+ dicos*)
+ os=dicos
+ ;;
+ pikeos*)
+ # Until real need of OS specific support for
+ # particular features comes up, bare metal
+ # configurations are quite functional.
+ case $cpu in
+ arm*)
+ os=eabi
+ ;;
+ *)
+ os=
+ obj=elf
+ ;;
+ esac
+ ;;
+ aout* | coff* | elf* | pe*)
+ # These are machine code file formats, not OSes
+ obj=$os
+ os=
+ ;;
+ *)
+ # No normalization, but not necessarily accepted, that comes below.
+ ;;
+esac
+
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+kernel=
+obj=
+case $cpu-$vendor in
+ score-*)
+ os=
+ obj=elf
+ ;;
+ spu-*)
+ os=
+ obj=elf
+ ;;
+ *-acorn)
+ os=riscix1.2
+ ;;
+ arm*-rebel)
+ kernel=linux
+ os=gnu
+ ;;
+ arm*-semi)
+ os=
+ obj=aout
+ ;;
+ c4x-* | tic4x-*)
+ os=
+ obj=coff
+ ;;
+ c8051-*)
+ os=
+ obj=elf
+ ;;
+ clipper-intergraph)
+ os=clix
+ ;;
+ hexagon-*)
+ os=
+ obj=elf
+ ;;
+ tic54x-*)
+ os=
+ obj=coff
+ ;;
+ tic55x-*)
+ os=
+ obj=coff
+ ;;
+ tic6x-*)
+ os=
+ obj=coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=tops20
+ ;;
+ pdp11-*)
+ os=none
+ ;;
+ *-dec | vax-*)
+ os=ultrix4.2
+ ;;
+ m68*-apollo)
+ os=domain
+ ;;
+ i386-sun)
+ os=sunos4.0.2
+ ;;
+ m68000-sun)
+ os=sunos3
+ ;;
+ m68*-cisco)
+ os=
+ obj=aout
+ ;;
+ mep-*)
+ os=
+ obj=elf
+ ;;
+ # The -sgi and -siemens entries must be before the mips- entry
+ # or we get the wrong os.
+ *-sgi)
+ os=irix
+ ;;
+ *-siemens)
+ os=sysv4
+ ;;
+ mips*-cisco)
+ os=
+ obj=elf
+ ;;
+ mips*-*|nanomips*-*)
+ os=
+ obj=elf
+ ;;
+ or32-*)
+ os=
+ obj=coff
+ ;;
+ # This must be before the sparc-* entry or we get the wrong os.
+ *-tti)
+ os=sysv3
+ ;;
+ sparc-* | *-sun)
+ os=sunos4.1.1
+ ;;
+ pru-*)
+ os=
+ obj=elf
+ ;;
+ *-be)
+ os=beos
+ ;;
+ *-ibm)
+ os=aix
+ ;;
+ *-knuth)
+ os=mmixware
+ ;;
+ *-wec)
+ os=proelf
+ ;;
+ *-winbond)
+ os=proelf
+ ;;
+ *-oki)
+ os=proelf
+ ;;
+ *-hp)
+ os=hpux
+ ;;
+ *-hitachi)
+ os=hiuxwe2
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=sysv
+ ;;
+ *-cbm)
+ os=amigaos
+ ;;
+ *-dg)
+ os=dgux
+ ;;
+ *-dolphin)
+ os=sysv3
+ ;;
+ m68k-ccur)
+ os=rtu
+ ;;
+ m88k-omron*)
+ os=luna
+ ;;
+ *-next)
+ os=nextstep
+ ;;
+ *-sequent)
+ os=ptx
+ ;;
+ *-crds)
+ os=unos
+ ;;
+ *-ns)
+ os=genix
+ ;;
+ i370-*)
+ os=mvs
+ ;;
+ *-gould)
+ os=sysv
+ ;;
+ *-highlevel)
+ os=bsd
+ ;;
+ *-encore)
+ os=bsd
+ ;;
+ *-masscomp)
+ os=rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=uxpv
+ ;;
+ *-rom68k)
+ os=
+ obj=coff
+ ;;
+ *-*bug)
+ os=
+ obj=coff
+ ;;
+ *-apple)
+ os=macos
+ ;;
+ *-atari*)
+ os=mint
+ ;;
+ *-wrs)
+ os=vxworks
+ ;;
+ *)
+ os=none
+ ;;
+esac
+
+fi
+
+# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
+
+case $os in
+ # Sometimes we do "kernel-libc", so those need to count as OSes.
+ llvm* | musl* | newlib* | relibc* | uclibc*)
+ ;;
+ # Likewise for "kernel-abi"
+ eabi* | gnueabi*)
+ ;;
+ # VxWorks passes extra cpu info in the 4th filed.
+ simlinux | simwindows | spe)
+ ;;
+ # See `case $cpu-$os` validation below
+ ghcjs)
+ ;;
+ # Now accept the basic system types.
+ # Each alternative MUST end in a * to match a version number.
+ abug \
+ | aix* \
+ | amdhsa* \
+ | amigados* \
+ | amigaos* \
+ | android* \
+ | aof* \
+ | aos* \
+ | aros* \
+ | atheos* \
+ | auroraux* \
+ | aux* \
+ | beos* \
+ | bitrig* \
+ | bme* \
+ | bosx* \
+ | bsd* \
+ | cegcc* \
+ | chorusos* \
+ | chorusrdb* \
+ | clix* \
+ | cloudabi* \
+ | cnk* \
+ | conix* \
+ | cos* \
+ | cxux* \
+ | cygwin* \
+ | darwin* \
+ | dgux* \
+ | dicos* \
+ | dnix* \
+ | domain* \
+ | dragonfly* \
+ | drops* \
+ | ebmon* \
+ | ecoff* \
+ | ekkobsd* \
+ | emscripten* \
+ | emx* \
+ | es* \
+ | fiwix* \
+ | freebsd* \
+ | fuchsia* \
+ | genix* \
+ | genode* \
+ | glidix* \
+ | gnu* \
+ | go32* \
+ | haiku* \
+ | hcos* \
+ | hiux* \
+ | hms* \
+ | hpux* \
+ | ieee* \
+ | interix* \
+ | ios* \
+ | iris* \
+ | irix* \
+ | ironclad* \
+ | isc* \
+ | its* \
+ | l4re* \
+ | libertybsd* \
+ | lites* \
+ | lnews* \
+ | luna* \
+ | lynxos* \
+ | mach* \
+ | macos* \
+ | magic* \
+ | mbr* \
+ | midipix* \
+ | midnightbsd* \
+ | mingw32* \
+ | mingw64* \
+ | minix* \
+ | mint* \
+ | mirbsd* \
+ | mks* \
+ | mlibc* \
+ | mmixware* \
+ | mon960* \
+ | morphos* \
+ | moss* \
+ | moxiebox* \
+ | mpeix* \
+ | mpw* \
+ | msdos* \
+ | msys* \
+ | mvs* \
+ | nacl* \
+ | netbsd* \
+ | netware* \
+ | newsos* \
+ | nextstep* \
+ | nindy* \
+ | nonstopux* \
+ | nova* \
+ | nsk* \
+ | nucleus* \
+ | nx6 \
+ | nx7 \
+ | oabi* \
+ | ohos* \
+ | onefs* \
+ | openbsd* \
+ | openedition* \
+ | openstep* \
+ | os108* \
+ | os2* \
+ | os400* \
+ | os68k* \
+ | os9* \
+ | ose* \
+ | osf* \
+ | oskit* \
+ | osx* \
+ | palmos* \
+ | phoenix* \
+ | plan9* \
+ | powermax* \
+ | powerunix* \
+ | proelf* \
+ | psos* \
+ | psp* \
+ | ptx* \
+ | pw32* \
+ | qnx* \
+ | rdos* \
+ | redox* \
+ | rhapsody* \
+ | riscix* \
+ | riscos* \
+ | rtems* \
+ | rtmk* \
+ | rtu* \
+ | scout* \
+ | secbsd* \
+ | sei* \
+ | serenity* \
+ | sim* \
+ | skyos* \
+ | solaris* \
+ | solidbsd* \
+ | sortix* \
+ | storm-chaos* \
+ | sunos \
+ | sunos[34]* \
+ | superux* \
+ | syllable* \
+ | sym* \
+ | sysv* \
+ | tenex* \
+ | tirtos* \
+ | toppers* \
+ | tops10* \
+ | tops20* \
+ | tpf* \
+ | tvos* \
+ | twizzler* \
+ | uclinux* \
+ | udi* \
+ | udk* \
+ | ultrix* \
+ | unicos* \
+ | uniplus* \
+ | unleashed* \
+ | unos* \
+ | uwin* \
+ | uxpv* \
+ | v88r* \
+ |*vms* \
+ | vos* \
+ | vsta* \
+ | vxsim* \
+ | vxworks* \
+ | wasi* \
+ | watchos* \
+ | wince* \
+ | windiss* \
+ | windows* \
+ | winnt* \
+ | xenix* \
+ | xray* \
+ | zephyr* \
+ | zvmoe* )
+ ;;
+ # This one is extra strict with allowed versions
+ sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ ;;
+ # This refers to builds using the UEFI calling convention
+ # (which depends on the architecture) and PE file format.
+ # Note that this is both a different calling convention and
+ # different file format than that of GNU-EFI
+ # (x86_64-w64-mingw32).
+ uefi)
+ ;;
+ none)
+ ;;
+ kernel* | msvc* )
+ # Restricted further below
+ ;;
+ '')
+ if test x"$obj" = x
+ then
+ echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&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:
--- /dev/null
+#! /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 <mpdecimal-bugs@bytereef.org>.
+#
+#
+# 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 </dev/null
+exec 6>&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 <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#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<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ 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-bugs@bytereef.org>.
+mpdecimal home page: <https://www.bytereef.org/mpdecimal/index.html>.
+_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 <stdio.h>
+#include <stdlib.h>
+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 <conftest.val; ac_retval=0
+else
+ ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+ fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+cat >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 <stdio.h>
+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 <stdarg.h>
+#include <stdio.h>
+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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> 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 <limits.h>
+#else
+# include <assert.h>
+#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 <ac_nonexistent.h>
+_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 <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+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 <string.h>
+
+_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 <stdlib.h>
+
+_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 <ctype.h>
+#include <stdlib.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+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-bugs@bytereef.org>.
+mpdecimal home page: <https://www.bytereef.org/mpdecimal/index.html>."
+
+_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 2>/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
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$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 = "\a"
+
+}
+{
+ 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
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = "\a"
+}
+/^[\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
--- /dev/null
+AC_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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+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
--- /dev/null
+
+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.
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+#!/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:
--- /dev/null
+
+Directory for shared object files.
+
--- /dev/null
+prefix=@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
--- /dev/null
+#!/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
--- /dev/null
+
+# ==============================================================================
+# 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
--- /dev/null
+
+# ======================================================================
+# 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
+
--- /dev/null
+/*
+ * 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 <cstdio>
+#include <cstdlib>
+#include <cstdint>
+#include <cassert>
+#include <ctime>
+
+#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;
+}
+
--- /dev/null
+/*
+ * 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 <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+
+#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;
+}
+
--- /dev/null
+/*
+ * 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 <cstdint>
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+
+#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<typename T>
+void
+raise(const std::string& msg)
+{
+ throw T(msg);
+}
+
+const cmap signal_map[] = {
+ { MPD_IEEE_Invalid_operation, "IEEEInvalidOperation", "decimal::IEEEInvalidOperation", raise<decimal::IEEEInvalidOperation> },
+ { MPD_Division_by_zero, "DivisionByZero", "decimal::DivisionByZero", raise<decimal::DivisionByZero> },
+ { MPD_Overflow, "Overflow", "decimal::Overflow", raise<decimal::Overflow> },
+ { MPD_Underflow, "Underflow", "decimal::Underflow", raise<decimal::Underflow> },
+ { MPD_Subnormal, "Subnormal", "decimal::Subnormal", raise<decimal::Subnormal> },
+ { MPD_Inexact, "Inexact", "decimal::Inexact", raise<decimal::Inexact> },
+ { MPD_Rounded, "Rounded", "decimal::Rounded", raise<decimal::Rounded> },
+ { MPD_Clamped, "Clamped", "decimal::Clamped", raise<decimal::Clamped> },
+ { UINT32_MAX, nullptr, nullptr, nullptr }
+};
+
+const cmap cond_map[] = {
+ { MPD_Invalid_operation, "InvalidOperation", "decimal::InvalidOperation", raise<decimal::InvalidOperation> },
+ { MPD_Conversion_syntax, "ConversionSyntax", "decimal::ConversionSyntax", raise<decimal::ConversionSyntax> },
+ { MPD_Division_impossible, "DivisionImpossible", "decimal::DivisionImpossible", raise<decimal::DivisionImpossible> },
+ { MPD_Division_undefined, "DivisionUndefined", "decimal::DivisionUndefined", raise<decimal::DivisionUndefined> },
+ { 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<mpd_ssize_t, int64_t>(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
--- /dev/null
+/*
+ * 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 <cassert>
+#include <cstddef>
+#include <cstdint>
+
+#include <algorithm>
+#include <atomic>
+#include <iostream>
+#include <limits>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <mpdecimal.h>
+
+#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 <typename dest_t, typename src_t>
+inline dest_t
+safe_downcast(src_t v) {
+ if (v < std::numeric_limits<dest_t>::min() ||
+ v > std::numeric_limits<dest_t>::max()) {
+ throw ValueError("cast changes the original value");
+ }
+
+ return static_cast<dest_t>(v);
+}
+
+inline std::shared_ptr<const char>
+shared_cp(const char *cp) {
+ if (cp == nullptr) {
+ throw RuntimeError("util::shared_cp: invalid nullptr argument");
+ }
+
+ return std::shared_ptr<const char>(cp, [](const char *s){ mpd_free(const_cast<char *>(s)); });
+}
+
+inline std::string
+string_from_cp(const char *cp) {
+ const auto p = shared_cp(cp);
+ return std::string(p.get());
+}
+
+template <typename T>
+struct int64_compat {
+#define INT64_SUBSET(T) \
+ (INT64_MIN <= std::numeric_limits<T>::min() && std::numeric_limits<T>::max() <= INT64_MAX)
+
+ static const bool value = std::is_same<T, int8_t>::value ||
+ std::is_same<T, int16_t>::value ||
+ std::is_same<T, int32_t>::value ||
+ std::is_same<T, int64_t>::value ||
+ (std::is_same<T, signed char>::value && INT64_SUBSET(signed char)) ||
+ (std::is_same<T, short>::value && INT64_SUBSET(short)) ||
+ (std::is_same<T, int>::value && INT64_SUBSET(int)) ||
+ (std::is_same<T, long>::value && INT64_SUBSET(long)) ||
+ (std::is_same<T, long long>::value && INT64_SUBSET(long long));
+};
+
+template <typename T>
+struct uint64_compat {
+#define UINT64_SUBSET(T) (std::numeric_limits<T>::max() <= UINT64_MAX)
+
+ static const bool value = std::is_same<T, uint8_t>::value ||
+ std::is_same<T, uint16_t>::value ||
+ std::is_same<T, uint32_t>::value ||
+ std::is_same<T, uint64_t>::value ||
+ (std::is_same<T, unsigned char>::value && UINT64_SUBSET(unsigned char)) ||
+ (std::is_same<T, unsigned short>::value && UINT64_SUBSET(unsigned short)) ||
+ (std::is_same<T, unsigned int>::value && UINT64_SUBSET(unsigned int)) ||
+ (std::is_same<T, unsigned long>::value && UINT64_SUBSET(unsigned long)) ||
+ (std::is_same<T, unsigned long long>::value && UINT64_SUBSET(unsigned long long));
+};
+
+#define ENABLE_IF_SIGNED(T) \
+ template<typename T, \
+ typename = typename std::enable_if<util::int64_compat<T>::value>::type>
+
+#define ENABLE_IF_UNSIGNED(T) \
+ template<typename T, \
+ typename = typename std::enable_if<util::uint64_compat<T>::value>::type, typename = void>
+
+#define ENABLE_IF_INTEGRAL(T) \
+ template<typename T, \
+ typename = typename std::enable_if<util::int64_compat<T>::value || util::uint64_compat<T>::value>::type>
+
+#define ASSERT_SIGNED(T) \
+ static_assert(util::int64_compat<T>::value, \
+ "internal error: selected type is not int64 compatible")
+
+#define ASSERT_UNSIGNED(T) \
+ static_assert(util::uint64_compat<T>::value, \
+ "internal error: selected type is not uint64 compatible")
+
+#define ASSERT_INTEGRAL(T) \
+ static_assert(util::int64_compat<T>::value || util::uint64_compat<T>::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<mpd_ssize_t, int64_t>(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<mpd_ssize_t, int64_t>(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<Decimal, Decimal> divmod(const Decimal& other, Context& c=context) const {
+ std::pair<Decimal, Decimal> 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<mpd_ssize_t, int64_t>(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<mpd_ssize_t, int64_t>(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<mpd_ssize_t, int64_t>(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<mpd_ssize_t, int64_t>(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_
--- /dev/null
+/*
+ * 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 <iostream>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <cassert>
+#include <climits>
+
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+#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;
+}
--- /dev/null
+
+Directory for shared object files
+=================================
+
+ symbols32.exp ==> 32-bit libmpdec API
+
+ symbols64.exp ==> 64-bit libmpdec API
+
--- /dev/null
+*** 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
--- /dev/null
+*** 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
--- /dev/null
+prefix=@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
--- /dev/null
+#!/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
--- /dev/null
+
+# ==============================================================================
+# 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
--- /dev/null
+
+# ======================================================================
+# 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
--- /dev/null
+
+
+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 <skrah@bytereef.org>
+
+
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <stdio.h>
+
+#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<slen; i++,j++) {
+ _mpd_divmod_pow10(&h, &l, src[i], r);
+ dest[j] = ph * l + hprev;
+ hprev = h;
+ }
+ /* write most significant word */
+ if (hprev != 0) { /* always the case if slen==q-1 */
+ dest[j] = hprev;
+ }
+ }
+ else {
+ if (q > 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <intrin.h>
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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"
+};
--- /dev/null
+/*
+ * 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 <stdint.h>
+
+#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_ */
--- /dev/null
+/*
+ * 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 <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <assert.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <assert.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+
+This directory contains a number of examples. In order to compile, run
+(for example):
+
+ gcc -Wall -W -O2 -o powmod powmod.c -lmpdec -lm
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <mpdecimal.h>
+
+
+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;
+}
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <mpdecimal.h>
+
+
+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;
+}
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <mpdecimal.h>
+
+
+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;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <mpdecimal.h>
+
+
+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;
+}
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <mpdecimal.h>
+
+
+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;
+}
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <mpdecimal.h>
+
+
+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;
+}
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <mpdecimal.h>
+
+
+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;
+}
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <mpdecimal.h>
+
+
+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;
+}
+
+
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <stdio.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <assert.h>
+
+#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<a+C; p0++,p1++,p2++) {
+
+ SIZE3_NTT(p0, p1, p2, w3table);
+ }
+
+ /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */
+ 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-1; 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. */
+ for (s = a; s < a+n; s += C) {
+ if (!six_step_fnt(s, C, modnum)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* backward transform, sign = 1; transform length = 3 * 2**n */
+int
+inv_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 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<a+C; p0++,p1++,p2++) {
+
+ SIZE3_NTT(p0, p1, p2, w3table);
+ }
+
+ return 1;
+}
--- /dev/null
+/*
+ * 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_FOURSTEP_H_
+#define LIBMPDEC_FOURSTEP_H_
+
+
+#include "mpdecimal.h"
+
+
+/* Internal header file: all symbols have local scope in the DSO */
+MPD_PRAGMA(MPD_HIDE_SYMBOLS_START)
+
+
+int four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum);
+int inv_four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum);
+
+
+MPD_PRAGMA(MPD_HIDE_SYMBOLS_END) /* restore previous scope rules */
+
+
+#endif /* LIBMPDEC_FOURSTEP_H_ */
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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<<j)) {
+ n = snprintf(cp, nmemb, "%s ", mpd_flag_string[j]);
+ if (n < 0 || n >= 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<<j)) {
+ n = snprintf(cp, nmemb, "%s, ", flag_string[j]);
+ if (n < 0 || n >= 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<<j);
+ if (f) {
+ if (f&MPD_IEEE_Invalid_operation) {
+ if (ieee_invalid_done) {
+ continue;
+ }
+ ieee_invalid_done = 1;
+ }
+ n = snprintf(cp, nmemb, "%s, ", signal_string[j]);
+ if (n < 0 || n >= 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 */
+ }
+}
--- /dev/null
+/*
+ * 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 <stdint.h>
+
+#include "mpdecimal.h"
+
+
+#if SIZE_MAX == MPD_SIZE_MAX
+ #define mpd_strtossize _mpd_strtossize
+#else
+#include <errno.h>
+
+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_ */
--- /dev/null
+
+
+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
+
+
+
--- /dev/null
+
+
+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.
+
+
+
--- /dev/null
+#
+# 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))
--- /dev/null
+
+
+(* 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/
+
+
+
--- /dev/null
+
+
+(* 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
+
+
+
--- /dev/null
+
+
+(* 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.
--- /dev/null
+
+
+(* 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/
+
+
--- /dev/null
+;
+; 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<x<2*m
+ (implies (and (<= m x)
+ (< x (* 2 m))
+ (rationalp x) (rationalp m))
+ (equal (mod x m)
+ (+ x (- m)))))
+
+(defthm modaux-1a
+ (implies (and (< x m) (< 0 x) (< 0 m)
+ (rationalp x) (rationalp m))
+ (equal (mod (- x) m)
+ (+ (- x) m))))
+
+(defthm modaux-1b
+ (implies (and (< (- x) m) (< x 0) (< 0 m)
+ (rationalp x) (rationalp m))
+ (equal (mod x m)
+ (+ x m)))
+ :hints (("Goal" :use ((:instance modaux-1a
+ (x (- x)))))))
+
+(defthm modaux-1c
+ (implies (and (< x m) (< 0 x) (< 0 m)
+ (rationalp x) (rationalp m))
+ (equal (mod x m)
+ x)))
+
+(defthm modaux-2a
+ (implies (and (< 0 b) (< b m)
+ (natp x) (natp b) (natp m)
+ (< (mod (+ b x) m) b))
+ (equal (mod (+ (- m) b x) m)
+ (+ (- m) b (mod x m)))))
+
+(defthm modaux-2b
+ (implies (and (< 0 b) (< b m)
+ (natp x) (natp b) (natp m)
+ (< (mod (+ b x) m) b))
+ (equal (mod (+ b x) m)
+ (+ (- m) b (mod x m))))
+ :hints (("Goal" :use (modaux-2a))))
+
+(defthm linear-mod-1
+ (implies (and (< x m) (< b m)
+ (natp x) (natp b)
+ (rationalp m))
+ (equal (< x (mod (+ (- b) x) m))
+ (< x b)))
+ :hints (("Goal" :use ((:instance modaux-1a
+ (x (+ b (- x))))))))
+
+(defthm linear-mod-2
+ (implies (and (< 0 b) (< b m)
+ (natp x) (natp b)
+ (natp m))
+ (equal (< (mod x m)
+ (mod (+ (- b) x) m))
+ (< (mod x m) b))))
+
+(defthm linear-mod-3
+ (implies (and (< x m) (< b m)
+ (natp x) (natp b)
+ (rationalp m))
+ (equal (<= b (mod (+ b x) m))
+ (< (+ b x) m)))
+ :hints (("Goal" :use ((:instance elim-mod-m<x<2*m
+ (x (+ b x)))))))
+
+(defthm modaux-2c
+ (implies (and (< 0 b) (< b m)
+ (natp x) (natp b) (natp m)
+ (<= b (mod (+ b x) m)))
+ (equal (mod (+ b x) m)
+ (+ b (mod x m))))
+ :hints (("Subgoal *1/8''" :use (linear-mod-3))))
+
+(defthmd modaux-2d
+ (implies (and (< x m) (< 0 x) (< 0 m)
+ (< (- m) b) (< b 0) (rationalp m)
+ (<= x (mod (+ b x) m))
+ (rationalp x) (rationalp b))
+ (equal (+ (- m) (mod (+ b x) m))
+ (+ b x)))
+ :hints (("Goal" :cases ((<= 0 (+ b x))))
+ ("Subgoal 2'" :use ((:instance modaux-1b
+ (x (+ b x)))))))
+
+(defthm mod-m-b
+ (implies (and (< 0 x) (< 0 b) (< 0 m)
+ (< x b) (< b m)
+ (natp x) (natp b) (natp m))
+ (equal (mod (+ (mod (- x) m) b) m)
+ (mod (- x) b))))
+
+
+;; =====================================================================
+;; addmod, submod
+;; =====================================================================
+
+(defun addmod (a b m base)
+ (let* ((s (mod (+ a b) base))
+ (s (if (< s a) (mod (- s m) base) s))
+ (s (if (>= 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<x<2*m
+ (x (+ a b)))))))
+
+(defun submod (a b m base)
+ (let* ((d (mod (- a b) base))
+ (d (if (< a d) (mod (+ d m) base) d)))
+ d))
+
+(defthmd submod-aux1
+ (implies (and (< a (mod (+ a (- b)) base))
+ (< 0 base) (< a base) (<= b base)
+ (natp base) (natp a) (natp b))
+ (< a b))
+ :rule-classes :forward-chaining)
+
+(defthmd submod-aux2
+ (implies (and (<= (mod (+ a (- b)) base) a)
+ (< 0 base) (< a base) (< b base)
+ (natp base) (natp a) (natp b))
+ (<= b a))
+ :rule-classes :forward-chaining)
+
+(defthmd submod-correct
+ (implies (and (< 0 m) (< m base)
+ (< a m) (<= b m)
+ (natp m) (natp base)
+ (natp a) (natp b))
+ (equal (submod a b m base)
+ (mod (- a b) m)))
+ :hints (("Goal" :cases ((<= base (+ a b))))
+ ("Subgoal 2.2" :use ((:instance submod-aux1)))
+ ("Subgoal 2.2'''" :cases ((and (< 0 (+ a (- b) m))
+ (< (+ a (- b) m) m))))
+ ("Subgoal 2.1" :use ((:instance submod-aux2)))
+ ("Subgoal 1.2" :use ((:instance submod-aux1)))
+ ("Subgoal 1.1" :use ((:instance submod-aux2)))))
+
+
+(defun submod-2 (a b m base)
+ (let* ((d (mod (- a b) base))
+ (d (if (< a b) (mod (+ d m) base) d)))
+ d))
+
+(defthm submod-2-correct
+ (implies (and (< 0 m) (< m base)
+ (< a m) (<= b m)
+ (natp m) (natp base)
+ (natp a) (natp b))
+ (equal (submod-2 a b m base)
+ (mod (- a b) m)))
+ :hints (("Subgoal 2'" :cases ((and (< 0 (+ a (- b) m))
+ (< (+ a (- b) m) m))))))
+
+
+;; =========================================================================
+;; ext-submod is correct
+;; =========================================================================
+
+; a < 2*m, b < 2*m
+(defun ext-submod (a b m base)
+ (let* ((a (if (>= 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<x<2*m for the final reduction.
+; For p1, two modular reductions are sufficient, for p2 and p3 three.
+; ---------------------------------------------------------------------
+
+;; p1: the first reduction is less than 2**96
+(defthmd simple-mod-reduce-p1-<-2**96
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p1 hi lo)
+ (expt 2 96))))
+
+;; p1: the second reduction is less than 2*p1
+(defthmd simple-mod-reduce-p1-<-2*p1
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 96))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p1 hi lo)
+ (* 2 (p1)))))
+
+
+;; p2: the first reduction is less than 2**98
+(defthmd simple-mod-reduce-p2-<-2**98
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p2 hi lo)
+ (expt 2 98))))
+
+;; p2: the second reduction is less than 2**69
+(defthmd simple-mod-reduce-p2-<-2*69
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 98))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p2 hi lo)
+ (expt 2 69))))
+
+;; p3: the third reduction is less than 2*p2
+(defthmd simple-mod-reduce-p2-<-2*p2
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 69))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p2 hi lo)
+ (* 2 (p2)))))
+
+
+;; p3: the first reduction is less than 2**104
+(defthmd simple-mod-reduce-p3-<-2**104
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p3 hi lo)
+ (expt 2 104))))
+
+;; p3: the second reduction is less than 2**81
+(defthmd simple-mod-reduce-p3-<-2**81
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 104))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p3 hi lo)
+ (expt 2 81))))
+
+;; p3: the third reduction is less than 2*p3
+(defthmd simple-mod-reduce-p3-<-2*p3
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 81))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p3 hi lo)
+ (* 2 (p3)))))
+
+
+; -------------------------------------------------------------------------
+; The simple modular reductions, adapted for compiler friendly C
+; -------------------------------------------------------------------------
+
+(defun mod-reduce-p1 (hi lo)
+ (let* ((y hi)
+ (x y)
+ (hi (>> 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)))))))
+
+
+
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <stdint.h>
+
+#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_ */
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <float.h>
+ #pragma float_control(precise, on)
+ #pragma fenv_access(on)
+ #elif !defined(__OpenBSD__) && !defined(__NetBSD__)
+ /* The C99 standard requires the pragma */
+ #include <fenv.h>
+ #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)<<log2rsize;
+ return (rsize == x) ? x : x<<1;
+ }
+ else if (rsize <= MPD_MAXTRANSFORM_2N) {
+ x = ((mpd_size_t)1)<<log2rsize;
+ if (rsize == x) return x;
+ step = x>>1;
+ x += step;
+ return (rsize <= x) ? x : x + step;
+ }
+ else if (rsize <= MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2) {
+ return MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2;
+ }
+ else if (rsize <= 3*MPD_MAXTRANSFORM_2N) {
+ return 3*MPD_MAXTRANSFORM_2N;
+ }
+ else {
+ return MPD_SIZE_MAX;
+ }
+}
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <cinttypes>
+ #include <climits>
+ #include <cstdint>
+ #include <cstdio>
+ #include <cstdlib>
+ #define MPD_UINT8_C(x) (static_cast<uint8_t>(x))
+extern "C" {
+#else
+ #include <inttypes.h>
+ #include <limits.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #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_ */
--- /dev/null
+/*
+ * 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 <cinttypes>
+ #include <climits>
+ #include <cstdint>
+ #include <cstdio>
+ #include <cstdlib>
+ #define MPD_UINT8_C(x) (static_cast<uint8_t>(x))
+extern "C" {
+#else
+ #include <inttypes.h>
+ #include <limits.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #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_ */
--- /dev/null
+/*
+ * 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 <cinttypes>
+ #include <climits>
+ #include <cstdint>
+ #include <cstdio>
+ #include <cstdlib>
+ #define MPD_UINT8_C(x) (static_cast<uint8_t>(x))
+extern "C" {
+#else
+ #include <inttypes.h>
+ #include <limits.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #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_ */
--- /dev/null
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <stdlib.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <stdio.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <assert.h>
+
+#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 <intrin.h>
+#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_ */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+;
+; 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
+
+
--- /dev/null
+
+# ==============================================================================
+# 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
--- /dev/null
+
+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
+
--- /dev/null
+
+
+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
+#
+
+
+
--- /dev/null
+
+-- 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
+
--- /dev/null
+/*
+ * 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 <climits>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+
+#include <algorithm>
+#include <array>
+#include <limits>
+#include <list>
+#include <map>
+#include <random>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#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<std::exception, DecimalException>::value));
+
+ assertTrue((std::is_base_of<DecimalException, IEEEInvalidOperation>::value));
+ assertTrue((std::is_base_of<IEEEInvalidOperation, ConversionSyntax>::value));
+ assertTrue((std::is_base_of<IEEEInvalidOperation, DivisionImpossible>::value));
+ assertTrue((std::is_base_of<IEEEInvalidOperation, DivisionUndefined>::value));
+ assertTrue((std::is_base_of<IEEEInvalidOperation, InvalidOperation>::value));
+
+ assertTrue((std::is_base_of<DecimalException, DivisionByZero>::value));
+ assertTrue((std::is_base_of<DecimalException, Overflow>::value));
+ assertTrue((std::is_base_of<DecimalException, Underflow>::value));
+ assertTrue((std::is_base_of<DecimalException, Subnormal>::value));
+ assertTrue((std::is_base_of<DecimalException, Inexact>::value));
+ assertTrue((std::is_base_of<DecimalException, Rounded>::value));
+ assertTrue((std::is_base_of<DecimalException, Clamped>::value));
+
+ assertTrue((std::is_base_of<std::exception, ValueError>::value));
+ assertTrue((std::is_base_of<std::exception, RuntimeError>::value));
+ assertTrue((std::is_base_of<std::exception, MallocError>::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<class T>
+static void
+signed_construction()
+{
+ const T min = std::numeric_limits<T>::min();
+ const T max = std::numeric_limits<T>::max();
+
+ const std::vector<T> 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<T> signs = {-1, 1};
+ for (int n = 0; n < std::numeric_limits<T>::digits; n++) {
+ for (const T& sign : signs) {
+ for (T x = -5; x < 5; x++) {
+ const T i = static_cast<T>(sign * ((static_cast<T>(1) << n) + x));
+ const Decimal d = {i};
+ assertEqual(d, i);
+ assertEqual(i, d);
+ }
+ }
+ }
+}
+
+template<class T>
+static void
+unsigned_construction()
+{
+ const T max = std::numeric_limits<T>::max();
+
+ const std::vector<T> 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<T>::digits; n++) {
+ for (T x = 0; x < 5; x++) {
+ const T i = static_cast<T>((static_cast<T>(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 char>();
+ signed_construction<short>();
+ signed_construction<int>();
+ signed_construction<long>();
+ signed_construction<long long>();
+
+ signed_construction<int8_t>();
+ signed_construction<int16_t>();
+ signed_construction<int32_t>();
+ signed_construction<int64_t>();
+
+ unsigned_construction<unsigned char>();
+ unsigned_construction<unsigned short>();
+ unsigned_construction<unsigned int>();
+ unsigned_construction<unsigned long>();
+ unsigned_construction<unsigned long long>();
+
+ unsigned_construction<uint8_t>();
+ unsigned_construction<uint16_t>();
+ unsigned_construction<uint32_t>();
+ unsigned_construction<uint64_t>();
+
+ /*****************************************************************/
+ /* 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<class T>
+static void
+signed_construction_ctx(Context& ctx)
+{
+ const T min = std::numeric_limits<T>::min();
+ const T max = std::numeric_limits<T>::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<class T>
+static void
+unsigned_construction_ctx(Context& ctx)
+{
+ const T v = std::numeric_limits<T>::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<signed char>(ctx);
+ signed_construction_ctx<short>(ctx);
+ signed_construction_ctx<int>(ctx);
+ signed_construction_ctx<long>(ctx);
+ signed_construction_ctx<long long>(ctx);
+
+ signed_construction_ctx<int8_t>(ctx);
+ signed_construction_ctx<int16_t>(ctx);
+ signed_construction_ctx<int32_t>(ctx);
+ signed_construction_ctx<int64_t>(ctx);
+
+ unsigned_construction_ctx<unsigned char>(ctx);
+ unsigned_construction_ctx<unsigned short>(ctx);
+ unsigned_construction_ctx<unsigned int>(ctx);
+ unsigned_construction_ctx<unsigned long>(ctx);
+ unsigned_construction_ctx<unsigned long long>(ctx);
+
+ unsigned_construction_ctx<uint8_t>(ctx);
+ unsigned_construction_ctx<uint16_t>(ctx);
+ unsigned_construction_ctx<uint32_t>(ctx);
+ unsigned_construction_ctx<uint64_t>(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 <class T>
+static void
+signed_assignment()
+{
+ const T min = std::numeric_limits<T>::min();
+ const T max = std::numeric_limits<T>::max();
+ const std::vector<T> 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 <class T>
+static void
+unsigned_assignment()
+{
+ const T max = std::numeric_limits<T>::max();
+ const std::vector<T> 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 char>();
+ signed_assignment<short>();
+ signed_assignment<int>();
+ signed_assignment<long>();
+ signed_assignment<long long>();
+
+ signed_assignment<int8_t>();
+ signed_assignment<int16_t>();
+ signed_assignment<int32_t>();
+ signed_assignment<int64_t>();
+
+ unsigned_assignment<unsigned char>();
+ unsigned_assignment<unsigned short>();
+ unsigned_assignment<unsigned int>();
+ unsigned_assignment<unsigned long>();
+ unsigned_assignment<unsigned long long>();
+
+ unsigned_assignment<uint8_t>();
+ unsigned_assignment<uint16_t>();
+ unsigned_assignment<uint32_t>();
+ unsigned_assignment<uint64_t>();
+}
+
+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<uintptr_t>(x), reinterpret_cast<uintptr_t>(d) + 10 * (sizeof *d));
+
+ x -= 10;
+ assertEqual(reinterpret_cast<uintptr_t>(x), reinterpret_cast<uintptr_t>(d));
+#endif
+
+ delete x;
+}
+
+
+/******************************************************************************/
+/* Comparison operators */
+/******************************************************************************/
+
+template<class T>
+static void
+signed_comparison()
+{
+ const T min = std::numeric_limits<T>::min();
+ const T max = std::numeric_limits<T>::max();
+ const std::vector<T> 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<class T>
+static void
+unsigned_comparison()
+{
+ const T max = std::numeric_limits<T>::max();
+ const std::vector<T> 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 char>();
+ signed_comparison<short>();
+ signed_comparison<int>();
+ signed_comparison<long>();
+ signed_comparison<long long>();
+
+ signed_comparison<int8_t>();
+ signed_comparison<int16_t>();
+ signed_comparison<int32_t>();
+ signed_comparison<int64_t>();
+
+ unsigned_comparison<unsigned char>();
+ unsigned_comparison<unsigned short>();
+ unsigned_comparison<unsigned int>();
+ unsigned_comparison<unsigned long>();
+ unsigned_comparison<unsigned long long>();
+
+ unsigned_comparison<uint8_t>();
+ unsigned_comparison<uint16_t>();
+ unsigned_comparison<uint32_t>();
+ unsigned_comparison<uint64_t>();
+
+
+ /* 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 <class T>
+static void
+signed_arithmetic()
+{
+ const T min = std::numeric_limits<T>::min();
+ const T max = std::numeric_limits<T>::max();
+ const std::vector<T> 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 <class T>
+static void
+unsigned_arithmetic()
+{
+ const T max = std::numeric_limits<T>::max();
+ const std::vector<T> 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 char>();
+ signed_arithmetic<short>();
+ signed_arithmetic<int>();
+ signed_arithmetic<long>();
+ signed_arithmetic<long long>();
+
+ signed_arithmetic<int8_t>();
+ signed_arithmetic<int16_t>();
+ signed_arithmetic<int32_t>();
+ signed_arithmetic<int64_t>();
+
+ unsigned_arithmetic<unsigned char>();
+ unsigned_arithmetic<unsigned short>();
+ unsigned_arithmetic<unsigned int>();
+ unsigned_arithmetic<unsigned long>();
+ unsigned_arithmetic<unsigned long long>();
+
+ unsigned_arithmetic<uint8_t>();
+ unsigned_arithmetic<uint16_t>();
+ unsigned_arithmetic<uint32_t>();
+ unsigned_arithmetic<uint64_t>();
+}
+
+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<uintptr_t>(x), reinterpret_cast<uintptr_t>(d) + 10 * (sizeof *d));
+
+ x = x - 10;
+ assertEqual(reinterpret_cast<uintptr_t>(x), reinterpret_cast<uintptr_t>(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<std::pair<const char *, long long>> 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<std::pair<const char *, long long>> 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<std::pair<const char *, long long>> 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<const char *>(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<Decimal> 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<const char *, Decimal> map1;
+ std::vector<const char *> 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<Decimal, const char *> map2;
+ std::vector<const char *> 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<Decimal> 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<Decimal> 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<const char *, Decimal> map1;
+ std::vector<const char *> 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<Decimal, Decimal> map2;
+ std::vector<const char *> 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<std::vector<const char *>> 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<const char *>& 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<struct test_case, NUM_TESTS> 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<std::string>& 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<std::string>& 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<struct test_case, NUM_TESTS>& tests)
+{
+ const size_t n = tests.size();
+ std::vector<std::string> 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<struct test_case, NUM_TESTS>& tests)
+{
+ const size_t n = tests.size();
+ std::vector<std::string> status(n, "PASS");
+ std::vector<std::thread> 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<struct test_case, NUM_TESTS>& tests)
+{
+ const size_t n = tests.size();
+ std::vector<std::string> status(n, "PASS");
+ std::random_device rd;
+ std::mt19937 g(rd());
+ std::vector<size_t> 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<struct test_case, NUM_TESTS>& tests)
+{
+ const size_t n = tests.size();
+ std::vector<std::string> status(n, "PASS");
+ std::vector<std::thread> t(n);
+ std::random_device rd;
+ std::mt19937 g(rd());
+ std::vector<size_t> 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<std::string> 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);
+ }
+ }
+}
--- /dev/null
+@ECHO OFF\r
+\r
+cd ..\tests\r
+call gettests.bat\r
+cd ..\tests++\r
+\r
+if not exist testdata mkdir testdata\r
+if not exist testdata\baseconv.decTest copy /y ..\tests\testdata_dist\* testdata\r
+if not exist testdata\add.decTest copy /y ..\tests\testdata\* testdata\r
--- /dev/null
+#!/bin/sh
+
+cd ../tests && ./gettests.sh "$1" || exit 1
+cd ../tests++ && cp -Rp ../tests/testdata . || exit 1
+
--- /dev/null
+
+-- 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
+
+
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+/*
+ * 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 <pthread.h>
+ #endif
+#endif
+
+#include <cctype>
+#include <cerrno>
+#include <cinttypes>
+#include <clocale>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+
+#include <algorithm>
+#include <atomic>
+#include <fstream>
+#include <iostream>
+#include <random>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <utility>
+#include <vector>
+
+#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<std::string>& 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<mpd_ssize_t>(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<unsigned char>(*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<unsigned char>(*end))) {
+ break;
+ }
+ if (!istokchar(static_cast<unsigned char>(*end))) {
+ return -1;
+ }
+ }
+ next_start = end;
+ return 0;
+ }
+ }
+
+ start = next_start = end;
+ return 0;
+}
+
+/* split a line into tokens */
+static std::vector<std::string>
+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<std::string> 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<char> ptr(new char[strlen(s)+1], std::default_delete<char[]>());
+ 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<unsigned char, unsigned int>(u);
+ *cp++ = static_cast<char>(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<char> 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<unsigned char, unsigned long>(ul);
+ bytes.push_back(static_cast<char>(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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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, Decimal> (Decimal::*DecimalPair_DecimalDecimalContext)(const Decimal&, Context&) const;
+
+static void
+DecPair_DecDecCtx_RunSingle(std::pair<Decimal, Decimal>& result, Decimal& tmp1, Decimal& tmp2,
+ const std::vector<std::string>& 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<std::string>& token,
+ const bool scan_equal,
+ const bool extended)
+{
+ Context maxcontext{readcontext(extended)};
+ std::pair<Decimal, Decimal> 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string> 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<uint32_t> 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<std::string> 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<int>(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<std::string>& status)
+{
+ for (auto p : status) {
+ if (p != "PASS") {
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static void
+do_file(const std::string& filename, std::vector<std::string>& 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<std::string>& files)
+{
+ const size_t n = files.size();
+ std::vector<std::string> 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<std::string>& files)
+{
+ const size_t n = files.size();
+ std::vector<std::string> status(n, "PASS");
+ std::vector<std::thread> 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<std::string> *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<struct thread_info *>(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<std::string>& files)
+{
+ const size_t n = files.size();
+ std::vector<std::string> status(n, "PASS");
+ std::vector<struct thread_info> 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<std::string>
+collect_files(const std::string& topfile)
+{
+ std::vector<std::string> 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<std::string> 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<std::string> 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 << "<stdin> ... " << e.what() << "\n" << std::flush;
+ return EXIT_FAILURE;
+ }
+ std::cout << "<stdin> ... PASS\n\n" << std::flush;
+ return EXIT_SUCCESS;
+ }
+
+ /* Collect test files */
+ std::vector<std::string> 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);
+ }
+}
--- /dev/null
+/*
+ * 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 <cstdlib>
+#include <cstdint>
+#include <cinttypes>
+
+#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 */
--- /dev/null
+/*
+ * 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 <exception>
+#include <string>
+#include <sstream>
+#include <vector>
+
+
+namespace test {
+
+
+/******************************************************************************/
+/* Util */
+/******************************************************************************/
+
+template<typename T>
+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<typename T, typename... Args>
+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<typename... Args>
+ explicit Failure(Args... args) : m(stringize(args...)) {}
+ virtual const char* what() const noexcept;
+};
+
+template<typename... Args>
+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<class T, class U>
+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<class T, class U>
+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<typename Exc, typename F>
+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<ex>(__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_
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+
+# ==============================================================================
+# 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
--- /dev/null
+
+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
--- /dev/null
+
+
+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
+#
+
+
+
--- /dev/null
+
+-- 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
+
+
--- /dev/null
+@ECHO OFF\r
+\r
+if not exist testdata mkdir testdata\r
+rem copy additional tests\r
+if not exist testdata\baseconv.decTest copy /y testdata_dist\* testdata\r
+\r
+if exist testdata\add.decTest goto OUT\r
+\r
+rem get official tests\r
+if exist dectest.zip goto UNZIP\r
+powershell -Command "wget http://speleotrove.com/decimal/dectest.zip -outfile dectest.zip"\r
+\r
+:UNZIP\r
+powershell -Command "Expand-Archive dectest.zip -DestinationPath testdata"\r
+\r
+:OUT\r
--- /dev/null
+#!/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
--- /dev/null
+
+-- 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
+
+
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "mpdecimal.h"
+#include "test.h"
+#include "vctest.h"
+
+
+#define MAXLINE 400000
+#define MAXTOKEN 32
+
+#ifndef _MSC_VER
+ #include <inttypes.h>
+ #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;
+}
--- /dev/null
+/*
+ * 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 <stdbool.h>
+#include <stdlib.h>
+
+#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;
+ }
+}
--- /dev/null
+/*
+ * 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 <stdbool.h>
+#include <stdio.h>
+
+#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_ */
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+-- 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
+
--- /dev/null
+-- 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
+
--- /dev/null
+-- 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
--- /dev/null
+-- 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
+
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+-- 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
+
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+
+
+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
+
+
+
+
+
--- /dev/null
+@ECHO off\r
+\r
+"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt\r
+set /p vcpath=<vcpath.txt\r
+del vcpath.txt\r
+call "%vcpath%\VC\Auxiliary\Build\vcvarsall.bat" x86\r
+\r
+\r
+if not exist dist32 mkdir dist32\r
+if exist dist32\* del /q dist32\*\r
+\r
+\r
+cd ..\libmpdec\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake MACHINE=ppro profile\r
+\r
+copy /y "libmpdec-4.0.1.lib" ..\vcbuild\dist32\r
+copy /y "libmpdec-4.0.1.dll" ..\vcbuild\dist32\r
+copy /y "libmpdec-4.0.1.dll.lib" ..\vcbuild\dist32\r
+copy /y "libmpdec-4.0.1.dll.exp" ..\vcbuild\dist32\r
+copy /y "mpdecimal.h" ..\vcbuild\dist32\r
+\r
+\r
+cd ..\libmpdec++\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake\r
+\r
+copy /y "libmpdec++-4.0.1.lib" ..\vcbuild\dist32\r
+copy /y "libmpdec++-4.0.1.dll" ..\vcbuild\dist32\r
+copy /y "libmpdec++-4.0.1.dll.lib" ..\vcbuild\dist32\r
+copy /y "libmpdec++-4.0.1.dll.exp" ..\vcbuild\dist32\r
+copy /y "decimal.hh" ..\vcbuild\dist32\r
+\r
+\r
+cd ..\vcbuild\r
+\r
+\r
+\r
--- /dev/null
+@ECHO off\r
+\r
+"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt\r
+set /p vcpath=<vcpath.txt\r
+del vcpath.txt\r
+call "%vcpath%\VC\Auxiliary\Build\vcvarsall.bat" x64\r
+\r
+if not exist dist64 mkdir dist64\r
+if exist dist64\* del /q dist64\*\r
+\r
+cd ..\libmpdec\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake MACHINE=x64 profile\r
+\r
+copy /y "libmpdec-4.0.1.lib" ..\vcbuild\dist64\r
+copy /y "libmpdec-4.0.1.dll" ..\vcbuild\dist64\r
+copy /y "libmpdec-4.0.1.dll.lib" ..\vcbuild\dist64\r
+copy /y "libmpdec-4.0.1.dll.exp" ..\vcbuild\dist64\r
+copy /y "mpdecimal.h" ..\vcbuild\dist64\r
+\r
+\r
+cd ..\libmpdec++\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake\r
+\r
+copy /y "libmpdec++-4.0.1.lib" ..\vcbuild\dist64\r
+copy /y "libmpdec++-4.0.1.dll" ..\vcbuild\dist64\r
+copy /y "libmpdec++-4.0.1.dll.lib" ..\vcbuild\dist64\r
+copy /y "libmpdec++-4.0.1.dll.exp" ..\vcbuild\dist64\r
+copy /y "decimal.hh" ..\vcbuild\dist64\r
+\r
+cd ..\vcbuild\r
+\r
+\r
+\r
--- /dev/null
+@ECHO OFF\r
+\r
+rem Release or debug build.\r
+set DBG=0\r
+if "%1%" == "/d" set DBG=1\r
+\r
+rem Build libmpdec tests.\r
+cd ..\tests\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake DEBUG=%DBG%\r
+\r
+rem # Download the official test cases (text files).\r
+call gettests.bat\r
+\r
+echo.\r
+echo # ========================================================================\r
+echo # libmpdec: static library\r
+echo # ========================================================================\r
+echo.\r
+\r
+echo.\r
+<nul (set /p x="Running official tests ... ")\r
+echo.\r
+echo.\r
+runtest.exe official.decTest\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running additional tests ... ")\r
+echo.\r
+echo.\r
+runtest.exe additional.decTest\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+echo # ========================================================================\r
+echo # libmpdec: shared library\r
+echo # ========================================================================\r
+echo.\r
+\r
+echo.\r
+<nul (set /p x="Running official tests ... ")\r
+echo.\r
+echo.\r
+runtest_shared.exe official.decTest\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running additional tests ... ")\r
+echo.\r
+echo.\r
+runtest_shared.exe additional.decTest\r
+if %errorlevel% neq 0 goto out\r
+\r
+\r
+rem Build libmpdec++ tests.\r
+cd ..\tests++\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake DEBUG=%DBG%\r
+\r
+rem # Copy or download the official test cases (text files).\r
+call gettests.bat\r
+\r
+echo.\r
+echo # ========================================================================\r
+echo # libmpdec++: static library\r
+echo # ========================================================================\r
+echo.\r
+\r
+echo.\r
+<nul (set /p x="Running official tests ... ")\r
+echo.\r
+echo.\r
+runtest.exe official.topTest --thread\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running additional tests ... ")\r
+echo.\r
+echo.\r
+runtest.exe additional.topTest --thread\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running API tests (single thread) ... ")\r
+echo.\r
+echo.\r
+apitest.exe\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running API tests (threaded) ... ")\r
+echo.\r
+echo.\r
+apitest.exe --thread\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+echo # ========================================================================\r
+echo # libmpdec++: shared library\r
+echo # ========================================================================\r
+echo.\r
+\r
+echo.\r
+<nul (set /p x="Running official tests ... ")\r
+echo.\r
+echo.\r
+runtest_shared.exe official.topTest --thread\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running additional tests ... ")\r
+echo.\r
+echo.\r
+runtest_shared.exe additional.topTest --thread\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running API tests (single thread) ... ")\r
+echo.\r
+echo.\r
+apitest_shared.exe\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running API tests (threaded) ... ")\r
+echo.\r
+echo.\r
+apitest_shared.exe --thread\r
+if %errorlevel% neq 0 goto out\r
+\r
+\r
+:out\r
+set exitcode=%errorlevel%\r
+cd ..\vcbuild\r
+exit /b %exitcode%\r
--- /dev/null
+@ECHO OFF\r
+\r
+\r
+rem Choose release or debug build.\r
+set DBG=0\r
+if "%1%" == "/d" set DBG=1\r
+\r
+rem Build libmpdec tests.\r
+cd ..\tests\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake DEBUG=%DBG%\r
+\r
+\r
+rem # Download the official test cases (text files).\r
+call gettests.bat\r
+\r
+echo.\r
+echo # ========================================================================\r
+echo # libmpdec: static library\r
+echo # ========================================================================\r
+echo.\r
+\r
+echo.\r
+<nul (set /p x="Running official tests with allocation failures ... ")\r
+echo.\r
+echo.\r
+runtest.exe official.decTest --alloc\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running additional tests with allocation failures ... ")\r
+echo.\r
+echo.\r
+runtest.exe additional.decTest --alloc\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+echo # ========================================================================\r
+echo # libmpdec: shared library\r
+echo # ========================================================================\r
+echo.\r
+\r
+echo.\r
+<nul (set /p x="Running official tests with allocation failures ... ")\r
+echo.\r
+echo.\r
+runtest_shared.exe official.decTest --alloc\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running additional tests with allocation failures ... ")\r
+echo.\r
+echo.\r
+runtest_shared.exe additional.decTest --alloc\r
+if %errorlevel% neq 0 goto out\r
+\r
+\r
+rem Build libmpdec++ tests.\r
+cd ..\tests++\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake DEBUG=%DBG%\r
+\r
+rem # Copy or download the official test cases (text files).\r
+call gettests.bat\r
+\r
+echo.\r
+echo # ========================================================================\r
+echo # libmpdec++: static library\r
+echo # ========================================================================\r
+echo.\r
+\r
+echo.\r
+<nul (set /p x="Running official tests with allocation failures ... ")\r
+echo.\r
+echo.\r
+runtest.exe official.topTest --thread --alloc\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running additional tests with allocation failures ... ")\r
+echo.\r
+echo.\r
+runtest.exe additional.topTest --thread --alloc\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running API tests (single thread) ... ")\r
+echo.\r
+echo.\r
+apitest.exe\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running API tests (threaded) ... ")\r
+echo.\r
+echo.\r
+apitest.exe --thread\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+echo # ========================================================================\r
+echo # libmpdec++: shared library\r
+echo # ========================================================================\r
+echo.\r
+\r
+echo.\r
+<nul (set /p x="Running official tests with allocation failures ... ")\r
+echo.\r
+echo.\r
+runtest_shared.exe official.topTest --thread --alloc\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running additional tests with allocation failures ... ")\r
+echo.\r
+echo.\r
+runtest_shared.exe additional.topTest --thread --alloc\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running API tests (single thread) ... ")\r
+echo.\r
+echo.\r
+apitest_shared.exe\r
+if %errorlevel% neq 0 goto out\r
+\r
+echo.\r
+<nul (set /p x="Running API tests (threaded) ... ")\r
+echo.\r
+echo.\r
+apitest_shared.exe --thread\r
+if %errorlevel% neq 0 goto out\r
+\r
+\r
+:out\r
+set exitcode=%errorlevel%\r
+cd ..\vcbuild\r
+exit /b %exitcode%\r
--- /dev/null
+@ECHO off\r
+\r
+set dbg=0\r
+set machine=ppro\r
+\r
+:getopt\r
+if "%~1"=="/d" (set dbg=1) & shift & goto getopt\r
+if "%~1"=="/m" (set machine=%2) & shift & shift & goto getopt\r
+\r
+rem These options are for testing only, always use 'ppro' (the default). The\r
+rem 'ansi-legacy' option has been removed since it is not needed on Windows.\r
+if "%machine%"=="ppro" goto success\r
+if "%machine%"=="ansi32" goto success\r
+echo "valid values for /m are [ppro, ansi32]"\r
+exit /b 1\r
+:success\r
+\r
+"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt\r
+set /p vcpath=<vcpath.txt\r
+del vcpath.txt\r
+call "%vcpath%\VC\Auxiliary\Build\vcvarsall.bat" x86\r
+\r
+if not exist dist32 mkdir dist32\r
+if exist dist32\* del /q dist32\*\r
+\r
+cd ..\libmpdec\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake MACHINE=%machine% DEBUG=%dbg%\r
+\r
+copy /y "libmpdec-4.0.1.lib" ..\vcbuild\dist32\r
+copy /y "libmpdec-4.0.1.dll" ..\vcbuild\dist32\r
+copy /y "libmpdec-4.0.1.dll.lib" ..\vcbuild\dist32\r
+copy /y "libmpdec-4.0.1.dll.exp" ..\vcbuild\dist32\r
+copy /y "mpdecimal.h" ..\vcbuild\dist32\r
+\r
+cd ..\libmpdec++\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake DEBUG=%dbg%\r
+\r
+copy /y "libmpdec++-4.0.1.lib" ..\vcbuild\dist32\r
+copy /y "libmpdec++-4.0.1.dll" ..\vcbuild\dist32\r
+copy /y "libmpdec++-4.0.1.dll.lib" ..\vcbuild\dist32\r
+copy /y "libmpdec++-4.0.1.dll.exp" ..\vcbuild\dist32\r
+copy /y "decimal.hh" ..\vcbuild\dist32\r
+\r
+cd ..\vcbuild\r
--- /dev/null
+@ECHO off\r
+\r
+set dbg=0\r
+set machine=x64\r
+\r
+:getopt\r
+if "%~1"=="/d" (set dbg=1) & shift & goto getopt\r
+if "%~1"=="/m" (set machine=%2) & shift & shift & goto getopt\r
+\r
+if "%machine%"=="x64" goto success\r
+if "%machine%"=="ansi64" goto success\r
+echo "valid values for /m are [x64, ansi64]"\r
+exit /b 1\r
+:success\r
+\r
+"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt\r
+set /p vcpath=<vcpath.txt\r
+del vcpath.txt\r
+call "%vcpath%\VC\Auxiliary\Build\vcvarsall.bat" x64\r
+\r
+if not exist dist64 mkdir dist64\r
+if exist dist64\* del /q dist64\*\r
+\r
+cd ..\libmpdec\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake MACHINE=%machine% DEBUG=%dbg%\r
+\r
+copy /y "libmpdec-4.0.1.lib" ..\vcbuild\dist64\r
+copy /y "libmpdec-4.0.1.dll" ..\vcbuild\dist64\r
+copy /y "libmpdec-4.0.1.dll.lib" ..\vcbuild\dist64\r
+copy /y "libmpdec-4.0.1.dll.exp" ..\vcbuild\dist64\r
+copy /y "mpdecimal.h" ..\vcbuild\dist64\r
+\r
+\r
+cd ..\libmpdec++\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake DEBUG=%dbg%\r
+\r
+copy /y "libmpdec++-4.0.1.lib" ..\vcbuild\dist64\r
+copy /y "libmpdec++-4.0.1.dll" ..\vcbuild\dist64\r
+copy /y "libmpdec++-4.0.1.dll.lib" ..\vcbuild\dist64\r
+copy /y "libmpdec++-4.0.1.dll.exp" ..\vcbuild\dist64\r
+copy /y "decimal.hh" ..\vcbuild\dist64\r
+\r
+cd ..\vcbuild\r
+\r
+\r
+\r
--- /dev/null
+@ECHO off\r
+\r
+set dbg=0\r
+set machine=ansi32\r
+\r
+"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt\r
+set /p vcpath=<vcpath.txt\r
+del vcpath.txt\r
+call "%vcpath%\VC\Auxiliary\Build\vcvarsall.bat" x64_arm\r
+\r
+if not exist dist_arm32 mkdir dist_arm32\r
+if exist dist_arm32\* del /q dist_arm32\*\r
+\r
+cd ..\libmpdec\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake MACHINE=%machine% DEBUG=%dbg%\r
+\r
+copy /y "libmpdec-4.0.1.lib" ..\vcbuild\dist_arm32\r
+copy /y "libmpdec-4.0.1.dll" ..\vcbuild\dist_arm32\r
+copy /y "libmpdec-4.0.1.dll.lib" ..\vcbuild\dist_arm32\r
+copy /y "libmpdec-4.0.1.dll.exp" ..\vcbuild\dist_arm32\r
+copy /y "mpdecimal.h" ..\vcbuild\dist_arm32\r
+\r
+\r
+cd ..\libmpdec++\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake DEBUG=%dbg%\r
+\r
+copy /y "libmpdec++-4.0.1.lib" ..\vcbuild\dist_arm32\r
+copy /y "libmpdec++-4.0.1.dll" ..\vcbuild\dist_arm32\r
+copy /y "libmpdec++-4.0.1.dll.lib" ..\vcbuild\dist_arm32\r
+copy /y "libmpdec++-4.0.1.dll.exp" ..\vcbuild\dist_arm32\r
+copy /y "decimal.hh" ..\vcbuild\dist_arm32\r
+\r
+cd ..\vcbuild\r
+\r
--- /dev/null
+@ECHO off\r
+\r
+set dbg=0\r
+set machine=ansi64\r
+\r
+"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt\r
+set /p vcpath=<vcpath.txt\r
+del vcpath.txt\r
+call "%vcpath%\VC\Auxiliary\Build\vcvarsall.bat" x64_arm64\r
+\r
+if not exist dist_arm64 mkdir dist_arm64\r
+if exist dist_arm64\* del /q dist_arm64\*\r
+\r
+cd ..\libmpdec\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake MACHINE=%machine% DEBUG=%dbg%\r
+\r
+copy /y "libmpdec-4.0.1.lib" ..\vcbuild\dist_arm64\r
+copy /y "libmpdec-4.0.1.dll" ..\vcbuild\dist_arm64\r
+copy /y "libmpdec-4.0.1.dll.lib" ..\vcbuild\dist_arm64\r
+copy /y "libmpdec-4.0.1.dll.exp" ..\vcbuild\dist_arm64\r
+copy /y "mpdecimal.h" ..\vcbuild\dist_arm64\r
+\r
+\r
+cd ..\libmpdec++\r
+copy /y Makefile.vc Makefile\r
+nmake clean\r
+nmake DEBUG=%dbg%\r
+\r
+copy /y "libmpdec++-4.0.1.lib" ..\vcbuild\dist_arm64\r
+copy /y "libmpdec++-4.0.1.dll" ..\vcbuild\dist_arm64\r
+copy /y "libmpdec++-4.0.1.dll.lib" ..\vcbuild\dist_arm64\r
+copy /y "libmpdec++-4.0.1.dll.exp" ..\vcbuild\dist_arm64\r
+copy /y "decimal.hh" ..\vcbuild\dist_arm64\r
+\r
+cd ..\vcbuild\r
--- /dev/null
+@ECHO off\r
+\r
+"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt\r
+set /p vcpath=<vcpath.txt\r
+del vcpath.txt\r
+call "%vcpath%\VC\Auxiliary\Build\vcvarsall.bat" x64\r
+\r
+cd ..\libmpdec\r
+if exist Makefile nmake clean\r
+\r
+cd ..\libmpdec++\r
+if exist Makefile nmake clean\r
+\r
+cd ..\tests\r
+if exist Makefile nmake clean\r
+\r
+cd ..\tests++\r
+if exist Makefile nmake clean\r
+\r
+cd ..\vcbuild\r
+if exist dist64 rd /q /s dist64\r
+if exist dist32 rd /q /s dist32\r
+if exist dist_arm64 rd /q /s dist_arm64\r
+if exist dist_arm32 rd /q /s dist_arm32\r
--- /dev/null
+@ECHO off\r
+\r
+"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -property installationPath > vcpath.txt\r
+set /p vcpath=<vcpath.txt\r
+del vcpath.txt\r
+call "%vcpath%\VC\Auxiliary\Build\vcvarsall.bat" x64\r
+\r
+cd ..\libmpdec\r
+if exist Makefile nmake distclean\r
+\r
+cd ..\libmpdec++\r
+if exist Makefile nmake distclean\r
+\r
+cd ..\tests\r
+if exist Makefile nmake distclean\r
+\r
+cd ..\tests++\r
+if exist Makefile nmake distclean\r
+\r
+cd ..\vcbuild\r
+if exist additional.decTest del /q additional.decTest\r
+if exist official.decTest del /q official.decTest\r
+if exist dectest.zip del /q dectest.zip\r
+if exist dist64 rd /q /s dist64\r
+if exist dist32 rd /q /s dist32\r
+if exist dist_arm64 rd /q /s dist_arm64\r
+if exist dist_arm32 rd /q /s dist_arm32\r
+if exist testdata rd /q /s testdata\r
+\r