17db96d56Sopenharmony_ci/*
27db96d56Sopenharmony_ci * Copyright (c) 2008-2020 Stefan Krah. All rights reserved.
37db96d56Sopenharmony_ci *
47db96d56Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
57db96d56Sopenharmony_ci * modification, are permitted provided that the following conditions
67db96d56Sopenharmony_ci * are met:
77db96d56Sopenharmony_ci *
87db96d56Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
97db96d56Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
107db96d56Sopenharmony_ci *
117db96d56Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
127db96d56Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
137db96d56Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
147db96d56Sopenharmony_ci *
157db96d56Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
167db96d56Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
177db96d56Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
187db96d56Sopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197db96d56Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207db96d56Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
217db96d56Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227db96d56Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237db96d56Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247db96d56Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257db96d56Sopenharmony_ci * SUCH DAMAGE.
267db96d56Sopenharmony_ci */
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci#include "mpdecimal.h"
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ci#include <assert.h>
327db96d56Sopenharmony_ci#include <limits.h>
337db96d56Sopenharmony_ci#include <math.h>
347db96d56Sopenharmony_ci#include <stdio.h>
357db96d56Sopenharmony_ci#include <stdlib.h>
367db96d56Sopenharmony_ci#include <string.h>
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ci#include "basearith.h"
397db96d56Sopenharmony_ci#include "bits.h"
407db96d56Sopenharmony_ci#include "constants.h"
417db96d56Sopenharmony_ci#include "convolute.h"
427db96d56Sopenharmony_ci#include "crt.h"
437db96d56Sopenharmony_ci#include "mpalloc.h"
447db96d56Sopenharmony_ci#include "typearith.h"
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci#ifdef PPRO
477db96d56Sopenharmony_ci  #if defined(_MSC_VER)
487db96d56Sopenharmony_ci    #include <float.h>
497db96d56Sopenharmony_ci    #pragma float_control(precise, on)
507db96d56Sopenharmony_ci    #pragma fenv_access(on)
517db96d56Sopenharmony_ci  #elif !defined(__OpenBSD__) && !defined(__NetBSD__)
527db96d56Sopenharmony_ci    /* C99 */
537db96d56Sopenharmony_ci    #include <fenv.h>
547db96d56Sopenharmony_ci    #pragma STDC FENV_ACCESS ON
557db96d56Sopenharmony_ci  #endif
567db96d56Sopenharmony_ci#endif
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_ci/* Disable warning that is part of -Wextra since gcc 7.0. */
607db96d56Sopenharmony_ci#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && __GNUC__ >= 7
617db96d56Sopenharmony_ci  #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
627db96d56Sopenharmony_ci#endif
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci#if defined(_MSC_VER)
667db96d56Sopenharmony_ci  #define ALWAYS_INLINE __forceinline
677db96d56Sopenharmony_ci#elif defined (__IBMC__) || defined(LEGACY_COMPILER)
687db96d56Sopenharmony_ci  #define ALWAYS_INLINE
697db96d56Sopenharmony_ci  #undef inline
707db96d56Sopenharmony_ci  #define inline
717db96d56Sopenharmony_ci#else
727db96d56Sopenharmony_ci  #ifdef TEST_COVERAGE
737db96d56Sopenharmony_ci    #define ALWAYS_INLINE
747db96d56Sopenharmony_ci  #else
757db96d56Sopenharmony_ci    #define ALWAYS_INLINE inline __attribute__ ((always_inline))
767db96d56Sopenharmony_ci  #endif
777db96d56Sopenharmony_ci#endif
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_ci#define MPD_NEWTONDIV_CUTOFF 1024L
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci#define MPD_NEW_STATIC(name, flags, exp, digits, len) \
837db96d56Sopenharmony_ci        mpd_uint_t name##_data[MPD_MINALLOC_MAX];                    \
847db96d56Sopenharmony_ci        mpd_t name = {flags|MPD_STATIC|MPD_STATIC_DATA, exp, digits, \
857db96d56Sopenharmony_ci                      len, MPD_MINALLOC_MAX, name##_data}
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_ci#define MPD_NEW_CONST(name, flags, exp, digits, len, alloc, initval) \
887db96d56Sopenharmony_ci        mpd_uint_t name##_data[alloc] = {initval};                   \
897db96d56Sopenharmony_ci        mpd_t name = {flags|MPD_STATIC|MPD_CONST_DATA, exp, digits,  \
907db96d56Sopenharmony_ci                      len, alloc, name##_data}
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ci#define MPD_NEW_SHARED(name, a) \
937db96d56Sopenharmony_ci        mpd_t name = {(a->flags&~MPD_DATAFLAGS)|MPD_STATIC|MPD_SHARED_DATA, \
947db96d56Sopenharmony_ci                      a->exp, a->digits, a->len, a->alloc, a->data}
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci
977db96d56Sopenharmony_cistatic mpd_uint_t data_one[1] = {1};
987db96d56Sopenharmony_cistatic mpd_uint_t data_zero[1] = {0};
997db96d56Sopenharmony_cistatic const mpd_t one = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_one};
1007db96d56Sopenharmony_cistatic const mpd_t minus_one = {MPD_NEG|MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1,
1017db96d56Sopenharmony_ci                                data_one};
1027db96d56Sopenharmony_cistatic const mpd_t zero = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_zero};
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_cistatic inline void _mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx,
1057db96d56Sopenharmony_ci                                  uint32_t *status);
1067db96d56Sopenharmony_cistatic void _settriple(mpd_t *result, uint8_t sign, mpd_uint_t a,
1077db96d56Sopenharmony_ci                       mpd_ssize_t exp);
1087db96d56Sopenharmony_cistatic inline mpd_ssize_t _mpd_real_size(mpd_uint_t *data, mpd_ssize_t size);
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_cistatic int _mpd_cmp_abs(const mpd_t *a, const mpd_t *b);
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_cistatic void _mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b,
1137db96d56Sopenharmony_ci                      const mpd_context_t *ctx, uint32_t *status);
1147db96d56Sopenharmony_cistatic inline void _mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
1157db96d56Sopenharmony_ci                             const mpd_context_t *ctx, uint32_t *status);
1167db96d56Sopenharmony_cistatic void _mpd_base_ndivmod(mpd_t *q, mpd_t *r, const mpd_t *a,
1177db96d56Sopenharmony_ci                              const mpd_t *b, uint32_t *status);
1187db96d56Sopenharmony_cistatic inline void _mpd_qpow_uint(mpd_t *result, const mpd_t *base,
1197db96d56Sopenharmony_ci                                  mpd_uint_t exp, uint8_t resultsign,
1207db96d56Sopenharmony_ci                                  const mpd_context_t *ctx, uint32_t *status);
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_cistatic mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n);
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ci/******************************************************************************/
1267db96d56Sopenharmony_ci/*                                  Version                                   */
1277db96d56Sopenharmony_ci/******************************************************************************/
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_ciconst char *
1307db96d56Sopenharmony_cimpd_version(void)
1317db96d56Sopenharmony_ci{
1327db96d56Sopenharmony_ci    return MPD_VERSION;
1337db96d56Sopenharmony_ci}
1347db96d56Sopenharmony_ci
1357db96d56Sopenharmony_ci
1367db96d56Sopenharmony_ci/******************************************************************************/
1377db96d56Sopenharmony_ci/*                  Performance critical inline functions                     */
1387db96d56Sopenharmony_ci/******************************************************************************/
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci#ifdef CONFIG_64
1417db96d56Sopenharmony_ci/* Digits in a word, primarily useful for the most significant word. */
1427db96d56Sopenharmony_ciALWAYS_INLINE int
1437db96d56Sopenharmony_cimpd_word_digits(mpd_uint_t word)
1447db96d56Sopenharmony_ci{
1457db96d56Sopenharmony_ci    if (word < mpd_pow10[9]) {
1467db96d56Sopenharmony_ci        if (word < mpd_pow10[4]) {
1477db96d56Sopenharmony_ci            if (word < mpd_pow10[2]) {
1487db96d56Sopenharmony_ci                return (word < mpd_pow10[1]) ? 1 : 2;
1497db96d56Sopenharmony_ci            }
1507db96d56Sopenharmony_ci            return (word < mpd_pow10[3]) ? 3 : 4;
1517db96d56Sopenharmony_ci        }
1527db96d56Sopenharmony_ci        if (word < mpd_pow10[6]) {
1537db96d56Sopenharmony_ci            return (word < mpd_pow10[5]) ? 5 : 6;
1547db96d56Sopenharmony_ci        }
1557db96d56Sopenharmony_ci        if (word < mpd_pow10[8]) {
1567db96d56Sopenharmony_ci            return (word < mpd_pow10[7]) ? 7 : 8;
1577db96d56Sopenharmony_ci        }
1587db96d56Sopenharmony_ci        return 9;
1597db96d56Sopenharmony_ci    }
1607db96d56Sopenharmony_ci    if (word < mpd_pow10[14]) {
1617db96d56Sopenharmony_ci        if (word < mpd_pow10[11]) {
1627db96d56Sopenharmony_ci            return (word < mpd_pow10[10]) ? 10 : 11;
1637db96d56Sopenharmony_ci        }
1647db96d56Sopenharmony_ci        if (word < mpd_pow10[13]) {
1657db96d56Sopenharmony_ci            return (word < mpd_pow10[12]) ? 12 : 13;
1667db96d56Sopenharmony_ci        }
1677db96d56Sopenharmony_ci        return 14;
1687db96d56Sopenharmony_ci    }
1697db96d56Sopenharmony_ci    if (word < mpd_pow10[18]) {
1707db96d56Sopenharmony_ci        if (word < mpd_pow10[16]) {
1717db96d56Sopenharmony_ci            return (word < mpd_pow10[15]) ? 15 : 16;
1727db96d56Sopenharmony_ci        }
1737db96d56Sopenharmony_ci        return (word < mpd_pow10[17]) ? 17 : 18;
1747db96d56Sopenharmony_ci    }
1757db96d56Sopenharmony_ci
1767db96d56Sopenharmony_ci    return (word < mpd_pow10[19]) ? 19 : 20;
1777db96d56Sopenharmony_ci}
1787db96d56Sopenharmony_ci#else
1797db96d56Sopenharmony_ciALWAYS_INLINE int
1807db96d56Sopenharmony_cimpd_word_digits(mpd_uint_t word)
1817db96d56Sopenharmony_ci{
1827db96d56Sopenharmony_ci    if (word < mpd_pow10[4]) {
1837db96d56Sopenharmony_ci        if (word < mpd_pow10[2]) {
1847db96d56Sopenharmony_ci            return (word < mpd_pow10[1]) ? 1 : 2;
1857db96d56Sopenharmony_ci        }
1867db96d56Sopenharmony_ci        return (word < mpd_pow10[3]) ? 3 : 4;
1877db96d56Sopenharmony_ci    }
1887db96d56Sopenharmony_ci    if (word < mpd_pow10[6]) {
1897db96d56Sopenharmony_ci        return (word < mpd_pow10[5]) ? 5 : 6;
1907db96d56Sopenharmony_ci    }
1917db96d56Sopenharmony_ci    if (word < mpd_pow10[8]) {
1927db96d56Sopenharmony_ci        return (word < mpd_pow10[7]) ? 7 : 8;
1937db96d56Sopenharmony_ci    }
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci    return (word < mpd_pow10[9]) ? 9 : 10;
1967db96d56Sopenharmony_ci}
1977db96d56Sopenharmony_ci#endif
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ci/* Adjusted exponent */
2017db96d56Sopenharmony_ciALWAYS_INLINE mpd_ssize_t
2027db96d56Sopenharmony_cimpd_adjexp(const mpd_t *dec)
2037db96d56Sopenharmony_ci{
2047db96d56Sopenharmony_ci    return (dec->exp + dec->digits) - 1;
2057db96d56Sopenharmony_ci}
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ci/* Etiny */
2087db96d56Sopenharmony_ciALWAYS_INLINE mpd_ssize_t
2097db96d56Sopenharmony_cimpd_etiny(const mpd_context_t *ctx)
2107db96d56Sopenharmony_ci{
2117db96d56Sopenharmony_ci    return ctx->emin - (ctx->prec - 1);
2127db96d56Sopenharmony_ci}
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_ci/* Etop: used for folding down in IEEE clamping */
2157db96d56Sopenharmony_ciALWAYS_INLINE mpd_ssize_t
2167db96d56Sopenharmony_cimpd_etop(const mpd_context_t *ctx)
2177db96d56Sopenharmony_ci{
2187db96d56Sopenharmony_ci    return ctx->emax - (ctx->prec - 1);
2197db96d56Sopenharmony_ci}
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ci/* Most significant word */
2227db96d56Sopenharmony_ciALWAYS_INLINE mpd_uint_t
2237db96d56Sopenharmony_cimpd_msword(const mpd_t *dec)
2247db96d56Sopenharmony_ci{
2257db96d56Sopenharmony_ci    assert(dec->len > 0);
2267db96d56Sopenharmony_ci    return dec->data[dec->len-1];
2277db96d56Sopenharmony_ci}
2287db96d56Sopenharmony_ci
2297db96d56Sopenharmony_ci/* Most significant digit of a word */
2307db96d56Sopenharmony_ciinline mpd_uint_t
2317db96d56Sopenharmony_cimpd_msd(mpd_uint_t word)
2327db96d56Sopenharmony_ci{
2337db96d56Sopenharmony_ci    int n;
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ci    n = mpd_word_digits(word);
2367db96d56Sopenharmony_ci    return word / mpd_pow10[n-1];
2377db96d56Sopenharmony_ci}
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ci/* Least significant digit of a word */
2407db96d56Sopenharmony_ciALWAYS_INLINE mpd_uint_t
2417db96d56Sopenharmony_cimpd_lsd(mpd_uint_t word)
2427db96d56Sopenharmony_ci{
2437db96d56Sopenharmony_ci    return word % 10;
2447db96d56Sopenharmony_ci}
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ci/* Coefficient size needed to store 'digits' */
2477db96d56Sopenharmony_cimpd_ssize_t
2487db96d56Sopenharmony_cimpd_digits_to_size(mpd_ssize_t digits)
2497db96d56Sopenharmony_ci{
2507db96d56Sopenharmony_ci    mpd_ssize_t q, r;
2517db96d56Sopenharmony_ci
2527db96d56Sopenharmony_ci    _mpd_idiv_word(&q, &r, digits, MPD_RDIGITS);
2537db96d56Sopenharmony_ci    return (r == 0) ? q : q+1;
2547db96d56Sopenharmony_ci}
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci/* Number of digits in the exponent. Not defined for MPD_SSIZE_MIN. */
2577db96d56Sopenharmony_ciinline int
2587db96d56Sopenharmony_cimpd_exp_digits(mpd_ssize_t exp)
2597db96d56Sopenharmony_ci{
2607db96d56Sopenharmony_ci    exp = (exp < 0) ? -exp : exp;
2617db96d56Sopenharmony_ci    return mpd_word_digits(exp);
2627db96d56Sopenharmony_ci}
2637db96d56Sopenharmony_ci
2647db96d56Sopenharmony_ci/* Canonical */
2657db96d56Sopenharmony_ciALWAYS_INLINE int
2667db96d56Sopenharmony_cimpd_iscanonical(const mpd_t *dec)
2677db96d56Sopenharmony_ci{
2687db96d56Sopenharmony_ci    (void)dec;
2697db96d56Sopenharmony_ci    return 1;
2707db96d56Sopenharmony_ci}
2717db96d56Sopenharmony_ci
2727db96d56Sopenharmony_ci/* Finite */
2737db96d56Sopenharmony_ciALWAYS_INLINE int
2747db96d56Sopenharmony_cimpd_isfinite(const mpd_t *dec)
2757db96d56Sopenharmony_ci{
2767db96d56Sopenharmony_ci    return !(dec->flags & MPD_SPECIAL);
2777db96d56Sopenharmony_ci}
2787db96d56Sopenharmony_ci
2797db96d56Sopenharmony_ci/* Infinite */
2807db96d56Sopenharmony_ciALWAYS_INLINE int
2817db96d56Sopenharmony_cimpd_isinfinite(const mpd_t *dec)
2827db96d56Sopenharmony_ci{
2837db96d56Sopenharmony_ci    return dec->flags & MPD_INF;
2847db96d56Sopenharmony_ci}
2857db96d56Sopenharmony_ci
2867db96d56Sopenharmony_ci/* NaN */
2877db96d56Sopenharmony_ciALWAYS_INLINE int
2887db96d56Sopenharmony_cimpd_isnan(const mpd_t *dec)
2897db96d56Sopenharmony_ci{
2907db96d56Sopenharmony_ci    return dec->flags & (MPD_NAN|MPD_SNAN);
2917db96d56Sopenharmony_ci}
2927db96d56Sopenharmony_ci
2937db96d56Sopenharmony_ci/* Negative */
2947db96d56Sopenharmony_ciALWAYS_INLINE int
2957db96d56Sopenharmony_cimpd_isnegative(const mpd_t *dec)
2967db96d56Sopenharmony_ci{
2977db96d56Sopenharmony_ci    return dec->flags & MPD_NEG;
2987db96d56Sopenharmony_ci}
2997db96d56Sopenharmony_ci
3007db96d56Sopenharmony_ci/* Positive */
3017db96d56Sopenharmony_ciALWAYS_INLINE int
3027db96d56Sopenharmony_cimpd_ispositive(const mpd_t *dec)
3037db96d56Sopenharmony_ci{
3047db96d56Sopenharmony_ci    return !(dec->flags & MPD_NEG);
3057db96d56Sopenharmony_ci}
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_ci/* qNaN */
3087db96d56Sopenharmony_ciALWAYS_INLINE int
3097db96d56Sopenharmony_cimpd_isqnan(const mpd_t *dec)
3107db96d56Sopenharmony_ci{
3117db96d56Sopenharmony_ci    return dec->flags & MPD_NAN;
3127db96d56Sopenharmony_ci}
3137db96d56Sopenharmony_ci
3147db96d56Sopenharmony_ci/* Signed */
3157db96d56Sopenharmony_ciALWAYS_INLINE int
3167db96d56Sopenharmony_cimpd_issigned(const mpd_t *dec)
3177db96d56Sopenharmony_ci{
3187db96d56Sopenharmony_ci    return dec->flags & MPD_NEG;
3197db96d56Sopenharmony_ci}
3207db96d56Sopenharmony_ci
3217db96d56Sopenharmony_ci/* sNaN */
3227db96d56Sopenharmony_ciALWAYS_INLINE int
3237db96d56Sopenharmony_cimpd_issnan(const mpd_t *dec)
3247db96d56Sopenharmony_ci{
3257db96d56Sopenharmony_ci    return dec->flags & MPD_SNAN;
3267db96d56Sopenharmony_ci}
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci/* Special */
3297db96d56Sopenharmony_ciALWAYS_INLINE int
3307db96d56Sopenharmony_cimpd_isspecial(const mpd_t *dec)
3317db96d56Sopenharmony_ci{
3327db96d56Sopenharmony_ci    return dec->flags & MPD_SPECIAL;
3337db96d56Sopenharmony_ci}
3347db96d56Sopenharmony_ci
3357db96d56Sopenharmony_ci/* Zero */
3367db96d56Sopenharmony_ciALWAYS_INLINE int
3377db96d56Sopenharmony_cimpd_iszero(const mpd_t *dec)
3387db96d56Sopenharmony_ci{
3397db96d56Sopenharmony_ci    return !mpd_isspecial(dec) && mpd_msword(dec) == 0;
3407db96d56Sopenharmony_ci}
3417db96d56Sopenharmony_ci
3427db96d56Sopenharmony_ci/* Test for zero when specials have been ruled out already */
3437db96d56Sopenharmony_ciALWAYS_INLINE int
3447db96d56Sopenharmony_cimpd_iszerocoeff(const mpd_t *dec)
3457db96d56Sopenharmony_ci{
3467db96d56Sopenharmony_ci    return mpd_msword(dec) == 0;
3477db96d56Sopenharmony_ci}
3487db96d56Sopenharmony_ci
3497db96d56Sopenharmony_ci/* Normal */
3507db96d56Sopenharmony_ciinline int
3517db96d56Sopenharmony_cimpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx)
3527db96d56Sopenharmony_ci{
3537db96d56Sopenharmony_ci    if (mpd_isspecial(dec)) return 0;
3547db96d56Sopenharmony_ci    if (mpd_iszerocoeff(dec)) return 0;
3557db96d56Sopenharmony_ci
3567db96d56Sopenharmony_ci    return mpd_adjexp(dec) >= ctx->emin;
3577db96d56Sopenharmony_ci}
3587db96d56Sopenharmony_ci
3597db96d56Sopenharmony_ci/* Subnormal */
3607db96d56Sopenharmony_ciinline int
3617db96d56Sopenharmony_cimpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx)
3627db96d56Sopenharmony_ci{
3637db96d56Sopenharmony_ci    if (mpd_isspecial(dec)) return 0;
3647db96d56Sopenharmony_ci    if (mpd_iszerocoeff(dec)) return 0;
3657db96d56Sopenharmony_ci
3667db96d56Sopenharmony_ci    return mpd_adjexp(dec) < ctx->emin;
3677db96d56Sopenharmony_ci}
3687db96d56Sopenharmony_ci
3697db96d56Sopenharmony_ci/* Odd word */
3707db96d56Sopenharmony_ciALWAYS_INLINE int
3717db96d56Sopenharmony_cimpd_isoddword(mpd_uint_t word)
3727db96d56Sopenharmony_ci{
3737db96d56Sopenharmony_ci    return word & 1;
3747db96d56Sopenharmony_ci}
3757db96d56Sopenharmony_ci
3767db96d56Sopenharmony_ci/* Odd coefficient */
3777db96d56Sopenharmony_ciALWAYS_INLINE int
3787db96d56Sopenharmony_cimpd_isoddcoeff(const mpd_t *dec)
3797db96d56Sopenharmony_ci{
3807db96d56Sopenharmony_ci    return mpd_isoddword(dec->data[0]);
3817db96d56Sopenharmony_ci}
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci/* 0 if dec is positive, 1 if dec is negative */
3847db96d56Sopenharmony_ciALWAYS_INLINE uint8_t
3857db96d56Sopenharmony_cimpd_sign(const mpd_t *dec)
3867db96d56Sopenharmony_ci{
3877db96d56Sopenharmony_ci    return dec->flags & MPD_NEG;
3887db96d56Sopenharmony_ci}
3897db96d56Sopenharmony_ci
3907db96d56Sopenharmony_ci/* 1 if dec is positive, -1 if dec is negative */
3917db96d56Sopenharmony_ciALWAYS_INLINE int
3927db96d56Sopenharmony_cimpd_arith_sign(const mpd_t *dec)
3937db96d56Sopenharmony_ci{
3947db96d56Sopenharmony_ci    return 1 - 2 * mpd_isnegative(dec);
3957db96d56Sopenharmony_ci}
3967db96d56Sopenharmony_ci
3977db96d56Sopenharmony_ci/* Radix */
3987db96d56Sopenharmony_ciALWAYS_INLINE long
3997db96d56Sopenharmony_cimpd_radix(void)
4007db96d56Sopenharmony_ci{
4017db96d56Sopenharmony_ci    return 10;
4027db96d56Sopenharmony_ci}
4037db96d56Sopenharmony_ci
4047db96d56Sopenharmony_ci/* Dynamic decimal */
4057db96d56Sopenharmony_ciALWAYS_INLINE int
4067db96d56Sopenharmony_cimpd_isdynamic(const mpd_t *dec)
4077db96d56Sopenharmony_ci{
4087db96d56Sopenharmony_ci    return !(dec->flags & MPD_STATIC);
4097db96d56Sopenharmony_ci}
4107db96d56Sopenharmony_ci
4117db96d56Sopenharmony_ci/* Static decimal */
4127db96d56Sopenharmony_ciALWAYS_INLINE int
4137db96d56Sopenharmony_cimpd_isstatic(const mpd_t *dec)
4147db96d56Sopenharmony_ci{
4157db96d56Sopenharmony_ci    return dec->flags & MPD_STATIC;
4167db96d56Sopenharmony_ci}
4177db96d56Sopenharmony_ci
4187db96d56Sopenharmony_ci/* Data of decimal is dynamic */
4197db96d56Sopenharmony_ciALWAYS_INLINE int
4207db96d56Sopenharmony_cimpd_isdynamic_data(const mpd_t *dec)
4217db96d56Sopenharmony_ci{
4227db96d56Sopenharmony_ci    return !(dec->flags & MPD_DATAFLAGS);
4237db96d56Sopenharmony_ci}
4247db96d56Sopenharmony_ci
4257db96d56Sopenharmony_ci/* Data of decimal is static */
4267db96d56Sopenharmony_ciALWAYS_INLINE int
4277db96d56Sopenharmony_cimpd_isstatic_data(const mpd_t *dec)
4287db96d56Sopenharmony_ci{
4297db96d56Sopenharmony_ci    return dec->flags & MPD_STATIC_DATA;
4307db96d56Sopenharmony_ci}
4317db96d56Sopenharmony_ci
4327db96d56Sopenharmony_ci/* Data of decimal is shared */
4337db96d56Sopenharmony_ciALWAYS_INLINE int
4347db96d56Sopenharmony_cimpd_isshared_data(const mpd_t *dec)
4357db96d56Sopenharmony_ci{
4367db96d56Sopenharmony_ci    return dec->flags & MPD_SHARED_DATA;
4377db96d56Sopenharmony_ci}
4387db96d56Sopenharmony_ci
4397db96d56Sopenharmony_ci/* Data of decimal is const */
4407db96d56Sopenharmony_ciALWAYS_INLINE int
4417db96d56Sopenharmony_cimpd_isconst_data(const mpd_t *dec)
4427db96d56Sopenharmony_ci{
4437db96d56Sopenharmony_ci    return dec->flags & MPD_CONST_DATA;
4447db96d56Sopenharmony_ci}
4457db96d56Sopenharmony_ci
4467db96d56Sopenharmony_ci
4477db96d56Sopenharmony_ci/******************************************************************************/
4487db96d56Sopenharmony_ci/*                         Inline memory handling                             */
4497db96d56Sopenharmony_ci/******************************************************************************/
4507db96d56Sopenharmony_ci
4517db96d56Sopenharmony_ci/* Fill destination with zeros */
4527db96d56Sopenharmony_ciALWAYS_INLINE void
4537db96d56Sopenharmony_cimpd_uint_zero(mpd_uint_t *dest, mpd_size_t len)
4547db96d56Sopenharmony_ci{
4557db96d56Sopenharmony_ci    mpd_size_t i;
4567db96d56Sopenharmony_ci
4577db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
4587db96d56Sopenharmony_ci        dest[i] = 0;
4597db96d56Sopenharmony_ci    }
4607db96d56Sopenharmony_ci}
4617db96d56Sopenharmony_ci
4627db96d56Sopenharmony_ci/* Free a decimal */
4637db96d56Sopenharmony_ciALWAYS_INLINE void
4647db96d56Sopenharmony_cimpd_del(mpd_t *dec)
4657db96d56Sopenharmony_ci{
4667db96d56Sopenharmony_ci    if (mpd_isdynamic_data(dec)) {
4677db96d56Sopenharmony_ci        mpd_free(dec->data);
4687db96d56Sopenharmony_ci    }
4697db96d56Sopenharmony_ci    if (mpd_isdynamic(dec)) {
4707db96d56Sopenharmony_ci        mpd_free(dec);
4717db96d56Sopenharmony_ci    }
4727db96d56Sopenharmony_ci}
4737db96d56Sopenharmony_ci
4747db96d56Sopenharmony_ci/*
4757db96d56Sopenharmony_ci * Resize the coefficient. Existing data up to 'nwords' is left untouched.
4767db96d56Sopenharmony_ci * Return 1 on success, 0 otherwise.
4777db96d56Sopenharmony_ci *
4787db96d56Sopenharmony_ci * Input invariant: MPD_MINALLOC <= result->alloc.
4797db96d56Sopenharmony_ci *
4807db96d56Sopenharmony_ci * Case nwords == result->alloc:
4817db96d56Sopenharmony_ci *     'result' is unchanged. Return 1.
4827db96d56Sopenharmony_ci *
4837db96d56Sopenharmony_ci * Case nwords > result->alloc:
4847db96d56Sopenharmony_ci *   Case realloc success:
4857db96d56Sopenharmony_ci *     The value of 'result' does not change. Return 1.
4867db96d56Sopenharmony_ci *   Case realloc failure:
4877db96d56Sopenharmony_ci *     'result' is NaN, status is updated with MPD_Malloc_error. Return 0.
4887db96d56Sopenharmony_ci *
4897db96d56Sopenharmony_ci * Case nwords < result->alloc:
4907db96d56Sopenharmony_ci *   Case is_static_data or realloc failure [1]:
4917db96d56Sopenharmony_ci *     'result' is unchanged. Return 1.
4927db96d56Sopenharmony_ci *   Case realloc success:
4937db96d56Sopenharmony_ci *     The value of result is undefined (expected). Return 1.
4947db96d56Sopenharmony_ci *
4957db96d56Sopenharmony_ci *
4967db96d56Sopenharmony_ci * [1] In that case the old (now oversized) area is still valid.
4977db96d56Sopenharmony_ci */
4987db96d56Sopenharmony_ciALWAYS_INLINE int
4997db96d56Sopenharmony_cimpd_qresize(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
5007db96d56Sopenharmony_ci{
5017db96d56Sopenharmony_ci    assert(!mpd_isconst_data(result)); /* illegal operation for a const */
5027db96d56Sopenharmony_ci    assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
5037db96d56Sopenharmony_ci    assert(MPD_MINALLOC <= result->alloc);
5047db96d56Sopenharmony_ci
5057db96d56Sopenharmony_ci    nwords = (nwords <= MPD_MINALLOC) ? MPD_MINALLOC : nwords;
5067db96d56Sopenharmony_ci    if (nwords == result->alloc) {
5077db96d56Sopenharmony_ci        return 1;
5087db96d56Sopenharmony_ci    }
5097db96d56Sopenharmony_ci    if (mpd_isstatic_data(result)) {
5107db96d56Sopenharmony_ci        if (nwords > result->alloc) {
5117db96d56Sopenharmony_ci            return mpd_switch_to_dyn(result, nwords, status);
5127db96d56Sopenharmony_ci        }
5137db96d56Sopenharmony_ci        return 1;
5147db96d56Sopenharmony_ci    }
5157db96d56Sopenharmony_ci
5167db96d56Sopenharmony_ci    return mpd_realloc_dyn(result, nwords, status);
5177db96d56Sopenharmony_ci}
5187db96d56Sopenharmony_ci
5197db96d56Sopenharmony_ci/* Same as mpd_qresize, but do not set the result no NaN on failure. */
5207db96d56Sopenharmony_cistatic ALWAYS_INLINE int
5217db96d56Sopenharmony_cimpd_qresize_cxx(mpd_t *result, mpd_ssize_t nwords)
5227db96d56Sopenharmony_ci{
5237db96d56Sopenharmony_ci    assert(!mpd_isconst_data(result)); /* illegal operation for a const */
5247db96d56Sopenharmony_ci    assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
5257db96d56Sopenharmony_ci    assert(MPD_MINALLOC <= result->alloc);
5267db96d56Sopenharmony_ci
5277db96d56Sopenharmony_ci    nwords = (nwords <= MPD_MINALLOC) ? MPD_MINALLOC : nwords;
5287db96d56Sopenharmony_ci    if (nwords == result->alloc) {
5297db96d56Sopenharmony_ci        return 1;
5307db96d56Sopenharmony_ci    }
5317db96d56Sopenharmony_ci    if (mpd_isstatic_data(result)) {
5327db96d56Sopenharmony_ci        if (nwords > result->alloc) {
5337db96d56Sopenharmony_ci            return mpd_switch_to_dyn_cxx(result, nwords);
5347db96d56Sopenharmony_ci        }
5357db96d56Sopenharmony_ci        return 1;
5367db96d56Sopenharmony_ci    }
5377db96d56Sopenharmony_ci
5387db96d56Sopenharmony_ci    return mpd_realloc_dyn_cxx(result, nwords);
5397db96d56Sopenharmony_ci}
5407db96d56Sopenharmony_ci
5417db96d56Sopenharmony_ci/* Same as mpd_qresize, but the complete coefficient (including the old
5427db96d56Sopenharmony_ci * memory area!) is initialized to zero. */
5437db96d56Sopenharmony_ciALWAYS_INLINE int
5447db96d56Sopenharmony_cimpd_qresize_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
5457db96d56Sopenharmony_ci{
5467db96d56Sopenharmony_ci    assert(!mpd_isconst_data(result)); /* illegal operation for a const */
5477db96d56Sopenharmony_ci    assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
5487db96d56Sopenharmony_ci    assert(MPD_MINALLOC <= result->alloc);
5497db96d56Sopenharmony_ci
5507db96d56Sopenharmony_ci    nwords = (nwords <= MPD_MINALLOC) ? MPD_MINALLOC : nwords;
5517db96d56Sopenharmony_ci    if (nwords != result->alloc) {
5527db96d56Sopenharmony_ci        if (mpd_isstatic_data(result)) {
5537db96d56Sopenharmony_ci            if (nwords > result->alloc) {
5547db96d56Sopenharmony_ci                return mpd_switch_to_dyn_zero(result, nwords, status);
5557db96d56Sopenharmony_ci            }
5567db96d56Sopenharmony_ci        }
5577db96d56Sopenharmony_ci        else if (!mpd_realloc_dyn(result, nwords, status)) {
5587db96d56Sopenharmony_ci            return 0;
5597db96d56Sopenharmony_ci        }
5607db96d56Sopenharmony_ci    }
5617db96d56Sopenharmony_ci
5627db96d56Sopenharmony_ci    mpd_uint_zero(result->data, nwords);
5637db96d56Sopenharmony_ci    return 1;
5647db96d56Sopenharmony_ci}
5657db96d56Sopenharmony_ci
5667db96d56Sopenharmony_ci/*
5677db96d56Sopenharmony_ci * Reduce memory size for the coefficient to MPD_MINALLOC. In theory,
5687db96d56Sopenharmony_ci * realloc may fail even when reducing the memory size. But in that case
5697db96d56Sopenharmony_ci * the old memory area is always big enough, so checking for MPD_Malloc_error
5707db96d56Sopenharmony_ci * is not imperative.
5717db96d56Sopenharmony_ci */
5727db96d56Sopenharmony_ciALWAYS_INLINE void
5737db96d56Sopenharmony_cimpd_minalloc(mpd_t *result)
5747db96d56Sopenharmony_ci{
5757db96d56Sopenharmony_ci    assert(!mpd_isconst_data(result)); /* illegal operation for a const */
5767db96d56Sopenharmony_ci    assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
5777db96d56Sopenharmony_ci
5787db96d56Sopenharmony_ci    if (!mpd_isstatic_data(result) && result->alloc > MPD_MINALLOC) {
5797db96d56Sopenharmony_ci        uint8_t err = 0;
5807db96d56Sopenharmony_ci        result->data = mpd_realloc(result->data, MPD_MINALLOC,
5817db96d56Sopenharmony_ci                                   sizeof *result->data, &err);
5827db96d56Sopenharmony_ci        if (!err) {
5837db96d56Sopenharmony_ci            result->alloc = MPD_MINALLOC;
5847db96d56Sopenharmony_ci        }
5857db96d56Sopenharmony_ci    }
5867db96d56Sopenharmony_ci}
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_ciint
5897db96d56Sopenharmony_cimpd_resize(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx)
5907db96d56Sopenharmony_ci{
5917db96d56Sopenharmony_ci    uint32_t status = 0;
5927db96d56Sopenharmony_ci    if (!mpd_qresize(result, nwords, &status)) {
5937db96d56Sopenharmony_ci        mpd_addstatus_raise(ctx, status);
5947db96d56Sopenharmony_ci        return 0;
5957db96d56Sopenharmony_ci    }
5967db96d56Sopenharmony_ci    return 1;
5977db96d56Sopenharmony_ci}
5987db96d56Sopenharmony_ci
5997db96d56Sopenharmony_ciint
6007db96d56Sopenharmony_cimpd_resize_zero(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx)
6017db96d56Sopenharmony_ci{
6027db96d56Sopenharmony_ci    uint32_t status = 0;
6037db96d56Sopenharmony_ci    if (!mpd_qresize_zero(result, nwords, &status)) {
6047db96d56Sopenharmony_ci        mpd_addstatus_raise(ctx, status);
6057db96d56Sopenharmony_ci        return 0;
6067db96d56Sopenharmony_ci    }
6077db96d56Sopenharmony_ci    return 1;
6087db96d56Sopenharmony_ci}
6097db96d56Sopenharmony_ci
6107db96d56Sopenharmony_ci
6117db96d56Sopenharmony_ci/******************************************************************************/
6127db96d56Sopenharmony_ci/*                       Set attributes of a decimal                          */
6137db96d56Sopenharmony_ci/******************************************************************************/
6147db96d56Sopenharmony_ci
6157db96d56Sopenharmony_ci/* Set digits. Assumption: result->len is initialized and > 0. */
6167db96d56Sopenharmony_ciinline void
6177db96d56Sopenharmony_cimpd_setdigits(mpd_t *result)
6187db96d56Sopenharmony_ci{
6197db96d56Sopenharmony_ci    mpd_ssize_t wdigits = mpd_word_digits(mpd_msword(result));
6207db96d56Sopenharmony_ci    result->digits = wdigits + (result->len-1) * MPD_RDIGITS;
6217db96d56Sopenharmony_ci}
6227db96d56Sopenharmony_ci
6237db96d56Sopenharmony_ci/* Set sign */
6247db96d56Sopenharmony_ciALWAYS_INLINE void
6257db96d56Sopenharmony_cimpd_set_sign(mpd_t *result, uint8_t sign)
6267db96d56Sopenharmony_ci{
6277db96d56Sopenharmony_ci    result->flags &= ~MPD_NEG;
6287db96d56Sopenharmony_ci    result->flags |= sign;
6297db96d56Sopenharmony_ci}
6307db96d56Sopenharmony_ci
6317db96d56Sopenharmony_ci/* Copy sign from another decimal */
6327db96d56Sopenharmony_ciALWAYS_INLINE void
6337db96d56Sopenharmony_cimpd_signcpy(mpd_t *result, const mpd_t *a)
6347db96d56Sopenharmony_ci{
6357db96d56Sopenharmony_ci    uint8_t sign = a->flags&MPD_NEG;
6367db96d56Sopenharmony_ci
6377db96d56Sopenharmony_ci    result->flags &= ~MPD_NEG;
6387db96d56Sopenharmony_ci    result->flags |= sign;
6397db96d56Sopenharmony_ci}
6407db96d56Sopenharmony_ci
6417db96d56Sopenharmony_ci/* Set infinity */
6427db96d56Sopenharmony_ciALWAYS_INLINE void
6437db96d56Sopenharmony_cimpd_set_infinity(mpd_t *result)
6447db96d56Sopenharmony_ci{
6457db96d56Sopenharmony_ci    result->flags &= ~MPD_SPECIAL;
6467db96d56Sopenharmony_ci    result->flags |= MPD_INF;
6477db96d56Sopenharmony_ci}
6487db96d56Sopenharmony_ci
6497db96d56Sopenharmony_ci/* Set qNaN */
6507db96d56Sopenharmony_ciALWAYS_INLINE void
6517db96d56Sopenharmony_cimpd_set_qnan(mpd_t *result)
6527db96d56Sopenharmony_ci{
6537db96d56Sopenharmony_ci    result->flags &= ~MPD_SPECIAL;
6547db96d56Sopenharmony_ci    result->flags |= MPD_NAN;
6557db96d56Sopenharmony_ci}
6567db96d56Sopenharmony_ci
6577db96d56Sopenharmony_ci/* Set sNaN */
6587db96d56Sopenharmony_ciALWAYS_INLINE void
6597db96d56Sopenharmony_cimpd_set_snan(mpd_t *result)
6607db96d56Sopenharmony_ci{
6617db96d56Sopenharmony_ci    result->flags &= ~MPD_SPECIAL;
6627db96d56Sopenharmony_ci    result->flags |= MPD_SNAN;
6637db96d56Sopenharmony_ci}
6647db96d56Sopenharmony_ci
6657db96d56Sopenharmony_ci/* Set to negative */
6667db96d56Sopenharmony_ciALWAYS_INLINE void
6677db96d56Sopenharmony_cimpd_set_negative(mpd_t *result)
6687db96d56Sopenharmony_ci{
6697db96d56Sopenharmony_ci    result->flags |= MPD_NEG;
6707db96d56Sopenharmony_ci}
6717db96d56Sopenharmony_ci
6727db96d56Sopenharmony_ci/* Set to positive */
6737db96d56Sopenharmony_ciALWAYS_INLINE void
6747db96d56Sopenharmony_cimpd_set_positive(mpd_t *result)
6757db96d56Sopenharmony_ci{
6767db96d56Sopenharmony_ci    result->flags &= ~MPD_NEG;
6777db96d56Sopenharmony_ci}
6787db96d56Sopenharmony_ci
6797db96d56Sopenharmony_ci/* Set to dynamic */
6807db96d56Sopenharmony_ciALWAYS_INLINE void
6817db96d56Sopenharmony_cimpd_set_dynamic(mpd_t *result)
6827db96d56Sopenharmony_ci{
6837db96d56Sopenharmony_ci    result->flags &= ~MPD_STATIC;
6847db96d56Sopenharmony_ci}
6857db96d56Sopenharmony_ci
6867db96d56Sopenharmony_ci/* Set to static */
6877db96d56Sopenharmony_ciALWAYS_INLINE void
6887db96d56Sopenharmony_cimpd_set_static(mpd_t *result)
6897db96d56Sopenharmony_ci{
6907db96d56Sopenharmony_ci    result->flags |= MPD_STATIC;
6917db96d56Sopenharmony_ci}
6927db96d56Sopenharmony_ci
6937db96d56Sopenharmony_ci/* Set data to dynamic */
6947db96d56Sopenharmony_ciALWAYS_INLINE void
6957db96d56Sopenharmony_cimpd_set_dynamic_data(mpd_t *result)
6967db96d56Sopenharmony_ci{
6977db96d56Sopenharmony_ci    result->flags &= ~MPD_DATAFLAGS;
6987db96d56Sopenharmony_ci}
6997db96d56Sopenharmony_ci
7007db96d56Sopenharmony_ci/* Set data to static */
7017db96d56Sopenharmony_ciALWAYS_INLINE void
7027db96d56Sopenharmony_cimpd_set_static_data(mpd_t *result)
7037db96d56Sopenharmony_ci{
7047db96d56Sopenharmony_ci    result->flags &= ~MPD_DATAFLAGS;
7057db96d56Sopenharmony_ci    result->flags |= MPD_STATIC_DATA;
7067db96d56Sopenharmony_ci}
7077db96d56Sopenharmony_ci
7087db96d56Sopenharmony_ci/* Set data to shared */
7097db96d56Sopenharmony_ciALWAYS_INLINE void
7107db96d56Sopenharmony_cimpd_set_shared_data(mpd_t *result)
7117db96d56Sopenharmony_ci{
7127db96d56Sopenharmony_ci    result->flags &= ~MPD_DATAFLAGS;
7137db96d56Sopenharmony_ci    result->flags |= MPD_SHARED_DATA;
7147db96d56Sopenharmony_ci}
7157db96d56Sopenharmony_ci
7167db96d56Sopenharmony_ci/* Set data to const */
7177db96d56Sopenharmony_ciALWAYS_INLINE void
7187db96d56Sopenharmony_cimpd_set_const_data(mpd_t *result)
7197db96d56Sopenharmony_ci{
7207db96d56Sopenharmony_ci    result->flags &= ~MPD_DATAFLAGS;
7217db96d56Sopenharmony_ci    result->flags |= MPD_CONST_DATA;
7227db96d56Sopenharmony_ci}
7237db96d56Sopenharmony_ci
7247db96d56Sopenharmony_ci/* Clear flags, preserving memory attributes. */
7257db96d56Sopenharmony_ciALWAYS_INLINE void
7267db96d56Sopenharmony_cimpd_clear_flags(mpd_t *result)
7277db96d56Sopenharmony_ci{
7287db96d56Sopenharmony_ci    result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
7297db96d56Sopenharmony_ci}
7307db96d56Sopenharmony_ci
7317db96d56Sopenharmony_ci/* Set flags, preserving memory attributes. */
7327db96d56Sopenharmony_ciALWAYS_INLINE void
7337db96d56Sopenharmony_cimpd_set_flags(mpd_t *result, uint8_t flags)
7347db96d56Sopenharmony_ci{
7357db96d56Sopenharmony_ci    result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
7367db96d56Sopenharmony_ci    result->flags |= flags;
7377db96d56Sopenharmony_ci}
7387db96d56Sopenharmony_ci
7397db96d56Sopenharmony_ci/* Copy flags, preserving memory attributes of result. */
7407db96d56Sopenharmony_ciALWAYS_INLINE void
7417db96d56Sopenharmony_cimpd_copy_flags(mpd_t *result, const mpd_t *a)
7427db96d56Sopenharmony_ci{
7437db96d56Sopenharmony_ci    uint8_t aflags = a->flags;
7447db96d56Sopenharmony_ci    result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
7457db96d56Sopenharmony_ci    result->flags |= (aflags & ~(MPD_STATIC|MPD_DATAFLAGS));
7467db96d56Sopenharmony_ci}
7477db96d56Sopenharmony_ci
7487db96d56Sopenharmony_ci/* Initialize a workcontext from ctx. Set traps, flags and newtrap to 0. */
7497db96d56Sopenharmony_cistatic inline void
7507db96d56Sopenharmony_cimpd_workcontext(mpd_context_t *workctx, const mpd_context_t *ctx)
7517db96d56Sopenharmony_ci{
7527db96d56Sopenharmony_ci    workctx->prec = ctx->prec;
7537db96d56Sopenharmony_ci    workctx->emax = ctx->emax;
7547db96d56Sopenharmony_ci    workctx->emin = ctx->emin;
7557db96d56Sopenharmony_ci    workctx->round = ctx->round;
7567db96d56Sopenharmony_ci    workctx->traps = 0;
7577db96d56Sopenharmony_ci    workctx->status = 0;
7587db96d56Sopenharmony_ci    workctx->newtrap = 0;
7597db96d56Sopenharmony_ci    workctx->clamp = ctx->clamp;
7607db96d56Sopenharmony_ci    workctx->allcr = ctx->allcr;
7617db96d56Sopenharmony_ci}
7627db96d56Sopenharmony_ci
7637db96d56Sopenharmony_ci
7647db96d56Sopenharmony_ci/******************************************************************************/
7657db96d56Sopenharmony_ci/*                  Getting and setting parts of decimals                     */
7667db96d56Sopenharmony_ci/******************************************************************************/
7677db96d56Sopenharmony_ci
7687db96d56Sopenharmony_ci/* Flip the sign of a decimal */
7697db96d56Sopenharmony_cistatic inline void
7707db96d56Sopenharmony_ci_mpd_negate(mpd_t *dec)
7717db96d56Sopenharmony_ci{
7727db96d56Sopenharmony_ci    dec->flags ^= MPD_NEG;
7737db96d56Sopenharmony_ci}
7747db96d56Sopenharmony_ci
7757db96d56Sopenharmony_ci/* Set coefficient to zero */
7767db96d56Sopenharmony_civoid
7777db96d56Sopenharmony_cimpd_zerocoeff(mpd_t *result)
7787db96d56Sopenharmony_ci{
7797db96d56Sopenharmony_ci    mpd_minalloc(result);
7807db96d56Sopenharmony_ci    result->digits = 1;
7817db96d56Sopenharmony_ci    result->len = 1;
7827db96d56Sopenharmony_ci    result->data[0] = 0;
7837db96d56Sopenharmony_ci}
7847db96d56Sopenharmony_ci
7857db96d56Sopenharmony_ci/* Set the coefficient to all nines. */
7867db96d56Sopenharmony_civoid
7877db96d56Sopenharmony_cimpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status)
7887db96d56Sopenharmony_ci{
7897db96d56Sopenharmony_ci    mpd_ssize_t len, r;
7907db96d56Sopenharmony_ci
7917db96d56Sopenharmony_ci    _mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS);
7927db96d56Sopenharmony_ci    len = (r == 0) ? len : len+1;
7937db96d56Sopenharmony_ci
7947db96d56Sopenharmony_ci    if (!mpd_qresize(result, len, status)) {
7957db96d56Sopenharmony_ci        return;
7967db96d56Sopenharmony_ci    }
7977db96d56Sopenharmony_ci
7987db96d56Sopenharmony_ci    result->len = len;
7997db96d56Sopenharmony_ci    result->digits = ctx->prec;
8007db96d56Sopenharmony_ci
8017db96d56Sopenharmony_ci    --len;
8027db96d56Sopenharmony_ci    if (r > 0) {
8037db96d56Sopenharmony_ci        result->data[len--] = mpd_pow10[r]-1;
8047db96d56Sopenharmony_ci    }
8057db96d56Sopenharmony_ci    for (; len >= 0; --len) {
8067db96d56Sopenharmony_ci        result->data[len] = MPD_RADIX-1;
8077db96d56Sopenharmony_ci    }
8087db96d56Sopenharmony_ci}
8097db96d56Sopenharmony_ci
8107db96d56Sopenharmony_ci/*
8117db96d56Sopenharmony_ci * Cut off the most significant digits so that the rest fits in ctx->prec.
8127db96d56Sopenharmony_ci * Cannot fail.
8137db96d56Sopenharmony_ci */
8147db96d56Sopenharmony_cistatic void
8157db96d56Sopenharmony_ci_mpd_cap(mpd_t *result, const mpd_context_t *ctx)
8167db96d56Sopenharmony_ci{
8177db96d56Sopenharmony_ci    uint32_t dummy;
8187db96d56Sopenharmony_ci    mpd_ssize_t len, r;
8197db96d56Sopenharmony_ci
8207db96d56Sopenharmony_ci    if (result->len > 0 && result->digits > ctx->prec) {
8217db96d56Sopenharmony_ci        _mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS);
8227db96d56Sopenharmony_ci        len = (r == 0) ? len : len+1;
8237db96d56Sopenharmony_ci
8247db96d56Sopenharmony_ci        if (r != 0) {
8257db96d56Sopenharmony_ci            result->data[len-1] %= mpd_pow10[r];
8267db96d56Sopenharmony_ci        }
8277db96d56Sopenharmony_ci
8287db96d56Sopenharmony_ci        len = _mpd_real_size(result->data, len);
8297db96d56Sopenharmony_ci        /* resize to fewer words cannot fail */
8307db96d56Sopenharmony_ci        mpd_qresize(result, len, &dummy);
8317db96d56Sopenharmony_ci        result->len = len;
8327db96d56Sopenharmony_ci        mpd_setdigits(result);
8337db96d56Sopenharmony_ci    }
8347db96d56Sopenharmony_ci    if (mpd_iszero(result)) {
8357db96d56Sopenharmony_ci        _settriple(result, mpd_sign(result), 0, result->exp);
8367db96d56Sopenharmony_ci    }
8377db96d56Sopenharmony_ci}
8387db96d56Sopenharmony_ci
8397db96d56Sopenharmony_ci/*
8407db96d56Sopenharmony_ci * Cut off the most significant digits of a NaN payload so that the rest
8417db96d56Sopenharmony_ci * fits in ctx->prec - ctx->clamp. Cannot fail.
8427db96d56Sopenharmony_ci */
8437db96d56Sopenharmony_cistatic void
8447db96d56Sopenharmony_ci_mpd_fix_nan(mpd_t *result, const mpd_context_t *ctx)
8457db96d56Sopenharmony_ci{
8467db96d56Sopenharmony_ci    uint32_t dummy;
8477db96d56Sopenharmony_ci    mpd_ssize_t prec;
8487db96d56Sopenharmony_ci    mpd_ssize_t len, r;
8497db96d56Sopenharmony_ci
8507db96d56Sopenharmony_ci    prec = ctx->prec - ctx->clamp;
8517db96d56Sopenharmony_ci    if (result->len > 0 && result->digits > prec) {
8527db96d56Sopenharmony_ci        if (prec == 0) {
8537db96d56Sopenharmony_ci            mpd_minalloc(result);
8547db96d56Sopenharmony_ci            result->len = result->digits = 0;
8557db96d56Sopenharmony_ci        }
8567db96d56Sopenharmony_ci        else {
8577db96d56Sopenharmony_ci            _mpd_idiv_word(&len, &r, prec, MPD_RDIGITS);
8587db96d56Sopenharmony_ci            len = (r == 0) ? len : len+1;
8597db96d56Sopenharmony_ci
8607db96d56Sopenharmony_ci            if (r != 0) {
8617db96d56Sopenharmony_ci                 result->data[len-1] %= mpd_pow10[r];
8627db96d56Sopenharmony_ci            }
8637db96d56Sopenharmony_ci
8647db96d56Sopenharmony_ci            len = _mpd_real_size(result->data, len);
8657db96d56Sopenharmony_ci            /* resize to fewer words cannot fail */
8667db96d56Sopenharmony_ci            mpd_qresize(result, len, &dummy);
8677db96d56Sopenharmony_ci            result->len = len;
8687db96d56Sopenharmony_ci            mpd_setdigits(result);
8697db96d56Sopenharmony_ci            if (mpd_iszerocoeff(result)) {
8707db96d56Sopenharmony_ci                /* NaN0 is not a valid representation */
8717db96d56Sopenharmony_ci                result->len = result->digits = 0;
8727db96d56Sopenharmony_ci            }
8737db96d56Sopenharmony_ci        }
8747db96d56Sopenharmony_ci    }
8757db96d56Sopenharmony_ci}
8767db96d56Sopenharmony_ci
8777db96d56Sopenharmony_ci/*
8787db96d56Sopenharmony_ci * Get n most significant digits from a decimal, where 0 < n <= MPD_UINT_DIGITS.
8797db96d56Sopenharmony_ci * Assumes MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for 32 and 64 bit
8807db96d56Sopenharmony_ci * machines.
8817db96d56Sopenharmony_ci *
8827db96d56Sopenharmony_ci * The result of the operation will be in lo. If the operation is impossible,
8837db96d56Sopenharmony_ci * hi will be nonzero. This is used to indicate an error.
8847db96d56Sopenharmony_ci */
8857db96d56Sopenharmony_cistatic inline void
8867db96d56Sopenharmony_ci_mpd_get_msdigits(mpd_uint_t *hi, mpd_uint_t *lo, const mpd_t *dec,
8877db96d56Sopenharmony_ci                  unsigned int n)
8887db96d56Sopenharmony_ci{
8897db96d56Sopenharmony_ci    mpd_uint_t r, tmp;
8907db96d56Sopenharmony_ci
8917db96d56Sopenharmony_ci    assert(0 < n && n <= MPD_RDIGITS+1);
8927db96d56Sopenharmony_ci
8937db96d56Sopenharmony_ci    _mpd_div_word(&tmp, &r, dec->digits, MPD_RDIGITS);
8947db96d56Sopenharmony_ci    r = (r == 0) ? MPD_RDIGITS : r; /* digits in the most significant word */
8957db96d56Sopenharmony_ci
8967db96d56Sopenharmony_ci    *hi = 0;
8977db96d56Sopenharmony_ci    *lo = dec->data[dec->len-1];
8987db96d56Sopenharmony_ci    if (n <= r) {
8997db96d56Sopenharmony_ci        *lo /= mpd_pow10[r-n];
9007db96d56Sopenharmony_ci    }
9017db96d56Sopenharmony_ci    else if (dec->len > 1) {
9027db96d56Sopenharmony_ci        /* at this point 1 <= r < n <= MPD_RDIGITS+1 */
9037db96d56Sopenharmony_ci        _mpd_mul_words(hi, lo, *lo, mpd_pow10[n-r]);
9047db96d56Sopenharmony_ci        tmp = dec->data[dec->len-2] / mpd_pow10[MPD_RDIGITS-(n-r)];
9057db96d56Sopenharmony_ci        *lo = *lo + tmp;
9067db96d56Sopenharmony_ci        if (*lo < tmp) (*hi)++;
9077db96d56Sopenharmony_ci    }
9087db96d56Sopenharmony_ci}
9097db96d56Sopenharmony_ci
9107db96d56Sopenharmony_ci
9117db96d56Sopenharmony_ci/******************************************************************************/
9127db96d56Sopenharmony_ci/*                   Gathering information about a decimal                    */
9137db96d56Sopenharmony_ci/******************************************************************************/
9147db96d56Sopenharmony_ci
9157db96d56Sopenharmony_ci/* The real size of the coefficient without leading zero words. */
9167db96d56Sopenharmony_cistatic inline mpd_ssize_t
9177db96d56Sopenharmony_ci_mpd_real_size(mpd_uint_t *data, mpd_ssize_t size)
9187db96d56Sopenharmony_ci{
9197db96d56Sopenharmony_ci    while (size > 1 && data[size-1] == 0) {
9207db96d56Sopenharmony_ci        size--;
9217db96d56Sopenharmony_ci    }
9227db96d56Sopenharmony_ci
9237db96d56Sopenharmony_ci    return size;
9247db96d56Sopenharmony_ci}
9257db96d56Sopenharmony_ci
9267db96d56Sopenharmony_ci/* Return number of trailing zeros. No errors are possible. */
9277db96d56Sopenharmony_cimpd_ssize_t
9287db96d56Sopenharmony_cimpd_trail_zeros(const mpd_t *dec)
9297db96d56Sopenharmony_ci{
9307db96d56Sopenharmony_ci    mpd_uint_t word;
9317db96d56Sopenharmony_ci    mpd_ssize_t i, tz = 0;
9327db96d56Sopenharmony_ci
9337db96d56Sopenharmony_ci    for (i=0; i < dec->len; ++i) {
9347db96d56Sopenharmony_ci        if (dec->data[i] != 0) {
9357db96d56Sopenharmony_ci            word = dec->data[i];
9367db96d56Sopenharmony_ci            tz = i * MPD_RDIGITS;
9377db96d56Sopenharmony_ci            while (word % 10 == 0) {
9387db96d56Sopenharmony_ci                word /= 10;
9397db96d56Sopenharmony_ci                tz++;
9407db96d56Sopenharmony_ci            }
9417db96d56Sopenharmony_ci            break;
9427db96d56Sopenharmony_ci        }
9437db96d56Sopenharmony_ci    }
9447db96d56Sopenharmony_ci
9457db96d56Sopenharmony_ci    return tz;
9467db96d56Sopenharmony_ci}
9477db96d56Sopenharmony_ci
9487db96d56Sopenharmony_ci/* Integer: Undefined for specials */
9497db96d56Sopenharmony_cistatic int
9507db96d56Sopenharmony_ci_mpd_isint(const mpd_t *dec)
9517db96d56Sopenharmony_ci{
9527db96d56Sopenharmony_ci    mpd_ssize_t tz;
9537db96d56Sopenharmony_ci
9547db96d56Sopenharmony_ci    if (mpd_iszerocoeff(dec)) {
9557db96d56Sopenharmony_ci        return 1;
9567db96d56Sopenharmony_ci    }
9577db96d56Sopenharmony_ci
9587db96d56Sopenharmony_ci    tz = mpd_trail_zeros(dec);
9597db96d56Sopenharmony_ci    return (dec->exp + tz >= 0);
9607db96d56Sopenharmony_ci}
9617db96d56Sopenharmony_ci
9627db96d56Sopenharmony_ci/* Integer */
9637db96d56Sopenharmony_ciint
9647db96d56Sopenharmony_cimpd_isinteger(const mpd_t *dec)
9657db96d56Sopenharmony_ci{
9667db96d56Sopenharmony_ci    if (mpd_isspecial(dec)) {
9677db96d56Sopenharmony_ci        return 0;
9687db96d56Sopenharmony_ci    }
9697db96d56Sopenharmony_ci    return _mpd_isint(dec);
9707db96d56Sopenharmony_ci}
9717db96d56Sopenharmony_ci
9727db96d56Sopenharmony_ci/* Word is a power of 10 */
9737db96d56Sopenharmony_cistatic int
9747db96d56Sopenharmony_cimpd_word_ispow10(mpd_uint_t word)
9757db96d56Sopenharmony_ci{
9767db96d56Sopenharmony_ci    int n;
9777db96d56Sopenharmony_ci
9787db96d56Sopenharmony_ci    n = mpd_word_digits(word);
9797db96d56Sopenharmony_ci    if (word == mpd_pow10[n-1]) {
9807db96d56Sopenharmony_ci        return 1;
9817db96d56Sopenharmony_ci    }
9827db96d56Sopenharmony_ci
9837db96d56Sopenharmony_ci    return 0;
9847db96d56Sopenharmony_ci}
9857db96d56Sopenharmony_ci
9867db96d56Sopenharmony_ci/* Coefficient is a power of 10 */
9877db96d56Sopenharmony_cistatic int
9887db96d56Sopenharmony_cimpd_coeff_ispow10(const mpd_t *dec)
9897db96d56Sopenharmony_ci{
9907db96d56Sopenharmony_ci    if (mpd_word_ispow10(mpd_msword(dec))) {
9917db96d56Sopenharmony_ci        if (_mpd_isallzero(dec->data, dec->len-1)) {
9927db96d56Sopenharmony_ci            return 1;
9937db96d56Sopenharmony_ci        }
9947db96d56Sopenharmony_ci    }
9957db96d56Sopenharmony_ci
9967db96d56Sopenharmony_ci    return 0;
9977db96d56Sopenharmony_ci}
9987db96d56Sopenharmony_ci
9997db96d56Sopenharmony_ci/* All digits of a word are nines */
10007db96d56Sopenharmony_cistatic int
10017db96d56Sopenharmony_cimpd_word_isallnine(mpd_uint_t word)
10027db96d56Sopenharmony_ci{
10037db96d56Sopenharmony_ci    int n;
10047db96d56Sopenharmony_ci
10057db96d56Sopenharmony_ci    n = mpd_word_digits(word);
10067db96d56Sopenharmony_ci    if (word == mpd_pow10[n]-1) {
10077db96d56Sopenharmony_ci        return 1;
10087db96d56Sopenharmony_ci    }
10097db96d56Sopenharmony_ci
10107db96d56Sopenharmony_ci    return 0;
10117db96d56Sopenharmony_ci}
10127db96d56Sopenharmony_ci
10137db96d56Sopenharmony_ci/* All digits of the coefficient are nines */
10147db96d56Sopenharmony_cistatic int
10157db96d56Sopenharmony_cimpd_coeff_isallnine(const mpd_t *dec)
10167db96d56Sopenharmony_ci{
10177db96d56Sopenharmony_ci    if (mpd_word_isallnine(mpd_msword(dec))) {
10187db96d56Sopenharmony_ci        if (_mpd_isallnine(dec->data, dec->len-1)) {
10197db96d56Sopenharmony_ci            return 1;
10207db96d56Sopenharmony_ci        }
10217db96d56Sopenharmony_ci    }
10227db96d56Sopenharmony_ci
10237db96d56Sopenharmony_ci    return 0;
10247db96d56Sopenharmony_ci}
10257db96d56Sopenharmony_ci
10267db96d56Sopenharmony_ci/* Odd decimal: Undefined for non-integers! */
10277db96d56Sopenharmony_ciint
10287db96d56Sopenharmony_cimpd_isodd(const mpd_t *dec)
10297db96d56Sopenharmony_ci{
10307db96d56Sopenharmony_ci    mpd_uint_t q, r;
10317db96d56Sopenharmony_ci    assert(mpd_isinteger(dec));
10327db96d56Sopenharmony_ci    if (mpd_iszerocoeff(dec)) return 0;
10337db96d56Sopenharmony_ci    if (dec->exp < 0) {
10347db96d56Sopenharmony_ci        _mpd_div_word(&q, &r, -dec->exp, MPD_RDIGITS);
10357db96d56Sopenharmony_ci        q = dec->data[q] / mpd_pow10[r];
10367db96d56Sopenharmony_ci        return mpd_isoddword(q);
10377db96d56Sopenharmony_ci    }
10387db96d56Sopenharmony_ci    return dec->exp == 0 && mpd_isoddword(dec->data[0]);
10397db96d56Sopenharmony_ci}
10407db96d56Sopenharmony_ci
10417db96d56Sopenharmony_ci/* Even: Undefined for non-integers! */
10427db96d56Sopenharmony_ciint
10437db96d56Sopenharmony_cimpd_iseven(const mpd_t *dec)
10447db96d56Sopenharmony_ci{
10457db96d56Sopenharmony_ci    return !mpd_isodd(dec);
10467db96d56Sopenharmony_ci}
10477db96d56Sopenharmony_ci
10487db96d56Sopenharmony_ci/******************************************************************************/
10497db96d56Sopenharmony_ci/*                      Getting and setting decimals                          */
10507db96d56Sopenharmony_ci/******************************************************************************/
10517db96d56Sopenharmony_ci
10527db96d56Sopenharmony_ci/* Internal function: Set a static decimal from a triple, no error checking. */
10537db96d56Sopenharmony_cistatic void
10547db96d56Sopenharmony_ci_ssettriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp)
10557db96d56Sopenharmony_ci{
10567db96d56Sopenharmony_ci    mpd_set_flags(result, sign);
10577db96d56Sopenharmony_ci    result->exp = exp;
10587db96d56Sopenharmony_ci    _mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX);
10597db96d56Sopenharmony_ci    result->len = (result->data[1] == 0) ? 1 : 2;
10607db96d56Sopenharmony_ci    mpd_setdigits(result);
10617db96d56Sopenharmony_ci}
10627db96d56Sopenharmony_ci
10637db96d56Sopenharmony_ci/* Internal function: Set a decimal from a triple, no error checking. */
10647db96d56Sopenharmony_cistatic void
10657db96d56Sopenharmony_ci_settriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp)
10667db96d56Sopenharmony_ci{
10677db96d56Sopenharmony_ci    mpd_minalloc(result);
10687db96d56Sopenharmony_ci    mpd_set_flags(result, sign);
10697db96d56Sopenharmony_ci    result->exp = exp;
10707db96d56Sopenharmony_ci    _mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX);
10717db96d56Sopenharmony_ci    result->len = (result->data[1] == 0) ? 1 : 2;
10727db96d56Sopenharmony_ci    mpd_setdigits(result);
10737db96d56Sopenharmony_ci}
10747db96d56Sopenharmony_ci
10757db96d56Sopenharmony_ci/* Set a special number from a triple */
10767db96d56Sopenharmony_civoid
10777db96d56Sopenharmony_cimpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type)
10787db96d56Sopenharmony_ci{
10797db96d56Sopenharmony_ci    mpd_minalloc(result);
10807db96d56Sopenharmony_ci    result->flags &= ~(MPD_NEG|MPD_SPECIAL);
10817db96d56Sopenharmony_ci    result->flags |= (sign|type);
10827db96d56Sopenharmony_ci    result->exp = result->digits = result->len = 0;
10837db96d56Sopenharmony_ci}
10847db96d56Sopenharmony_ci
10857db96d56Sopenharmony_ci/* Set result of NaN with an error status */
10867db96d56Sopenharmony_civoid
10877db96d56Sopenharmony_cimpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status)
10887db96d56Sopenharmony_ci{
10897db96d56Sopenharmony_ci    mpd_minalloc(result);
10907db96d56Sopenharmony_ci    mpd_set_qnan(result);
10917db96d56Sopenharmony_ci    mpd_set_positive(result);
10927db96d56Sopenharmony_ci    result->exp = result->digits = result->len = 0;
10937db96d56Sopenharmony_ci    *status |= flags;
10947db96d56Sopenharmony_ci}
10957db96d56Sopenharmony_ci
10967db96d56Sopenharmony_ci/* quietly set a static decimal from an mpd_ssize_t */
10977db96d56Sopenharmony_civoid
10987db96d56Sopenharmony_cimpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx,
10997db96d56Sopenharmony_ci                uint32_t *status)
11007db96d56Sopenharmony_ci{
11017db96d56Sopenharmony_ci    mpd_uint_t u;
11027db96d56Sopenharmony_ci    uint8_t sign = MPD_POS;
11037db96d56Sopenharmony_ci
11047db96d56Sopenharmony_ci    if (a < 0) {
11057db96d56Sopenharmony_ci        if (a == MPD_SSIZE_MIN) {
11067db96d56Sopenharmony_ci            u = (mpd_uint_t)MPD_SSIZE_MAX +
11077db96d56Sopenharmony_ci                (-(MPD_SSIZE_MIN+MPD_SSIZE_MAX));
11087db96d56Sopenharmony_ci        }
11097db96d56Sopenharmony_ci        else {
11107db96d56Sopenharmony_ci            u = -a;
11117db96d56Sopenharmony_ci        }
11127db96d56Sopenharmony_ci        sign = MPD_NEG;
11137db96d56Sopenharmony_ci    }
11147db96d56Sopenharmony_ci    else {
11157db96d56Sopenharmony_ci        u = a;
11167db96d56Sopenharmony_ci    }
11177db96d56Sopenharmony_ci    _ssettriple(result, sign, u, 0);
11187db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
11197db96d56Sopenharmony_ci}
11207db96d56Sopenharmony_ci
11217db96d56Sopenharmony_ci/* quietly set a static decimal from an mpd_uint_t */
11227db96d56Sopenharmony_civoid
11237db96d56Sopenharmony_cimpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx,
11247db96d56Sopenharmony_ci               uint32_t *status)
11257db96d56Sopenharmony_ci{
11267db96d56Sopenharmony_ci    _ssettriple(result, MPD_POS, a, 0);
11277db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
11287db96d56Sopenharmony_ci}
11297db96d56Sopenharmony_ci
11307db96d56Sopenharmony_ci/* quietly set a static decimal from an int32_t */
11317db96d56Sopenharmony_civoid
11327db96d56Sopenharmony_cimpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx,
11337db96d56Sopenharmony_ci              uint32_t *status)
11347db96d56Sopenharmony_ci{
11357db96d56Sopenharmony_ci    mpd_qsset_ssize(result, a, ctx, status);
11367db96d56Sopenharmony_ci}
11377db96d56Sopenharmony_ci
11387db96d56Sopenharmony_ci/* quietly set a static decimal from a uint32_t */
11397db96d56Sopenharmony_civoid
11407db96d56Sopenharmony_cimpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx,
11417db96d56Sopenharmony_ci              uint32_t *status)
11427db96d56Sopenharmony_ci{
11437db96d56Sopenharmony_ci    mpd_qsset_uint(result, a, ctx, status);
11447db96d56Sopenharmony_ci}
11457db96d56Sopenharmony_ci
11467db96d56Sopenharmony_ci#ifdef CONFIG_64
11477db96d56Sopenharmony_ci/* quietly set a static decimal from an int64_t */
11487db96d56Sopenharmony_civoid
11497db96d56Sopenharmony_cimpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
11507db96d56Sopenharmony_ci              uint32_t *status)
11517db96d56Sopenharmony_ci{
11527db96d56Sopenharmony_ci    mpd_qsset_ssize(result, a, ctx, status);
11537db96d56Sopenharmony_ci}
11547db96d56Sopenharmony_ci
11557db96d56Sopenharmony_ci/* quietly set a static decimal from a uint64_t */
11567db96d56Sopenharmony_civoid
11577db96d56Sopenharmony_cimpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
11587db96d56Sopenharmony_ci              uint32_t *status)
11597db96d56Sopenharmony_ci{
11607db96d56Sopenharmony_ci    mpd_qsset_uint(result, a, ctx, status);
11617db96d56Sopenharmony_ci}
11627db96d56Sopenharmony_ci#endif
11637db96d56Sopenharmony_ci
11647db96d56Sopenharmony_ci/* quietly set a decimal from an mpd_ssize_t */
11657db96d56Sopenharmony_civoid
11667db96d56Sopenharmony_cimpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx,
11677db96d56Sopenharmony_ci               uint32_t *status)
11687db96d56Sopenharmony_ci{
11697db96d56Sopenharmony_ci    mpd_minalloc(result);
11707db96d56Sopenharmony_ci    mpd_qsset_ssize(result, a, ctx, status);
11717db96d56Sopenharmony_ci}
11727db96d56Sopenharmony_ci
11737db96d56Sopenharmony_ci/* quietly set a decimal from an mpd_uint_t */
11747db96d56Sopenharmony_civoid
11757db96d56Sopenharmony_cimpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx,
11767db96d56Sopenharmony_ci              uint32_t *status)
11777db96d56Sopenharmony_ci{
11787db96d56Sopenharmony_ci    _settriple(result, MPD_POS, a, 0);
11797db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
11807db96d56Sopenharmony_ci}
11817db96d56Sopenharmony_ci
11827db96d56Sopenharmony_ci/* quietly set a decimal from an int32_t */
11837db96d56Sopenharmony_civoid
11847db96d56Sopenharmony_cimpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx,
11857db96d56Sopenharmony_ci             uint32_t *status)
11867db96d56Sopenharmony_ci{
11877db96d56Sopenharmony_ci    mpd_qset_ssize(result, a, ctx, status);
11887db96d56Sopenharmony_ci}
11897db96d56Sopenharmony_ci
11907db96d56Sopenharmony_ci/* quietly set a decimal from a uint32_t */
11917db96d56Sopenharmony_civoid
11927db96d56Sopenharmony_cimpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx,
11937db96d56Sopenharmony_ci             uint32_t *status)
11947db96d56Sopenharmony_ci{
11957db96d56Sopenharmony_ci    mpd_qset_uint(result, a, ctx, status);
11967db96d56Sopenharmony_ci}
11977db96d56Sopenharmony_ci
11987db96d56Sopenharmony_ci#if defined(CONFIG_32) && !defined(LEGACY_COMPILER)
11997db96d56Sopenharmony_ci/* set a decimal from a uint64_t */
12007db96d56Sopenharmony_cistatic void
12017db96d56Sopenharmony_ci_c32setu64(mpd_t *result, uint64_t u, uint8_t sign, uint32_t *status)
12027db96d56Sopenharmony_ci{
12037db96d56Sopenharmony_ci    mpd_uint_t w[3];
12047db96d56Sopenharmony_ci    uint64_t q;
12057db96d56Sopenharmony_ci    int i, len;
12067db96d56Sopenharmony_ci
12077db96d56Sopenharmony_ci    len = 0;
12087db96d56Sopenharmony_ci    do {
12097db96d56Sopenharmony_ci        q = u / MPD_RADIX;
12107db96d56Sopenharmony_ci        w[len] = (mpd_uint_t)(u - q * MPD_RADIX);
12117db96d56Sopenharmony_ci        u = q; len++;
12127db96d56Sopenharmony_ci    } while (u != 0);
12137db96d56Sopenharmony_ci
12147db96d56Sopenharmony_ci    if (!mpd_qresize(result, len, status)) {
12157db96d56Sopenharmony_ci        return;
12167db96d56Sopenharmony_ci    }
12177db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
12187db96d56Sopenharmony_ci        result->data[i] = w[i];
12197db96d56Sopenharmony_ci    }
12207db96d56Sopenharmony_ci
12217db96d56Sopenharmony_ci    mpd_set_flags(result, sign);
12227db96d56Sopenharmony_ci    result->exp = 0;
12237db96d56Sopenharmony_ci    result->len = len;
12247db96d56Sopenharmony_ci    mpd_setdigits(result);
12257db96d56Sopenharmony_ci}
12267db96d56Sopenharmony_ci
12277db96d56Sopenharmony_cistatic void
12287db96d56Sopenharmony_ci_c32_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
12297db96d56Sopenharmony_ci              uint32_t *status)
12307db96d56Sopenharmony_ci{
12317db96d56Sopenharmony_ci    _c32setu64(result, a, MPD_POS, status);
12327db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
12337db96d56Sopenharmony_ci}
12347db96d56Sopenharmony_ci
12357db96d56Sopenharmony_ci/* set a decimal from an int64_t */
12367db96d56Sopenharmony_cistatic void
12377db96d56Sopenharmony_ci_c32_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
12387db96d56Sopenharmony_ci              uint32_t *status)
12397db96d56Sopenharmony_ci{
12407db96d56Sopenharmony_ci    uint64_t u;
12417db96d56Sopenharmony_ci    uint8_t sign = MPD_POS;
12427db96d56Sopenharmony_ci
12437db96d56Sopenharmony_ci    if (a < 0) {
12447db96d56Sopenharmony_ci        if (a == INT64_MIN) {
12457db96d56Sopenharmony_ci            u = (uint64_t)INT64_MAX + (-(INT64_MIN+INT64_MAX));
12467db96d56Sopenharmony_ci        }
12477db96d56Sopenharmony_ci        else {
12487db96d56Sopenharmony_ci            u = -a;
12497db96d56Sopenharmony_ci        }
12507db96d56Sopenharmony_ci        sign = MPD_NEG;
12517db96d56Sopenharmony_ci    }
12527db96d56Sopenharmony_ci    else {
12537db96d56Sopenharmony_ci        u = a;
12547db96d56Sopenharmony_ci    }
12557db96d56Sopenharmony_ci    _c32setu64(result, u, sign, status);
12567db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
12577db96d56Sopenharmony_ci}
12587db96d56Sopenharmony_ci#endif /* CONFIG_32 && !LEGACY_COMPILER */
12597db96d56Sopenharmony_ci
12607db96d56Sopenharmony_ci#ifndef LEGACY_COMPILER
12617db96d56Sopenharmony_ci/* quietly set a decimal from an int64_t */
12627db96d56Sopenharmony_civoid
12637db96d56Sopenharmony_cimpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
12647db96d56Sopenharmony_ci             uint32_t *status)
12657db96d56Sopenharmony_ci{
12667db96d56Sopenharmony_ci#ifdef CONFIG_64
12677db96d56Sopenharmony_ci    mpd_qset_ssize(result, a, ctx, status);
12687db96d56Sopenharmony_ci#else
12697db96d56Sopenharmony_ci    _c32_qset_i64(result, a, ctx, status);
12707db96d56Sopenharmony_ci#endif
12717db96d56Sopenharmony_ci}
12727db96d56Sopenharmony_ci
12737db96d56Sopenharmony_ci/* quietly set a decimal from an int64_t, use a maxcontext for conversion */
12747db96d56Sopenharmony_civoid
12757db96d56Sopenharmony_cimpd_qset_i64_exact(mpd_t *result, int64_t a, uint32_t *status)
12767db96d56Sopenharmony_ci{
12777db96d56Sopenharmony_ci    mpd_context_t maxcontext;
12787db96d56Sopenharmony_ci
12797db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
12807db96d56Sopenharmony_ci#ifdef CONFIG_64
12817db96d56Sopenharmony_ci    mpd_qset_ssize(result, a, &maxcontext, status);
12827db96d56Sopenharmony_ci#else
12837db96d56Sopenharmony_ci    _c32_qset_i64(result, a, &maxcontext, status);
12847db96d56Sopenharmony_ci#endif
12857db96d56Sopenharmony_ci
12867db96d56Sopenharmony_ci    if (*status & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
12877db96d56Sopenharmony_ci        /* we want exact results */
12887db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
12897db96d56Sopenharmony_ci    }
12907db96d56Sopenharmony_ci    *status &= MPD_Errors;
12917db96d56Sopenharmony_ci}
12927db96d56Sopenharmony_ci
12937db96d56Sopenharmony_ci/* quietly set a decimal from a uint64_t */
12947db96d56Sopenharmony_civoid
12957db96d56Sopenharmony_cimpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
12967db96d56Sopenharmony_ci             uint32_t *status)
12977db96d56Sopenharmony_ci{
12987db96d56Sopenharmony_ci#ifdef CONFIG_64
12997db96d56Sopenharmony_ci    mpd_qset_uint(result, a, ctx, status);
13007db96d56Sopenharmony_ci#else
13017db96d56Sopenharmony_ci    _c32_qset_u64(result, a, ctx, status);
13027db96d56Sopenharmony_ci#endif
13037db96d56Sopenharmony_ci}
13047db96d56Sopenharmony_ci
13057db96d56Sopenharmony_ci/* quietly set a decimal from a uint64_t, use a maxcontext for conversion */
13067db96d56Sopenharmony_civoid
13077db96d56Sopenharmony_cimpd_qset_u64_exact(mpd_t *result, uint64_t a, uint32_t *status)
13087db96d56Sopenharmony_ci{
13097db96d56Sopenharmony_ci    mpd_context_t maxcontext;
13107db96d56Sopenharmony_ci
13117db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
13127db96d56Sopenharmony_ci#ifdef CONFIG_64
13137db96d56Sopenharmony_ci    mpd_qset_uint(result, a, &maxcontext, status);
13147db96d56Sopenharmony_ci#else
13157db96d56Sopenharmony_ci    _c32_qset_u64(result, a, &maxcontext, status);
13167db96d56Sopenharmony_ci#endif
13177db96d56Sopenharmony_ci
13187db96d56Sopenharmony_ci    if (*status & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
13197db96d56Sopenharmony_ci        /* we want exact results */
13207db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
13217db96d56Sopenharmony_ci    }
13227db96d56Sopenharmony_ci    *status &= MPD_Errors;
13237db96d56Sopenharmony_ci}
13247db96d56Sopenharmony_ci#endif /* !LEGACY_COMPILER */
13257db96d56Sopenharmony_ci
13267db96d56Sopenharmony_ci/*
13277db96d56Sopenharmony_ci * Quietly get an mpd_uint_t from a decimal. Assumes
13287db96d56Sopenharmony_ci * MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for
13297db96d56Sopenharmony_ci * 32 and 64 bit machines.
13307db96d56Sopenharmony_ci *
13317db96d56Sopenharmony_ci * If the operation is impossible, MPD_Invalid_operation is set.
13327db96d56Sopenharmony_ci */
13337db96d56Sopenharmony_cistatic mpd_uint_t
13347db96d56Sopenharmony_ci_mpd_qget_uint(int use_sign, const mpd_t *a, uint32_t *status)
13357db96d56Sopenharmony_ci{
13367db96d56Sopenharmony_ci    mpd_t tmp;
13377db96d56Sopenharmony_ci    mpd_uint_t tmp_data[2];
13387db96d56Sopenharmony_ci    mpd_uint_t lo, hi;
13397db96d56Sopenharmony_ci
13407db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
13417db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
13427db96d56Sopenharmony_ci        return MPD_UINT_MAX;
13437db96d56Sopenharmony_ci    }
13447db96d56Sopenharmony_ci    if (mpd_iszero(a)) {
13457db96d56Sopenharmony_ci        return 0;
13467db96d56Sopenharmony_ci    }
13477db96d56Sopenharmony_ci    if (use_sign && mpd_isnegative(a)) {
13487db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
13497db96d56Sopenharmony_ci        return MPD_UINT_MAX;
13507db96d56Sopenharmony_ci    }
13517db96d56Sopenharmony_ci
13527db96d56Sopenharmony_ci    if (a->digits+a->exp > MPD_RDIGITS+1) {
13537db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
13547db96d56Sopenharmony_ci        return MPD_UINT_MAX;
13557db96d56Sopenharmony_ci    }
13567db96d56Sopenharmony_ci
13577db96d56Sopenharmony_ci    if (a->exp < 0) {
13587db96d56Sopenharmony_ci        if (!_mpd_isint(a)) {
13597db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
13607db96d56Sopenharmony_ci            return MPD_UINT_MAX;
13617db96d56Sopenharmony_ci        }
13627db96d56Sopenharmony_ci        /* At this point a->digits+a->exp <= MPD_RDIGITS+1,
13637db96d56Sopenharmony_ci         * so the shift fits. */
13647db96d56Sopenharmony_ci        tmp.data = tmp_data;
13657db96d56Sopenharmony_ci        tmp.flags = MPD_STATIC|MPD_STATIC_DATA;
13667db96d56Sopenharmony_ci        tmp.alloc = 2;
13677db96d56Sopenharmony_ci        mpd_qsshiftr(&tmp, a, -a->exp);
13687db96d56Sopenharmony_ci        tmp.exp = 0;
13697db96d56Sopenharmony_ci        a = &tmp;
13707db96d56Sopenharmony_ci    }
13717db96d56Sopenharmony_ci
13727db96d56Sopenharmony_ci    _mpd_get_msdigits(&hi, &lo, a, MPD_RDIGITS+1);
13737db96d56Sopenharmony_ci    if (hi) {
13747db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
13757db96d56Sopenharmony_ci        return MPD_UINT_MAX;
13767db96d56Sopenharmony_ci    }
13777db96d56Sopenharmony_ci
13787db96d56Sopenharmony_ci    if (a->exp > 0) {
13797db96d56Sopenharmony_ci        _mpd_mul_words(&hi, &lo, lo, mpd_pow10[a->exp]);
13807db96d56Sopenharmony_ci        if (hi) {
13817db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
13827db96d56Sopenharmony_ci            return MPD_UINT_MAX;
13837db96d56Sopenharmony_ci        }
13847db96d56Sopenharmony_ci    }
13857db96d56Sopenharmony_ci
13867db96d56Sopenharmony_ci    return lo;
13877db96d56Sopenharmony_ci}
13887db96d56Sopenharmony_ci
13897db96d56Sopenharmony_ci/*
13907db96d56Sopenharmony_ci * Sets Invalid_operation for:
13917db96d56Sopenharmony_ci *   - specials
13927db96d56Sopenharmony_ci *   - negative numbers (except negative zero)
13937db96d56Sopenharmony_ci *   - non-integers
13947db96d56Sopenharmony_ci *   - overflow
13957db96d56Sopenharmony_ci */
13967db96d56Sopenharmony_cimpd_uint_t
13977db96d56Sopenharmony_cimpd_qget_uint(const mpd_t *a, uint32_t *status)
13987db96d56Sopenharmony_ci{
13997db96d56Sopenharmony_ci    return _mpd_qget_uint(1, a, status);
14007db96d56Sopenharmony_ci}
14017db96d56Sopenharmony_ci
14027db96d56Sopenharmony_ci/* Same as above, but gets the absolute value, i.e. the sign is ignored. */
14037db96d56Sopenharmony_cimpd_uint_t
14047db96d56Sopenharmony_cimpd_qabs_uint(const mpd_t *a, uint32_t *status)
14057db96d56Sopenharmony_ci{
14067db96d56Sopenharmony_ci    return _mpd_qget_uint(0, a, status);
14077db96d56Sopenharmony_ci}
14087db96d56Sopenharmony_ci
14097db96d56Sopenharmony_ci/* quietly get an mpd_ssize_t from a decimal */
14107db96d56Sopenharmony_cimpd_ssize_t
14117db96d56Sopenharmony_cimpd_qget_ssize(const mpd_t *a, uint32_t *status)
14127db96d56Sopenharmony_ci{
14137db96d56Sopenharmony_ci    uint32_t workstatus = 0;
14147db96d56Sopenharmony_ci    mpd_uint_t u;
14157db96d56Sopenharmony_ci    int isneg;
14167db96d56Sopenharmony_ci
14177db96d56Sopenharmony_ci    u = mpd_qabs_uint(a, &workstatus);
14187db96d56Sopenharmony_ci    if (workstatus&MPD_Invalid_operation) {
14197db96d56Sopenharmony_ci        *status |= workstatus;
14207db96d56Sopenharmony_ci        return MPD_SSIZE_MAX;
14217db96d56Sopenharmony_ci    }
14227db96d56Sopenharmony_ci
14237db96d56Sopenharmony_ci    isneg = mpd_isnegative(a);
14247db96d56Sopenharmony_ci    if (u <= MPD_SSIZE_MAX) {
14257db96d56Sopenharmony_ci        return isneg ? -((mpd_ssize_t)u) : (mpd_ssize_t)u;
14267db96d56Sopenharmony_ci    }
14277db96d56Sopenharmony_ci    else if (isneg && u+(MPD_SSIZE_MIN+MPD_SSIZE_MAX) == MPD_SSIZE_MAX) {
14287db96d56Sopenharmony_ci        return MPD_SSIZE_MIN;
14297db96d56Sopenharmony_ci    }
14307db96d56Sopenharmony_ci
14317db96d56Sopenharmony_ci    *status |= MPD_Invalid_operation;
14327db96d56Sopenharmony_ci    return MPD_SSIZE_MAX;
14337db96d56Sopenharmony_ci}
14347db96d56Sopenharmony_ci
14357db96d56Sopenharmony_ci#if defined(CONFIG_32) && !defined(LEGACY_COMPILER)
14367db96d56Sopenharmony_ci/*
14377db96d56Sopenharmony_ci * Quietly get a uint64_t from a decimal. If the operation is impossible,
14387db96d56Sopenharmony_ci * MPD_Invalid_operation is set.
14397db96d56Sopenharmony_ci */
14407db96d56Sopenharmony_cistatic uint64_t
14417db96d56Sopenharmony_ci_c32_qget_u64(int use_sign, const mpd_t *a, uint32_t *status)
14427db96d56Sopenharmony_ci{
14437db96d56Sopenharmony_ci    MPD_NEW_STATIC(tmp,0,0,20,3);
14447db96d56Sopenharmony_ci    mpd_context_t maxcontext;
14457db96d56Sopenharmony_ci    uint64_t ret;
14467db96d56Sopenharmony_ci
14477db96d56Sopenharmony_ci    tmp_data[0] = 709551615;
14487db96d56Sopenharmony_ci    tmp_data[1] = 446744073;
14497db96d56Sopenharmony_ci    tmp_data[2] = 18;
14507db96d56Sopenharmony_ci
14517db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
14527db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
14537db96d56Sopenharmony_ci        return UINT64_MAX;
14547db96d56Sopenharmony_ci    }
14557db96d56Sopenharmony_ci    if (mpd_iszero(a)) {
14567db96d56Sopenharmony_ci        return 0;
14577db96d56Sopenharmony_ci    }
14587db96d56Sopenharmony_ci    if (use_sign && mpd_isnegative(a)) {
14597db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
14607db96d56Sopenharmony_ci        return UINT64_MAX;
14617db96d56Sopenharmony_ci    }
14627db96d56Sopenharmony_ci    if (!_mpd_isint(a)) {
14637db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
14647db96d56Sopenharmony_ci        return UINT64_MAX;
14657db96d56Sopenharmony_ci    }
14667db96d56Sopenharmony_ci
14677db96d56Sopenharmony_ci    if (_mpd_cmp_abs(a, &tmp) > 0) {
14687db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
14697db96d56Sopenharmony_ci        return UINT64_MAX;
14707db96d56Sopenharmony_ci    }
14717db96d56Sopenharmony_ci
14727db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
14737db96d56Sopenharmony_ci    mpd_qrescale(&tmp, a, 0, &maxcontext, &maxcontext.status);
14747db96d56Sopenharmony_ci    maxcontext.status &= ~MPD_Rounded;
14757db96d56Sopenharmony_ci    if (maxcontext.status != 0) {
14767db96d56Sopenharmony_ci        *status |= (maxcontext.status|MPD_Invalid_operation); /* GCOV_NOT_REACHED */
14777db96d56Sopenharmony_ci        return UINT64_MAX; /* GCOV_NOT_REACHED */
14787db96d56Sopenharmony_ci    }
14797db96d56Sopenharmony_ci
14807db96d56Sopenharmony_ci    ret = 0;
14817db96d56Sopenharmony_ci    switch (tmp.len) {
14827db96d56Sopenharmony_ci    case 3:
14837db96d56Sopenharmony_ci        ret += (uint64_t)tmp_data[2] * 1000000000000000000ULL;
14847db96d56Sopenharmony_ci    case 2:
14857db96d56Sopenharmony_ci        ret += (uint64_t)tmp_data[1] * 1000000000ULL;
14867db96d56Sopenharmony_ci    case 1:
14877db96d56Sopenharmony_ci        ret += tmp_data[0];
14887db96d56Sopenharmony_ci        break;
14897db96d56Sopenharmony_ci    default:
14907db96d56Sopenharmony_ci        abort(); /* GCOV_NOT_REACHED */
14917db96d56Sopenharmony_ci    }
14927db96d56Sopenharmony_ci
14937db96d56Sopenharmony_ci    return ret;
14947db96d56Sopenharmony_ci}
14957db96d56Sopenharmony_ci
14967db96d56Sopenharmony_cistatic int64_t
14977db96d56Sopenharmony_ci_c32_qget_i64(const mpd_t *a, uint32_t *status)
14987db96d56Sopenharmony_ci{
14997db96d56Sopenharmony_ci    uint64_t u;
15007db96d56Sopenharmony_ci    int isneg;
15017db96d56Sopenharmony_ci
15027db96d56Sopenharmony_ci    u = _c32_qget_u64(0, a, status);
15037db96d56Sopenharmony_ci    if (*status&MPD_Invalid_operation) {
15047db96d56Sopenharmony_ci        return INT64_MAX;
15057db96d56Sopenharmony_ci    }
15067db96d56Sopenharmony_ci
15077db96d56Sopenharmony_ci    isneg = mpd_isnegative(a);
15087db96d56Sopenharmony_ci    if (u <= INT64_MAX) {
15097db96d56Sopenharmony_ci        return isneg ? -((int64_t)u) : (int64_t)u;
15107db96d56Sopenharmony_ci    }
15117db96d56Sopenharmony_ci    else if (isneg && u+(INT64_MIN+INT64_MAX) == INT64_MAX) {
15127db96d56Sopenharmony_ci        return INT64_MIN;
15137db96d56Sopenharmony_ci    }
15147db96d56Sopenharmony_ci
15157db96d56Sopenharmony_ci    *status |= MPD_Invalid_operation;
15167db96d56Sopenharmony_ci    return INT64_MAX;
15177db96d56Sopenharmony_ci}
15187db96d56Sopenharmony_ci#endif /* CONFIG_32 && !LEGACY_COMPILER */
15197db96d56Sopenharmony_ci
15207db96d56Sopenharmony_ci#ifdef CONFIG_64
15217db96d56Sopenharmony_ci/* quietly get a uint64_t from a decimal */
15227db96d56Sopenharmony_ciuint64_t
15237db96d56Sopenharmony_cimpd_qget_u64(const mpd_t *a, uint32_t *status)
15247db96d56Sopenharmony_ci{
15257db96d56Sopenharmony_ci    return mpd_qget_uint(a, status);
15267db96d56Sopenharmony_ci}
15277db96d56Sopenharmony_ci
15287db96d56Sopenharmony_ci/* quietly get an int64_t from a decimal */
15297db96d56Sopenharmony_ciint64_t
15307db96d56Sopenharmony_cimpd_qget_i64(const mpd_t *a, uint32_t *status)
15317db96d56Sopenharmony_ci{
15327db96d56Sopenharmony_ci    return mpd_qget_ssize(a, status);
15337db96d56Sopenharmony_ci}
15347db96d56Sopenharmony_ci
15357db96d56Sopenharmony_ci/* quietly get a uint32_t from a decimal */
15367db96d56Sopenharmony_ciuint32_t
15377db96d56Sopenharmony_cimpd_qget_u32(const mpd_t *a, uint32_t *status)
15387db96d56Sopenharmony_ci{
15397db96d56Sopenharmony_ci    uint32_t workstatus = 0;
15407db96d56Sopenharmony_ci    uint64_t x = mpd_qget_uint(a, &workstatus);
15417db96d56Sopenharmony_ci
15427db96d56Sopenharmony_ci    if (workstatus&MPD_Invalid_operation) {
15437db96d56Sopenharmony_ci        *status |= workstatus;
15447db96d56Sopenharmony_ci        return UINT32_MAX;
15457db96d56Sopenharmony_ci    }
15467db96d56Sopenharmony_ci    if (x > UINT32_MAX) {
15477db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
15487db96d56Sopenharmony_ci        return UINT32_MAX;
15497db96d56Sopenharmony_ci    }
15507db96d56Sopenharmony_ci
15517db96d56Sopenharmony_ci    return (uint32_t)x;
15527db96d56Sopenharmony_ci}
15537db96d56Sopenharmony_ci
15547db96d56Sopenharmony_ci/* quietly get an int32_t from a decimal */
15557db96d56Sopenharmony_ciint32_t
15567db96d56Sopenharmony_cimpd_qget_i32(const mpd_t *a, uint32_t *status)
15577db96d56Sopenharmony_ci{
15587db96d56Sopenharmony_ci    uint32_t workstatus = 0;
15597db96d56Sopenharmony_ci    int64_t x = mpd_qget_ssize(a, &workstatus);
15607db96d56Sopenharmony_ci
15617db96d56Sopenharmony_ci    if (workstatus&MPD_Invalid_operation) {
15627db96d56Sopenharmony_ci        *status |= workstatus;
15637db96d56Sopenharmony_ci        return INT32_MAX;
15647db96d56Sopenharmony_ci    }
15657db96d56Sopenharmony_ci    if (x < INT32_MIN || x > INT32_MAX) {
15667db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
15677db96d56Sopenharmony_ci        return INT32_MAX;
15687db96d56Sopenharmony_ci    }
15697db96d56Sopenharmony_ci
15707db96d56Sopenharmony_ci    return (int32_t)x;
15717db96d56Sopenharmony_ci}
15727db96d56Sopenharmony_ci#else
15737db96d56Sopenharmony_ci#ifndef LEGACY_COMPILER
15747db96d56Sopenharmony_ci/* quietly get a uint64_t from a decimal */
15757db96d56Sopenharmony_ciuint64_t
15767db96d56Sopenharmony_cimpd_qget_u64(const mpd_t *a, uint32_t *status)
15777db96d56Sopenharmony_ci{
15787db96d56Sopenharmony_ci    uint32_t workstatus = 0;
15797db96d56Sopenharmony_ci    uint64_t x = _c32_qget_u64(1, a, &workstatus);
15807db96d56Sopenharmony_ci    *status |= workstatus;
15817db96d56Sopenharmony_ci    return x;
15827db96d56Sopenharmony_ci}
15837db96d56Sopenharmony_ci
15847db96d56Sopenharmony_ci/* quietly get an int64_t from a decimal */
15857db96d56Sopenharmony_ciint64_t
15867db96d56Sopenharmony_cimpd_qget_i64(const mpd_t *a, uint32_t *status)
15877db96d56Sopenharmony_ci{
15887db96d56Sopenharmony_ci    uint32_t workstatus = 0;
15897db96d56Sopenharmony_ci    int64_t x = _c32_qget_i64(a, &workstatus);
15907db96d56Sopenharmony_ci    *status |= workstatus;
15917db96d56Sopenharmony_ci    return x;
15927db96d56Sopenharmony_ci}
15937db96d56Sopenharmony_ci#endif
15947db96d56Sopenharmony_ci
15957db96d56Sopenharmony_ci/* quietly get a uint32_t from a decimal */
15967db96d56Sopenharmony_ciuint32_t
15977db96d56Sopenharmony_cimpd_qget_u32(const mpd_t *a, uint32_t *status)
15987db96d56Sopenharmony_ci{
15997db96d56Sopenharmony_ci    return mpd_qget_uint(a, status);
16007db96d56Sopenharmony_ci}
16017db96d56Sopenharmony_ci
16027db96d56Sopenharmony_ci/* quietly get an int32_t from a decimal */
16037db96d56Sopenharmony_ciint32_t
16047db96d56Sopenharmony_cimpd_qget_i32(const mpd_t *a, uint32_t *status)
16057db96d56Sopenharmony_ci{
16067db96d56Sopenharmony_ci    return mpd_qget_ssize(a, status);
16077db96d56Sopenharmony_ci}
16087db96d56Sopenharmony_ci#endif
16097db96d56Sopenharmony_ci
16107db96d56Sopenharmony_ci
16117db96d56Sopenharmony_ci/******************************************************************************/
16127db96d56Sopenharmony_ci/*         Filtering input of functions, finalizing output of functions       */
16137db96d56Sopenharmony_ci/******************************************************************************/
16147db96d56Sopenharmony_ci
16157db96d56Sopenharmony_ci/*
16167db96d56Sopenharmony_ci * Check if the operand is NaN, copy to result and return 1 if this is
16177db96d56Sopenharmony_ci * the case. Copying can fail since NaNs are allowed to have a payload that
16187db96d56Sopenharmony_ci * does not fit in MPD_MINALLOC.
16197db96d56Sopenharmony_ci */
16207db96d56Sopenharmony_ciint
16217db96d56Sopenharmony_cimpd_qcheck_nan(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
16227db96d56Sopenharmony_ci               uint32_t *status)
16237db96d56Sopenharmony_ci{
16247db96d56Sopenharmony_ci    if (mpd_isnan(a)) {
16257db96d56Sopenharmony_ci        *status |= mpd_issnan(a) ? MPD_Invalid_operation : 0;
16267db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
16277db96d56Sopenharmony_ci        mpd_set_qnan(result);
16287db96d56Sopenharmony_ci        _mpd_fix_nan(result, ctx);
16297db96d56Sopenharmony_ci        return 1;
16307db96d56Sopenharmony_ci    }
16317db96d56Sopenharmony_ci    return 0;
16327db96d56Sopenharmony_ci}
16337db96d56Sopenharmony_ci
16347db96d56Sopenharmony_ci/*
16357db96d56Sopenharmony_ci * Check if either operand is NaN, copy to result and return 1 if this
16367db96d56Sopenharmony_ci * is the case. Copying can fail since NaNs are allowed to have a payload
16377db96d56Sopenharmony_ci * that does not fit in MPD_MINALLOC.
16387db96d56Sopenharmony_ci */
16397db96d56Sopenharmony_ciint
16407db96d56Sopenharmony_cimpd_qcheck_nans(mpd_t *result, const mpd_t *a, const mpd_t *b,
16417db96d56Sopenharmony_ci                const mpd_context_t *ctx, uint32_t *status)
16427db96d56Sopenharmony_ci{
16437db96d56Sopenharmony_ci    if ((a->flags|b->flags)&(MPD_NAN|MPD_SNAN)) {
16447db96d56Sopenharmony_ci        const mpd_t *choice = b;
16457db96d56Sopenharmony_ci        if (mpd_issnan(a)) {
16467db96d56Sopenharmony_ci            choice = a;
16477db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
16487db96d56Sopenharmony_ci        }
16497db96d56Sopenharmony_ci        else if (mpd_issnan(b)) {
16507db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
16517db96d56Sopenharmony_ci        }
16527db96d56Sopenharmony_ci        else if (mpd_isqnan(a)) {
16537db96d56Sopenharmony_ci            choice = a;
16547db96d56Sopenharmony_ci        }
16557db96d56Sopenharmony_ci        mpd_qcopy(result, choice, status);
16567db96d56Sopenharmony_ci        mpd_set_qnan(result);
16577db96d56Sopenharmony_ci        _mpd_fix_nan(result, ctx);
16587db96d56Sopenharmony_ci        return 1;
16597db96d56Sopenharmony_ci    }
16607db96d56Sopenharmony_ci    return 0;
16617db96d56Sopenharmony_ci}
16627db96d56Sopenharmony_ci
16637db96d56Sopenharmony_ci/*
16647db96d56Sopenharmony_ci * Check if one of the operands is NaN, copy to result and return 1 if this
16657db96d56Sopenharmony_ci * is the case. Copying can fail since NaNs are allowed to have a payload
16667db96d56Sopenharmony_ci * that does not fit in MPD_MINALLOC.
16677db96d56Sopenharmony_ci */
16687db96d56Sopenharmony_cistatic int
16697db96d56Sopenharmony_cimpd_qcheck_3nans(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c,
16707db96d56Sopenharmony_ci                 const mpd_context_t *ctx, uint32_t *status)
16717db96d56Sopenharmony_ci{
16727db96d56Sopenharmony_ci    if ((a->flags|b->flags|c->flags)&(MPD_NAN|MPD_SNAN)) {
16737db96d56Sopenharmony_ci        const mpd_t *choice = c;
16747db96d56Sopenharmony_ci        if (mpd_issnan(a)) {
16757db96d56Sopenharmony_ci            choice = a;
16767db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
16777db96d56Sopenharmony_ci        }
16787db96d56Sopenharmony_ci        else if (mpd_issnan(b)) {
16797db96d56Sopenharmony_ci            choice = b;
16807db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
16817db96d56Sopenharmony_ci        }
16827db96d56Sopenharmony_ci        else if (mpd_issnan(c)) {
16837db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
16847db96d56Sopenharmony_ci        }
16857db96d56Sopenharmony_ci        else if (mpd_isqnan(a)) {
16867db96d56Sopenharmony_ci            choice = a;
16877db96d56Sopenharmony_ci        }
16887db96d56Sopenharmony_ci        else if (mpd_isqnan(b)) {
16897db96d56Sopenharmony_ci            choice = b;
16907db96d56Sopenharmony_ci        }
16917db96d56Sopenharmony_ci        mpd_qcopy(result, choice, status);
16927db96d56Sopenharmony_ci        mpd_set_qnan(result);
16937db96d56Sopenharmony_ci        _mpd_fix_nan(result, ctx);
16947db96d56Sopenharmony_ci        return 1;
16957db96d56Sopenharmony_ci    }
16967db96d56Sopenharmony_ci    return 0;
16977db96d56Sopenharmony_ci}
16987db96d56Sopenharmony_ci
16997db96d56Sopenharmony_ci/* Check if rounding digit 'rnd' leads to an increment. */
17007db96d56Sopenharmony_cistatic inline int
17017db96d56Sopenharmony_ci_mpd_rnd_incr(const mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx)
17027db96d56Sopenharmony_ci{
17037db96d56Sopenharmony_ci    int ld;
17047db96d56Sopenharmony_ci
17057db96d56Sopenharmony_ci    switch (ctx->round) {
17067db96d56Sopenharmony_ci    case MPD_ROUND_DOWN: case MPD_ROUND_TRUNC:
17077db96d56Sopenharmony_ci        return 0;
17087db96d56Sopenharmony_ci    case MPD_ROUND_HALF_UP:
17097db96d56Sopenharmony_ci        return (rnd >= 5);
17107db96d56Sopenharmony_ci    case MPD_ROUND_HALF_EVEN:
17117db96d56Sopenharmony_ci        return (rnd > 5) || ((rnd == 5) && mpd_isoddcoeff(dec));
17127db96d56Sopenharmony_ci    case MPD_ROUND_CEILING:
17137db96d56Sopenharmony_ci        return !(rnd == 0 || mpd_isnegative(dec));
17147db96d56Sopenharmony_ci    case MPD_ROUND_FLOOR:
17157db96d56Sopenharmony_ci        return !(rnd == 0 || mpd_ispositive(dec));
17167db96d56Sopenharmony_ci    case MPD_ROUND_HALF_DOWN:
17177db96d56Sopenharmony_ci        return (rnd > 5);
17187db96d56Sopenharmony_ci    case MPD_ROUND_UP:
17197db96d56Sopenharmony_ci        return !(rnd == 0);
17207db96d56Sopenharmony_ci    case MPD_ROUND_05UP:
17217db96d56Sopenharmony_ci        ld = (int)mpd_lsd(dec->data[0]);
17227db96d56Sopenharmony_ci        return (!(rnd == 0) && (ld == 0 || ld == 5));
17237db96d56Sopenharmony_ci    default:
17247db96d56Sopenharmony_ci        /* Without a valid context, further results will be undefined. */
17257db96d56Sopenharmony_ci        return 0; /* GCOV_NOT_REACHED */
17267db96d56Sopenharmony_ci    }
17277db96d56Sopenharmony_ci}
17287db96d56Sopenharmony_ci
17297db96d56Sopenharmony_ci/*
17307db96d56Sopenharmony_ci * Apply rounding to a decimal that has been right-shifted into a full
17317db96d56Sopenharmony_ci * precision decimal. If an increment leads to an overflow of the precision,
17327db96d56Sopenharmony_ci * adjust the coefficient and the exponent and check the new exponent for
17337db96d56Sopenharmony_ci * overflow.
17347db96d56Sopenharmony_ci */
17357db96d56Sopenharmony_cistatic inline void
17367db96d56Sopenharmony_ci_mpd_apply_round(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
17377db96d56Sopenharmony_ci                 uint32_t *status)
17387db96d56Sopenharmony_ci{
17397db96d56Sopenharmony_ci    if (_mpd_rnd_incr(dec, rnd, ctx)) {
17407db96d56Sopenharmony_ci        /* We have a number with exactly ctx->prec digits. The increment
17417db96d56Sopenharmony_ci         * can only lead to an overflow if the decimal is all nines. In
17427db96d56Sopenharmony_ci         * that case, the result is a power of ten with prec+1 digits.
17437db96d56Sopenharmony_ci         *
17447db96d56Sopenharmony_ci         * If the precision is a multiple of MPD_RDIGITS, this situation is
17457db96d56Sopenharmony_ci         * detected by _mpd_baseincr returning a carry.
17467db96d56Sopenharmony_ci         * If the precision is not a multiple of MPD_RDIGITS, we have to
17477db96d56Sopenharmony_ci         * check if the result has one digit too many.
17487db96d56Sopenharmony_ci         */
17497db96d56Sopenharmony_ci        mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
17507db96d56Sopenharmony_ci        if (carry) {
17517db96d56Sopenharmony_ci            dec->data[dec->len-1] = mpd_pow10[MPD_RDIGITS-1];
17527db96d56Sopenharmony_ci            dec->exp += 1;
17537db96d56Sopenharmony_ci            _mpd_check_exp(dec, ctx, status);
17547db96d56Sopenharmony_ci            return;
17557db96d56Sopenharmony_ci        }
17567db96d56Sopenharmony_ci        mpd_setdigits(dec);
17577db96d56Sopenharmony_ci        if (dec->digits > ctx->prec) {
17587db96d56Sopenharmony_ci            mpd_qshiftr_inplace(dec, 1);
17597db96d56Sopenharmony_ci            dec->exp += 1;
17607db96d56Sopenharmony_ci            dec->digits = ctx->prec;
17617db96d56Sopenharmony_ci            _mpd_check_exp(dec, ctx, status);
17627db96d56Sopenharmony_ci        }
17637db96d56Sopenharmony_ci    }
17647db96d56Sopenharmony_ci}
17657db96d56Sopenharmony_ci
17667db96d56Sopenharmony_ci/*
17677db96d56Sopenharmony_ci * Apply rounding to a decimal. Allow overflow of the precision.
17687db96d56Sopenharmony_ci */
17697db96d56Sopenharmony_cistatic inline void
17707db96d56Sopenharmony_ci_mpd_apply_round_excess(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
17717db96d56Sopenharmony_ci                        uint32_t *status)
17727db96d56Sopenharmony_ci{
17737db96d56Sopenharmony_ci    if (_mpd_rnd_incr(dec, rnd, ctx)) {
17747db96d56Sopenharmony_ci        mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
17757db96d56Sopenharmony_ci        if (carry) {
17767db96d56Sopenharmony_ci            if (!mpd_qresize(dec, dec->len+1, status)) {
17777db96d56Sopenharmony_ci                return;
17787db96d56Sopenharmony_ci            }
17797db96d56Sopenharmony_ci            dec->data[dec->len] = 1;
17807db96d56Sopenharmony_ci            dec->len += 1;
17817db96d56Sopenharmony_ci        }
17827db96d56Sopenharmony_ci        mpd_setdigits(dec);
17837db96d56Sopenharmony_ci    }
17847db96d56Sopenharmony_ci}
17857db96d56Sopenharmony_ci
17867db96d56Sopenharmony_ci/*
17877db96d56Sopenharmony_ci * Apply rounding to a decimal that has been right-shifted into a decimal
17887db96d56Sopenharmony_ci * with full precision or less. Return failure if an increment would
17897db96d56Sopenharmony_ci * overflow the precision.
17907db96d56Sopenharmony_ci */
17917db96d56Sopenharmony_cistatic inline int
17927db96d56Sopenharmony_ci_mpd_apply_round_fit(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
17937db96d56Sopenharmony_ci                     uint32_t *status)
17947db96d56Sopenharmony_ci{
17957db96d56Sopenharmony_ci    if (_mpd_rnd_incr(dec, rnd, ctx)) {
17967db96d56Sopenharmony_ci        mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
17977db96d56Sopenharmony_ci        if (carry) {
17987db96d56Sopenharmony_ci            if (!mpd_qresize(dec, dec->len+1, status)) {
17997db96d56Sopenharmony_ci                return 0;
18007db96d56Sopenharmony_ci            }
18017db96d56Sopenharmony_ci            dec->data[dec->len] = 1;
18027db96d56Sopenharmony_ci            dec->len += 1;
18037db96d56Sopenharmony_ci        }
18047db96d56Sopenharmony_ci        mpd_setdigits(dec);
18057db96d56Sopenharmony_ci        if (dec->digits > ctx->prec) {
18067db96d56Sopenharmony_ci            mpd_seterror(dec, MPD_Invalid_operation, status);
18077db96d56Sopenharmony_ci            return 0;
18087db96d56Sopenharmony_ci        }
18097db96d56Sopenharmony_ci    }
18107db96d56Sopenharmony_ci    return 1;
18117db96d56Sopenharmony_ci}
18127db96d56Sopenharmony_ci
18137db96d56Sopenharmony_ci/* Check a normal number for overflow, underflow, clamping. If the operand
18147db96d56Sopenharmony_ci   is modified, it will be zero, special or (sub)normal with a coefficient
18157db96d56Sopenharmony_ci   that fits into the current context precision. */
18167db96d56Sopenharmony_cistatic inline void
18177db96d56Sopenharmony_ci_mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
18187db96d56Sopenharmony_ci{
18197db96d56Sopenharmony_ci    mpd_ssize_t adjexp, etiny, shift;
18207db96d56Sopenharmony_ci    int rnd;
18217db96d56Sopenharmony_ci
18227db96d56Sopenharmony_ci    adjexp = mpd_adjexp(dec);
18237db96d56Sopenharmony_ci    if (adjexp > ctx->emax) {
18247db96d56Sopenharmony_ci
18257db96d56Sopenharmony_ci        if (mpd_iszerocoeff(dec)) {
18267db96d56Sopenharmony_ci            dec->exp = ctx->emax;
18277db96d56Sopenharmony_ci            if (ctx->clamp) {
18287db96d56Sopenharmony_ci                dec->exp -= (ctx->prec-1);
18297db96d56Sopenharmony_ci            }
18307db96d56Sopenharmony_ci            mpd_zerocoeff(dec);
18317db96d56Sopenharmony_ci            *status |= MPD_Clamped;
18327db96d56Sopenharmony_ci            return;
18337db96d56Sopenharmony_ci        }
18347db96d56Sopenharmony_ci
18357db96d56Sopenharmony_ci        switch (ctx->round) {
18367db96d56Sopenharmony_ci        case MPD_ROUND_HALF_UP: case MPD_ROUND_HALF_EVEN:
18377db96d56Sopenharmony_ci        case MPD_ROUND_HALF_DOWN: case MPD_ROUND_UP:
18387db96d56Sopenharmony_ci        case MPD_ROUND_TRUNC:
18397db96d56Sopenharmony_ci            mpd_setspecial(dec, mpd_sign(dec), MPD_INF);
18407db96d56Sopenharmony_ci            break;
18417db96d56Sopenharmony_ci        case MPD_ROUND_DOWN: case MPD_ROUND_05UP:
18427db96d56Sopenharmony_ci            mpd_qmaxcoeff(dec, ctx, status);
18437db96d56Sopenharmony_ci            dec->exp = ctx->emax - ctx->prec + 1;
18447db96d56Sopenharmony_ci            break;
18457db96d56Sopenharmony_ci        case MPD_ROUND_CEILING:
18467db96d56Sopenharmony_ci            if (mpd_isnegative(dec)) {
18477db96d56Sopenharmony_ci                mpd_qmaxcoeff(dec, ctx, status);
18487db96d56Sopenharmony_ci                dec->exp = ctx->emax - ctx->prec + 1;
18497db96d56Sopenharmony_ci            }
18507db96d56Sopenharmony_ci            else {
18517db96d56Sopenharmony_ci                mpd_setspecial(dec, MPD_POS, MPD_INF);
18527db96d56Sopenharmony_ci            }
18537db96d56Sopenharmony_ci            break;
18547db96d56Sopenharmony_ci        case MPD_ROUND_FLOOR:
18557db96d56Sopenharmony_ci            if (mpd_ispositive(dec)) {
18567db96d56Sopenharmony_ci                mpd_qmaxcoeff(dec, ctx, status);
18577db96d56Sopenharmony_ci                dec->exp = ctx->emax - ctx->prec + 1;
18587db96d56Sopenharmony_ci            }
18597db96d56Sopenharmony_ci            else {
18607db96d56Sopenharmony_ci                mpd_setspecial(dec, MPD_NEG, MPD_INF);
18617db96d56Sopenharmony_ci            }
18627db96d56Sopenharmony_ci            break;
18637db96d56Sopenharmony_ci        default: /* debug */
18647db96d56Sopenharmony_ci            abort(); /* GCOV_NOT_REACHED */
18657db96d56Sopenharmony_ci        }
18667db96d56Sopenharmony_ci
18677db96d56Sopenharmony_ci        *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
18687db96d56Sopenharmony_ci
18697db96d56Sopenharmony_ci    } /* fold down */
18707db96d56Sopenharmony_ci    else if (ctx->clamp && dec->exp > mpd_etop(ctx)) {
18717db96d56Sopenharmony_ci        /* At this point adjexp=exp+digits-1 <= emax and exp > etop=emax-prec+1:
18727db96d56Sopenharmony_ci         *   (1) shift = exp -emax+prec-1 > 0
18737db96d56Sopenharmony_ci         *   (2) digits+shift = exp+digits-1 - emax + prec <= prec */
18747db96d56Sopenharmony_ci        shift = dec->exp - mpd_etop(ctx);
18757db96d56Sopenharmony_ci        if (!mpd_qshiftl(dec, dec, shift, status)) {
18767db96d56Sopenharmony_ci            return;
18777db96d56Sopenharmony_ci        }
18787db96d56Sopenharmony_ci        dec->exp -= shift;
18797db96d56Sopenharmony_ci        *status |= MPD_Clamped;
18807db96d56Sopenharmony_ci        if (!mpd_iszerocoeff(dec) && adjexp < ctx->emin) {
18817db96d56Sopenharmony_ci            /* Underflow is impossible, since exp < etiny=emin-prec+1
18827db96d56Sopenharmony_ci             * and exp > etop=emax-prec+1 would imply emax < emin. */
18837db96d56Sopenharmony_ci            *status |= MPD_Subnormal;
18847db96d56Sopenharmony_ci        }
18857db96d56Sopenharmony_ci    }
18867db96d56Sopenharmony_ci    else if (adjexp < ctx->emin) {
18877db96d56Sopenharmony_ci
18887db96d56Sopenharmony_ci        etiny = mpd_etiny(ctx);
18897db96d56Sopenharmony_ci
18907db96d56Sopenharmony_ci        if (mpd_iszerocoeff(dec)) {
18917db96d56Sopenharmony_ci            if (dec->exp < etiny) {
18927db96d56Sopenharmony_ci                dec->exp = etiny;
18937db96d56Sopenharmony_ci                mpd_zerocoeff(dec);
18947db96d56Sopenharmony_ci                *status |= MPD_Clamped;
18957db96d56Sopenharmony_ci            }
18967db96d56Sopenharmony_ci            return;
18977db96d56Sopenharmony_ci        }
18987db96d56Sopenharmony_ci
18997db96d56Sopenharmony_ci        *status |= MPD_Subnormal;
19007db96d56Sopenharmony_ci        if (dec->exp < etiny) {
19017db96d56Sopenharmony_ci            /* At this point adjexp=exp+digits-1 < emin and exp < etiny=emin-prec+1:
19027db96d56Sopenharmony_ci             *   (1) shift = emin-prec+1 - exp > 0
19037db96d56Sopenharmony_ci             *   (2) digits-shift = exp+digits-1 - emin + prec < prec */
19047db96d56Sopenharmony_ci            shift = etiny - dec->exp;
19057db96d56Sopenharmony_ci            rnd = (int)mpd_qshiftr_inplace(dec, shift);
19067db96d56Sopenharmony_ci            dec->exp = etiny;
19077db96d56Sopenharmony_ci            /* We always have a spare digit in case of an increment. */
19087db96d56Sopenharmony_ci            _mpd_apply_round_excess(dec, rnd, ctx, status);
19097db96d56Sopenharmony_ci            *status |= MPD_Rounded;
19107db96d56Sopenharmony_ci            if (rnd) {
19117db96d56Sopenharmony_ci                *status |= (MPD_Inexact|MPD_Underflow);
19127db96d56Sopenharmony_ci                if (mpd_iszerocoeff(dec)) {
19137db96d56Sopenharmony_ci                    mpd_zerocoeff(dec);
19147db96d56Sopenharmony_ci                    *status |= MPD_Clamped;
19157db96d56Sopenharmony_ci                }
19167db96d56Sopenharmony_ci            }
19177db96d56Sopenharmony_ci        }
19187db96d56Sopenharmony_ci        /* Case exp >= etiny=emin-prec+1:
19197db96d56Sopenharmony_ci         *   (1) adjexp=exp+digits-1 < emin
19207db96d56Sopenharmony_ci         *   (2) digits < emin-exp+1 <= prec */
19217db96d56Sopenharmony_ci    }
19227db96d56Sopenharmony_ci}
19237db96d56Sopenharmony_ci
19247db96d56Sopenharmony_ci/* Transcendental functions do not always set Underflow reliably,
19257db96d56Sopenharmony_ci * since they only use as much precision as is necessary for correct
19267db96d56Sopenharmony_ci * rounding. If a result like 1.0000000000e-101 is finalized, there
19277db96d56Sopenharmony_ci * is no rounding digit that would trigger Underflow. But we can
19287db96d56Sopenharmony_ci * assume Inexact, so a short check suffices. */
19297db96d56Sopenharmony_cistatic inline void
19307db96d56Sopenharmony_cimpd_check_underflow(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
19317db96d56Sopenharmony_ci{
19327db96d56Sopenharmony_ci    if (mpd_adjexp(dec) < ctx->emin && !mpd_iszero(dec) &&
19337db96d56Sopenharmony_ci        dec->exp < mpd_etiny(ctx)) {
19347db96d56Sopenharmony_ci        *status |= MPD_Underflow;
19357db96d56Sopenharmony_ci    }
19367db96d56Sopenharmony_ci}
19377db96d56Sopenharmony_ci
19387db96d56Sopenharmony_ci/* Check if a normal number must be rounded after the exponent has been checked. */
19397db96d56Sopenharmony_cistatic inline void
19407db96d56Sopenharmony_ci_mpd_check_round(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
19417db96d56Sopenharmony_ci{
19427db96d56Sopenharmony_ci    mpd_uint_t rnd;
19437db96d56Sopenharmony_ci    mpd_ssize_t shift;
19447db96d56Sopenharmony_ci
19457db96d56Sopenharmony_ci    /* must handle specials: _mpd_check_exp() can produce infinities or NaNs */
19467db96d56Sopenharmony_ci    if (mpd_isspecial(dec)) {
19477db96d56Sopenharmony_ci        return;
19487db96d56Sopenharmony_ci    }
19497db96d56Sopenharmony_ci
19507db96d56Sopenharmony_ci    if (dec->digits > ctx->prec) {
19517db96d56Sopenharmony_ci        shift = dec->digits - ctx->prec;
19527db96d56Sopenharmony_ci        rnd = mpd_qshiftr_inplace(dec, shift);
19537db96d56Sopenharmony_ci        dec->exp += shift;
19547db96d56Sopenharmony_ci        _mpd_apply_round(dec, rnd, ctx, status);
19557db96d56Sopenharmony_ci        *status |= MPD_Rounded;
19567db96d56Sopenharmony_ci        if (rnd) {
19577db96d56Sopenharmony_ci            *status |= MPD_Inexact;
19587db96d56Sopenharmony_ci        }
19597db96d56Sopenharmony_ci    }
19607db96d56Sopenharmony_ci}
19617db96d56Sopenharmony_ci
19627db96d56Sopenharmony_ci/* Finalize all operations. */
19637db96d56Sopenharmony_civoid
19647db96d56Sopenharmony_cimpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status)
19657db96d56Sopenharmony_ci{
19667db96d56Sopenharmony_ci    if (mpd_isspecial(result)) {
19677db96d56Sopenharmony_ci        if (mpd_isnan(result)) {
19687db96d56Sopenharmony_ci            _mpd_fix_nan(result, ctx);
19697db96d56Sopenharmony_ci        }
19707db96d56Sopenharmony_ci        return;
19717db96d56Sopenharmony_ci    }
19727db96d56Sopenharmony_ci
19737db96d56Sopenharmony_ci    _mpd_check_exp(result, ctx, status);
19747db96d56Sopenharmony_ci    _mpd_check_round(result, ctx, status);
19757db96d56Sopenharmony_ci}
19767db96d56Sopenharmony_ci
19777db96d56Sopenharmony_ci
19787db96d56Sopenharmony_ci/******************************************************************************/
19797db96d56Sopenharmony_ci/*                                 Copying                                    */
19807db96d56Sopenharmony_ci/******************************************************************************/
19817db96d56Sopenharmony_ci
19827db96d56Sopenharmony_ci/* Internal function: Copy a decimal, share data with src: USE WITH CARE! */
19837db96d56Sopenharmony_cistatic inline void
19847db96d56Sopenharmony_ci_mpd_copy_shared(mpd_t *dest, const mpd_t *src)
19857db96d56Sopenharmony_ci{
19867db96d56Sopenharmony_ci    dest->flags = src->flags;
19877db96d56Sopenharmony_ci    dest->exp = src->exp;
19887db96d56Sopenharmony_ci    dest->digits = src->digits;
19897db96d56Sopenharmony_ci    dest->len = src->len;
19907db96d56Sopenharmony_ci    dest->alloc = src->alloc;
19917db96d56Sopenharmony_ci    dest->data = src->data;
19927db96d56Sopenharmony_ci
19937db96d56Sopenharmony_ci    mpd_set_shared_data(dest);
19947db96d56Sopenharmony_ci}
19957db96d56Sopenharmony_ci
19967db96d56Sopenharmony_ci/*
19977db96d56Sopenharmony_ci * Copy a decimal. In case of an error, status is set to MPD_Malloc_error.
19987db96d56Sopenharmony_ci */
19997db96d56Sopenharmony_ciint
20007db96d56Sopenharmony_cimpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status)
20017db96d56Sopenharmony_ci{
20027db96d56Sopenharmony_ci    if (result == a) return 1;
20037db96d56Sopenharmony_ci
20047db96d56Sopenharmony_ci    if (!mpd_qresize(result, a->len, status)) {
20057db96d56Sopenharmony_ci        return 0;
20067db96d56Sopenharmony_ci    }
20077db96d56Sopenharmony_ci
20087db96d56Sopenharmony_ci    mpd_copy_flags(result, a);
20097db96d56Sopenharmony_ci    result->exp = a->exp;
20107db96d56Sopenharmony_ci    result->digits = a->digits;
20117db96d56Sopenharmony_ci    result->len = a->len;
20127db96d56Sopenharmony_ci    memcpy(result->data, a->data, a->len * (sizeof *result->data));
20137db96d56Sopenharmony_ci
20147db96d56Sopenharmony_ci    return 1;
20157db96d56Sopenharmony_ci}
20167db96d56Sopenharmony_ci
20177db96d56Sopenharmony_ci/* Same as mpd_qcopy, but do not set the result to NaN on failure. */
20187db96d56Sopenharmony_ciint
20197db96d56Sopenharmony_cimpd_qcopy_cxx(mpd_t *result, const mpd_t *a)
20207db96d56Sopenharmony_ci{
20217db96d56Sopenharmony_ci    if (result == a) return 1;
20227db96d56Sopenharmony_ci
20237db96d56Sopenharmony_ci    if (!mpd_qresize_cxx(result, a->len)) {
20247db96d56Sopenharmony_ci        return 0;
20257db96d56Sopenharmony_ci    }
20267db96d56Sopenharmony_ci
20277db96d56Sopenharmony_ci    mpd_copy_flags(result, a);
20287db96d56Sopenharmony_ci    result->exp = a->exp;
20297db96d56Sopenharmony_ci    result->digits = a->digits;
20307db96d56Sopenharmony_ci    result->len = a->len;
20317db96d56Sopenharmony_ci    memcpy(result->data, a->data, a->len * (sizeof *result->data));
20327db96d56Sopenharmony_ci
20337db96d56Sopenharmony_ci    return 1;
20347db96d56Sopenharmony_ci}
20357db96d56Sopenharmony_ci
20367db96d56Sopenharmony_ci/*
20377db96d56Sopenharmony_ci * Copy to a decimal with a static buffer. The caller has to make sure that
20387db96d56Sopenharmony_ci * the buffer is big enough. Cannot fail.
20397db96d56Sopenharmony_ci */
20407db96d56Sopenharmony_cistatic void
20417db96d56Sopenharmony_cimpd_qcopy_static(mpd_t *result, const mpd_t *a)
20427db96d56Sopenharmony_ci{
20437db96d56Sopenharmony_ci    if (result == a) return;
20447db96d56Sopenharmony_ci
20457db96d56Sopenharmony_ci    memcpy(result->data, a->data, a->len * (sizeof *result->data));
20467db96d56Sopenharmony_ci
20477db96d56Sopenharmony_ci    mpd_copy_flags(result, a);
20487db96d56Sopenharmony_ci    result->exp = a->exp;
20497db96d56Sopenharmony_ci    result->digits = a->digits;
20507db96d56Sopenharmony_ci    result->len = a->len;
20517db96d56Sopenharmony_ci}
20527db96d56Sopenharmony_ci
20537db96d56Sopenharmony_ci/*
20547db96d56Sopenharmony_ci * Return a newly allocated copy of the operand. In case of an error,
20557db96d56Sopenharmony_ci * status is set to MPD_Malloc_error and the return value is NULL.
20567db96d56Sopenharmony_ci */
20577db96d56Sopenharmony_cimpd_t *
20587db96d56Sopenharmony_cimpd_qncopy(const mpd_t *a)
20597db96d56Sopenharmony_ci{
20607db96d56Sopenharmony_ci    mpd_t *result;
20617db96d56Sopenharmony_ci
20627db96d56Sopenharmony_ci    if ((result = mpd_qnew_size(a->len)) == NULL) {
20637db96d56Sopenharmony_ci        return NULL;
20647db96d56Sopenharmony_ci    }
20657db96d56Sopenharmony_ci    memcpy(result->data, a->data, a->len * (sizeof *result->data));
20667db96d56Sopenharmony_ci    mpd_copy_flags(result, a);
20677db96d56Sopenharmony_ci    result->exp = a->exp;
20687db96d56Sopenharmony_ci    result->digits = a->digits;
20697db96d56Sopenharmony_ci    result->len = a->len;
20707db96d56Sopenharmony_ci
20717db96d56Sopenharmony_ci    return result;
20727db96d56Sopenharmony_ci}
20737db96d56Sopenharmony_ci
20747db96d56Sopenharmony_ci/*
20757db96d56Sopenharmony_ci * Copy a decimal and set the sign to positive. In case of an error, the
20767db96d56Sopenharmony_ci * status is set to MPD_Malloc_error.
20777db96d56Sopenharmony_ci */
20787db96d56Sopenharmony_ciint
20797db96d56Sopenharmony_cimpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status)
20807db96d56Sopenharmony_ci{
20817db96d56Sopenharmony_ci    if (!mpd_qcopy(result, a, status)) {
20827db96d56Sopenharmony_ci        return 0;
20837db96d56Sopenharmony_ci    }
20847db96d56Sopenharmony_ci    mpd_set_positive(result);
20857db96d56Sopenharmony_ci    return 1;
20867db96d56Sopenharmony_ci}
20877db96d56Sopenharmony_ci
20887db96d56Sopenharmony_ci/*
20897db96d56Sopenharmony_ci * Copy a decimal and negate the sign. In case of an error, the
20907db96d56Sopenharmony_ci * status is set to MPD_Malloc_error.
20917db96d56Sopenharmony_ci */
20927db96d56Sopenharmony_ciint
20937db96d56Sopenharmony_cimpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status)
20947db96d56Sopenharmony_ci{
20957db96d56Sopenharmony_ci    if (!mpd_qcopy(result, a, status)) {
20967db96d56Sopenharmony_ci        return 0;
20977db96d56Sopenharmony_ci    }
20987db96d56Sopenharmony_ci    _mpd_negate(result);
20997db96d56Sopenharmony_ci    return 1;
21007db96d56Sopenharmony_ci}
21017db96d56Sopenharmony_ci
21027db96d56Sopenharmony_ci/*
21037db96d56Sopenharmony_ci * Copy a decimal, setting the sign of the first operand to the sign of the
21047db96d56Sopenharmony_ci * second operand. In case of an error, the status is set to MPD_Malloc_error.
21057db96d56Sopenharmony_ci */
21067db96d56Sopenharmony_ciint
21077db96d56Sopenharmony_cimpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status)
21087db96d56Sopenharmony_ci{
21097db96d56Sopenharmony_ci    uint8_t sign_b = mpd_sign(b); /* result may equal b! */
21107db96d56Sopenharmony_ci
21117db96d56Sopenharmony_ci    if (!mpd_qcopy(result, a, status)) {
21127db96d56Sopenharmony_ci        return 0;
21137db96d56Sopenharmony_ci    }
21147db96d56Sopenharmony_ci    mpd_set_sign(result, sign_b);
21157db96d56Sopenharmony_ci    return 1;
21167db96d56Sopenharmony_ci}
21177db96d56Sopenharmony_ci
21187db96d56Sopenharmony_ci
21197db96d56Sopenharmony_ci/******************************************************************************/
21207db96d56Sopenharmony_ci/*                                Comparisons                                 */
21217db96d56Sopenharmony_ci/******************************************************************************/
21227db96d56Sopenharmony_ci
21237db96d56Sopenharmony_ci/*
21247db96d56Sopenharmony_ci * For all functions that compare two operands and return an int the usual
21257db96d56Sopenharmony_ci * convention applies to the return value:
21267db96d56Sopenharmony_ci *
21277db96d56Sopenharmony_ci * -1 if op1 < op2
21287db96d56Sopenharmony_ci *  0 if op1 == op2
21297db96d56Sopenharmony_ci *  1 if op1 > op2
21307db96d56Sopenharmony_ci *
21317db96d56Sopenharmony_ci *  INT_MAX for error
21327db96d56Sopenharmony_ci */
21337db96d56Sopenharmony_ci
21347db96d56Sopenharmony_ci
21357db96d56Sopenharmony_ci/* Convenience macro. If a and b are not equal, return from the calling
21367db96d56Sopenharmony_ci * function with the correct comparison value. */
21377db96d56Sopenharmony_ci#define CMP_EQUAL_OR_RETURN(a, b)  \
21387db96d56Sopenharmony_ci        if (a != b) {              \
21397db96d56Sopenharmony_ci                if (a < b) {       \
21407db96d56Sopenharmony_ci                        return -1; \
21417db96d56Sopenharmony_ci                }                  \
21427db96d56Sopenharmony_ci                return 1;          \
21437db96d56Sopenharmony_ci        }
21447db96d56Sopenharmony_ci
21457db96d56Sopenharmony_ci/*
21467db96d56Sopenharmony_ci * Compare the data of big and small. This function does the equivalent
21477db96d56Sopenharmony_ci * of first shifting small to the left and then comparing the data of
21487db96d56Sopenharmony_ci * big and small, except that no allocation for the left shift is needed.
21497db96d56Sopenharmony_ci */
21507db96d56Sopenharmony_cistatic int
21517db96d56Sopenharmony_ci_mpd_basecmp(mpd_uint_t *big, mpd_uint_t *small, mpd_size_t n, mpd_size_t m,
21527db96d56Sopenharmony_ci             mpd_size_t shift)
21537db96d56Sopenharmony_ci{
21547db96d56Sopenharmony_ci#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
21557db96d56Sopenharmony_ci    /* spurious uninitialized warnings */
21567db96d56Sopenharmony_ci    mpd_uint_t l=l, lprev=lprev, h=h;
21577db96d56Sopenharmony_ci#else
21587db96d56Sopenharmony_ci    mpd_uint_t l, lprev, h;
21597db96d56Sopenharmony_ci#endif
21607db96d56Sopenharmony_ci    mpd_uint_t q, r;
21617db96d56Sopenharmony_ci    mpd_uint_t ph, x;
21627db96d56Sopenharmony_ci
21637db96d56Sopenharmony_ci    assert(m > 0 && n >= m && shift > 0);
21647db96d56Sopenharmony_ci
21657db96d56Sopenharmony_ci    _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS);
21667db96d56Sopenharmony_ci
21677db96d56Sopenharmony_ci    if (r != 0) {
21687db96d56Sopenharmony_ci
21697db96d56Sopenharmony_ci        ph = mpd_pow10[r];
21707db96d56Sopenharmony_ci
21717db96d56Sopenharmony_ci        --m; --n;
21727db96d56Sopenharmony_ci        _mpd_divmod_pow10(&h, &lprev, small[m--], MPD_RDIGITS-r);
21737db96d56Sopenharmony_ci        if (h != 0) {
21747db96d56Sopenharmony_ci            CMP_EQUAL_OR_RETURN(big[n], h)
21757db96d56Sopenharmony_ci            --n;
21767db96d56Sopenharmony_ci        }
21777db96d56Sopenharmony_ci        for (; m != MPD_SIZE_MAX; m--,n--) {
21787db96d56Sopenharmony_ci            _mpd_divmod_pow10(&h, &l, small[m], MPD_RDIGITS-r);
21797db96d56Sopenharmony_ci            x = ph * lprev + h;
21807db96d56Sopenharmony_ci            CMP_EQUAL_OR_RETURN(big[n], x)
21817db96d56Sopenharmony_ci            lprev = l;
21827db96d56Sopenharmony_ci        }
21837db96d56Sopenharmony_ci        x = ph * lprev;
21847db96d56Sopenharmony_ci        CMP_EQUAL_OR_RETURN(big[q], x)
21857db96d56Sopenharmony_ci    }
21867db96d56Sopenharmony_ci    else {
21877db96d56Sopenharmony_ci        while (--m != MPD_SIZE_MAX) {
21887db96d56Sopenharmony_ci            CMP_EQUAL_OR_RETURN(big[m+q], small[m])
21897db96d56Sopenharmony_ci        }
21907db96d56Sopenharmony_ci    }
21917db96d56Sopenharmony_ci
21927db96d56Sopenharmony_ci    return !_mpd_isallzero(big, q);
21937db96d56Sopenharmony_ci}
21947db96d56Sopenharmony_ci
21957db96d56Sopenharmony_ci/* Compare two decimals with the same adjusted exponent. */
21967db96d56Sopenharmony_cistatic int
21977db96d56Sopenharmony_ci_mpd_cmp_same_adjexp(const mpd_t *a, const mpd_t *b)
21987db96d56Sopenharmony_ci{
21997db96d56Sopenharmony_ci    mpd_ssize_t shift, i;
22007db96d56Sopenharmony_ci
22017db96d56Sopenharmony_ci    if (a->exp != b->exp) {
22027db96d56Sopenharmony_ci        /* Cannot wrap: a->exp + a->digits = b->exp + b->digits, so
22037db96d56Sopenharmony_ci         * a->exp - b->exp = b->digits - a->digits. */
22047db96d56Sopenharmony_ci        shift = a->exp - b->exp;
22057db96d56Sopenharmony_ci        if (shift > 0) {
22067db96d56Sopenharmony_ci            return -1 * _mpd_basecmp(b->data, a->data, b->len, a->len, shift);
22077db96d56Sopenharmony_ci        }
22087db96d56Sopenharmony_ci        else {
22097db96d56Sopenharmony_ci            return _mpd_basecmp(a->data, b->data, a->len, b->len, -shift);
22107db96d56Sopenharmony_ci        }
22117db96d56Sopenharmony_ci    }
22127db96d56Sopenharmony_ci
22137db96d56Sopenharmony_ci    /*
22147db96d56Sopenharmony_ci     * At this point adjexp(a) == adjexp(b) and a->exp == b->exp,
22157db96d56Sopenharmony_ci     * so a->digits == b->digits, therefore a->len == b->len.
22167db96d56Sopenharmony_ci     */
22177db96d56Sopenharmony_ci    for (i = a->len-1; i >= 0; --i) {
22187db96d56Sopenharmony_ci        CMP_EQUAL_OR_RETURN(a->data[i], b->data[i])
22197db96d56Sopenharmony_ci    }
22207db96d56Sopenharmony_ci
22217db96d56Sopenharmony_ci    return 0;
22227db96d56Sopenharmony_ci}
22237db96d56Sopenharmony_ci
22247db96d56Sopenharmony_ci/* Compare two numerical values. */
22257db96d56Sopenharmony_cistatic int
22267db96d56Sopenharmony_ci_mpd_cmp(const mpd_t *a, const mpd_t *b)
22277db96d56Sopenharmony_ci{
22287db96d56Sopenharmony_ci    mpd_ssize_t adjexp_a, adjexp_b;
22297db96d56Sopenharmony_ci
22307db96d56Sopenharmony_ci    /* equal pointers */
22317db96d56Sopenharmony_ci    if (a == b) {
22327db96d56Sopenharmony_ci        return 0;
22337db96d56Sopenharmony_ci    }
22347db96d56Sopenharmony_ci
22357db96d56Sopenharmony_ci    /* infinities */
22367db96d56Sopenharmony_ci    if (mpd_isinfinite(a)) {
22377db96d56Sopenharmony_ci        if (mpd_isinfinite(b)) {
22387db96d56Sopenharmony_ci            return mpd_isnegative(b) - mpd_isnegative(a);
22397db96d56Sopenharmony_ci        }
22407db96d56Sopenharmony_ci        return mpd_arith_sign(a);
22417db96d56Sopenharmony_ci    }
22427db96d56Sopenharmony_ci    if (mpd_isinfinite(b)) {
22437db96d56Sopenharmony_ci        return -mpd_arith_sign(b);
22447db96d56Sopenharmony_ci    }
22457db96d56Sopenharmony_ci
22467db96d56Sopenharmony_ci    /* zeros */
22477db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
22487db96d56Sopenharmony_ci        if (mpd_iszerocoeff(b)) {
22497db96d56Sopenharmony_ci            return 0;
22507db96d56Sopenharmony_ci        }
22517db96d56Sopenharmony_ci        return -mpd_arith_sign(b);
22527db96d56Sopenharmony_ci    }
22537db96d56Sopenharmony_ci    if (mpd_iszerocoeff(b)) {
22547db96d56Sopenharmony_ci        return mpd_arith_sign(a);
22557db96d56Sopenharmony_ci    }
22567db96d56Sopenharmony_ci
22577db96d56Sopenharmony_ci    /* different signs */
22587db96d56Sopenharmony_ci    if (mpd_sign(a) != mpd_sign(b)) {
22597db96d56Sopenharmony_ci        return mpd_sign(b) - mpd_sign(a);
22607db96d56Sopenharmony_ci    }
22617db96d56Sopenharmony_ci
22627db96d56Sopenharmony_ci    /* different adjusted exponents */
22637db96d56Sopenharmony_ci    adjexp_a = mpd_adjexp(a);
22647db96d56Sopenharmony_ci    adjexp_b = mpd_adjexp(b);
22657db96d56Sopenharmony_ci    if (adjexp_a != adjexp_b) {
22667db96d56Sopenharmony_ci        if (adjexp_a < adjexp_b) {
22677db96d56Sopenharmony_ci            return -1 * mpd_arith_sign(a);
22687db96d56Sopenharmony_ci        }
22697db96d56Sopenharmony_ci        return mpd_arith_sign(a);
22707db96d56Sopenharmony_ci    }
22717db96d56Sopenharmony_ci
22727db96d56Sopenharmony_ci    /* same adjusted exponents */
22737db96d56Sopenharmony_ci    return _mpd_cmp_same_adjexp(a, b) * mpd_arith_sign(a);
22747db96d56Sopenharmony_ci}
22757db96d56Sopenharmony_ci
22767db96d56Sopenharmony_ci/* Compare the absolutes of two numerical values. */
22777db96d56Sopenharmony_cistatic int
22787db96d56Sopenharmony_ci_mpd_cmp_abs(const mpd_t *a, const mpd_t *b)
22797db96d56Sopenharmony_ci{
22807db96d56Sopenharmony_ci    mpd_ssize_t adjexp_a, adjexp_b;
22817db96d56Sopenharmony_ci
22827db96d56Sopenharmony_ci    /* equal pointers */
22837db96d56Sopenharmony_ci    if (a == b) {
22847db96d56Sopenharmony_ci        return 0;
22857db96d56Sopenharmony_ci    }
22867db96d56Sopenharmony_ci
22877db96d56Sopenharmony_ci    /* infinities */
22887db96d56Sopenharmony_ci    if (mpd_isinfinite(a)) {
22897db96d56Sopenharmony_ci        if (mpd_isinfinite(b)) {
22907db96d56Sopenharmony_ci            return 0;
22917db96d56Sopenharmony_ci        }
22927db96d56Sopenharmony_ci        return 1;
22937db96d56Sopenharmony_ci    }
22947db96d56Sopenharmony_ci    if (mpd_isinfinite(b)) {
22957db96d56Sopenharmony_ci        return -1;
22967db96d56Sopenharmony_ci    }
22977db96d56Sopenharmony_ci
22987db96d56Sopenharmony_ci    /* zeros */
22997db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
23007db96d56Sopenharmony_ci        if (mpd_iszerocoeff(b)) {
23017db96d56Sopenharmony_ci            return 0;
23027db96d56Sopenharmony_ci        }
23037db96d56Sopenharmony_ci        return -1;
23047db96d56Sopenharmony_ci    }
23057db96d56Sopenharmony_ci    if (mpd_iszerocoeff(b)) {
23067db96d56Sopenharmony_ci        return 1;
23077db96d56Sopenharmony_ci    }
23087db96d56Sopenharmony_ci
23097db96d56Sopenharmony_ci    /* different adjusted exponents */
23107db96d56Sopenharmony_ci    adjexp_a = mpd_adjexp(a);
23117db96d56Sopenharmony_ci    adjexp_b = mpd_adjexp(b);
23127db96d56Sopenharmony_ci    if (adjexp_a != adjexp_b) {
23137db96d56Sopenharmony_ci        if (adjexp_a < adjexp_b) {
23147db96d56Sopenharmony_ci            return -1;
23157db96d56Sopenharmony_ci        }
23167db96d56Sopenharmony_ci        return 1;
23177db96d56Sopenharmony_ci    }
23187db96d56Sopenharmony_ci
23197db96d56Sopenharmony_ci    /* same adjusted exponents */
23207db96d56Sopenharmony_ci    return _mpd_cmp_same_adjexp(a, b);
23217db96d56Sopenharmony_ci}
23227db96d56Sopenharmony_ci
23237db96d56Sopenharmony_ci/* Compare two values and return an integer result. */
23247db96d56Sopenharmony_ciint
23257db96d56Sopenharmony_cimpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status)
23267db96d56Sopenharmony_ci{
23277db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
23287db96d56Sopenharmony_ci        if (mpd_isnan(a) || mpd_isnan(b)) {
23297db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
23307db96d56Sopenharmony_ci            return INT_MAX;
23317db96d56Sopenharmony_ci        }
23327db96d56Sopenharmony_ci    }
23337db96d56Sopenharmony_ci
23347db96d56Sopenharmony_ci    return _mpd_cmp(a, b);
23357db96d56Sopenharmony_ci}
23367db96d56Sopenharmony_ci
23377db96d56Sopenharmony_ci/*
23387db96d56Sopenharmony_ci * Compare a and b, convert the usual integer result to a decimal and
23397db96d56Sopenharmony_ci * store it in 'result'. For convenience, the integer result of the comparison
23407db96d56Sopenharmony_ci * is returned. Comparisons involving NaNs return NaN/INT_MAX.
23417db96d56Sopenharmony_ci */
23427db96d56Sopenharmony_ciint
23437db96d56Sopenharmony_cimpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b,
23447db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
23457db96d56Sopenharmony_ci{
23467db96d56Sopenharmony_ci    int c;
23477db96d56Sopenharmony_ci
23487db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
23497db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
23507db96d56Sopenharmony_ci            return INT_MAX;
23517db96d56Sopenharmony_ci        }
23527db96d56Sopenharmony_ci    }
23537db96d56Sopenharmony_ci
23547db96d56Sopenharmony_ci    c = _mpd_cmp(a, b);
23557db96d56Sopenharmony_ci    _settriple(result, (c < 0), (c != 0), 0);
23567db96d56Sopenharmony_ci    return c;
23577db96d56Sopenharmony_ci}
23587db96d56Sopenharmony_ci
23597db96d56Sopenharmony_ci/* Same as mpd_compare(), but signal for all NaNs, i.e. also for quiet NaNs. */
23607db96d56Sopenharmony_ciint
23617db96d56Sopenharmony_cimpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b,
23627db96d56Sopenharmony_ci                    const mpd_context_t *ctx, uint32_t *status)
23637db96d56Sopenharmony_ci{
23647db96d56Sopenharmony_ci    int c;
23657db96d56Sopenharmony_ci
23667db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
23677db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
23687db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
23697db96d56Sopenharmony_ci            return INT_MAX;
23707db96d56Sopenharmony_ci        }
23717db96d56Sopenharmony_ci    }
23727db96d56Sopenharmony_ci
23737db96d56Sopenharmony_ci    c = _mpd_cmp(a, b);
23747db96d56Sopenharmony_ci    _settriple(result, (c < 0), (c != 0), 0);
23757db96d56Sopenharmony_ci    return c;
23767db96d56Sopenharmony_ci}
23777db96d56Sopenharmony_ci
23787db96d56Sopenharmony_ci/* Compare the operands using a total order. */
23797db96d56Sopenharmony_ciint
23807db96d56Sopenharmony_cimpd_cmp_total(const mpd_t *a, const mpd_t *b)
23817db96d56Sopenharmony_ci{
23827db96d56Sopenharmony_ci    mpd_t aa, bb;
23837db96d56Sopenharmony_ci    int nan_a, nan_b;
23847db96d56Sopenharmony_ci    int c;
23857db96d56Sopenharmony_ci
23867db96d56Sopenharmony_ci    if (mpd_sign(a) != mpd_sign(b)) {
23877db96d56Sopenharmony_ci        return mpd_sign(b) - mpd_sign(a);
23887db96d56Sopenharmony_ci    }
23897db96d56Sopenharmony_ci
23907db96d56Sopenharmony_ci
23917db96d56Sopenharmony_ci    if (mpd_isnan(a)) {
23927db96d56Sopenharmony_ci        c = 1;
23937db96d56Sopenharmony_ci        if (mpd_isnan(b)) {
23947db96d56Sopenharmony_ci            nan_a = (mpd_isqnan(a)) ? 1 : 0;
23957db96d56Sopenharmony_ci            nan_b = (mpd_isqnan(b)) ? 1 : 0;
23967db96d56Sopenharmony_ci            if (nan_b == nan_a) {
23977db96d56Sopenharmony_ci                if (a->len > 0 && b->len > 0) {
23987db96d56Sopenharmony_ci                    _mpd_copy_shared(&aa, a);
23997db96d56Sopenharmony_ci                    _mpd_copy_shared(&bb, b);
24007db96d56Sopenharmony_ci                    aa.exp = bb.exp = 0;
24017db96d56Sopenharmony_ci                    /* compare payload */
24027db96d56Sopenharmony_ci                    c = _mpd_cmp_abs(&aa, &bb);
24037db96d56Sopenharmony_ci                }
24047db96d56Sopenharmony_ci                else {
24057db96d56Sopenharmony_ci                    c = (a->len > 0) - (b->len > 0);
24067db96d56Sopenharmony_ci                }
24077db96d56Sopenharmony_ci            }
24087db96d56Sopenharmony_ci            else {
24097db96d56Sopenharmony_ci                c = nan_a - nan_b;
24107db96d56Sopenharmony_ci            }
24117db96d56Sopenharmony_ci        }
24127db96d56Sopenharmony_ci    }
24137db96d56Sopenharmony_ci    else if (mpd_isnan(b)) {
24147db96d56Sopenharmony_ci        c = -1;
24157db96d56Sopenharmony_ci    }
24167db96d56Sopenharmony_ci    else {
24177db96d56Sopenharmony_ci        c = _mpd_cmp_abs(a, b);
24187db96d56Sopenharmony_ci        if (c == 0 && a->exp != b->exp) {
24197db96d56Sopenharmony_ci            c = (a->exp < b->exp) ? -1 : 1;
24207db96d56Sopenharmony_ci        }
24217db96d56Sopenharmony_ci    }
24227db96d56Sopenharmony_ci
24237db96d56Sopenharmony_ci    return c * mpd_arith_sign(a);
24247db96d56Sopenharmony_ci}
24257db96d56Sopenharmony_ci
24267db96d56Sopenharmony_ci/*
24277db96d56Sopenharmony_ci * Compare a and b according to a total order, convert the usual integer result
24287db96d56Sopenharmony_ci * to a decimal and store it in 'result'. For convenience, the integer result
24297db96d56Sopenharmony_ci * of the comparison is returned.
24307db96d56Sopenharmony_ci */
24317db96d56Sopenharmony_ciint
24327db96d56Sopenharmony_cimpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b)
24337db96d56Sopenharmony_ci{
24347db96d56Sopenharmony_ci    int c;
24357db96d56Sopenharmony_ci
24367db96d56Sopenharmony_ci    c = mpd_cmp_total(a, b);
24377db96d56Sopenharmony_ci    _settriple(result, (c < 0), (c != 0), 0);
24387db96d56Sopenharmony_ci    return c;
24397db96d56Sopenharmony_ci}
24407db96d56Sopenharmony_ci
24417db96d56Sopenharmony_ci/* Compare the magnitude of the operands using a total order. */
24427db96d56Sopenharmony_ciint
24437db96d56Sopenharmony_cimpd_cmp_total_mag(const mpd_t *a, const mpd_t *b)
24447db96d56Sopenharmony_ci{
24457db96d56Sopenharmony_ci    mpd_t aa, bb;
24467db96d56Sopenharmony_ci
24477db96d56Sopenharmony_ci    _mpd_copy_shared(&aa, a);
24487db96d56Sopenharmony_ci    _mpd_copy_shared(&bb, b);
24497db96d56Sopenharmony_ci
24507db96d56Sopenharmony_ci    mpd_set_positive(&aa);
24517db96d56Sopenharmony_ci    mpd_set_positive(&bb);
24527db96d56Sopenharmony_ci
24537db96d56Sopenharmony_ci    return mpd_cmp_total(&aa, &bb);
24547db96d56Sopenharmony_ci}
24557db96d56Sopenharmony_ci
24567db96d56Sopenharmony_ci/*
24577db96d56Sopenharmony_ci * Compare the magnitude of a and b according to a total order, convert the
24587db96d56Sopenharmony_ci * the usual integer result to a decimal and store it in 'result'.
24597db96d56Sopenharmony_ci * For convenience, the integer result of the comparison is returned.
24607db96d56Sopenharmony_ci */
24617db96d56Sopenharmony_ciint
24627db96d56Sopenharmony_cimpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b)
24637db96d56Sopenharmony_ci{
24647db96d56Sopenharmony_ci    int c;
24657db96d56Sopenharmony_ci
24667db96d56Sopenharmony_ci    c = mpd_cmp_total_mag(a, b);
24677db96d56Sopenharmony_ci    _settriple(result, (c < 0), (c != 0), 0);
24687db96d56Sopenharmony_ci    return c;
24697db96d56Sopenharmony_ci}
24707db96d56Sopenharmony_ci
24717db96d56Sopenharmony_ci/* Determine an ordering for operands that are numerically equal. */
24727db96d56Sopenharmony_cistatic inline int
24737db96d56Sopenharmony_ci_mpd_cmp_numequal(const mpd_t *a, const mpd_t *b)
24747db96d56Sopenharmony_ci{
24757db96d56Sopenharmony_ci    int sign_a, sign_b;
24767db96d56Sopenharmony_ci    int c;
24777db96d56Sopenharmony_ci
24787db96d56Sopenharmony_ci    sign_a = mpd_sign(a);
24797db96d56Sopenharmony_ci    sign_b = mpd_sign(b);
24807db96d56Sopenharmony_ci    if (sign_a != sign_b) {
24817db96d56Sopenharmony_ci        c = sign_b - sign_a;
24827db96d56Sopenharmony_ci    }
24837db96d56Sopenharmony_ci    else {
24847db96d56Sopenharmony_ci        c = (a->exp < b->exp) ? -1 : 1;
24857db96d56Sopenharmony_ci        c *= mpd_arith_sign(a);
24867db96d56Sopenharmony_ci    }
24877db96d56Sopenharmony_ci
24887db96d56Sopenharmony_ci    return c;
24897db96d56Sopenharmony_ci}
24907db96d56Sopenharmony_ci
24917db96d56Sopenharmony_ci
24927db96d56Sopenharmony_ci/******************************************************************************/
24937db96d56Sopenharmony_ci/*                         Shifting the coefficient                           */
24947db96d56Sopenharmony_ci/******************************************************************************/
24957db96d56Sopenharmony_ci
24967db96d56Sopenharmony_ci/*
24977db96d56Sopenharmony_ci * Shift the coefficient of the operand to the left, no check for specials.
24987db96d56Sopenharmony_ci * Both operands may be the same pointer. If the result length has to be
24997db96d56Sopenharmony_ci * increased, mpd_qresize() might fail with MPD_Malloc_error.
25007db96d56Sopenharmony_ci */
25017db96d56Sopenharmony_ciint
25027db96d56Sopenharmony_cimpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status)
25037db96d56Sopenharmony_ci{
25047db96d56Sopenharmony_ci    mpd_ssize_t size;
25057db96d56Sopenharmony_ci
25067db96d56Sopenharmony_ci    assert(!mpd_isspecial(a));
25077db96d56Sopenharmony_ci    assert(n >= 0);
25087db96d56Sopenharmony_ci
25097db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a) || n == 0) {
25107db96d56Sopenharmony_ci        return mpd_qcopy(result, a, status);
25117db96d56Sopenharmony_ci    }
25127db96d56Sopenharmony_ci
25137db96d56Sopenharmony_ci    size = mpd_digits_to_size(a->digits+n);
25147db96d56Sopenharmony_ci    if (!mpd_qresize(result, size, status)) {
25157db96d56Sopenharmony_ci        return 0; /* result is NaN */
25167db96d56Sopenharmony_ci    }
25177db96d56Sopenharmony_ci
25187db96d56Sopenharmony_ci    _mpd_baseshiftl(result->data, a->data, size, a->len, n);
25197db96d56Sopenharmony_ci
25207db96d56Sopenharmony_ci    mpd_copy_flags(result, a);
25217db96d56Sopenharmony_ci    result->exp = a->exp;
25227db96d56Sopenharmony_ci    result->digits = a->digits+n;
25237db96d56Sopenharmony_ci    result->len = size;
25247db96d56Sopenharmony_ci
25257db96d56Sopenharmony_ci    return 1;
25267db96d56Sopenharmony_ci}
25277db96d56Sopenharmony_ci
25287db96d56Sopenharmony_ci/* Determine the rounding indicator if all digits of the coefficient are shifted
25297db96d56Sopenharmony_ci * out of the picture. */
25307db96d56Sopenharmony_cistatic mpd_uint_t
25317db96d56Sopenharmony_ci_mpd_get_rnd(const mpd_uint_t *data, mpd_ssize_t len, int use_msd)
25327db96d56Sopenharmony_ci{
25337db96d56Sopenharmony_ci    mpd_uint_t rnd = 0, rest = 0, word;
25347db96d56Sopenharmony_ci
25357db96d56Sopenharmony_ci    word = data[len-1];
25367db96d56Sopenharmony_ci    /* special treatment for the most significant digit if shift == digits */
25377db96d56Sopenharmony_ci    if (use_msd) {
25387db96d56Sopenharmony_ci        _mpd_divmod_pow10(&rnd, &rest, word, mpd_word_digits(word)-1);
25397db96d56Sopenharmony_ci        if (len > 1 && rest == 0) {
25407db96d56Sopenharmony_ci             rest = !_mpd_isallzero(data, len-1);
25417db96d56Sopenharmony_ci        }
25427db96d56Sopenharmony_ci    }
25437db96d56Sopenharmony_ci    else {
25447db96d56Sopenharmony_ci        rest = !_mpd_isallzero(data, len);
25457db96d56Sopenharmony_ci    }
25467db96d56Sopenharmony_ci
25477db96d56Sopenharmony_ci    return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd;
25487db96d56Sopenharmony_ci}
25497db96d56Sopenharmony_ci
25507db96d56Sopenharmony_ci/*
25517db96d56Sopenharmony_ci * Same as mpd_qshiftr(), but 'result' is an mpd_t with a static coefficient.
25527db96d56Sopenharmony_ci * It is the caller's responsibility to ensure that the coefficient is big
25537db96d56Sopenharmony_ci * enough. The function cannot fail.
25547db96d56Sopenharmony_ci */
25557db96d56Sopenharmony_cistatic mpd_uint_t
25567db96d56Sopenharmony_cimpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n)
25577db96d56Sopenharmony_ci{
25587db96d56Sopenharmony_ci    mpd_uint_t rnd;
25597db96d56Sopenharmony_ci    mpd_ssize_t size;
25607db96d56Sopenharmony_ci
25617db96d56Sopenharmony_ci    assert(!mpd_isspecial(a));
25627db96d56Sopenharmony_ci    assert(n >= 0);
25637db96d56Sopenharmony_ci
25647db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a) || n == 0) {
25657db96d56Sopenharmony_ci        mpd_qcopy_static(result, a);
25667db96d56Sopenharmony_ci        return 0;
25677db96d56Sopenharmony_ci    }
25687db96d56Sopenharmony_ci
25697db96d56Sopenharmony_ci    if (n >= a->digits) {
25707db96d56Sopenharmony_ci        rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits));
25717db96d56Sopenharmony_ci        mpd_zerocoeff(result);
25727db96d56Sopenharmony_ci    }
25737db96d56Sopenharmony_ci    else {
25747db96d56Sopenharmony_ci        result->digits = a->digits-n;
25757db96d56Sopenharmony_ci        size = mpd_digits_to_size(result->digits);
25767db96d56Sopenharmony_ci        rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
25777db96d56Sopenharmony_ci        result->len = size;
25787db96d56Sopenharmony_ci    }
25797db96d56Sopenharmony_ci
25807db96d56Sopenharmony_ci    mpd_copy_flags(result, a);
25817db96d56Sopenharmony_ci    result->exp = a->exp;
25827db96d56Sopenharmony_ci
25837db96d56Sopenharmony_ci    return rnd;
25847db96d56Sopenharmony_ci}
25857db96d56Sopenharmony_ci
25867db96d56Sopenharmony_ci/*
25877db96d56Sopenharmony_ci * Inplace shift of the coefficient to the right, no check for specials.
25887db96d56Sopenharmony_ci * Returns the rounding indicator for mpd_rnd_incr().
25897db96d56Sopenharmony_ci * The function cannot fail.
25907db96d56Sopenharmony_ci */
25917db96d56Sopenharmony_cimpd_uint_t
25927db96d56Sopenharmony_cimpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n)
25937db96d56Sopenharmony_ci{
25947db96d56Sopenharmony_ci    uint32_t dummy;
25957db96d56Sopenharmony_ci    mpd_uint_t rnd;
25967db96d56Sopenharmony_ci    mpd_ssize_t size;
25977db96d56Sopenharmony_ci
25987db96d56Sopenharmony_ci    assert(!mpd_isspecial(result));
25997db96d56Sopenharmony_ci    assert(n >= 0);
26007db96d56Sopenharmony_ci
26017db96d56Sopenharmony_ci    if (mpd_iszerocoeff(result) || n == 0) {
26027db96d56Sopenharmony_ci        return 0;
26037db96d56Sopenharmony_ci    }
26047db96d56Sopenharmony_ci
26057db96d56Sopenharmony_ci    if (n >= result->digits) {
26067db96d56Sopenharmony_ci        rnd = _mpd_get_rnd(result->data, result->len, (n==result->digits));
26077db96d56Sopenharmony_ci        mpd_zerocoeff(result);
26087db96d56Sopenharmony_ci    }
26097db96d56Sopenharmony_ci    else {
26107db96d56Sopenharmony_ci        rnd = _mpd_baseshiftr(result->data, result->data, result->len, n);
26117db96d56Sopenharmony_ci        result->digits -= n;
26127db96d56Sopenharmony_ci        size = mpd_digits_to_size(result->digits);
26137db96d56Sopenharmony_ci        /* reducing the size cannot fail */
26147db96d56Sopenharmony_ci        mpd_qresize(result, size, &dummy);
26157db96d56Sopenharmony_ci        result->len = size;
26167db96d56Sopenharmony_ci    }
26177db96d56Sopenharmony_ci
26187db96d56Sopenharmony_ci    return rnd;
26197db96d56Sopenharmony_ci}
26207db96d56Sopenharmony_ci
26217db96d56Sopenharmony_ci/*
26227db96d56Sopenharmony_ci * Shift the coefficient of the operand to the right, no check for specials.
26237db96d56Sopenharmony_ci * Both operands may be the same pointer. Returns the rounding indicator to
26247db96d56Sopenharmony_ci * be used by mpd_rnd_incr(). If the result length has to be increased,
26257db96d56Sopenharmony_ci * mpd_qcopy() or mpd_qresize() might fail with MPD_Malloc_error. In those
26267db96d56Sopenharmony_ci * cases, MPD_UINT_MAX is returned.
26277db96d56Sopenharmony_ci */
26287db96d56Sopenharmony_cimpd_uint_t
26297db96d56Sopenharmony_cimpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status)
26307db96d56Sopenharmony_ci{
26317db96d56Sopenharmony_ci    mpd_uint_t rnd;
26327db96d56Sopenharmony_ci    mpd_ssize_t size;
26337db96d56Sopenharmony_ci
26347db96d56Sopenharmony_ci    assert(!mpd_isspecial(a));
26357db96d56Sopenharmony_ci    assert(n >= 0);
26367db96d56Sopenharmony_ci
26377db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a) || n == 0) {
26387db96d56Sopenharmony_ci        if (!mpd_qcopy(result, a, status)) {
26397db96d56Sopenharmony_ci            return MPD_UINT_MAX;
26407db96d56Sopenharmony_ci        }
26417db96d56Sopenharmony_ci        return 0;
26427db96d56Sopenharmony_ci    }
26437db96d56Sopenharmony_ci
26447db96d56Sopenharmony_ci    if (n >= a->digits) {
26457db96d56Sopenharmony_ci        rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits));
26467db96d56Sopenharmony_ci        mpd_zerocoeff(result);
26477db96d56Sopenharmony_ci    }
26487db96d56Sopenharmony_ci    else {
26497db96d56Sopenharmony_ci        result->digits = a->digits-n;
26507db96d56Sopenharmony_ci        size = mpd_digits_to_size(result->digits);
26517db96d56Sopenharmony_ci        if (result == a) {
26527db96d56Sopenharmony_ci            rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
26537db96d56Sopenharmony_ci            /* reducing the size cannot fail */
26547db96d56Sopenharmony_ci            mpd_qresize(result, size, status);
26557db96d56Sopenharmony_ci        }
26567db96d56Sopenharmony_ci        else {
26577db96d56Sopenharmony_ci            if (!mpd_qresize(result, size, status)) {
26587db96d56Sopenharmony_ci                return MPD_UINT_MAX;
26597db96d56Sopenharmony_ci            }
26607db96d56Sopenharmony_ci            rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
26617db96d56Sopenharmony_ci        }
26627db96d56Sopenharmony_ci        result->len = size;
26637db96d56Sopenharmony_ci    }
26647db96d56Sopenharmony_ci
26657db96d56Sopenharmony_ci    mpd_copy_flags(result, a);
26667db96d56Sopenharmony_ci    result->exp = a->exp;
26677db96d56Sopenharmony_ci
26687db96d56Sopenharmony_ci    return rnd;
26697db96d56Sopenharmony_ci}
26707db96d56Sopenharmony_ci
26717db96d56Sopenharmony_ci
26727db96d56Sopenharmony_ci/******************************************************************************/
26737db96d56Sopenharmony_ci/*                         Miscellaneous operations                           */
26747db96d56Sopenharmony_ci/******************************************************************************/
26757db96d56Sopenharmony_ci
26767db96d56Sopenharmony_ci/* Logical And */
26777db96d56Sopenharmony_civoid
26787db96d56Sopenharmony_cimpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b,
26797db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
26807db96d56Sopenharmony_ci{
26817db96d56Sopenharmony_ci    const mpd_t *big = a, *small = b;
26827db96d56Sopenharmony_ci    mpd_uint_t x, y, z, xbit, ybit;
26837db96d56Sopenharmony_ci    int k, mswdigits;
26847db96d56Sopenharmony_ci    mpd_ssize_t i;
26857db96d56Sopenharmony_ci
26867db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b) ||
26877db96d56Sopenharmony_ci        mpd_isnegative(a) || mpd_isnegative(b) ||
26887db96d56Sopenharmony_ci        a->exp != 0 || b->exp != 0) {
26897db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
26907db96d56Sopenharmony_ci        return;
26917db96d56Sopenharmony_ci    }
26927db96d56Sopenharmony_ci    if (b->digits > a->digits) {
26937db96d56Sopenharmony_ci        big = b;
26947db96d56Sopenharmony_ci        small = a;
26957db96d56Sopenharmony_ci    }
26967db96d56Sopenharmony_ci    if (!mpd_qresize(result, big->len, status)) {
26977db96d56Sopenharmony_ci        return;
26987db96d56Sopenharmony_ci    }
26997db96d56Sopenharmony_ci
27007db96d56Sopenharmony_ci
27017db96d56Sopenharmony_ci    /* full words */
27027db96d56Sopenharmony_ci    for (i = 0; i < small->len-1; i++) {
27037db96d56Sopenharmony_ci        x = small->data[i];
27047db96d56Sopenharmony_ci        y = big->data[i];
27057db96d56Sopenharmony_ci        z = 0;
27067db96d56Sopenharmony_ci        for (k = 0; k < MPD_RDIGITS; k++) {
27077db96d56Sopenharmony_ci            xbit = x % 10;
27087db96d56Sopenharmony_ci            x /= 10;
27097db96d56Sopenharmony_ci            ybit = y % 10;
27107db96d56Sopenharmony_ci            y /= 10;
27117db96d56Sopenharmony_ci            if (xbit > 1 || ybit > 1) {
27127db96d56Sopenharmony_ci                goto invalid_operation;
27137db96d56Sopenharmony_ci            }
27147db96d56Sopenharmony_ci            z += (xbit&ybit) ? mpd_pow10[k] : 0;
27157db96d56Sopenharmony_ci        }
27167db96d56Sopenharmony_ci        result->data[i] = z;
27177db96d56Sopenharmony_ci    }
27187db96d56Sopenharmony_ci    /* most significant word of small */
27197db96d56Sopenharmony_ci    x = small->data[i];
27207db96d56Sopenharmony_ci    y = big->data[i];
27217db96d56Sopenharmony_ci    z = 0;
27227db96d56Sopenharmony_ci    mswdigits = mpd_word_digits(x);
27237db96d56Sopenharmony_ci    for (k = 0; k < mswdigits; k++) {
27247db96d56Sopenharmony_ci        xbit = x % 10;
27257db96d56Sopenharmony_ci        x /= 10;
27267db96d56Sopenharmony_ci        ybit = y % 10;
27277db96d56Sopenharmony_ci        y /= 10;
27287db96d56Sopenharmony_ci        if (xbit > 1 || ybit > 1) {
27297db96d56Sopenharmony_ci            goto invalid_operation;
27307db96d56Sopenharmony_ci        }
27317db96d56Sopenharmony_ci        z += (xbit&ybit) ? mpd_pow10[k] : 0;
27327db96d56Sopenharmony_ci    }
27337db96d56Sopenharmony_ci    result->data[i++] = z;
27347db96d56Sopenharmony_ci
27357db96d56Sopenharmony_ci    /* scan the rest of y for digits > 1 */
27367db96d56Sopenharmony_ci    for (; k < MPD_RDIGITS; k++) {
27377db96d56Sopenharmony_ci        ybit = y % 10;
27387db96d56Sopenharmony_ci        y /= 10;
27397db96d56Sopenharmony_ci        if (ybit > 1) {
27407db96d56Sopenharmony_ci            goto invalid_operation;
27417db96d56Sopenharmony_ci        }
27427db96d56Sopenharmony_ci    }
27437db96d56Sopenharmony_ci    /* scan the rest of big for digits > 1 */
27447db96d56Sopenharmony_ci    for (; i < big->len; i++) {
27457db96d56Sopenharmony_ci        y = big->data[i];
27467db96d56Sopenharmony_ci        for (k = 0; k < MPD_RDIGITS; k++) {
27477db96d56Sopenharmony_ci            ybit = y % 10;
27487db96d56Sopenharmony_ci            y /= 10;
27497db96d56Sopenharmony_ci            if (ybit > 1) {
27507db96d56Sopenharmony_ci                goto invalid_operation;
27517db96d56Sopenharmony_ci            }
27527db96d56Sopenharmony_ci        }
27537db96d56Sopenharmony_ci    }
27547db96d56Sopenharmony_ci
27557db96d56Sopenharmony_ci    mpd_clear_flags(result);
27567db96d56Sopenharmony_ci    result->exp = 0;
27577db96d56Sopenharmony_ci    result->len = _mpd_real_size(result->data, small->len);
27587db96d56Sopenharmony_ci    mpd_qresize(result, result->len, status);
27597db96d56Sopenharmony_ci    mpd_setdigits(result);
27607db96d56Sopenharmony_ci    _mpd_cap(result, ctx);
27617db96d56Sopenharmony_ci    return;
27627db96d56Sopenharmony_ci
27637db96d56Sopenharmony_ciinvalid_operation:
27647db96d56Sopenharmony_ci    mpd_seterror(result, MPD_Invalid_operation, status);
27657db96d56Sopenharmony_ci}
27667db96d56Sopenharmony_ci
27677db96d56Sopenharmony_ci/* Class of an operand. Returns a pointer to the constant name. */
27687db96d56Sopenharmony_ciconst char *
27697db96d56Sopenharmony_cimpd_class(const mpd_t *a, const mpd_context_t *ctx)
27707db96d56Sopenharmony_ci{
27717db96d56Sopenharmony_ci    if (mpd_isnan(a)) {
27727db96d56Sopenharmony_ci        if (mpd_isqnan(a))
27737db96d56Sopenharmony_ci            return "NaN";
27747db96d56Sopenharmony_ci        else
27757db96d56Sopenharmony_ci            return "sNaN";
27767db96d56Sopenharmony_ci    }
27777db96d56Sopenharmony_ci    else if (mpd_ispositive(a)) {
27787db96d56Sopenharmony_ci        if (mpd_isinfinite(a))
27797db96d56Sopenharmony_ci            return "+Infinity";
27807db96d56Sopenharmony_ci        else if (mpd_iszero(a))
27817db96d56Sopenharmony_ci            return "+Zero";
27827db96d56Sopenharmony_ci        else if (mpd_isnormal(a, ctx))
27837db96d56Sopenharmony_ci            return "+Normal";
27847db96d56Sopenharmony_ci        else
27857db96d56Sopenharmony_ci            return "+Subnormal";
27867db96d56Sopenharmony_ci    }
27877db96d56Sopenharmony_ci    else {
27887db96d56Sopenharmony_ci        if (mpd_isinfinite(a))
27897db96d56Sopenharmony_ci            return "-Infinity";
27907db96d56Sopenharmony_ci        else if (mpd_iszero(a))
27917db96d56Sopenharmony_ci            return "-Zero";
27927db96d56Sopenharmony_ci        else if (mpd_isnormal(a, ctx))
27937db96d56Sopenharmony_ci            return "-Normal";
27947db96d56Sopenharmony_ci        else
27957db96d56Sopenharmony_ci            return "-Subnormal";
27967db96d56Sopenharmony_ci    }
27977db96d56Sopenharmony_ci}
27987db96d56Sopenharmony_ci
27997db96d56Sopenharmony_ci/* Logical Xor */
28007db96d56Sopenharmony_civoid
28017db96d56Sopenharmony_cimpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
28027db96d56Sopenharmony_ci            uint32_t *status)
28037db96d56Sopenharmony_ci{
28047db96d56Sopenharmony_ci    mpd_uint_t x, z, xbit;
28057db96d56Sopenharmony_ci    mpd_ssize_t i, digits, len;
28067db96d56Sopenharmony_ci    mpd_ssize_t q, r;
28077db96d56Sopenharmony_ci    int k;
28087db96d56Sopenharmony_ci
28097db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isnegative(a) || a->exp != 0) {
28107db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
28117db96d56Sopenharmony_ci        return;
28127db96d56Sopenharmony_ci    }
28137db96d56Sopenharmony_ci
28147db96d56Sopenharmony_ci    digits = (a->digits < ctx->prec) ? ctx->prec : a->digits;
28157db96d56Sopenharmony_ci    _mpd_idiv_word(&q, &r, digits, MPD_RDIGITS);
28167db96d56Sopenharmony_ci    len = (r == 0) ? q : q+1;
28177db96d56Sopenharmony_ci    if (!mpd_qresize(result, len, status)) {
28187db96d56Sopenharmony_ci        return;
28197db96d56Sopenharmony_ci    }
28207db96d56Sopenharmony_ci
28217db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
28227db96d56Sopenharmony_ci        x = (i < a->len) ? a->data[i] : 0;
28237db96d56Sopenharmony_ci        z = 0;
28247db96d56Sopenharmony_ci        for (k = 0; k < MPD_RDIGITS; k++) {
28257db96d56Sopenharmony_ci            xbit = x % 10;
28267db96d56Sopenharmony_ci            x /= 10;
28277db96d56Sopenharmony_ci            if (xbit > 1) {
28287db96d56Sopenharmony_ci                goto invalid_operation;
28297db96d56Sopenharmony_ci            }
28307db96d56Sopenharmony_ci            z += !xbit ? mpd_pow10[k] : 0;
28317db96d56Sopenharmony_ci        }
28327db96d56Sopenharmony_ci        result->data[i] = z;
28337db96d56Sopenharmony_ci    }
28347db96d56Sopenharmony_ci
28357db96d56Sopenharmony_ci    mpd_clear_flags(result);
28367db96d56Sopenharmony_ci    result->exp = 0;
28377db96d56Sopenharmony_ci    result->len = _mpd_real_size(result->data, len);
28387db96d56Sopenharmony_ci    mpd_qresize(result, result->len, status);
28397db96d56Sopenharmony_ci    mpd_setdigits(result);
28407db96d56Sopenharmony_ci    _mpd_cap(result, ctx);
28417db96d56Sopenharmony_ci    return;
28427db96d56Sopenharmony_ci
28437db96d56Sopenharmony_ciinvalid_operation:
28447db96d56Sopenharmony_ci    mpd_seterror(result, MPD_Invalid_operation, status);
28457db96d56Sopenharmony_ci}
28467db96d56Sopenharmony_ci
28477db96d56Sopenharmony_ci/* Exponent of the magnitude of the most significant digit of the operand. */
28487db96d56Sopenharmony_civoid
28497db96d56Sopenharmony_cimpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
28507db96d56Sopenharmony_ci          uint32_t *status)
28517db96d56Sopenharmony_ci{
28527db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
28537db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
28547db96d56Sopenharmony_ci            return;
28557db96d56Sopenharmony_ci        }
28567db96d56Sopenharmony_ci        mpd_setspecial(result, MPD_POS, MPD_INF);
28577db96d56Sopenharmony_ci    }
28587db96d56Sopenharmony_ci    else if (mpd_iszerocoeff(a)) {
28597db96d56Sopenharmony_ci        mpd_setspecial(result, MPD_NEG, MPD_INF);
28607db96d56Sopenharmony_ci        *status |= MPD_Division_by_zero;
28617db96d56Sopenharmony_ci    }
28627db96d56Sopenharmony_ci    else {
28637db96d56Sopenharmony_ci        mpd_qset_ssize(result, mpd_adjexp(a), ctx, status);
28647db96d56Sopenharmony_ci    }
28657db96d56Sopenharmony_ci}
28667db96d56Sopenharmony_ci
28677db96d56Sopenharmony_ci/* Logical Or */
28687db96d56Sopenharmony_civoid
28697db96d56Sopenharmony_cimpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b,
28707db96d56Sopenharmony_ci        const mpd_context_t *ctx, uint32_t *status)
28717db96d56Sopenharmony_ci{
28727db96d56Sopenharmony_ci    const mpd_t *big = a, *small = b;
28737db96d56Sopenharmony_ci    mpd_uint_t x, y, z, xbit, ybit;
28747db96d56Sopenharmony_ci    int k, mswdigits;
28757db96d56Sopenharmony_ci    mpd_ssize_t i;
28767db96d56Sopenharmony_ci
28777db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b) ||
28787db96d56Sopenharmony_ci        mpd_isnegative(a) || mpd_isnegative(b) ||
28797db96d56Sopenharmony_ci        a->exp != 0 || b->exp != 0) {
28807db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
28817db96d56Sopenharmony_ci        return;
28827db96d56Sopenharmony_ci    }
28837db96d56Sopenharmony_ci    if (b->digits > a->digits) {
28847db96d56Sopenharmony_ci        big = b;
28857db96d56Sopenharmony_ci        small = a;
28867db96d56Sopenharmony_ci    }
28877db96d56Sopenharmony_ci    if (!mpd_qresize(result, big->len, status)) {
28887db96d56Sopenharmony_ci        return;
28897db96d56Sopenharmony_ci    }
28907db96d56Sopenharmony_ci
28917db96d56Sopenharmony_ci
28927db96d56Sopenharmony_ci    /* full words */
28937db96d56Sopenharmony_ci    for (i = 0; i < small->len-1; i++) {
28947db96d56Sopenharmony_ci        x = small->data[i];
28957db96d56Sopenharmony_ci        y = big->data[i];
28967db96d56Sopenharmony_ci        z = 0;
28977db96d56Sopenharmony_ci        for (k = 0; k < MPD_RDIGITS; k++) {
28987db96d56Sopenharmony_ci            xbit = x % 10;
28997db96d56Sopenharmony_ci            x /= 10;
29007db96d56Sopenharmony_ci            ybit = y % 10;
29017db96d56Sopenharmony_ci            y /= 10;
29027db96d56Sopenharmony_ci            if (xbit > 1 || ybit > 1) {
29037db96d56Sopenharmony_ci                goto invalid_operation;
29047db96d56Sopenharmony_ci            }
29057db96d56Sopenharmony_ci            z += (xbit|ybit) ? mpd_pow10[k] : 0;
29067db96d56Sopenharmony_ci        }
29077db96d56Sopenharmony_ci        result->data[i] = z;
29087db96d56Sopenharmony_ci    }
29097db96d56Sopenharmony_ci    /* most significant word of small */
29107db96d56Sopenharmony_ci    x = small->data[i];
29117db96d56Sopenharmony_ci    y = big->data[i];
29127db96d56Sopenharmony_ci    z = 0;
29137db96d56Sopenharmony_ci    mswdigits = mpd_word_digits(x);
29147db96d56Sopenharmony_ci    for (k = 0; k < mswdigits; k++) {
29157db96d56Sopenharmony_ci        xbit = x % 10;
29167db96d56Sopenharmony_ci        x /= 10;
29177db96d56Sopenharmony_ci        ybit = y % 10;
29187db96d56Sopenharmony_ci        y /= 10;
29197db96d56Sopenharmony_ci        if (xbit > 1 || ybit > 1) {
29207db96d56Sopenharmony_ci            goto invalid_operation;
29217db96d56Sopenharmony_ci        }
29227db96d56Sopenharmony_ci        z += (xbit|ybit) ? mpd_pow10[k] : 0;
29237db96d56Sopenharmony_ci    }
29247db96d56Sopenharmony_ci
29257db96d56Sopenharmony_ci    /* scan for digits > 1 and copy the rest of y */
29267db96d56Sopenharmony_ci    for (; k < MPD_RDIGITS; k++) {
29277db96d56Sopenharmony_ci        ybit = y % 10;
29287db96d56Sopenharmony_ci        y /= 10;
29297db96d56Sopenharmony_ci        if (ybit > 1) {
29307db96d56Sopenharmony_ci            goto invalid_operation;
29317db96d56Sopenharmony_ci        }
29327db96d56Sopenharmony_ci        z += ybit*mpd_pow10[k];
29337db96d56Sopenharmony_ci    }
29347db96d56Sopenharmony_ci    result->data[i++] = z;
29357db96d56Sopenharmony_ci    /* scan for digits > 1 and copy the rest of big */
29367db96d56Sopenharmony_ci    for (; i < big->len; i++) {
29377db96d56Sopenharmony_ci        y = big->data[i];
29387db96d56Sopenharmony_ci        for (k = 0; k < MPD_RDIGITS; k++) {
29397db96d56Sopenharmony_ci            ybit = y % 10;
29407db96d56Sopenharmony_ci            y /= 10;
29417db96d56Sopenharmony_ci            if (ybit > 1) {
29427db96d56Sopenharmony_ci                goto invalid_operation;
29437db96d56Sopenharmony_ci            }
29447db96d56Sopenharmony_ci        }
29457db96d56Sopenharmony_ci        result->data[i] = big->data[i];
29467db96d56Sopenharmony_ci    }
29477db96d56Sopenharmony_ci
29487db96d56Sopenharmony_ci    mpd_clear_flags(result);
29497db96d56Sopenharmony_ci    result->exp = 0;
29507db96d56Sopenharmony_ci    result->len = _mpd_real_size(result->data, big->len);
29517db96d56Sopenharmony_ci    mpd_qresize(result, result->len, status);
29527db96d56Sopenharmony_ci    mpd_setdigits(result);
29537db96d56Sopenharmony_ci    _mpd_cap(result, ctx);
29547db96d56Sopenharmony_ci    return;
29557db96d56Sopenharmony_ci
29567db96d56Sopenharmony_ciinvalid_operation:
29577db96d56Sopenharmony_ci    mpd_seterror(result, MPD_Invalid_operation, status);
29587db96d56Sopenharmony_ci}
29597db96d56Sopenharmony_ci
29607db96d56Sopenharmony_ci/*
29617db96d56Sopenharmony_ci * Rotate the coefficient of 'a' by 'b' digits. 'b' must be an integer with
29627db96d56Sopenharmony_ci * exponent 0.
29637db96d56Sopenharmony_ci */
29647db96d56Sopenharmony_civoid
29657db96d56Sopenharmony_cimpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b,
29667db96d56Sopenharmony_ci            const mpd_context_t *ctx, uint32_t *status)
29677db96d56Sopenharmony_ci{
29687db96d56Sopenharmony_ci    uint32_t workstatus = 0;
29697db96d56Sopenharmony_ci    MPD_NEW_STATIC(tmp,0,0,0,0);
29707db96d56Sopenharmony_ci    MPD_NEW_STATIC(big,0,0,0,0);
29717db96d56Sopenharmony_ci    MPD_NEW_STATIC(small,0,0,0,0);
29727db96d56Sopenharmony_ci    mpd_ssize_t n, lshift, rshift;
29737db96d56Sopenharmony_ci
29747db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
29757db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
29767db96d56Sopenharmony_ci            return;
29777db96d56Sopenharmony_ci        }
29787db96d56Sopenharmony_ci    }
29797db96d56Sopenharmony_ci    if (b->exp != 0 || mpd_isinfinite(b)) {
29807db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
29817db96d56Sopenharmony_ci        return;
29827db96d56Sopenharmony_ci    }
29837db96d56Sopenharmony_ci
29847db96d56Sopenharmony_ci    n = mpd_qget_ssize(b, &workstatus);
29857db96d56Sopenharmony_ci    if (workstatus&MPD_Invalid_operation) {
29867db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
29877db96d56Sopenharmony_ci        return;
29887db96d56Sopenharmony_ci    }
29897db96d56Sopenharmony_ci    if (n > ctx->prec || n < -ctx->prec) {
29907db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
29917db96d56Sopenharmony_ci        return;
29927db96d56Sopenharmony_ci    }
29937db96d56Sopenharmony_ci    if (mpd_isinfinite(a)) {
29947db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
29957db96d56Sopenharmony_ci        return;
29967db96d56Sopenharmony_ci    }
29977db96d56Sopenharmony_ci
29987db96d56Sopenharmony_ci    if (n >= 0) {
29997db96d56Sopenharmony_ci        lshift = n;
30007db96d56Sopenharmony_ci        rshift = ctx->prec-n;
30017db96d56Sopenharmony_ci    }
30027db96d56Sopenharmony_ci    else {
30037db96d56Sopenharmony_ci        lshift = ctx->prec+n;
30047db96d56Sopenharmony_ci        rshift = -n;
30057db96d56Sopenharmony_ci    }
30067db96d56Sopenharmony_ci
30077db96d56Sopenharmony_ci    if (a->digits > ctx->prec) {
30087db96d56Sopenharmony_ci        if (!mpd_qcopy(&tmp, a, status)) {
30097db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Malloc_error, status);
30107db96d56Sopenharmony_ci            goto finish;
30117db96d56Sopenharmony_ci        }
30127db96d56Sopenharmony_ci        _mpd_cap(&tmp, ctx);
30137db96d56Sopenharmony_ci        a = &tmp;
30147db96d56Sopenharmony_ci    }
30157db96d56Sopenharmony_ci
30167db96d56Sopenharmony_ci    if (!mpd_qshiftl(&big, a, lshift, status)) {
30177db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Malloc_error, status);
30187db96d56Sopenharmony_ci        goto finish;
30197db96d56Sopenharmony_ci    }
30207db96d56Sopenharmony_ci    _mpd_cap(&big, ctx);
30217db96d56Sopenharmony_ci
30227db96d56Sopenharmony_ci    if (mpd_qshiftr(&small, a, rshift, status) == MPD_UINT_MAX) {
30237db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Malloc_error, status);
30247db96d56Sopenharmony_ci        goto finish;
30257db96d56Sopenharmony_ci    }
30267db96d56Sopenharmony_ci    _mpd_qadd(result, &big, &small, ctx, status);
30277db96d56Sopenharmony_ci
30287db96d56Sopenharmony_ci
30297db96d56Sopenharmony_cifinish:
30307db96d56Sopenharmony_ci    mpd_del(&tmp);
30317db96d56Sopenharmony_ci    mpd_del(&big);
30327db96d56Sopenharmony_ci    mpd_del(&small);
30337db96d56Sopenharmony_ci}
30347db96d56Sopenharmony_ci
30357db96d56Sopenharmony_ci/*
30367db96d56Sopenharmony_ci * b must be an integer with exponent 0 and in the range +-2*(emax + prec).
30377db96d56Sopenharmony_ci * XXX: In my opinion +-(2*emax + prec) would be more sensible.
30387db96d56Sopenharmony_ci * The result is a with the value of b added to its exponent.
30397db96d56Sopenharmony_ci */
30407db96d56Sopenharmony_civoid
30417db96d56Sopenharmony_cimpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b,
30427db96d56Sopenharmony_ci            const mpd_context_t *ctx, uint32_t *status)
30437db96d56Sopenharmony_ci{
30447db96d56Sopenharmony_ci    uint32_t workstatus = 0;
30457db96d56Sopenharmony_ci    mpd_uint_t n, maxjump;
30467db96d56Sopenharmony_ci#ifndef LEGACY_COMPILER
30477db96d56Sopenharmony_ci    int64_t exp;
30487db96d56Sopenharmony_ci#else
30497db96d56Sopenharmony_ci    mpd_uint_t x;
30507db96d56Sopenharmony_ci    int x_sign, n_sign;
30517db96d56Sopenharmony_ci    mpd_ssize_t exp;
30527db96d56Sopenharmony_ci#endif
30537db96d56Sopenharmony_ci
30547db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
30557db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
30567db96d56Sopenharmony_ci            return;
30577db96d56Sopenharmony_ci        }
30587db96d56Sopenharmony_ci    }
30597db96d56Sopenharmony_ci    if (b->exp != 0 || mpd_isinfinite(b)) {
30607db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
30617db96d56Sopenharmony_ci        return;
30627db96d56Sopenharmony_ci    }
30637db96d56Sopenharmony_ci
30647db96d56Sopenharmony_ci    n = mpd_qabs_uint(b, &workstatus);
30657db96d56Sopenharmony_ci    /* the spec demands this */
30667db96d56Sopenharmony_ci    maxjump = 2 * (mpd_uint_t)(ctx->emax + ctx->prec);
30677db96d56Sopenharmony_ci
30687db96d56Sopenharmony_ci    if (n > maxjump || workstatus&MPD_Invalid_operation) {
30697db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
30707db96d56Sopenharmony_ci        return;
30717db96d56Sopenharmony_ci    }
30727db96d56Sopenharmony_ci    if (mpd_isinfinite(a)) {
30737db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
30747db96d56Sopenharmony_ci        return;
30757db96d56Sopenharmony_ci    }
30767db96d56Sopenharmony_ci
30777db96d56Sopenharmony_ci#ifndef LEGACY_COMPILER
30787db96d56Sopenharmony_ci    exp = a->exp + (int64_t)n * mpd_arith_sign(b);
30797db96d56Sopenharmony_ci    exp = (exp > MPD_EXP_INF) ? MPD_EXP_INF : exp;
30807db96d56Sopenharmony_ci    exp = (exp < MPD_EXP_CLAMP) ? MPD_EXP_CLAMP : exp;
30817db96d56Sopenharmony_ci#else
30827db96d56Sopenharmony_ci    x = (a->exp < 0) ? -a->exp : a->exp;
30837db96d56Sopenharmony_ci    x_sign = (a->exp < 0) ? 1 : 0;
30847db96d56Sopenharmony_ci    n_sign = mpd_isnegative(b) ? 1 : 0;
30857db96d56Sopenharmony_ci
30867db96d56Sopenharmony_ci    if (x_sign == n_sign) {
30877db96d56Sopenharmony_ci        x = x + n;
30887db96d56Sopenharmony_ci        if (x < n) x = MPD_UINT_MAX;
30897db96d56Sopenharmony_ci    }
30907db96d56Sopenharmony_ci    else {
30917db96d56Sopenharmony_ci        x_sign = (x >= n) ? x_sign : n_sign;
30927db96d56Sopenharmony_ci        x = (x >= n) ? x - n : n - x;
30937db96d56Sopenharmony_ci    }
30947db96d56Sopenharmony_ci    if (!x_sign && x > MPD_EXP_INF) x = MPD_EXP_INF;
30957db96d56Sopenharmony_ci    if (x_sign && x > -MPD_EXP_CLAMP) x = -MPD_EXP_CLAMP;
30967db96d56Sopenharmony_ci    exp = x_sign ? -((mpd_ssize_t)x) : (mpd_ssize_t)x;
30977db96d56Sopenharmony_ci#endif
30987db96d56Sopenharmony_ci
30997db96d56Sopenharmony_ci    mpd_qcopy(result, a, status);
31007db96d56Sopenharmony_ci    result->exp = (mpd_ssize_t)exp;
31017db96d56Sopenharmony_ci
31027db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
31037db96d56Sopenharmony_ci}
31047db96d56Sopenharmony_ci
31057db96d56Sopenharmony_ci/*
31067db96d56Sopenharmony_ci * Shift the coefficient by n digits, positive n is a left shift. In the case
31077db96d56Sopenharmony_ci * of a left shift, the result is decapitated to fit the context precision. If
31087db96d56Sopenharmony_ci * you don't want that, use mpd_shiftl().
31097db96d56Sopenharmony_ci */
31107db96d56Sopenharmony_civoid
31117db96d56Sopenharmony_cimpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx,
31127db96d56Sopenharmony_ci            uint32_t *status)
31137db96d56Sopenharmony_ci{
31147db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
31157db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
31167db96d56Sopenharmony_ci            return;
31177db96d56Sopenharmony_ci        }
31187db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
31197db96d56Sopenharmony_ci        return;
31207db96d56Sopenharmony_ci    }
31217db96d56Sopenharmony_ci
31227db96d56Sopenharmony_ci    if (n >= 0 && n <= ctx->prec) {
31237db96d56Sopenharmony_ci        mpd_qshiftl(result, a, n, status);
31247db96d56Sopenharmony_ci        _mpd_cap(result, ctx);
31257db96d56Sopenharmony_ci    }
31267db96d56Sopenharmony_ci    else if (n < 0 && n >= -ctx->prec) {
31277db96d56Sopenharmony_ci        if (!mpd_qcopy(result, a, status)) {
31287db96d56Sopenharmony_ci            return;
31297db96d56Sopenharmony_ci        }
31307db96d56Sopenharmony_ci        _mpd_cap(result, ctx);
31317db96d56Sopenharmony_ci        mpd_qshiftr_inplace(result, -n);
31327db96d56Sopenharmony_ci    }
31337db96d56Sopenharmony_ci    else {
31347db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
31357db96d56Sopenharmony_ci    }
31367db96d56Sopenharmony_ci}
31377db96d56Sopenharmony_ci
31387db96d56Sopenharmony_ci/*
31397db96d56Sopenharmony_ci * Same as mpd_shiftn(), but the shift is specified by the decimal b, which
31407db96d56Sopenharmony_ci * must be an integer with a zero exponent. Infinities remain infinities.
31417db96d56Sopenharmony_ci */
31427db96d56Sopenharmony_civoid
31437db96d56Sopenharmony_cimpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx,
31447db96d56Sopenharmony_ci           uint32_t *status)
31457db96d56Sopenharmony_ci{
31467db96d56Sopenharmony_ci    uint32_t workstatus = 0;
31477db96d56Sopenharmony_ci    mpd_ssize_t n;
31487db96d56Sopenharmony_ci
31497db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
31507db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
31517db96d56Sopenharmony_ci            return;
31527db96d56Sopenharmony_ci        }
31537db96d56Sopenharmony_ci    }
31547db96d56Sopenharmony_ci    if (b->exp != 0 || mpd_isinfinite(b)) {
31557db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
31567db96d56Sopenharmony_ci        return;
31577db96d56Sopenharmony_ci    }
31587db96d56Sopenharmony_ci
31597db96d56Sopenharmony_ci    n = mpd_qget_ssize(b, &workstatus);
31607db96d56Sopenharmony_ci    if (workstatus&MPD_Invalid_operation) {
31617db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
31627db96d56Sopenharmony_ci        return;
31637db96d56Sopenharmony_ci    }
31647db96d56Sopenharmony_ci    if (n > ctx->prec || n < -ctx->prec) {
31657db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
31667db96d56Sopenharmony_ci        return;
31677db96d56Sopenharmony_ci    }
31687db96d56Sopenharmony_ci    if (mpd_isinfinite(a)) {
31697db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
31707db96d56Sopenharmony_ci        return;
31717db96d56Sopenharmony_ci    }
31727db96d56Sopenharmony_ci
31737db96d56Sopenharmony_ci    if (n >= 0) {
31747db96d56Sopenharmony_ci        mpd_qshiftl(result, a, n, status);
31757db96d56Sopenharmony_ci        _mpd_cap(result, ctx);
31767db96d56Sopenharmony_ci    }
31777db96d56Sopenharmony_ci    else {
31787db96d56Sopenharmony_ci        if (!mpd_qcopy(result, a, status)) {
31797db96d56Sopenharmony_ci            return;
31807db96d56Sopenharmony_ci        }
31817db96d56Sopenharmony_ci        _mpd_cap(result, ctx);
31827db96d56Sopenharmony_ci        mpd_qshiftr_inplace(result, -n);
31837db96d56Sopenharmony_ci    }
31847db96d56Sopenharmony_ci}
31857db96d56Sopenharmony_ci
31867db96d56Sopenharmony_ci/* Logical Xor */
31877db96d56Sopenharmony_civoid
31887db96d56Sopenharmony_cimpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b,
31897db96d56Sopenharmony_ci        const mpd_context_t *ctx, uint32_t *status)
31907db96d56Sopenharmony_ci{
31917db96d56Sopenharmony_ci    const mpd_t *big = a, *small = b;
31927db96d56Sopenharmony_ci    mpd_uint_t x, y, z, xbit, ybit;
31937db96d56Sopenharmony_ci    int k, mswdigits;
31947db96d56Sopenharmony_ci    mpd_ssize_t i;
31957db96d56Sopenharmony_ci
31967db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b) ||
31977db96d56Sopenharmony_ci        mpd_isnegative(a) || mpd_isnegative(b) ||
31987db96d56Sopenharmony_ci        a->exp != 0 || b->exp != 0) {
31997db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
32007db96d56Sopenharmony_ci        return;
32017db96d56Sopenharmony_ci    }
32027db96d56Sopenharmony_ci    if (b->digits > a->digits) {
32037db96d56Sopenharmony_ci        big = b;
32047db96d56Sopenharmony_ci        small = a;
32057db96d56Sopenharmony_ci    }
32067db96d56Sopenharmony_ci    if (!mpd_qresize(result, big->len, status)) {
32077db96d56Sopenharmony_ci        return;
32087db96d56Sopenharmony_ci    }
32097db96d56Sopenharmony_ci
32107db96d56Sopenharmony_ci
32117db96d56Sopenharmony_ci    /* full words */
32127db96d56Sopenharmony_ci    for (i = 0; i < small->len-1; i++) {
32137db96d56Sopenharmony_ci        x = small->data[i];
32147db96d56Sopenharmony_ci        y = big->data[i];
32157db96d56Sopenharmony_ci        z = 0;
32167db96d56Sopenharmony_ci        for (k = 0; k < MPD_RDIGITS; k++) {
32177db96d56Sopenharmony_ci            xbit = x % 10;
32187db96d56Sopenharmony_ci            x /= 10;
32197db96d56Sopenharmony_ci            ybit = y % 10;
32207db96d56Sopenharmony_ci            y /= 10;
32217db96d56Sopenharmony_ci            if (xbit > 1 || ybit > 1) {
32227db96d56Sopenharmony_ci                goto invalid_operation;
32237db96d56Sopenharmony_ci            }
32247db96d56Sopenharmony_ci            z += (xbit^ybit) ? mpd_pow10[k] : 0;
32257db96d56Sopenharmony_ci        }
32267db96d56Sopenharmony_ci        result->data[i] = z;
32277db96d56Sopenharmony_ci    }
32287db96d56Sopenharmony_ci    /* most significant word of small */
32297db96d56Sopenharmony_ci    x = small->data[i];
32307db96d56Sopenharmony_ci    y = big->data[i];
32317db96d56Sopenharmony_ci    z = 0;
32327db96d56Sopenharmony_ci    mswdigits = mpd_word_digits(x);
32337db96d56Sopenharmony_ci    for (k = 0; k < mswdigits; k++) {
32347db96d56Sopenharmony_ci        xbit = x % 10;
32357db96d56Sopenharmony_ci        x /= 10;
32367db96d56Sopenharmony_ci        ybit = y % 10;
32377db96d56Sopenharmony_ci        y /= 10;
32387db96d56Sopenharmony_ci        if (xbit > 1 || ybit > 1) {
32397db96d56Sopenharmony_ci            goto invalid_operation;
32407db96d56Sopenharmony_ci        }
32417db96d56Sopenharmony_ci        z += (xbit^ybit) ? mpd_pow10[k] : 0;
32427db96d56Sopenharmony_ci    }
32437db96d56Sopenharmony_ci
32447db96d56Sopenharmony_ci    /* scan for digits > 1 and copy the rest of y */
32457db96d56Sopenharmony_ci    for (; k < MPD_RDIGITS; k++) {
32467db96d56Sopenharmony_ci        ybit = y % 10;
32477db96d56Sopenharmony_ci        y /= 10;
32487db96d56Sopenharmony_ci        if (ybit > 1) {
32497db96d56Sopenharmony_ci            goto invalid_operation;
32507db96d56Sopenharmony_ci        }
32517db96d56Sopenharmony_ci        z += ybit*mpd_pow10[k];
32527db96d56Sopenharmony_ci    }
32537db96d56Sopenharmony_ci    result->data[i++] = z;
32547db96d56Sopenharmony_ci    /* scan for digits > 1 and copy the rest of big */
32557db96d56Sopenharmony_ci    for (; i < big->len; i++) {
32567db96d56Sopenharmony_ci        y = big->data[i];
32577db96d56Sopenharmony_ci        for (k = 0; k < MPD_RDIGITS; k++) {
32587db96d56Sopenharmony_ci            ybit = y % 10;
32597db96d56Sopenharmony_ci            y /= 10;
32607db96d56Sopenharmony_ci            if (ybit > 1) {
32617db96d56Sopenharmony_ci                goto invalid_operation;
32627db96d56Sopenharmony_ci            }
32637db96d56Sopenharmony_ci        }
32647db96d56Sopenharmony_ci        result->data[i] = big->data[i];
32657db96d56Sopenharmony_ci    }
32667db96d56Sopenharmony_ci
32677db96d56Sopenharmony_ci    mpd_clear_flags(result);
32687db96d56Sopenharmony_ci    result->exp = 0;
32697db96d56Sopenharmony_ci    result->len = _mpd_real_size(result->data, big->len);
32707db96d56Sopenharmony_ci    mpd_qresize(result, result->len, status);
32717db96d56Sopenharmony_ci    mpd_setdigits(result);
32727db96d56Sopenharmony_ci    _mpd_cap(result, ctx);
32737db96d56Sopenharmony_ci    return;
32747db96d56Sopenharmony_ci
32757db96d56Sopenharmony_ciinvalid_operation:
32767db96d56Sopenharmony_ci    mpd_seterror(result, MPD_Invalid_operation, status);
32777db96d56Sopenharmony_ci}
32787db96d56Sopenharmony_ci
32797db96d56Sopenharmony_ci
32807db96d56Sopenharmony_ci/******************************************************************************/
32817db96d56Sopenharmony_ci/*                         Arithmetic operations                              */
32827db96d56Sopenharmony_ci/******************************************************************************/
32837db96d56Sopenharmony_ci
32847db96d56Sopenharmony_ci/*
32857db96d56Sopenharmony_ci * The absolute value of a. If a is negative, the result is the same
32867db96d56Sopenharmony_ci * as the result of the minus operation. Otherwise, the result is the
32877db96d56Sopenharmony_ci * result of the plus operation.
32887db96d56Sopenharmony_ci */
32897db96d56Sopenharmony_civoid
32907db96d56Sopenharmony_cimpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
32917db96d56Sopenharmony_ci         uint32_t *status)
32927db96d56Sopenharmony_ci{
32937db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
32947db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
32957db96d56Sopenharmony_ci            return;
32967db96d56Sopenharmony_ci        }
32977db96d56Sopenharmony_ci    }
32987db96d56Sopenharmony_ci
32997db96d56Sopenharmony_ci    if (mpd_isnegative(a)) {
33007db96d56Sopenharmony_ci        mpd_qminus(result, a, ctx, status);
33017db96d56Sopenharmony_ci    }
33027db96d56Sopenharmony_ci    else {
33037db96d56Sopenharmony_ci        mpd_qplus(result, a, ctx, status);
33047db96d56Sopenharmony_ci    }
33057db96d56Sopenharmony_ci}
33067db96d56Sopenharmony_ci
33077db96d56Sopenharmony_cistatic inline void
33087db96d56Sopenharmony_ci_mpd_ptrswap(const mpd_t **a, const mpd_t **b)
33097db96d56Sopenharmony_ci{
33107db96d56Sopenharmony_ci    const mpd_t *t = *a;
33117db96d56Sopenharmony_ci    *a = *b;
33127db96d56Sopenharmony_ci    *b = t;
33137db96d56Sopenharmony_ci}
33147db96d56Sopenharmony_ci
33157db96d56Sopenharmony_ci/* Add or subtract infinities. */
33167db96d56Sopenharmony_cistatic void
33177db96d56Sopenharmony_ci_mpd_qaddsub_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b,
33187db96d56Sopenharmony_ci                 uint32_t *status)
33197db96d56Sopenharmony_ci{
33207db96d56Sopenharmony_ci    if (mpd_isinfinite(a)) {
33217db96d56Sopenharmony_ci        if (mpd_sign(a) != sign_b && mpd_isinfinite(b)) {
33227db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
33237db96d56Sopenharmony_ci        }
33247db96d56Sopenharmony_ci        else {
33257db96d56Sopenharmony_ci            mpd_setspecial(result, mpd_sign(a), MPD_INF);
33267db96d56Sopenharmony_ci        }
33277db96d56Sopenharmony_ci        return;
33287db96d56Sopenharmony_ci    }
33297db96d56Sopenharmony_ci    assert(mpd_isinfinite(b));
33307db96d56Sopenharmony_ci    mpd_setspecial(result, sign_b, MPD_INF);
33317db96d56Sopenharmony_ci}
33327db96d56Sopenharmony_ci
33337db96d56Sopenharmony_ci/* Add or subtract non-special numbers. */
33347db96d56Sopenharmony_cistatic void
33357db96d56Sopenharmony_ci_mpd_qaddsub(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b,
33367db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
33377db96d56Sopenharmony_ci{
33387db96d56Sopenharmony_ci    const mpd_t *big, *small;
33397db96d56Sopenharmony_ci    MPD_NEW_STATIC(big_aligned,0,0,0,0);
33407db96d56Sopenharmony_ci    MPD_NEW_CONST(tiny,0,0,1,1,1,1);
33417db96d56Sopenharmony_ci    mpd_uint_t carry;
33427db96d56Sopenharmony_ci    mpd_ssize_t newsize, shift;
33437db96d56Sopenharmony_ci    mpd_ssize_t exp, i;
33447db96d56Sopenharmony_ci    int swap = 0;
33457db96d56Sopenharmony_ci
33467db96d56Sopenharmony_ci
33477db96d56Sopenharmony_ci    /* compare exponents */
33487db96d56Sopenharmony_ci    big = a; small = b;
33497db96d56Sopenharmony_ci    if (big->exp != small->exp) {
33507db96d56Sopenharmony_ci        if (small->exp > big->exp) {
33517db96d56Sopenharmony_ci            _mpd_ptrswap(&big, &small);
33527db96d56Sopenharmony_ci            swap++;
33537db96d56Sopenharmony_ci        }
33547db96d56Sopenharmony_ci        /* align the coefficients */
33557db96d56Sopenharmony_ci        if (!mpd_iszerocoeff(big)) {
33567db96d56Sopenharmony_ci            exp = big->exp - 1;
33577db96d56Sopenharmony_ci            exp += (big->digits > ctx->prec) ? 0 : big->digits-ctx->prec-1;
33587db96d56Sopenharmony_ci            if (mpd_adjexp(small) < exp) {
33597db96d56Sopenharmony_ci                /*
33607db96d56Sopenharmony_ci                 * Avoid huge shifts by substituting a value for small that is
33617db96d56Sopenharmony_ci                 * guaranteed to produce the same results.
33627db96d56Sopenharmony_ci                 *
33637db96d56Sopenharmony_ci                 * adjexp(small) < exp if and only if:
33647db96d56Sopenharmony_ci                 *
33657db96d56Sopenharmony_ci                 *   bdigits <= prec AND
33667db96d56Sopenharmony_ci                 *   bdigits+shift >= prec+2+sdigits AND
33677db96d56Sopenharmony_ci                 *   exp = bexp+bdigits-prec-2
33687db96d56Sopenharmony_ci                 *
33697db96d56Sopenharmony_ci                 *     1234567000000000  ->  bdigits + shift
33707db96d56Sopenharmony_ci                 *     ----------XX1234  ->  sdigits
33717db96d56Sopenharmony_ci                 *     ----------X1      ->  tiny-digits
33727db96d56Sopenharmony_ci                 *     |- prec -|
33737db96d56Sopenharmony_ci                 *
33747db96d56Sopenharmony_ci                 *      OR
33757db96d56Sopenharmony_ci                 *
33767db96d56Sopenharmony_ci                 *   bdigits > prec AND
33777db96d56Sopenharmony_ci                 *   shift > sdigits AND
33787db96d56Sopenharmony_ci                 *   exp = bexp-1
33797db96d56Sopenharmony_ci                 *
33807db96d56Sopenharmony_ci                 *     1234567892100000  ->  bdigits + shift
33817db96d56Sopenharmony_ci                 *     ----------XX1234  ->  sdigits
33827db96d56Sopenharmony_ci                 *     ----------X1      ->  tiny-digits
33837db96d56Sopenharmony_ci                 *     |- prec -|
33847db96d56Sopenharmony_ci                 *
33857db96d56Sopenharmony_ci                 * If tiny is zero, adding or subtracting is a no-op.
33867db96d56Sopenharmony_ci                 * Otherwise, adding tiny generates a non-zero digit either
33877db96d56Sopenharmony_ci                 * below the rounding digit or the least significant digit
33887db96d56Sopenharmony_ci                 * of big. When subtracting, tiny is in the same position as
33897db96d56Sopenharmony_ci                 * the carry that would be generated by subtracting sdigits.
33907db96d56Sopenharmony_ci                 */
33917db96d56Sopenharmony_ci                mpd_copy_flags(&tiny, small);
33927db96d56Sopenharmony_ci                tiny.exp = exp;
33937db96d56Sopenharmony_ci                tiny.digits = 1;
33947db96d56Sopenharmony_ci                tiny.len = 1;
33957db96d56Sopenharmony_ci                tiny.data[0] = mpd_iszerocoeff(small) ? 0 : 1;
33967db96d56Sopenharmony_ci                small = &tiny;
33977db96d56Sopenharmony_ci            }
33987db96d56Sopenharmony_ci            /* This cannot wrap: the difference is positive and <= maxprec */
33997db96d56Sopenharmony_ci            shift = big->exp - small->exp;
34007db96d56Sopenharmony_ci            if (!mpd_qshiftl(&big_aligned, big, shift, status)) {
34017db96d56Sopenharmony_ci                mpd_seterror(result, MPD_Malloc_error, status);
34027db96d56Sopenharmony_ci                goto finish;
34037db96d56Sopenharmony_ci            }
34047db96d56Sopenharmony_ci            big = &big_aligned;
34057db96d56Sopenharmony_ci        }
34067db96d56Sopenharmony_ci    }
34077db96d56Sopenharmony_ci    result->exp = small->exp;
34087db96d56Sopenharmony_ci
34097db96d56Sopenharmony_ci
34107db96d56Sopenharmony_ci    /* compare length of coefficients */
34117db96d56Sopenharmony_ci    if (big->len < small->len) {
34127db96d56Sopenharmony_ci        _mpd_ptrswap(&big, &small);
34137db96d56Sopenharmony_ci        swap++;
34147db96d56Sopenharmony_ci    }
34157db96d56Sopenharmony_ci
34167db96d56Sopenharmony_ci    newsize = big->len;
34177db96d56Sopenharmony_ci    if (!mpd_qresize(result, newsize, status)) {
34187db96d56Sopenharmony_ci        goto finish;
34197db96d56Sopenharmony_ci    }
34207db96d56Sopenharmony_ci
34217db96d56Sopenharmony_ci    if (mpd_sign(a) == sign_b) {
34227db96d56Sopenharmony_ci
34237db96d56Sopenharmony_ci        carry = _mpd_baseadd(result->data, big->data, small->data,
34247db96d56Sopenharmony_ci                             big->len, small->len);
34257db96d56Sopenharmony_ci
34267db96d56Sopenharmony_ci        if (carry) {
34277db96d56Sopenharmony_ci            newsize = big->len + 1;
34287db96d56Sopenharmony_ci            if (!mpd_qresize(result, newsize, status)) {
34297db96d56Sopenharmony_ci                goto finish;
34307db96d56Sopenharmony_ci            }
34317db96d56Sopenharmony_ci            result->data[newsize-1] = carry;
34327db96d56Sopenharmony_ci        }
34337db96d56Sopenharmony_ci
34347db96d56Sopenharmony_ci        result->len = newsize;
34357db96d56Sopenharmony_ci        mpd_set_flags(result, sign_b);
34367db96d56Sopenharmony_ci    }
34377db96d56Sopenharmony_ci    else {
34387db96d56Sopenharmony_ci        if (big->len == small->len) {
34397db96d56Sopenharmony_ci            for (i=big->len-1; i >= 0; --i) {
34407db96d56Sopenharmony_ci                if (big->data[i] != small->data[i]) {
34417db96d56Sopenharmony_ci                    if (big->data[i] < small->data[i]) {
34427db96d56Sopenharmony_ci                        _mpd_ptrswap(&big, &small);
34437db96d56Sopenharmony_ci                        swap++;
34447db96d56Sopenharmony_ci                    }
34457db96d56Sopenharmony_ci                    break;
34467db96d56Sopenharmony_ci                }
34477db96d56Sopenharmony_ci            }
34487db96d56Sopenharmony_ci        }
34497db96d56Sopenharmony_ci
34507db96d56Sopenharmony_ci        _mpd_basesub(result->data, big->data, small->data,
34517db96d56Sopenharmony_ci                     big->len, small->len);
34527db96d56Sopenharmony_ci        newsize = _mpd_real_size(result->data, big->len);
34537db96d56Sopenharmony_ci        /* resize to smaller cannot fail */
34547db96d56Sopenharmony_ci        (void)mpd_qresize(result, newsize, status);
34557db96d56Sopenharmony_ci
34567db96d56Sopenharmony_ci        result->len = newsize;
34577db96d56Sopenharmony_ci        sign_b = (swap & 1) ? sign_b : mpd_sign(a);
34587db96d56Sopenharmony_ci        mpd_set_flags(result, sign_b);
34597db96d56Sopenharmony_ci
34607db96d56Sopenharmony_ci        if (mpd_iszerocoeff(result)) {
34617db96d56Sopenharmony_ci            mpd_set_positive(result);
34627db96d56Sopenharmony_ci            if (ctx->round == MPD_ROUND_FLOOR) {
34637db96d56Sopenharmony_ci                mpd_set_negative(result);
34647db96d56Sopenharmony_ci            }
34657db96d56Sopenharmony_ci        }
34667db96d56Sopenharmony_ci    }
34677db96d56Sopenharmony_ci
34687db96d56Sopenharmony_ci    mpd_setdigits(result);
34697db96d56Sopenharmony_ci
34707db96d56Sopenharmony_cifinish:
34717db96d56Sopenharmony_ci    mpd_del(&big_aligned);
34727db96d56Sopenharmony_ci}
34737db96d56Sopenharmony_ci
34747db96d56Sopenharmony_ci/* Add a and b. No specials, no finalizing. */
34757db96d56Sopenharmony_cistatic void
34767db96d56Sopenharmony_ci_mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b,
34777db96d56Sopenharmony_ci          const mpd_context_t *ctx, uint32_t *status)
34787db96d56Sopenharmony_ci{
34797db96d56Sopenharmony_ci    _mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status);
34807db96d56Sopenharmony_ci}
34817db96d56Sopenharmony_ci
34827db96d56Sopenharmony_ci/* Subtract b from a. No specials, no finalizing. */
34837db96d56Sopenharmony_cistatic void
34847db96d56Sopenharmony_ci_mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b,
34857db96d56Sopenharmony_ci          const mpd_context_t *ctx, uint32_t *status)
34867db96d56Sopenharmony_ci{
34877db96d56Sopenharmony_ci     _mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status);
34887db96d56Sopenharmony_ci}
34897db96d56Sopenharmony_ci
34907db96d56Sopenharmony_ci/* Add a and b. */
34917db96d56Sopenharmony_civoid
34927db96d56Sopenharmony_cimpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b,
34937db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
34947db96d56Sopenharmony_ci{
34957db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
34967db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
34977db96d56Sopenharmony_ci            return;
34987db96d56Sopenharmony_ci        }
34997db96d56Sopenharmony_ci        _mpd_qaddsub_inf(result, a, b, mpd_sign(b), status);
35007db96d56Sopenharmony_ci        return;
35017db96d56Sopenharmony_ci    }
35027db96d56Sopenharmony_ci
35037db96d56Sopenharmony_ci    _mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status);
35047db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
35057db96d56Sopenharmony_ci}
35067db96d56Sopenharmony_ci
35077db96d56Sopenharmony_ci/* Add a and b. Set NaN/Invalid_operation if the result is inexact. */
35087db96d56Sopenharmony_cistatic void
35097db96d56Sopenharmony_ci_mpd_qadd_exact(mpd_t *result, const mpd_t *a, const mpd_t *b,
35107db96d56Sopenharmony_ci                const mpd_context_t *ctx, uint32_t *status)
35117db96d56Sopenharmony_ci{
35127db96d56Sopenharmony_ci    uint32_t workstatus = 0;
35137db96d56Sopenharmony_ci
35147db96d56Sopenharmony_ci    mpd_qadd(result, a, b, ctx, &workstatus);
35157db96d56Sopenharmony_ci    *status |= workstatus;
35167db96d56Sopenharmony_ci    if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
35177db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
35187db96d56Sopenharmony_ci    }
35197db96d56Sopenharmony_ci}
35207db96d56Sopenharmony_ci
35217db96d56Sopenharmony_ci/* Subtract b from a. */
35227db96d56Sopenharmony_civoid
35237db96d56Sopenharmony_cimpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b,
35247db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
35257db96d56Sopenharmony_ci{
35267db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
35277db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
35287db96d56Sopenharmony_ci            return;
35297db96d56Sopenharmony_ci        }
35307db96d56Sopenharmony_ci        _mpd_qaddsub_inf(result, a, b, !mpd_sign(b), status);
35317db96d56Sopenharmony_ci        return;
35327db96d56Sopenharmony_ci    }
35337db96d56Sopenharmony_ci
35347db96d56Sopenharmony_ci    _mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status);
35357db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
35367db96d56Sopenharmony_ci}
35377db96d56Sopenharmony_ci
35387db96d56Sopenharmony_ci/* Subtract b from a. Set NaN/Invalid_operation if the result is inexact. */
35397db96d56Sopenharmony_cistatic void
35407db96d56Sopenharmony_ci_mpd_qsub_exact(mpd_t *result, const mpd_t *a, const mpd_t *b,
35417db96d56Sopenharmony_ci                const mpd_context_t *ctx, uint32_t *status)
35427db96d56Sopenharmony_ci{
35437db96d56Sopenharmony_ci    uint32_t workstatus = 0;
35447db96d56Sopenharmony_ci
35457db96d56Sopenharmony_ci    mpd_qsub(result, a, b, ctx, &workstatus);
35467db96d56Sopenharmony_ci    *status |= workstatus;
35477db96d56Sopenharmony_ci    if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
35487db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
35497db96d56Sopenharmony_ci    }
35507db96d56Sopenharmony_ci}
35517db96d56Sopenharmony_ci
35527db96d56Sopenharmony_ci/* Add decimal and mpd_ssize_t. */
35537db96d56Sopenharmony_civoid
35547db96d56Sopenharmony_cimpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b,
35557db96d56Sopenharmony_ci               const mpd_context_t *ctx, uint32_t *status)
35567db96d56Sopenharmony_ci{
35577db96d56Sopenharmony_ci    mpd_context_t maxcontext;
35587db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
35597db96d56Sopenharmony_ci
35607db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
35617db96d56Sopenharmony_ci    mpd_qsset_ssize(&bb, b, &maxcontext, status);
35627db96d56Sopenharmony_ci    mpd_qadd(result, a, &bb, ctx, status);
35637db96d56Sopenharmony_ci    mpd_del(&bb);
35647db96d56Sopenharmony_ci}
35657db96d56Sopenharmony_ci
35667db96d56Sopenharmony_ci/* Add decimal and mpd_uint_t. */
35677db96d56Sopenharmony_civoid
35687db96d56Sopenharmony_cimpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b,
35697db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
35707db96d56Sopenharmony_ci{
35717db96d56Sopenharmony_ci    mpd_context_t maxcontext;
35727db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
35737db96d56Sopenharmony_ci
35747db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
35757db96d56Sopenharmony_ci    mpd_qsset_uint(&bb, b, &maxcontext, status);
35767db96d56Sopenharmony_ci    mpd_qadd(result, a, &bb, ctx, status);
35777db96d56Sopenharmony_ci    mpd_del(&bb);
35787db96d56Sopenharmony_ci}
35797db96d56Sopenharmony_ci
35807db96d56Sopenharmony_ci/* Subtract mpd_ssize_t from decimal. */
35817db96d56Sopenharmony_civoid
35827db96d56Sopenharmony_cimpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b,
35837db96d56Sopenharmony_ci               const mpd_context_t *ctx, uint32_t *status)
35847db96d56Sopenharmony_ci{
35857db96d56Sopenharmony_ci    mpd_context_t maxcontext;
35867db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
35877db96d56Sopenharmony_ci
35887db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
35897db96d56Sopenharmony_ci    mpd_qsset_ssize(&bb, b, &maxcontext, status);
35907db96d56Sopenharmony_ci    mpd_qsub(result, a, &bb, ctx, status);
35917db96d56Sopenharmony_ci    mpd_del(&bb);
35927db96d56Sopenharmony_ci}
35937db96d56Sopenharmony_ci
35947db96d56Sopenharmony_ci/* Subtract mpd_uint_t from decimal. */
35957db96d56Sopenharmony_civoid
35967db96d56Sopenharmony_cimpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b,
35977db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
35987db96d56Sopenharmony_ci{
35997db96d56Sopenharmony_ci    mpd_context_t maxcontext;
36007db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
36017db96d56Sopenharmony_ci
36027db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
36037db96d56Sopenharmony_ci    mpd_qsset_uint(&bb, b, &maxcontext, status);
36047db96d56Sopenharmony_ci    mpd_qsub(result, a, &bb, ctx, status);
36057db96d56Sopenharmony_ci    mpd_del(&bb);
36067db96d56Sopenharmony_ci}
36077db96d56Sopenharmony_ci
36087db96d56Sopenharmony_ci/* Add decimal and int32_t. */
36097db96d56Sopenharmony_civoid
36107db96d56Sopenharmony_cimpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b,
36117db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36127db96d56Sopenharmony_ci{
36137db96d56Sopenharmony_ci    mpd_qadd_ssize(result, a, b, ctx, status);
36147db96d56Sopenharmony_ci}
36157db96d56Sopenharmony_ci
36167db96d56Sopenharmony_ci/* Add decimal and uint32_t. */
36177db96d56Sopenharmony_civoid
36187db96d56Sopenharmony_cimpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b,
36197db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36207db96d56Sopenharmony_ci{
36217db96d56Sopenharmony_ci    mpd_qadd_uint(result, a, b, ctx, status);
36227db96d56Sopenharmony_ci}
36237db96d56Sopenharmony_ci
36247db96d56Sopenharmony_ci#ifdef CONFIG_64
36257db96d56Sopenharmony_ci/* Add decimal and int64_t. */
36267db96d56Sopenharmony_civoid
36277db96d56Sopenharmony_cimpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b,
36287db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36297db96d56Sopenharmony_ci{
36307db96d56Sopenharmony_ci    mpd_qadd_ssize(result, a, b, ctx, status);
36317db96d56Sopenharmony_ci}
36327db96d56Sopenharmony_ci
36337db96d56Sopenharmony_ci/* Add decimal and uint64_t. */
36347db96d56Sopenharmony_civoid
36357db96d56Sopenharmony_cimpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b,
36367db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36377db96d56Sopenharmony_ci{
36387db96d56Sopenharmony_ci    mpd_qadd_uint(result, a, b, ctx, status);
36397db96d56Sopenharmony_ci}
36407db96d56Sopenharmony_ci#elif !defined(LEGACY_COMPILER)
36417db96d56Sopenharmony_ci/* Add decimal and int64_t. */
36427db96d56Sopenharmony_civoid
36437db96d56Sopenharmony_cimpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b,
36447db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36457db96d56Sopenharmony_ci{
36467db96d56Sopenharmony_ci    mpd_context_t maxcontext;
36477db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
36487db96d56Sopenharmony_ci
36497db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
36507db96d56Sopenharmony_ci    mpd_qset_i64(&bb, b, &maxcontext, status);
36517db96d56Sopenharmony_ci    mpd_qadd(result, a, &bb, ctx, status);
36527db96d56Sopenharmony_ci    mpd_del(&bb);
36537db96d56Sopenharmony_ci}
36547db96d56Sopenharmony_ci
36557db96d56Sopenharmony_ci/* Add decimal and uint64_t. */
36567db96d56Sopenharmony_civoid
36577db96d56Sopenharmony_cimpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b,
36587db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36597db96d56Sopenharmony_ci{
36607db96d56Sopenharmony_ci    mpd_context_t maxcontext;
36617db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
36627db96d56Sopenharmony_ci
36637db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
36647db96d56Sopenharmony_ci    mpd_qset_u64(&bb, b, &maxcontext, status);
36657db96d56Sopenharmony_ci    mpd_qadd(result, a, &bb, ctx, status);
36667db96d56Sopenharmony_ci    mpd_del(&bb);
36677db96d56Sopenharmony_ci}
36687db96d56Sopenharmony_ci#endif
36697db96d56Sopenharmony_ci
36707db96d56Sopenharmony_ci/* Subtract int32_t from decimal. */
36717db96d56Sopenharmony_civoid
36727db96d56Sopenharmony_cimpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b,
36737db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36747db96d56Sopenharmony_ci{
36757db96d56Sopenharmony_ci    mpd_qsub_ssize(result, a, b, ctx, status);
36767db96d56Sopenharmony_ci}
36777db96d56Sopenharmony_ci
36787db96d56Sopenharmony_ci/* Subtract uint32_t from decimal. */
36797db96d56Sopenharmony_civoid
36807db96d56Sopenharmony_cimpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b,
36817db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36827db96d56Sopenharmony_ci{
36837db96d56Sopenharmony_ci    mpd_qsub_uint(result, a, b, ctx, status);
36847db96d56Sopenharmony_ci}
36857db96d56Sopenharmony_ci
36867db96d56Sopenharmony_ci#ifdef CONFIG_64
36877db96d56Sopenharmony_ci/* Subtract int64_t from decimal. */
36887db96d56Sopenharmony_civoid
36897db96d56Sopenharmony_cimpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b,
36907db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36917db96d56Sopenharmony_ci{
36927db96d56Sopenharmony_ci    mpd_qsub_ssize(result, a, b, ctx, status);
36937db96d56Sopenharmony_ci}
36947db96d56Sopenharmony_ci
36957db96d56Sopenharmony_ci/* Subtract uint64_t from decimal. */
36967db96d56Sopenharmony_civoid
36977db96d56Sopenharmony_cimpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b,
36987db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
36997db96d56Sopenharmony_ci{
37007db96d56Sopenharmony_ci    mpd_qsub_uint(result, a, b, ctx, status);
37017db96d56Sopenharmony_ci}
37027db96d56Sopenharmony_ci#elif !defined(LEGACY_COMPILER)
37037db96d56Sopenharmony_ci/* Subtract int64_t from decimal. */
37047db96d56Sopenharmony_civoid
37057db96d56Sopenharmony_cimpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b,
37067db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
37077db96d56Sopenharmony_ci{
37087db96d56Sopenharmony_ci    mpd_context_t maxcontext;
37097db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
37107db96d56Sopenharmony_ci
37117db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
37127db96d56Sopenharmony_ci    mpd_qset_i64(&bb, b, &maxcontext, status);
37137db96d56Sopenharmony_ci    mpd_qsub(result, a, &bb, ctx, status);
37147db96d56Sopenharmony_ci    mpd_del(&bb);
37157db96d56Sopenharmony_ci}
37167db96d56Sopenharmony_ci
37177db96d56Sopenharmony_ci/* Subtract uint64_t from decimal. */
37187db96d56Sopenharmony_civoid
37197db96d56Sopenharmony_cimpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b,
37207db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
37217db96d56Sopenharmony_ci{
37227db96d56Sopenharmony_ci    mpd_context_t maxcontext;
37237db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
37247db96d56Sopenharmony_ci
37257db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
37267db96d56Sopenharmony_ci    mpd_qset_u64(&bb, b, &maxcontext, status);
37277db96d56Sopenharmony_ci    mpd_qsub(result, a, &bb, ctx, status);
37287db96d56Sopenharmony_ci    mpd_del(&bb);
37297db96d56Sopenharmony_ci}
37307db96d56Sopenharmony_ci#endif
37317db96d56Sopenharmony_ci
37327db96d56Sopenharmony_ci
37337db96d56Sopenharmony_ci/* Divide infinities. */
37347db96d56Sopenharmony_cistatic void
37357db96d56Sopenharmony_ci_mpd_qdiv_inf(mpd_t *result, const mpd_t *a, const mpd_t *b,
37367db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
37377db96d56Sopenharmony_ci{
37387db96d56Sopenharmony_ci    if (mpd_isinfinite(a)) {
37397db96d56Sopenharmony_ci        if (mpd_isinfinite(b)) {
37407db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
37417db96d56Sopenharmony_ci            return;
37427db96d56Sopenharmony_ci        }
37437db96d56Sopenharmony_ci        mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
37447db96d56Sopenharmony_ci        return;
37457db96d56Sopenharmony_ci    }
37467db96d56Sopenharmony_ci    assert(mpd_isinfinite(b));
37477db96d56Sopenharmony_ci    _settriple(result, mpd_sign(a)^mpd_sign(b), 0, mpd_etiny(ctx));
37487db96d56Sopenharmony_ci    *status |= MPD_Clamped;
37497db96d56Sopenharmony_ci}
37507db96d56Sopenharmony_ci
37517db96d56Sopenharmony_cienum {NO_IDEAL_EXP, SET_IDEAL_EXP};
37527db96d56Sopenharmony_ci/* Divide a by b. */
37537db96d56Sopenharmony_cistatic void
37547db96d56Sopenharmony_ci_mpd_qdiv(int action, mpd_t *q, const mpd_t *a, const mpd_t *b,
37557db96d56Sopenharmony_ci          const mpd_context_t *ctx, uint32_t *status)
37567db96d56Sopenharmony_ci{
37577db96d56Sopenharmony_ci    MPD_NEW_STATIC(aligned,0,0,0,0);
37587db96d56Sopenharmony_ci    mpd_uint_t ld;
37597db96d56Sopenharmony_ci    mpd_ssize_t shift, exp, tz;
37607db96d56Sopenharmony_ci    mpd_ssize_t newsize;
37617db96d56Sopenharmony_ci    mpd_ssize_t ideal_exp;
37627db96d56Sopenharmony_ci    mpd_uint_t rem;
37637db96d56Sopenharmony_ci    uint8_t sign_a = mpd_sign(a);
37647db96d56Sopenharmony_ci    uint8_t sign_b = mpd_sign(b);
37657db96d56Sopenharmony_ci
37667db96d56Sopenharmony_ci
37677db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
37687db96d56Sopenharmony_ci        if (mpd_qcheck_nans(q, a, b, ctx, status)) {
37697db96d56Sopenharmony_ci            return;
37707db96d56Sopenharmony_ci        }
37717db96d56Sopenharmony_ci        _mpd_qdiv_inf(q, a, b, ctx, status);
37727db96d56Sopenharmony_ci        return;
37737db96d56Sopenharmony_ci    }
37747db96d56Sopenharmony_ci    if (mpd_iszerocoeff(b)) {
37757db96d56Sopenharmony_ci        if (mpd_iszerocoeff(a)) {
37767db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Division_undefined, status);
37777db96d56Sopenharmony_ci        }
37787db96d56Sopenharmony_ci        else {
37797db96d56Sopenharmony_ci            mpd_setspecial(q, sign_a^sign_b, MPD_INF);
37807db96d56Sopenharmony_ci            *status |= MPD_Division_by_zero;
37817db96d56Sopenharmony_ci        }
37827db96d56Sopenharmony_ci        return;
37837db96d56Sopenharmony_ci    }
37847db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
37857db96d56Sopenharmony_ci        exp = a->exp - b->exp;
37867db96d56Sopenharmony_ci        _settriple(q, sign_a^sign_b, 0, exp);
37877db96d56Sopenharmony_ci        mpd_qfinalize(q, ctx, status);
37887db96d56Sopenharmony_ci        return;
37897db96d56Sopenharmony_ci    }
37907db96d56Sopenharmony_ci
37917db96d56Sopenharmony_ci    shift = (b->digits - a->digits) + ctx->prec + 1;
37927db96d56Sopenharmony_ci    ideal_exp = a->exp - b->exp;
37937db96d56Sopenharmony_ci    exp = ideal_exp - shift;
37947db96d56Sopenharmony_ci    if (shift > 0) {
37957db96d56Sopenharmony_ci        if (!mpd_qshiftl(&aligned, a, shift, status)) {
37967db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Malloc_error, status);
37977db96d56Sopenharmony_ci            goto finish;
37987db96d56Sopenharmony_ci        }
37997db96d56Sopenharmony_ci        a = &aligned;
38007db96d56Sopenharmony_ci    }
38017db96d56Sopenharmony_ci    else if (shift < 0) {
38027db96d56Sopenharmony_ci        shift = -shift;
38037db96d56Sopenharmony_ci        if (!mpd_qshiftl(&aligned, b, shift, status)) {
38047db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Malloc_error, status);
38057db96d56Sopenharmony_ci            goto finish;
38067db96d56Sopenharmony_ci        }
38077db96d56Sopenharmony_ci        b = &aligned;
38087db96d56Sopenharmony_ci    }
38097db96d56Sopenharmony_ci
38107db96d56Sopenharmony_ci
38117db96d56Sopenharmony_ci    newsize = a->len - b->len + 1;
38127db96d56Sopenharmony_ci    if ((q != b && q != a) || (q == b && newsize > b->len)) {
38137db96d56Sopenharmony_ci        if (!mpd_qresize(q, newsize, status)) {
38147db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Malloc_error, status);
38157db96d56Sopenharmony_ci            goto finish;
38167db96d56Sopenharmony_ci        }
38177db96d56Sopenharmony_ci    }
38187db96d56Sopenharmony_ci
38197db96d56Sopenharmony_ci
38207db96d56Sopenharmony_ci    if (b->len == 1) {
38217db96d56Sopenharmony_ci        rem = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]);
38227db96d56Sopenharmony_ci    }
38237db96d56Sopenharmony_ci    else if (b->len <= MPD_NEWTONDIV_CUTOFF) {
38247db96d56Sopenharmony_ci        int ret = _mpd_basedivmod(q->data, NULL, a->data, b->data,
38257db96d56Sopenharmony_ci                                  a->len, b->len);
38267db96d56Sopenharmony_ci        if (ret < 0) {
38277db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Malloc_error, status);
38287db96d56Sopenharmony_ci            goto finish;
38297db96d56Sopenharmony_ci        }
38307db96d56Sopenharmony_ci        rem = ret;
38317db96d56Sopenharmony_ci    }
38327db96d56Sopenharmony_ci    else {
38337db96d56Sopenharmony_ci        MPD_NEW_STATIC(r,0,0,0,0);
38347db96d56Sopenharmony_ci        _mpd_base_ndivmod(q, &r, a, b, status);
38357db96d56Sopenharmony_ci        if (mpd_isspecial(q) || mpd_isspecial(&r)) {
38367db96d56Sopenharmony_ci            mpd_setspecial(q, MPD_POS, MPD_NAN);
38377db96d56Sopenharmony_ci            mpd_del(&r);
38387db96d56Sopenharmony_ci            goto finish;
38397db96d56Sopenharmony_ci        }
38407db96d56Sopenharmony_ci        rem = !mpd_iszerocoeff(&r);
38417db96d56Sopenharmony_ci        mpd_del(&r);
38427db96d56Sopenharmony_ci        newsize = q->len;
38437db96d56Sopenharmony_ci    }
38447db96d56Sopenharmony_ci
38457db96d56Sopenharmony_ci    newsize = _mpd_real_size(q->data, newsize);
38467db96d56Sopenharmony_ci    /* resize to smaller cannot fail */
38477db96d56Sopenharmony_ci    mpd_qresize(q, newsize, status);
38487db96d56Sopenharmony_ci    mpd_set_flags(q, sign_a^sign_b);
38497db96d56Sopenharmony_ci    q->len = newsize;
38507db96d56Sopenharmony_ci    mpd_setdigits(q);
38517db96d56Sopenharmony_ci
38527db96d56Sopenharmony_ci    shift = ideal_exp - exp;
38537db96d56Sopenharmony_ci    if (rem) {
38547db96d56Sopenharmony_ci        ld = mpd_lsd(q->data[0]);
38557db96d56Sopenharmony_ci        if (ld == 0 || ld == 5) {
38567db96d56Sopenharmony_ci            q->data[0] += 1;
38577db96d56Sopenharmony_ci        }
38587db96d56Sopenharmony_ci    }
38597db96d56Sopenharmony_ci    else if (action == SET_IDEAL_EXP && shift > 0) {
38607db96d56Sopenharmony_ci        tz = mpd_trail_zeros(q);
38617db96d56Sopenharmony_ci        shift = (tz > shift) ? shift : tz;
38627db96d56Sopenharmony_ci        mpd_qshiftr_inplace(q, shift);
38637db96d56Sopenharmony_ci        exp += shift;
38647db96d56Sopenharmony_ci    }
38657db96d56Sopenharmony_ci
38667db96d56Sopenharmony_ci    q->exp = exp;
38677db96d56Sopenharmony_ci
38687db96d56Sopenharmony_ci
38697db96d56Sopenharmony_cifinish:
38707db96d56Sopenharmony_ci    mpd_del(&aligned);
38717db96d56Sopenharmony_ci    mpd_qfinalize(q, ctx, status);
38727db96d56Sopenharmony_ci}
38737db96d56Sopenharmony_ci
38747db96d56Sopenharmony_ci/* Divide a by b. */
38757db96d56Sopenharmony_civoid
38767db96d56Sopenharmony_cimpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b,
38777db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
38787db96d56Sopenharmony_ci{
38797db96d56Sopenharmony_ci    MPD_NEW_STATIC(aa,0,0,0,0);
38807db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
38817db96d56Sopenharmony_ci    uint32_t xstatus = 0;
38827db96d56Sopenharmony_ci
38837db96d56Sopenharmony_ci    if (q == a) {
38847db96d56Sopenharmony_ci        if (!mpd_qcopy(&aa, a, status)) {
38857db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Malloc_error, status);
38867db96d56Sopenharmony_ci            goto out;
38877db96d56Sopenharmony_ci        }
38887db96d56Sopenharmony_ci        a = &aa;
38897db96d56Sopenharmony_ci    }
38907db96d56Sopenharmony_ci
38917db96d56Sopenharmony_ci    if (q == b) {
38927db96d56Sopenharmony_ci        if (!mpd_qcopy(&bb, b, status)) {
38937db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Malloc_error, status);
38947db96d56Sopenharmony_ci            goto out;
38957db96d56Sopenharmony_ci        }
38967db96d56Sopenharmony_ci        b = &bb;
38977db96d56Sopenharmony_ci    }
38987db96d56Sopenharmony_ci
38997db96d56Sopenharmony_ci    _mpd_qdiv(SET_IDEAL_EXP, q, a, b, ctx, &xstatus);
39007db96d56Sopenharmony_ci
39017db96d56Sopenharmony_ci    if (xstatus & (MPD_Malloc_error|MPD_Division_impossible)) {
39027db96d56Sopenharmony_ci        /* Inexact quotients (the usual case) fill the entire context precision,
39037db96d56Sopenharmony_ci         * which can lead to the above errors for very high precisions. Retry
39047db96d56Sopenharmony_ci         * the operation with a lower precision in case the result is exact.
39057db96d56Sopenharmony_ci         *
39067db96d56Sopenharmony_ci         * We need an upper bound for the number of digits of a_coeff / b_coeff
39077db96d56Sopenharmony_ci         * when the result is exact.  If a_coeff' * 1 / b_coeff' is in lowest
39087db96d56Sopenharmony_ci         * terms, then maxdigits(a_coeff') + maxdigits(1 / b_coeff') is a suitable
39097db96d56Sopenharmony_ci         * bound.
39107db96d56Sopenharmony_ci         *
39117db96d56Sopenharmony_ci         * 1 / b_coeff' is exact iff b_coeff' exclusively has prime factors 2 or 5.
39127db96d56Sopenharmony_ci         * The largest amount of digits is generated if b_coeff' is a power of 2 or
39137db96d56Sopenharmony_ci         * a power of 5 and is less than or equal to log5(b_coeff') <= log2(b_coeff').
39147db96d56Sopenharmony_ci         *
39157db96d56Sopenharmony_ci         * We arrive at a total upper bound:
39167db96d56Sopenharmony_ci         *
39177db96d56Sopenharmony_ci         *   maxdigits(a_coeff') + maxdigits(1 / b_coeff') <=
39187db96d56Sopenharmony_ci         *   log10(a_coeff) + log2(b_coeff) =
39197db96d56Sopenharmony_ci         *   log10(a_coeff) + log10(b_coeff) / log10(2) <=
39207db96d56Sopenharmony_ci         *   a->digits + b->digits * 4;
39217db96d56Sopenharmony_ci         */
39227db96d56Sopenharmony_ci        mpd_context_t workctx = *ctx;
39237db96d56Sopenharmony_ci        uint32_t ystatus = 0;
39247db96d56Sopenharmony_ci
39257db96d56Sopenharmony_ci        workctx.prec = a->digits + b->digits * 4;
39267db96d56Sopenharmony_ci        if (workctx.prec >= ctx->prec) {
39277db96d56Sopenharmony_ci            *status |= (xstatus&MPD_Errors);
39287db96d56Sopenharmony_ci            goto out;  /* No point in retrying, keep the original error. */
39297db96d56Sopenharmony_ci        }
39307db96d56Sopenharmony_ci
39317db96d56Sopenharmony_ci        _mpd_qdiv(SET_IDEAL_EXP, q, a, b, &workctx, &ystatus);
39327db96d56Sopenharmony_ci        if (ystatus != 0) {
39337db96d56Sopenharmony_ci            ystatus = *status | ((ystatus|xstatus)&MPD_Errors);
39347db96d56Sopenharmony_ci            mpd_seterror(q, ystatus, status);
39357db96d56Sopenharmony_ci        }
39367db96d56Sopenharmony_ci    }
39377db96d56Sopenharmony_ci    else {
39387db96d56Sopenharmony_ci        *status |= xstatus;
39397db96d56Sopenharmony_ci    }
39407db96d56Sopenharmony_ci
39417db96d56Sopenharmony_ci
39427db96d56Sopenharmony_ciout:
39437db96d56Sopenharmony_ci    mpd_del(&aa);
39447db96d56Sopenharmony_ci    mpd_del(&bb);
39457db96d56Sopenharmony_ci}
39467db96d56Sopenharmony_ci
39477db96d56Sopenharmony_ci/* Internal function. */
39487db96d56Sopenharmony_cistatic void
39497db96d56Sopenharmony_ci_mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
39507db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
39517db96d56Sopenharmony_ci{
39527db96d56Sopenharmony_ci    MPD_NEW_STATIC(aligned,0,0,0,0);
39537db96d56Sopenharmony_ci    mpd_ssize_t qsize, rsize;
39547db96d56Sopenharmony_ci    mpd_ssize_t ideal_exp, expdiff, shift;
39557db96d56Sopenharmony_ci    uint8_t sign_a = mpd_sign(a);
39567db96d56Sopenharmony_ci    uint8_t sign_ab = mpd_sign(a)^mpd_sign(b);
39577db96d56Sopenharmony_ci
39587db96d56Sopenharmony_ci
39597db96d56Sopenharmony_ci    ideal_exp = (a->exp > b->exp) ?  b->exp : a->exp;
39607db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
39617db96d56Sopenharmony_ci        if (!mpd_qcopy(r, a, status)) {
39627db96d56Sopenharmony_ci            goto nanresult; /* GCOV_NOT_REACHED */
39637db96d56Sopenharmony_ci        }
39647db96d56Sopenharmony_ci        r->exp = ideal_exp;
39657db96d56Sopenharmony_ci        _settriple(q, sign_ab, 0, 0);
39667db96d56Sopenharmony_ci        return;
39677db96d56Sopenharmony_ci    }
39687db96d56Sopenharmony_ci
39697db96d56Sopenharmony_ci    expdiff = mpd_adjexp(a) - mpd_adjexp(b);
39707db96d56Sopenharmony_ci    if (expdiff < 0) {
39717db96d56Sopenharmony_ci        if (a->exp > b->exp) {
39727db96d56Sopenharmony_ci            /* positive and less than b->digits - a->digits */
39737db96d56Sopenharmony_ci            shift = a->exp - b->exp;
39747db96d56Sopenharmony_ci            if (!mpd_qshiftl(r, a, shift, status)) {
39757db96d56Sopenharmony_ci                goto nanresult;
39767db96d56Sopenharmony_ci            }
39777db96d56Sopenharmony_ci            r->exp = ideal_exp;
39787db96d56Sopenharmony_ci        }
39797db96d56Sopenharmony_ci        else {
39807db96d56Sopenharmony_ci            if (!mpd_qcopy(r, a, status)) {
39817db96d56Sopenharmony_ci                goto nanresult;
39827db96d56Sopenharmony_ci            }
39837db96d56Sopenharmony_ci        }
39847db96d56Sopenharmony_ci        _settriple(q, sign_ab, 0, 0);
39857db96d56Sopenharmony_ci        return;
39867db96d56Sopenharmony_ci    }
39877db96d56Sopenharmony_ci    if (expdiff > ctx->prec) {
39887db96d56Sopenharmony_ci        *status |= MPD_Division_impossible;
39897db96d56Sopenharmony_ci        goto nanresult;
39907db96d56Sopenharmony_ci    }
39917db96d56Sopenharmony_ci
39927db96d56Sopenharmony_ci
39937db96d56Sopenharmony_ci    /*
39947db96d56Sopenharmony_ci     * At this point we have:
39957db96d56Sopenharmony_ci     *   (1) 0 <= a->exp + a->digits - b->exp - b->digits <= prec
39967db96d56Sopenharmony_ci     *   (2) a->exp - b->exp >= b->digits - a->digits
39977db96d56Sopenharmony_ci     *   (3) a->exp - b->exp <= prec + b->digits - a->digits
39987db96d56Sopenharmony_ci     */
39997db96d56Sopenharmony_ci    if (a->exp != b->exp) {
40007db96d56Sopenharmony_ci        shift = a->exp - b->exp;
40017db96d56Sopenharmony_ci        if (shift > 0) {
40027db96d56Sopenharmony_ci            /* by (3), after the shift a->digits <= prec + b->digits */
40037db96d56Sopenharmony_ci            if (!mpd_qshiftl(&aligned, a, shift, status)) {
40047db96d56Sopenharmony_ci                goto nanresult;
40057db96d56Sopenharmony_ci            }
40067db96d56Sopenharmony_ci            a = &aligned;
40077db96d56Sopenharmony_ci        }
40087db96d56Sopenharmony_ci        else  {
40097db96d56Sopenharmony_ci            shift = -shift;
40107db96d56Sopenharmony_ci            /* by (2), after the shift b->digits <= a->digits */
40117db96d56Sopenharmony_ci            if (!mpd_qshiftl(&aligned, b, shift, status)) {
40127db96d56Sopenharmony_ci                goto nanresult;
40137db96d56Sopenharmony_ci            }
40147db96d56Sopenharmony_ci            b = &aligned;
40157db96d56Sopenharmony_ci        }
40167db96d56Sopenharmony_ci    }
40177db96d56Sopenharmony_ci
40187db96d56Sopenharmony_ci
40197db96d56Sopenharmony_ci    qsize = a->len - b->len + 1;
40207db96d56Sopenharmony_ci    if (!(q == a && qsize < a->len) && !(q == b && qsize < b->len)) {
40217db96d56Sopenharmony_ci        if (!mpd_qresize(q, qsize, status)) {
40227db96d56Sopenharmony_ci            goto nanresult;
40237db96d56Sopenharmony_ci        }
40247db96d56Sopenharmony_ci    }
40257db96d56Sopenharmony_ci
40267db96d56Sopenharmony_ci    rsize = b->len;
40277db96d56Sopenharmony_ci    if (!(r == a && rsize < a->len)) {
40287db96d56Sopenharmony_ci        if (!mpd_qresize(r, rsize, status)) {
40297db96d56Sopenharmony_ci            goto nanresult;
40307db96d56Sopenharmony_ci        }
40317db96d56Sopenharmony_ci    }
40327db96d56Sopenharmony_ci
40337db96d56Sopenharmony_ci    if (b->len == 1) {
40347db96d56Sopenharmony_ci        assert(b->data[0] != 0); /* annotation for scan-build */
40357db96d56Sopenharmony_ci        if (a->len == 1) {
40367db96d56Sopenharmony_ci            _mpd_div_word(&q->data[0], &r->data[0], a->data[0], b->data[0]);
40377db96d56Sopenharmony_ci        }
40387db96d56Sopenharmony_ci        else {
40397db96d56Sopenharmony_ci            r->data[0] = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]);
40407db96d56Sopenharmony_ci        }
40417db96d56Sopenharmony_ci    }
40427db96d56Sopenharmony_ci    else if (b->len <= MPD_NEWTONDIV_CUTOFF) {
40437db96d56Sopenharmony_ci        int ret;
40447db96d56Sopenharmony_ci        ret = _mpd_basedivmod(q->data, r->data, a->data, b->data,
40457db96d56Sopenharmony_ci                              a->len, b->len);
40467db96d56Sopenharmony_ci        if (ret == -1) {
40477db96d56Sopenharmony_ci            *status |= MPD_Malloc_error;
40487db96d56Sopenharmony_ci            goto nanresult;
40497db96d56Sopenharmony_ci        }
40507db96d56Sopenharmony_ci    }
40517db96d56Sopenharmony_ci    else {
40527db96d56Sopenharmony_ci        _mpd_base_ndivmod(q, r, a, b, status);
40537db96d56Sopenharmony_ci        if (mpd_isspecial(q) || mpd_isspecial(r)) {
40547db96d56Sopenharmony_ci            goto nanresult;
40557db96d56Sopenharmony_ci        }
40567db96d56Sopenharmony_ci        qsize = q->len;
40577db96d56Sopenharmony_ci        rsize = r->len;
40587db96d56Sopenharmony_ci    }
40597db96d56Sopenharmony_ci
40607db96d56Sopenharmony_ci    qsize = _mpd_real_size(q->data, qsize);
40617db96d56Sopenharmony_ci    /* resize to smaller cannot fail */
40627db96d56Sopenharmony_ci    mpd_qresize(q, qsize, status);
40637db96d56Sopenharmony_ci    q->len = qsize;
40647db96d56Sopenharmony_ci    mpd_setdigits(q);
40657db96d56Sopenharmony_ci    mpd_set_flags(q, sign_ab);
40667db96d56Sopenharmony_ci    q->exp = 0;
40677db96d56Sopenharmony_ci    if (q->digits > ctx->prec) {
40687db96d56Sopenharmony_ci        *status |= MPD_Division_impossible;
40697db96d56Sopenharmony_ci        goto nanresult;
40707db96d56Sopenharmony_ci    }
40717db96d56Sopenharmony_ci
40727db96d56Sopenharmony_ci    rsize = _mpd_real_size(r->data, rsize);
40737db96d56Sopenharmony_ci    /* resize to smaller cannot fail */
40747db96d56Sopenharmony_ci    mpd_qresize(r, rsize, status);
40757db96d56Sopenharmony_ci    r->len = rsize;
40767db96d56Sopenharmony_ci    mpd_setdigits(r);
40777db96d56Sopenharmony_ci    mpd_set_flags(r, sign_a);
40787db96d56Sopenharmony_ci    r->exp = ideal_exp;
40797db96d56Sopenharmony_ci
40807db96d56Sopenharmony_ciout:
40817db96d56Sopenharmony_ci    mpd_del(&aligned);
40827db96d56Sopenharmony_ci    return;
40837db96d56Sopenharmony_ci
40847db96d56Sopenharmony_cinanresult:
40857db96d56Sopenharmony_ci    mpd_setspecial(q, MPD_POS, MPD_NAN);
40867db96d56Sopenharmony_ci    mpd_setspecial(r, MPD_POS, MPD_NAN);
40877db96d56Sopenharmony_ci    goto out;
40887db96d56Sopenharmony_ci}
40897db96d56Sopenharmony_ci
40907db96d56Sopenharmony_ci/* Integer division with remainder. */
40917db96d56Sopenharmony_civoid
40927db96d56Sopenharmony_cimpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
40937db96d56Sopenharmony_ci            const mpd_context_t *ctx, uint32_t *status)
40947db96d56Sopenharmony_ci{
40957db96d56Sopenharmony_ci    uint8_t sign = mpd_sign(a)^mpd_sign(b);
40967db96d56Sopenharmony_ci
40977db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
40987db96d56Sopenharmony_ci        if (mpd_qcheck_nans(q, a, b, ctx, status)) {
40997db96d56Sopenharmony_ci            mpd_qcopy(r, q, status);
41007db96d56Sopenharmony_ci            return;
41017db96d56Sopenharmony_ci        }
41027db96d56Sopenharmony_ci        if (mpd_isinfinite(a)) {
41037db96d56Sopenharmony_ci            if (mpd_isinfinite(b)) {
41047db96d56Sopenharmony_ci                mpd_setspecial(q, MPD_POS, MPD_NAN);
41057db96d56Sopenharmony_ci            }
41067db96d56Sopenharmony_ci            else {
41077db96d56Sopenharmony_ci                mpd_setspecial(q, sign, MPD_INF);
41087db96d56Sopenharmony_ci            }
41097db96d56Sopenharmony_ci            mpd_setspecial(r, MPD_POS, MPD_NAN);
41107db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
41117db96d56Sopenharmony_ci            return;
41127db96d56Sopenharmony_ci        }
41137db96d56Sopenharmony_ci        if (mpd_isinfinite(b)) {
41147db96d56Sopenharmony_ci            if (!mpd_qcopy(r, a, status)) {
41157db96d56Sopenharmony_ci                mpd_seterror(q, MPD_Malloc_error, status);
41167db96d56Sopenharmony_ci                return;
41177db96d56Sopenharmony_ci            }
41187db96d56Sopenharmony_ci            mpd_qfinalize(r, ctx, status);
41197db96d56Sopenharmony_ci            _settriple(q, sign, 0, 0);
41207db96d56Sopenharmony_ci            return;
41217db96d56Sopenharmony_ci        }
41227db96d56Sopenharmony_ci        /* debug */
41237db96d56Sopenharmony_ci        abort(); /* GCOV_NOT_REACHED */
41247db96d56Sopenharmony_ci    }
41257db96d56Sopenharmony_ci    if (mpd_iszerocoeff(b)) {
41267db96d56Sopenharmony_ci        if (mpd_iszerocoeff(a)) {
41277db96d56Sopenharmony_ci            mpd_setspecial(q, MPD_POS, MPD_NAN);
41287db96d56Sopenharmony_ci            mpd_setspecial(r, MPD_POS, MPD_NAN);
41297db96d56Sopenharmony_ci            *status |= MPD_Division_undefined;
41307db96d56Sopenharmony_ci        }
41317db96d56Sopenharmony_ci        else {
41327db96d56Sopenharmony_ci            mpd_setspecial(q, sign, MPD_INF);
41337db96d56Sopenharmony_ci            mpd_setspecial(r, MPD_POS, MPD_NAN);
41347db96d56Sopenharmony_ci            *status |= (MPD_Division_by_zero|MPD_Invalid_operation);
41357db96d56Sopenharmony_ci        }
41367db96d56Sopenharmony_ci        return;
41377db96d56Sopenharmony_ci    }
41387db96d56Sopenharmony_ci
41397db96d56Sopenharmony_ci    _mpd_qdivmod(q, r, a, b, ctx, status);
41407db96d56Sopenharmony_ci    mpd_qfinalize(q, ctx, status);
41417db96d56Sopenharmony_ci    mpd_qfinalize(r, ctx, status);
41427db96d56Sopenharmony_ci}
41437db96d56Sopenharmony_ci
41447db96d56Sopenharmony_civoid
41457db96d56Sopenharmony_cimpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b,
41467db96d56Sopenharmony_ci            const mpd_context_t *ctx, uint32_t *status)
41477db96d56Sopenharmony_ci{
41487db96d56Sopenharmony_ci    MPD_NEW_STATIC(r,0,0,0,0);
41497db96d56Sopenharmony_ci    uint8_t sign = mpd_sign(a)^mpd_sign(b);
41507db96d56Sopenharmony_ci
41517db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
41527db96d56Sopenharmony_ci        if (mpd_qcheck_nans(q, a, b, ctx, status)) {
41537db96d56Sopenharmony_ci            return;
41547db96d56Sopenharmony_ci        }
41557db96d56Sopenharmony_ci        if (mpd_isinfinite(a) && mpd_isinfinite(b)) {
41567db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Invalid_operation, status);
41577db96d56Sopenharmony_ci            return;
41587db96d56Sopenharmony_ci        }
41597db96d56Sopenharmony_ci        if (mpd_isinfinite(a)) {
41607db96d56Sopenharmony_ci            mpd_setspecial(q, sign, MPD_INF);
41617db96d56Sopenharmony_ci            return;
41627db96d56Sopenharmony_ci        }
41637db96d56Sopenharmony_ci        if (mpd_isinfinite(b)) {
41647db96d56Sopenharmony_ci            _settriple(q, sign, 0, 0);
41657db96d56Sopenharmony_ci            return;
41667db96d56Sopenharmony_ci        }
41677db96d56Sopenharmony_ci        /* debug */
41687db96d56Sopenharmony_ci        abort(); /* GCOV_NOT_REACHED */
41697db96d56Sopenharmony_ci    }
41707db96d56Sopenharmony_ci    if (mpd_iszerocoeff(b)) {
41717db96d56Sopenharmony_ci        if (mpd_iszerocoeff(a)) {
41727db96d56Sopenharmony_ci            mpd_seterror(q, MPD_Division_undefined, status);
41737db96d56Sopenharmony_ci        }
41747db96d56Sopenharmony_ci        else {
41757db96d56Sopenharmony_ci            mpd_setspecial(q, sign, MPD_INF);
41767db96d56Sopenharmony_ci            *status |= MPD_Division_by_zero;
41777db96d56Sopenharmony_ci        }
41787db96d56Sopenharmony_ci        return;
41797db96d56Sopenharmony_ci    }
41807db96d56Sopenharmony_ci
41817db96d56Sopenharmony_ci
41827db96d56Sopenharmony_ci    _mpd_qdivmod(q, &r, a, b, ctx, status);
41837db96d56Sopenharmony_ci    mpd_del(&r);
41847db96d56Sopenharmony_ci    mpd_qfinalize(q, ctx, status);
41857db96d56Sopenharmony_ci}
41867db96d56Sopenharmony_ci
41877db96d56Sopenharmony_ci/* Divide decimal by mpd_ssize_t. */
41887db96d56Sopenharmony_civoid
41897db96d56Sopenharmony_cimpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b,
41907db96d56Sopenharmony_ci               const mpd_context_t *ctx, uint32_t *status)
41917db96d56Sopenharmony_ci{
41927db96d56Sopenharmony_ci    mpd_context_t maxcontext;
41937db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
41947db96d56Sopenharmony_ci
41957db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
41967db96d56Sopenharmony_ci    mpd_qsset_ssize(&bb, b, &maxcontext, status);
41977db96d56Sopenharmony_ci    mpd_qdiv(result, a, &bb, ctx, status);
41987db96d56Sopenharmony_ci    mpd_del(&bb);
41997db96d56Sopenharmony_ci}
42007db96d56Sopenharmony_ci
42017db96d56Sopenharmony_ci/* Divide decimal by mpd_uint_t. */
42027db96d56Sopenharmony_civoid
42037db96d56Sopenharmony_cimpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b,
42047db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
42057db96d56Sopenharmony_ci{
42067db96d56Sopenharmony_ci    mpd_context_t maxcontext;
42077db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
42087db96d56Sopenharmony_ci
42097db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
42107db96d56Sopenharmony_ci    mpd_qsset_uint(&bb, b, &maxcontext, status);
42117db96d56Sopenharmony_ci    mpd_qdiv(result, a, &bb, ctx, status);
42127db96d56Sopenharmony_ci    mpd_del(&bb);
42137db96d56Sopenharmony_ci}
42147db96d56Sopenharmony_ci
42157db96d56Sopenharmony_ci/* Divide decimal by int32_t. */
42167db96d56Sopenharmony_civoid
42177db96d56Sopenharmony_cimpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b,
42187db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
42197db96d56Sopenharmony_ci{
42207db96d56Sopenharmony_ci    mpd_qdiv_ssize(result, a, b, ctx, status);
42217db96d56Sopenharmony_ci}
42227db96d56Sopenharmony_ci
42237db96d56Sopenharmony_ci/* Divide decimal by uint32_t. */
42247db96d56Sopenharmony_civoid
42257db96d56Sopenharmony_cimpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b,
42267db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
42277db96d56Sopenharmony_ci{
42287db96d56Sopenharmony_ci    mpd_qdiv_uint(result, a, b, ctx, status);
42297db96d56Sopenharmony_ci}
42307db96d56Sopenharmony_ci
42317db96d56Sopenharmony_ci#ifdef CONFIG_64
42327db96d56Sopenharmony_ci/* Divide decimal by int64_t. */
42337db96d56Sopenharmony_civoid
42347db96d56Sopenharmony_cimpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b,
42357db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
42367db96d56Sopenharmony_ci{
42377db96d56Sopenharmony_ci    mpd_qdiv_ssize(result, a, b, ctx, status);
42387db96d56Sopenharmony_ci}
42397db96d56Sopenharmony_ci
42407db96d56Sopenharmony_ci/* Divide decimal by uint64_t. */
42417db96d56Sopenharmony_civoid
42427db96d56Sopenharmony_cimpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b,
42437db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
42447db96d56Sopenharmony_ci{
42457db96d56Sopenharmony_ci    mpd_qdiv_uint(result, a, b, ctx, status);
42467db96d56Sopenharmony_ci}
42477db96d56Sopenharmony_ci#elif !defined(LEGACY_COMPILER)
42487db96d56Sopenharmony_ci/* Divide decimal by int64_t. */
42497db96d56Sopenharmony_civoid
42507db96d56Sopenharmony_cimpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b,
42517db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
42527db96d56Sopenharmony_ci{
42537db96d56Sopenharmony_ci    mpd_context_t maxcontext;
42547db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
42557db96d56Sopenharmony_ci
42567db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
42577db96d56Sopenharmony_ci    mpd_qset_i64(&bb, b, &maxcontext, status);
42587db96d56Sopenharmony_ci    mpd_qdiv(result, a, &bb, ctx, status);
42597db96d56Sopenharmony_ci    mpd_del(&bb);
42607db96d56Sopenharmony_ci}
42617db96d56Sopenharmony_ci
42627db96d56Sopenharmony_ci/* Divide decimal by uint64_t. */
42637db96d56Sopenharmony_civoid
42647db96d56Sopenharmony_cimpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b,
42657db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
42667db96d56Sopenharmony_ci{
42677db96d56Sopenharmony_ci    mpd_context_t maxcontext;
42687db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
42697db96d56Sopenharmony_ci
42707db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
42717db96d56Sopenharmony_ci    mpd_qset_u64(&bb, b, &maxcontext, status);
42727db96d56Sopenharmony_ci    mpd_qdiv(result, a, &bb, ctx, status);
42737db96d56Sopenharmony_ci    mpd_del(&bb);
42747db96d56Sopenharmony_ci}
42757db96d56Sopenharmony_ci#endif
42767db96d56Sopenharmony_ci
42777db96d56Sopenharmony_ci/* Pad the result with trailing zeros if it has fewer digits than prec. */
42787db96d56Sopenharmony_cistatic void
42797db96d56Sopenharmony_ci_mpd_zeropad(mpd_t *result, const mpd_context_t *ctx, uint32_t *status)
42807db96d56Sopenharmony_ci{
42817db96d56Sopenharmony_ci    if (!mpd_isspecial(result) && !mpd_iszero(result) &&
42827db96d56Sopenharmony_ci        result->digits < ctx->prec) {
42837db96d56Sopenharmony_ci       mpd_ssize_t shift = ctx->prec - result->digits;
42847db96d56Sopenharmony_ci       mpd_qshiftl(result, result, shift, status);
42857db96d56Sopenharmony_ci       result->exp -= shift;
42867db96d56Sopenharmony_ci    }
42877db96d56Sopenharmony_ci}
42887db96d56Sopenharmony_ci
42897db96d56Sopenharmony_ci/* Check if the result is guaranteed to be one. */
42907db96d56Sopenharmony_cistatic int
42917db96d56Sopenharmony_ci_mpd_qexp_check_one(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
42927db96d56Sopenharmony_ci                    uint32_t *status)
42937db96d56Sopenharmony_ci{
42947db96d56Sopenharmony_ci    MPD_NEW_CONST(lim,0,-(ctx->prec+1),1,1,1,9);
42957db96d56Sopenharmony_ci    MPD_NEW_SHARED(aa, a);
42967db96d56Sopenharmony_ci
42977db96d56Sopenharmony_ci    mpd_set_positive(&aa);
42987db96d56Sopenharmony_ci
42997db96d56Sopenharmony_ci    /* abs(a) <= 9 * 10**(-prec-1) */
43007db96d56Sopenharmony_ci    if (_mpd_cmp(&aa, &lim) <= 0) {
43017db96d56Sopenharmony_ci        _settriple(result, 0, 1, 0);
43027db96d56Sopenharmony_ci        *status |= MPD_Rounded|MPD_Inexact;
43037db96d56Sopenharmony_ci        return 1;
43047db96d56Sopenharmony_ci    }
43057db96d56Sopenharmony_ci
43067db96d56Sopenharmony_ci    return 0;
43077db96d56Sopenharmony_ci}
43087db96d56Sopenharmony_ci
43097db96d56Sopenharmony_ci/*
43107db96d56Sopenharmony_ci * Get the number of iterations for the Horner scheme in _mpd_qexp().
43117db96d56Sopenharmony_ci */
43127db96d56Sopenharmony_cistatic inline mpd_ssize_t
43137db96d56Sopenharmony_ci_mpd_get_exp_iterations(const mpd_t *r, mpd_ssize_t p)
43147db96d56Sopenharmony_ci{
43157db96d56Sopenharmony_ci    mpd_ssize_t log10pbyr; /* lower bound for log10(p / abs(r)) */
43167db96d56Sopenharmony_ci    mpd_ssize_t n;
43177db96d56Sopenharmony_ci
43187db96d56Sopenharmony_ci    assert(p >= 10);
43197db96d56Sopenharmony_ci    assert(!mpd_iszero(r));
43207db96d56Sopenharmony_ci    assert(-p < mpd_adjexp(r) && mpd_adjexp(r) <= -1);
43217db96d56Sopenharmony_ci
43227db96d56Sopenharmony_ci#ifdef CONFIG_64
43237db96d56Sopenharmony_ci    if (p > (mpd_ssize_t)(1ULL<<52)) {
43247db96d56Sopenharmony_ci        return MPD_SSIZE_MAX;
43257db96d56Sopenharmony_ci    }
43267db96d56Sopenharmony_ci#endif
43277db96d56Sopenharmony_ci
43287db96d56Sopenharmony_ci    /*
43297db96d56Sopenharmony_ci     * Lower bound for log10(p / abs(r)): adjexp(p) - (adjexp(r) + 1)
43307db96d56Sopenharmony_ci     * At this point (for CONFIG_64, CONFIG_32 is not problematic):
43317db96d56Sopenharmony_ci     *    1) 10 <= p <= 2**52
43327db96d56Sopenharmony_ci     *    2) -p < adjexp(r) <= -1
43337db96d56Sopenharmony_ci     *    3) 1 <= log10pbyr <= 2**52 + 14
43347db96d56Sopenharmony_ci     */
43357db96d56Sopenharmony_ci    log10pbyr = (mpd_word_digits(p)-1) - (mpd_adjexp(r)+1);
43367db96d56Sopenharmony_ci
43377db96d56Sopenharmony_ci    /*
43387db96d56Sopenharmony_ci     * The numerator in the paper is 1.435 * p - 1.182, calculated
43397db96d56Sopenharmony_ci     * exactly. We compensate for rounding errors by using 1.43503.
43407db96d56Sopenharmony_ci     * ACL2 proofs:
43417db96d56Sopenharmony_ci     *    1) exp-iter-approx-lower-bound: The term below evaluated
43427db96d56Sopenharmony_ci     *       in 53-bit floating point arithmetic is greater than or
43437db96d56Sopenharmony_ci     *       equal to the exact term used in the paper.
43447db96d56Sopenharmony_ci     *    2) exp-iter-approx-upper-bound: The term below is less than
43457db96d56Sopenharmony_ci     *       or equal to 3/2 * p <= 3/2 * 2**52.
43467db96d56Sopenharmony_ci     */
43477db96d56Sopenharmony_ci    n = (mpd_ssize_t)ceil((1.43503*(double)p - 1.182) / (double)log10pbyr);
43487db96d56Sopenharmony_ci    return n >= 3 ? n : 3;
43497db96d56Sopenharmony_ci}
43507db96d56Sopenharmony_ci
43517db96d56Sopenharmony_ci/*
43527db96d56Sopenharmony_ci * Internal function, specials have been dealt with. Apart from Overflow
43537db96d56Sopenharmony_ci * and Underflow, two cases must be considered for the error of the result:
43547db96d56Sopenharmony_ci *
43557db96d56Sopenharmony_ci *   1) abs(a) <= 9 * 10**(-prec-1)  ==>  result == 1
43567db96d56Sopenharmony_ci *
43577db96d56Sopenharmony_ci *      Absolute error: abs(1 - e**x) < 10**(-prec)
43587db96d56Sopenharmony_ci *      -------------------------------------------
43597db96d56Sopenharmony_ci *
43607db96d56Sopenharmony_ci *   2) abs(a) > 9 * 10**(-prec-1)
43617db96d56Sopenharmony_ci *
43627db96d56Sopenharmony_ci *      Relative error: abs(result - e**x) < 0.5 * 10**(-prec) * e**x
43637db96d56Sopenharmony_ci *      -------------------------------------------------------------
43647db96d56Sopenharmony_ci *
43657db96d56Sopenharmony_ci * The algorithm is from Hull&Abrham, Variable Precision Exponential Function,
43667db96d56Sopenharmony_ci * ACM Transactions on Mathematical Software, Vol. 12, No. 2, June 1986.
43677db96d56Sopenharmony_ci *
43687db96d56Sopenharmony_ci * Main differences:
43697db96d56Sopenharmony_ci *
43707db96d56Sopenharmony_ci *  - The number of iterations for the Horner scheme is calculated using
43717db96d56Sopenharmony_ci *    53-bit floating point arithmetic.
43727db96d56Sopenharmony_ci *
43737db96d56Sopenharmony_ci *  - In the error analysis for ER (relative error accumulated in the
43747db96d56Sopenharmony_ci *    evaluation of the truncated series) the reduced operand r may
43757db96d56Sopenharmony_ci *    have any number of digits.
43767db96d56Sopenharmony_ci *    ACL2 proof: exponent-relative-error
43777db96d56Sopenharmony_ci *
43787db96d56Sopenharmony_ci *  - The analysis for early abortion has been adapted for the mpd_t
43797db96d56Sopenharmony_ci *    ranges.
43807db96d56Sopenharmony_ci */
43817db96d56Sopenharmony_cistatic void
43827db96d56Sopenharmony_ci_mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
43837db96d56Sopenharmony_ci          uint32_t *status)
43847db96d56Sopenharmony_ci{
43857db96d56Sopenharmony_ci    mpd_context_t workctx;
43867db96d56Sopenharmony_ci    MPD_NEW_STATIC(tmp,0,0,0,0);
43877db96d56Sopenharmony_ci    MPD_NEW_STATIC(sum,0,0,0,0);
43887db96d56Sopenharmony_ci    MPD_NEW_CONST(word,0,0,1,1,1,1);
43897db96d56Sopenharmony_ci    mpd_ssize_t j, n, t;
43907db96d56Sopenharmony_ci
43917db96d56Sopenharmony_ci    assert(!mpd_isspecial(a));
43927db96d56Sopenharmony_ci
43937db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
43947db96d56Sopenharmony_ci        _settriple(result, MPD_POS, 1, 0);
43957db96d56Sopenharmony_ci        return;
43967db96d56Sopenharmony_ci    }
43977db96d56Sopenharmony_ci
43987db96d56Sopenharmony_ci    /*
43997db96d56Sopenharmony_ci     * We are calculating e^x = e^(r*10^t) = (e^r)^(10^t), where abs(r) < 1 and t >= 0.
44007db96d56Sopenharmony_ci     *
44017db96d56Sopenharmony_ci     * If t > 0, we have:
44027db96d56Sopenharmony_ci     *
44037db96d56Sopenharmony_ci     *   (1) 0.1 <= r < 1, so e^0.1 <= e^r. If t > MAX_T, overflow occurs:
44047db96d56Sopenharmony_ci     *
44057db96d56Sopenharmony_ci     *     MAX-EMAX+1 < log10(e^(0.1*10*t)) <= log10(e^(r*10^t)) < adjexp(e^(r*10^t))+1
44067db96d56Sopenharmony_ci     *
44077db96d56Sopenharmony_ci     *   (2) -1 < r <= -0.1, so e^r <= e^-0.1. If t > MAX_T, underflow occurs:
44087db96d56Sopenharmony_ci     *
44097db96d56Sopenharmony_ci     *     adjexp(e^(r*10^t)) <= log10(e^(r*10^t)) <= log10(e^(-0.1*10^t)) < MIN-ETINY
44107db96d56Sopenharmony_ci     */
44117db96d56Sopenharmony_ci#if defined(CONFIG_64)
44127db96d56Sopenharmony_ci    #define MPD_EXP_MAX_T 19
44137db96d56Sopenharmony_ci#elif defined(CONFIG_32)
44147db96d56Sopenharmony_ci    #define MPD_EXP_MAX_T 10
44157db96d56Sopenharmony_ci#endif
44167db96d56Sopenharmony_ci    t = a->digits + a->exp;
44177db96d56Sopenharmony_ci    t = (t > 0) ? t : 0;
44187db96d56Sopenharmony_ci    if (t > MPD_EXP_MAX_T) {
44197db96d56Sopenharmony_ci        if (mpd_ispositive(a)) {
44207db96d56Sopenharmony_ci            mpd_setspecial(result, MPD_POS, MPD_INF);
44217db96d56Sopenharmony_ci            *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
44227db96d56Sopenharmony_ci        }
44237db96d56Sopenharmony_ci        else {
44247db96d56Sopenharmony_ci            _settriple(result, MPD_POS, 0, mpd_etiny(ctx));
44257db96d56Sopenharmony_ci            *status |= (MPD_Inexact|MPD_Rounded|MPD_Subnormal|
44267db96d56Sopenharmony_ci                        MPD_Underflow|MPD_Clamped);
44277db96d56Sopenharmony_ci        }
44287db96d56Sopenharmony_ci        return;
44297db96d56Sopenharmony_ci    }
44307db96d56Sopenharmony_ci
44317db96d56Sopenharmony_ci    /* abs(a) <= 9 * 10**(-prec-1) */
44327db96d56Sopenharmony_ci    if (_mpd_qexp_check_one(result, a, ctx, status)) {
44337db96d56Sopenharmony_ci        return;
44347db96d56Sopenharmony_ci    }
44357db96d56Sopenharmony_ci
44367db96d56Sopenharmony_ci    mpd_maxcontext(&workctx);
44377db96d56Sopenharmony_ci    workctx.prec = ctx->prec + t + 2;
44387db96d56Sopenharmony_ci    workctx.prec = (workctx.prec < 10) ? 10 : workctx.prec;
44397db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_HALF_EVEN;
44407db96d56Sopenharmony_ci
44417db96d56Sopenharmony_ci    if (!mpd_qcopy(result, a, status)) {
44427db96d56Sopenharmony_ci        return;
44437db96d56Sopenharmony_ci    }
44447db96d56Sopenharmony_ci    result->exp -= t;
44457db96d56Sopenharmony_ci
44467db96d56Sopenharmony_ci    /*
44477db96d56Sopenharmony_ci     * At this point:
44487db96d56Sopenharmony_ci     *    1) 9 * 10**(-prec-1) < abs(a)
44497db96d56Sopenharmony_ci     *    2) 9 * 10**(-prec-t-1) < abs(r)
44507db96d56Sopenharmony_ci     *    3) log10(9) - prec - t - 1 < log10(abs(r)) < adjexp(abs(r)) + 1
44517db96d56Sopenharmony_ci     *    4) - prec - t - 2 < adjexp(abs(r)) <= -1
44527db96d56Sopenharmony_ci     */
44537db96d56Sopenharmony_ci    n = _mpd_get_exp_iterations(result, workctx.prec);
44547db96d56Sopenharmony_ci    if (n == MPD_SSIZE_MAX) {
44557db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_UNLIKELY */
44567db96d56Sopenharmony_ci        return; /* GCOV_UNLIKELY */
44577db96d56Sopenharmony_ci    }
44587db96d56Sopenharmony_ci
44597db96d56Sopenharmony_ci    _settriple(&sum, MPD_POS, 1, 0);
44607db96d56Sopenharmony_ci
44617db96d56Sopenharmony_ci    for (j = n-1; j >= 1; j--) {
44627db96d56Sopenharmony_ci        word.data[0] = j;
44637db96d56Sopenharmony_ci        mpd_setdigits(&word);
44647db96d56Sopenharmony_ci        mpd_qdiv(&tmp, result, &word, &workctx, &workctx.status);
44657db96d56Sopenharmony_ci        mpd_qfma(&sum, &sum, &tmp, &one, &workctx, &workctx.status);
44667db96d56Sopenharmony_ci    }
44677db96d56Sopenharmony_ci
44687db96d56Sopenharmony_ci#ifdef CONFIG_64
44697db96d56Sopenharmony_ci    _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status);
44707db96d56Sopenharmony_ci#else
44717db96d56Sopenharmony_ci    if (t <= MPD_MAX_POW10) {
44727db96d56Sopenharmony_ci        _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status);
44737db96d56Sopenharmony_ci    }
44747db96d56Sopenharmony_ci    else {
44757db96d56Sopenharmony_ci        t -= MPD_MAX_POW10;
44767db96d56Sopenharmony_ci        _mpd_qpow_uint(&tmp, &sum, mpd_pow10[MPD_MAX_POW10], MPD_POS,
44777db96d56Sopenharmony_ci                       &workctx, status);
44787db96d56Sopenharmony_ci        _mpd_qpow_uint(result, &tmp, mpd_pow10[t], MPD_POS, &workctx, status);
44797db96d56Sopenharmony_ci    }
44807db96d56Sopenharmony_ci#endif
44817db96d56Sopenharmony_ci
44827db96d56Sopenharmony_ci    mpd_del(&tmp);
44837db96d56Sopenharmony_ci    mpd_del(&sum);
44847db96d56Sopenharmony_ci    *status |= (workctx.status&MPD_Errors);
44857db96d56Sopenharmony_ci    *status |= (MPD_Inexact|MPD_Rounded);
44867db96d56Sopenharmony_ci}
44877db96d56Sopenharmony_ci
44887db96d56Sopenharmony_ci/* exp(a) */
44897db96d56Sopenharmony_civoid
44907db96d56Sopenharmony_cimpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
44917db96d56Sopenharmony_ci         uint32_t *status)
44927db96d56Sopenharmony_ci{
44937db96d56Sopenharmony_ci    mpd_context_t workctx;
44947db96d56Sopenharmony_ci
44957db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
44967db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
44977db96d56Sopenharmony_ci            return;
44987db96d56Sopenharmony_ci        }
44997db96d56Sopenharmony_ci        if (mpd_isnegative(a)) {
45007db96d56Sopenharmony_ci            _settriple(result, MPD_POS, 0, 0);
45017db96d56Sopenharmony_ci        }
45027db96d56Sopenharmony_ci        else {
45037db96d56Sopenharmony_ci            mpd_setspecial(result, MPD_POS, MPD_INF);
45047db96d56Sopenharmony_ci        }
45057db96d56Sopenharmony_ci        return;
45067db96d56Sopenharmony_ci    }
45077db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
45087db96d56Sopenharmony_ci        _settriple(result, MPD_POS, 1, 0);
45097db96d56Sopenharmony_ci        return;
45107db96d56Sopenharmony_ci    }
45117db96d56Sopenharmony_ci
45127db96d56Sopenharmony_ci    workctx = *ctx;
45137db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_HALF_EVEN;
45147db96d56Sopenharmony_ci
45157db96d56Sopenharmony_ci    if (ctx->allcr) {
45167db96d56Sopenharmony_ci        MPD_NEW_STATIC(t1, 0,0,0,0);
45177db96d56Sopenharmony_ci        MPD_NEW_STATIC(t2, 0,0,0,0);
45187db96d56Sopenharmony_ci        MPD_NEW_STATIC(ulp, 0,0,0,0);
45197db96d56Sopenharmony_ci        MPD_NEW_STATIC(aa, 0,0,0,0);
45207db96d56Sopenharmony_ci        mpd_ssize_t prec;
45217db96d56Sopenharmony_ci        mpd_ssize_t ulpexp;
45227db96d56Sopenharmony_ci        uint32_t workstatus;
45237db96d56Sopenharmony_ci
45247db96d56Sopenharmony_ci        if (result == a) {
45257db96d56Sopenharmony_ci            if (!mpd_qcopy(&aa, a, status)) {
45267db96d56Sopenharmony_ci                mpd_seterror(result, MPD_Malloc_error, status);
45277db96d56Sopenharmony_ci                return;
45287db96d56Sopenharmony_ci            }
45297db96d56Sopenharmony_ci            a = &aa;
45307db96d56Sopenharmony_ci        }
45317db96d56Sopenharmony_ci
45327db96d56Sopenharmony_ci        workctx.clamp = 0;
45337db96d56Sopenharmony_ci        prec = ctx->prec + 3;
45347db96d56Sopenharmony_ci        while (1) {
45357db96d56Sopenharmony_ci            workctx.prec = prec;
45367db96d56Sopenharmony_ci            workstatus = 0;
45377db96d56Sopenharmony_ci
45387db96d56Sopenharmony_ci            _mpd_qexp(result, a, &workctx, &workstatus);
45397db96d56Sopenharmony_ci            *status |= workstatus;
45407db96d56Sopenharmony_ci
45417db96d56Sopenharmony_ci            ulpexp = result->exp + result->digits - workctx.prec;
45427db96d56Sopenharmony_ci            if (workstatus & MPD_Underflow) {
45437db96d56Sopenharmony_ci                /* The effective work precision is result->digits. */
45447db96d56Sopenharmony_ci                ulpexp = result->exp;
45457db96d56Sopenharmony_ci            }
45467db96d56Sopenharmony_ci            _ssettriple(&ulp, MPD_POS, 1, ulpexp);
45477db96d56Sopenharmony_ci
45487db96d56Sopenharmony_ci            /*
45497db96d56Sopenharmony_ci             * At this point [1]:
45507db96d56Sopenharmony_ci             *   1) abs(result - e**x) < 0.5 * 10**(-prec) * e**x
45517db96d56Sopenharmony_ci             *   2) result - ulp < e**x < result + ulp
45527db96d56Sopenharmony_ci             *   3) result - ulp < result < result + ulp
45537db96d56Sopenharmony_ci             *
45547db96d56Sopenharmony_ci             * If round(result-ulp)==round(result+ulp), then
45557db96d56Sopenharmony_ci             * round(result)==round(e**x). Therefore the result
45567db96d56Sopenharmony_ci             * is correctly rounded.
45577db96d56Sopenharmony_ci             *
45587db96d56Sopenharmony_ci             * [1] If abs(a) <= 9 * 10**(-prec-1), use the absolute
45597db96d56Sopenharmony_ci             *     error for a similar argument.
45607db96d56Sopenharmony_ci             */
45617db96d56Sopenharmony_ci            workctx.prec = ctx->prec;
45627db96d56Sopenharmony_ci            mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
45637db96d56Sopenharmony_ci            mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
45647db96d56Sopenharmony_ci            if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
45657db96d56Sopenharmony_ci                mpd_qcmp(&t1, &t2, status) == 0) {
45667db96d56Sopenharmony_ci                workctx.clamp = ctx->clamp;
45677db96d56Sopenharmony_ci                _mpd_zeropad(result, &workctx, status);
45687db96d56Sopenharmony_ci                mpd_check_underflow(result, &workctx, status);
45697db96d56Sopenharmony_ci                mpd_qfinalize(result, &workctx, status);
45707db96d56Sopenharmony_ci                break;
45717db96d56Sopenharmony_ci            }
45727db96d56Sopenharmony_ci            prec += MPD_RDIGITS;
45737db96d56Sopenharmony_ci        }
45747db96d56Sopenharmony_ci        mpd_del(&t1);
45757db96d56Sopenharmony_ci        mpd_del(&t2);
45767db96d56Sopenharmony_ci        mpd_del(&ulp);
45777db96d56Sopenharmony_ci        mpd_del(&aa);
45787db96d56Sopenharmony_ci    }
45797db96d56Sopenharmony_ci    else {
45807db96d56Sopenharmony_ci        _mpd_qexp(result, a, &workctx, status);
45817db96d56Sopenharmony_ci        _mpd_zeropad(result, &workctx, status);
45827db96d56Sopenharmony_ci        mpd_check_underflow(result, &workctx, status);
45837db96d56Sopenharmony_ci        mpd_qfinalize(result, &workctx, status);
45847db96d56Sopenharmony_ci    }
45857db96d56Sopenharmony_ci}
45867db96d56Sopenharmony_ci
45877db96d56Sopenharmony_ci/* Fused multiply-add: (a * b) + c, with a single final rounding. */
45887db96d56Sopenharmony_civoid
45897db96d56Sopenharmony_cimpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c,
45907db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
45917db96d56Sopenharmony_ci{
45927db96d56Sopenharmony_ci    uint32_t workstatus = 0;
45937db96d56Sopenharmony_ci    mpd_t *cc = NULL;
45947db96d56Sopenharmony_ci
45957db96d56Sopenharmony_ci    if (result == c) {
45967db96d56Sopenharmony_ci        if ((cc = mpd_qncopy(c)) == NULL) {
45977db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Malloc_error, status);
45987db96d56Sopenharmony_ci            return;
45997db96d56Sopenharmony_ci        }
46007db96d56Sopenharmony_ci        c = cc;
46017db96d56Sopenharmony_ci    }
46027db96d56Sopenharmony_ci
46037db96d56Sopenharmony_ci    _mpd_qmul(result, a, b, ctx, &workstatus);
46047db96d56Sopenharmony_ci    if (!(workstatus&MPD_Invalid_operation)) {
46057db96d56Sopenharmony_ci        mpd_qadd(result, result, c, ctx, &workstatus);
46067db96d56Sopenharmony_ci    }
46077db96d56Sopenharmony_ci
46087db96d56Sopenharmony_ci    if (cc) mpd_del(cc);
46097db96d56Sopenharmony_ci    *status |= workstatus;
46107db96d56Sopenharmony_ci}
46117db96d56Sopenharmony_ci
46127db96d56Sopenharmony_ci/*
46137db96d56Sopenharmony_ci * Schedule the optimal precision increase for the Newton iteration.
46147db96d56Sopenharmony_ci *   v := input operand
46157db96d56Sopenharmony_ci *   z_0 := initial approximation
46167db96d56Sopenharmony_ci *   initprec := natural number such that abs(log(v) - z_0) < 10**-initprec
46177db96d56Sopenharmony_ci *   maxprec := target precision
46187db96d56Sopenharmony_ci *
46197db96d56Sopenharmony_ci * For convenience the output klist contains the elements in reverse order:
46207db96d56Sopenharmony_ci *   klist := [k_n-1, ..., k_0], where
46217db96d56Sopenharmony_ci *     1) k_0 <= initprec and
46227db96d56Sopenharmony_ci *     2) abs(log(v) - result) < 10**(-2*k_n-1 + 1) <= 10**-maxprec.
46237db96d56Sopenharmony_ci */
46247db96d56Sopenharmony_cistatic inline int
46257db96d56Sopenharmony_ciln_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], mpd_ssize_t maxprec,
46267db96d56Sopenharmony_ci                 mpd_ssize_t initprec)
46277db96d56Sopenharmony_ci{
46287db96d56Sopenharmony_ci    mpd_ssize_t k;
46297db96d56Sopenharmony_ci    int i;
46307db96d56Sopenharmony_ci
46317db96d56Sopenharmony_ci    assert(maxprec >= 2 && initprec >= 2);
46327db96d56Sopenharmony_ci    if (maxprec <= initprec) return -1;
46337db96d56Sopenharmony_ci
46347db96d56Sopenharmony_ci    i = 0; k = maxprec;
46357db96d56Sopenharmony_ci    do {
46367db96d56Sopenharmony_ci        k = (k+2) / 2;
46377db96d56Sopenharmony_ci        klist[i++] = k;
46387db96d56Sopenharmony_ci    } while (k > initprec);
46397db96d56Sopenharmony_ci
46407db96d56Sopenharmony_ci    return i-1;
46417db96d56Sopenharmony_ci}
46427db96d56Sopenharmony_ci
46437db96d56Sopenharmony_ci/* The constants have been verified with both decimal.py and mpfr. */
46447db96d56Sopenharmony_ci#ifdef CONFIG_64
46457db96d56Sopenharmony_ci#if MPD_RDIGITS != 19
46467db96d56Sopenharmony_ci  #error "mpdecimal.c: MPD_RDIGITS must be 19."
46477db96d56Sopenharmony_ci#endif
46487db96d56Sopenharmony_cistatic const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = {
46497db96d56Sopenharmony_ci  6983716328982174407ULL, 9089704281976336583ULL, 1515961135648465461ULL,
46507db96d56Sopenharmony_ci  4416816335727555703ULL, 2900988039194170265ULL, 2307925037472986509ULL,
46517db96d56Sopenharmony_ci   107598438319191292ULL, 3466624107184669231ULL, 4450099781311469159ULL,
46527db96d56Sopenharmony_ci  9807828059751193854ULL, 7713456862091670584ULL, 1492198849978748873ULL,
46537db96d56Sopenharmony_ci  6528728696511086257ULL, 2385392051446341972ULL, 8692180205189339507ULL,
46547db96d56Sopenharmony_ci  6518769751037497088ULL, 2375253577097505395ULL, 9095610299291824318ULL,
46557db96d56Sopenharmony_ci   982748238504564801ULL, 5438635917781170543ULL, 7547331541421808427ULL,
46567db96d56Sopenharmony_ci   752371033310119785ULL, 3171643095059950878ULL, 9785265383207606726ULL,
46577db96d56Sopenharmony_ci  2932258279850258550ULL, 5497347726624257094ULL, 2976979522110718264ULL,
46587db96d56Sopenharmony_ci  9221477656763693866ULL, 1979650047149510504ULL, 6674183485704422507ULL,
46597db96d56Sopenharmony_ci  9702766860595249671ULL, 9278096762712757753ULL, 9314848524948644871ULL,
46607db96d56Sopenharmony_ci  6826928280848118428ULL,  754403708474699401ULL,  230105703089634572ULL,
46617db96d56Sopenharmony_ci  1929203337658714166ULL, 7589402567763113569ULL, 4208241314695689016ULL,
46627db96d56Sopenharmony_ci  2922455440575892572ULL, 9356734206705811364ULL, 2684916746550586856ULL,
46637db96d56Sopenharmony_ci   644507064800027750ULL, 9476834636167921018ULL, 5659121373450747856ULL,
46647db96d56Sopenharmony_ci  2835522011480466371ULL, 6470806855677432162ULL, 7141748003688084012ULL,
46657db96d56Sopenharmony_ci  9619404400222105101ULL, 5504893431493939147ULL, 6674744042432743651ULL,
46667db96d56Sopenharmony_ci  2287698219886746543ULL, 7773262884616336622ULL, 1985283935053089653ULL,
46677db96d56Sopenharmony_ci  4680843799894826233ULL, 8168948290720832555ULL, 8067566662873690987ULL,
46687db96d56Sopenharmony_ci  6248633409525465082ULL, 9829834196778404228ULL, 3524802359972050895ULL,
46697db96d56Sopenharmony_ci  3327900967572609677ULL,  110148862877297603ULL,  179914546843642076ULL,
46707db96d56Sopenharmony_ci  2302585092994045684ULL
46717db96d56Sopenharmony_ci};
46727db96d56Sopenharmony_ci#else
46737db96d56Sopenharmony_ci#if MPD_RDIGITS != 9
46747db96d56Sopenharmony_ci  #error "mpdecimal.c: MPD_RDIGITS must be 9."
46757db96d56Sopenharmony_ci#endif
46767db96d56Sopenharmony_cistatic const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = {
46777db96d56Sopenharmony_ci  401682692UL, 708474699UL, 720754403UL,  30896345UL, 602301057UL, 765871416UL,
46787db96d56Sopenharmony_ci  192920333UL, 763113569UL, 589402567UL, 956890167UL,  82413146UL, 589257242UL,
46797db96d56Sopenharmony_ci  245544057UL, 811364292UL, 734206705UL, 868569356UL, 167465505UL, 775026849UL,
46807db96d56Sopenharmony_ci  706480002UL,  18064450UL, 636167921UL, 569476834UL, 734507478UL, 156591213UL,
46817db96d56Sopenharmony_ci  148046637UL, 283552201UL, 677432162UL, 470806855UL, 880840126UL, 417480036UL,
46827db96d56Sopenharmony_ci  210510171UL, 940440022UL, 939147961UL, 893431493UL, 436515504UL, 440424327UL,
46837db96d56Sopenharmony_ci  654366747UL, 821988674UL, 622228769UL, 884616336UL, 537773262UL, 350530896UL,
46847db96d56Sopenharmony_ci  319852839UL, 989482623UL, 468084379UL, 720832555UL, 168948290UL, 736909878UL,
46857db96d56Sopenharmony_ci  675666628UL, 546508280UL, 863340952UL, 404228624UL, 834196778UL, 508959829UL,
46867db96d56Sopenharmony_ci   23599720UL, 967735248UL,  96757260UL, 603332790UL, 862877297UL, 760110148UL,
46877db96d56Sopenharmony_ci  468436420UL, 401799145UL, 299404568UL, 230258509UL
46887db96d56Sopenharmony_ci};
46897db96d56Sopenharmony_ci#endif
46907db96d56Sopenharmony_ci/* _mpd_ln10 is used directly for precisions smaller than MINALLOC_MAX*RDIGITS.
46917db96d56Sopenharmony_ci   Otherwise, it serves as the initial approximation for calculating ln(10). */
46927db96d56Sopenharmony_cistatic const mpd_t _mpd_ln10 = {
46937db96d56Sopenharmony_ci  MPD_STATIC|MPD_CONST_DATA, -(MPD_MINALLOC_MAX*MPD_RDIGITS-1),
46947db96d56Sopenharmony_ci  MPD_MINALLOC_MAX*MPD_RDIGITS, MPD_MINALLOC_MAX, MPD_MINALLOC_MAX,
46957db96d56Sopenharmony_ci  (mpd_uint_t *)mpd_ln10_data
46967db96d56Sopenharmony_ci};
46977db96d56Sopenharmony_ci
46987db96d56Sopenharmony_ci/*
46997db96d56Sopenharmony_ci * Set 'result' to log(10).
47007db96d56Sopenharmony_ci *   Ulp error: abs(result - log(10)) < ulp(log(10))
47017db96d56Sopenharmony_ci *   Relative error: abs(result - log(10)) < 5 * 10**-prec * log(10)
47027db96d56Sopenharmony_ci *
47037db96d56Sopenharmony_ci * NOTE: The relative error is not derived from the ulp error, but
47047db96d56Sopenharmony_ci * calculated separately using the fact that 23/10 < log(10) < 24/10.
47057db96d56Sopenharmony_ci */
47067db96d56Sopenharmony_civoid
47077db96d56Sopenharmony_cimpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status)
47087db96d56Sopenharmony_ci{
47097db96d56Sopenharmony_ci    mpd_context_t varcontext, maxcontext;
47107db96d56Sopenharmony_ci    MPD_NEW_STATIC(tmp, 0,0,0,0);
47117db96d56Sopenharmony_ci    MPD_NEW_CONST(static10, 0,0,2,1,1,10);
47127db96d56Sopenharmony_ci    mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
47137db96d56Sopenharmony_ci    mpd_uint_t rnd;
47147db96d56Sopenharmony_ci    mpd_ssize_t shift;
47157db96d56Sopenharmony_ci    int i;
47167db96d56Sopenharmony_ci
47177db96d56Sopenharmony_ci    assert(prec >= 1);
47187db96d56Sopenharmony_ci
47197db96d56Sopenharmony_ci    shift = MPD_MINALLOC_MAX*MPD_RDIGITS-prec;
47207db96d56Sopenharmony_ci    shift = shift < 0 ? 0 : shift;
47217db96d56Sopenharmony_ci
47227db96d56Sopenharmony_ci    rnd = mpd_qshiftr(result, &_mpd_ln10, shift, status);
47237db96d56Sopenharmony_ci    if (rnd == MPD_UINT_MAX) {
47247db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Malloc_error, status);
47257db96d56Sopenharmony_ci        return;
47267db96d56Sopenharmony_ci    }
47277db96d56Sopenharmony_ci    result->exp = -(result->digits-1);
47287db96d56Sopenharmony_ci
47297db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
47307db96d56Sopenharmony_ci    if (prec < MPD_MINALLOC_MAX*MPD_RDIGITS) {
47317db96d56Sopenharmony_ci        maxcontext.prec = prec;
47327db96d56Sopenharmony_ci        _mpd_apply_round_excess(result, rnd, &maxcontext, status);
47337db96d56Sopenharmony_ci        *status |= (MPD_Inexact|MPD_Rounded);
47347db96d56Sopenharmony_ci        return;
47357db96d56Sopenharmony_ci    }
47367db96d56Sopenharmony_ci
47377db96d56Sopenharmony_ci    mpd_maxcontext(&varcontext);
47387db96d56Sopenharmony_ci    varcontext.round = MPD_ROUND_TRUNC;
47397db96d56Sopenharmony_ci
47407db96d56Sopenharmony_ci    i = ln_schedule_prec(klist, prec+2, -result->exp);
47417db96d56Sopenharmony_ci    for (; i >= 0; i--) {
47427db96d56Sopenharmony_ci        varcontext.prec = 2*klist[i]+3;
47437db96d56Sopenharmony_ci        result->flags ^= MPD_NEG;
47447db96d56Sopenharmony_ci        _mpd_qexp(&tmp, result, &varcontext, status);
47457db96d56Sopenharmony_ci        result->flags ^= MPD_NEG;
47467db96d56Sopenharmony_ci        mpd_qmul(&tmp, &static10, &tmp, &varcontext, status);
47477db96d56Sopenharmony_ci        mpd_qsub(&tmp, &tmp, &one, &maxcontext, status);
47487db96d56Sopenharmony_ci        mpd_qadd(result, result, &tmp, &maxcontext, status);
47497db96d56Sopenharmony_ci        if (mpd_isspecial(result)) {
47507db96d56Sopenharmony_ci            break;
47517db96d56Sopenharmony_ci        }
47527db96d56Sopenharmony_ci    }
47537db96d56Sopenharmony_ci
47547db96d56Sopenharmony_ci    mpd_del(&tmp);
47557db96d56Sopenharmony_ci    maxcontext.prec = prec;
47567db96d56Sopenharmony_ci    mpd_qfinalize(result, &maxcontext, status);
47577db96d56Sopenharmony_ci}
47587db96d56Sopenharmony_ci
47597db96d56Sopenharmony_ci/*
47607db96d56Sopenharmony_ci * Initial approximations for the ln() iteration. The values have the
47617db96d56Sopenharmony_ci * following properties (established with both decimal.py and mpfr):
47627db96d56Sopenharmony_ci *
47637db96d56Sopenharmony_ci * Index 0 - 400, logarithms of x in [1.00, 5.00]:
47647db96d56Sopenharmony_ci *   abs(lnapprox[i] * 10**-3 - log((i+100)/100)) < 10**-2
47657db96d56Sopenharmony_ci *   abs(lnapprox[i] * 10**-3 - log((i+1+100)/100)) < 10**-2
47667db96d56Sopenharmony_ci *
47677db96d56Sopenharmony_ci * Index 401 - 899, logarithms of x in (0.500, 0.999]:
47687db96d56Sopenharmony_ci *   abs(-lnapprox[i] * 10**-3 - log((i+100)/1000)) < 10**-2
47697db96d56Sopenharmony_ci *   abs(-lnapprox[i] * 10**-3 - log((i+1+100)/1000)) < 10**-2
47707db96d56Sopenharmony_ci */
47717db96d56Sopenharmony_cistatic const uint16_t lnapprox[900] = {
47727db96d56Sopenharmony_ci  /* index 0 - 400: log((i+100)/100) * 1000 */
47737db96d56Sopenharmony_ci  0, 10, 20, 30, 39, 49, 58, 68, 77, 86, 95, 104, 113, 122, 131, 140, 148, 157,
47747db96d56Sopenharmony_ci  166, 174, 182, 191, 199, 207, 215, 223, 231, 239, 247, 255, 262, 270, 278,
47757db96d56Sopenharmony_ci  285, 293, 300, 308, 315, 322, 329, 336, 344, 351, 358, 365, 372, 378, 385,
47767db96d56Sopenharmony_ci  392, 399, 406, 412, 419, 425, 432, 438, 445, 451, 457, 464, 470, 476, 482,
47777db96d56Sopenharmony_ci  489, 495, 501, 507, 513, 519, 525, 531, 536, 542, 548, 554, 560, 565, 571,
47787db96d56Sopenharmony_ci  577, 582, 588, 593, 599, 604, 610, 615, 621, 626, 631, 637, 642, 647, 652,
47797db96d56Sopenharmony_ci  658, 663, 668, 673, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728,
47807db96d56Sopenharmony_ci  732, 737, 742, 747, 751, 756, 761, 766, 770, 775, 779, 784, 788, 793, 798,
47817db96d56Sopenharmony_ci  802, 806, 811, 815, 820, 824, 829, 833, 837, 842, 846, 850, 854, 859, 863,
47827db96d56Sopenharmony_ci  867, 871, 876, 880, 884, 888, 892, 896, 900, 904, 908, 912, 916, 920, 924,
47837db96d56Sopenharmony_ci  928, 932, 936, 940, 944, 948, 952, 956, 959, 963, 967, 971, 975, 978, 982,
47847db96d56Sopenharmony_ci  986, 990, 993, 997, 1001, 1004, 1008, 1012, 1015, 1019, 1022, 1026, 1030,
47857db96d56Sopenharmony_ci  1033, 1037, 1040, 1044, 1047, 1051, 1054, 1058, 1061, 1065, 1068, 1072, 1075,
47867db96d56Sopenharmony_ci  1078, 1082, 1085, 1089, 1092, 1095, 1099, 1102, 1105, 1109, 1112, 1115, 1118,
47877db96d56Sopenharmony_ci  1122, 1125, 1128, 1131, 1135, 1138, 1141, 1144, 1147, 1151, 1154, 1157, 1160,
47887db96d56Sopenharmony_ci  1163, 1166, 1169, 1172, 1176, 1179, 1182, 1185, 1188, 1191, 1194, 1197, 1200,
47897db96d56Sopenharmony_ci  1203, 1206, 1209, 1212, 1215, 1218, 1221, 1224, 1227, 1230, 1233, 1235, 1238,
47907db96d56Sopenharmony_ci  1241, 1244, 1247, 1250, 1253, 1256, 1258, 1261, 1264, 1267, 1270, 1273, 1275,
47917db96d56Sopenharmony_ci  1278, 1281, 1284, 1286, 1289, 1292, 1295, 1297, 1300, 1303, 1306, 1308, 1311,
47927db96d56Sopenharmony_ci  1314, 1316, 1319, 1322, 1324, 1327, 1330, 1332, 1335, 1338, 1340, 1343, 1345,
47937db96d56Sopenharmony_ci  1348, 1351, 1353, 1356, 1358, 1361, 1364, 1366, 1369, 1371, 1374, 1376, 1379,
47947db96d56Sopenharmony_ci  1381, 1384, 1386, 1389, 1391, 1394, 1396, 1399, 1401, 1404, 1406, 1409, 1411,
47957db96d56Sopenharmony_ci  1413, 1416, 1418, 1421, 1423, 1426, 1428, 1430, 1433, 1435, 1437, 1440, 1442,
47967db96d56Sopenharmony_ci  1445, 1447, 1449, 1452, 1454, 1456, 1459, 1461, 1463, 1466, 1468, 1470, 1472,
47977db96d56Sopenharmony_ci  1475, 1477, 1479, 1482, 1484, 1486, 1488, 1491, 1493, 1495, 1497, 1500, 1502,
47987db96d56Sopenharmony_ci  1504, 1506, 1509, 1511, 1513, 1515, 1517, 1520, 1522, 1524, 1526, 1528, 1530,
47997db96d56Sopenharmony_ci  1533, 1535, 1537, 1539, 1541, 1543, 1545, 1548, 1550, 1552, 1554, 1556, 1558,
48007db96d56Sopenharmony_ci  1560, 1562, 1564, 1567, 1569, 1571, 1573, 1575, 1577, 1579, 1581, 1583, 1585,
48017db96d56Sopenharmony_ci  1587, 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1609,
48027db96d56Sopenharmony_ci  /* index 401 - 899: -log((i+100)/1000) * 1000 */
48037db96d56Sopenharmony_ci  691, 689, 687, 685, 683, 681, 679, 677, 675, 673, 671, 669, 668, 666, 664,
48047db96d56Sopenharmony_ci  662, 660, 658, 656, 654, 652, 650, 648, 646, 644, 642, 641, 639, 637, 635,
48057db96d56Sopenharmony_ci  633, 631, 629, 627, 626, 624, 622, 620, 618, 616, 614, 612, 611, 609, 607,
48067db96d56Sopenharmony_ci  605, 603, 602, 600, 598, 596, 594, 592, 591, 589, 587, 585, 583, 582, 580,
48077db96d56Sopenharmony_ci  578, 576, 574, 573, 571, 569, 567, 566, 564, 562, 560, 559, 557, 555, 553,
48087db96d56Sopenharmony_ci  552, 550, 548, 546, 545, 543, 541, 540, 538, 536, 534, 533, 531, 529, 528,
48097db96d56Sopenharmony_ci  526, 524, 523, 521, 519, 518, 516, 514, 512, 511, 509, 508, 506, 504, 502,
48107db96d56Sopenharmony_ci  501, 499, 498, 496, 494, 493, 491, 489, 488, 486, 484, 483, 481, 480, 478,
48117db96d56Sopenharmony_ci  476, 475, 473, 472, 470, 468, 467, 465, 464, 462, 460, 459, 457, 456, 454,
48127db96d56Sopenharmony_ci  453, 451, 449, 448, 446, 445, 443, 442, 440, 438, 437, 435, 434, 432, 431,
48137db96d56Sopenharmony_ci  429, 428, 426, 425, 423, 422, 420, 419, 417, 416, 414, 412, 411, 410, 408,
48147db96d56Sopenharmony_ci  406, 405, 404, 402, 400, 399, 398, 396, 394, 393, 392, 390, 389, 387, 386,
48157db96d56Sopenharmony_ci  384, 383, 381, 380, 378, 377, 375, 374, 372, 371, 370, 368, 367, 365, 364,
48167db96d56Sopenharmony_ci  362, 361, 360, 358, 357, 355, 354, 352, 351, 350, 348, 347, 345, 344, 342,
48177db96d56Sopenharmony_ci  341, 340, 338, 337, 336, 334, 333, 331, 330, 328, 327, 326, 324, 323, 322,
48187db96d56Sopenharmony_ci  320, 319, 318, 316, 315, 313, 312, 311, 309, 308, 306, 305, 304, 302, 301,
48197db96d56Sopenharmony_ci  300, 298, 297, 296, 294, 293, 292, 290, 289, 288, 286, 285, 284, 282, 281,
48207db96d56Sopenharmony_ci  280, 278, 277, 276, 274, 273, 272, 270, 269, 268, 267, 265, 264, 263, 261,
48217db96d56Sopenharmony_ci  260, 259, 258, 256, 255, 254, 252, 251, 250, 248, 247, 246, 245, 243, 242,
48227db96d56Sopenharmony_ci  241, 240, 238, 237, 236, 234, 233, 232, 231, 229, 228, 227, 226, 224, 223,
48237db96d56Sopenharmony_ci  222, 221, 219, 218, 217, 216, 214, 213, 212, 211, 210, 208, 207, 206, 205,
48247db96d56Sopenharmony_ci  203, 202, 201, 200, 198, 197, 196, 195, 194, 192, 191, 190, 189, 188, 186,
48257db96d56Sopenharmony_ci  185, 184, 183, 182, 180, 179, 178, 177, 176, 174, 173, 172, 171, 170, 168,
48267db96d56Sopenharmony_ci  167, 166, 165, 164, 162, 161, 160, 159, 158, 157, 156, 154, 153, 152, 151,
48277db96d56Sopenharmony_ci  150, 148, 147, 146, 145, 144, 143, 142, 140, 139, 138, 137, 136, 135, 134,
48287db96d56Sopenharmony_ci  132, 131, 130, 129, 128, 127, 126, 124, 123, 122, 121, 120, 119, 118, 116,
48297db96d56Sopenharmony_ci  115, 114, 113, 112, 111, 110, 109, 108, 106, 105, 104, 103, 102, 101, 100,
48307db96d56Sopenharmony_ci  99, 98, 97, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 84, 83, 82, 81, 80, 79,
48317db96d56Sopenharmony_ci  78, 77, 76, 75, 74, 73, 72, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59,
48327db96d56Sopenharmony_ci  58, 57, 56, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39,
48337db96d56Sopenharmony_ci  38, 37, 36, 35, 34, 33, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
48347db96d56Sopenharmony_ci  18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
48357db96d56Sopenharmony_ci};
48367db96d56Sopenharmony_ci
48377db96d56Sopenharmony_ci/*
48387db96d56Sopenharmony_ci * Internal ln() function that does not check for specials, zero or one.
48397db96d56Sopenharmony_ci * Relative error: abs(result - log(a)) < 0.1 * 10**-prec * abs(log(a))
48407db96d56Sopenharmony_ci */
48417db96d56Sopenharmony_cistatic void
48427db96d56Sopenharmony_ci_mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
48437db96d56Sopenharmony_ci         uint32_t *status)
48447db96d56Sopenharmony_ci{
48457db96d56Sopenharmony_ci    mpd_context_t varcontext, maxcontext;
48467db96d56Sopenharmony_ci    mpd_t *z = result;
48477db96d56Sopenharmony_ci    MPD_NEW_STATIC(v,0,0,0,0);
48487db96d56Sopenharmony_ci    MPD_NEW_STATIC(vtmp,0,0,0,0);
48497db96d56Sopenharmony_ci    MPD_NEW_STATIC(tmp,0,0,0,0);
48507db96d56Sopenharmony_ci    mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
48517db96d56Sopenharmony_ci    mpd_ssize_t maxprec, shift, t;
48527db96d56Sopenharmony_ci    mpd_ssize_t a_digits, a_exp;
48537db96d56Sopenharmony_ci    mpd_uint_t dummy, x;
48547db96d56Sopenharmony_ci    int i;
48557db96d56Sopenharmony_ci
48567db96d56Sopenharmony_ci    assert(!mpd_isspecial(a) && !mpd_iszerocoeff(a));
48577db96d56Sopenharmony_ci
48587db96d56Sopenharmony_ci    /*
48597db96d56Sopenharmony_ci     * We are calculating ln(a) = ln(v * 10^t) = ln(v) + t*ln(10),
48607db96d56Sopenharmony_ci     * where 0.5 < v <= 5.
48617db96d56Sopenharmony_ci     */
48627db96d56Sopenharmony_ci    if (!mpd_qcopy(&v, a, status)) {
48637db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Malloc_error, status);
48647db96d56Sopenharmony_ci        goto finish;
48657db96d56Sopenharmony_ci    }
48667db96d56Sopenharmony_ci
48677db96d56Sopenharmony_ci    /* Initial approximation: we have at least one non-zero digit */
48687db96d56Sopenharmony_ci    _mpd_get_msdigits(&dummy, &x, &v, 3);
48697db96d56Sopenharmony_ci    if (x < 10) x *= 10;
48707db96d56Sopenharmony_ci    if (x < 100) x *= 10;
48717db96d56Sopenharmony_ci    x -= 100;
48727db96d56Sopenharmony_ci
48737db96d56Sopenharmony_ci    /* a may equal z */
48747db96d56Sopenharmony_ci    a_digits = a->digits;
48757db96d56Sopenharmony_ci    a_exp = a->exp;
48767db96d56Sopenharmony_ci
48777db96d56Sopenharmony_ci    mpd_minalloc(z);
48787db96d56Sopenharmony_ci    mpd_clear_flags(z);
48797db96d56Sopenharmony_ci    z->data[0] = lnapprox[x];
48807db96d56Sopenharmony_ci    z->len = 1;
48817db96d56Sopenharmony_ci    z->exp = -3;
48827db96d56Sopenharmony_ci    mpd_setdigits(z);
48837db96d56Sopenharmony_ci
48847db96d56Sopenharmony_ci    if (x <= 400) {
48857db96d56Sopenharmony_ci        /* Reduce the input operand to 1.00 <= v <= 5.00. Let y = x + 100,
48867db96d56Sopenharmony_ci         * so 100 <= y <= 500. Since y contains the most significant digits
48877db96d56Sopenharmony_ci         * of v, y/100 <= v < (y+1)/100 and abs(z - log(v)) < 10**-2. */
48887db96d56Sopenharmony_ci        v.exp = -(a_digits - 1);
48897db96d56Sopenharmony_ci        t = a_exp + a_digits - 1;
48907db96d56Sopenharmony_ci    }
48917db96d56Sopenharmony_ci    else {
48927db96d56Sopenharmony_ci        /* Reduce the input operand to 0.500 < v <= 0.999. Let y = x + 100,
48937db96d56Sopenharmony_ci         * so 500 < y <= 999. Since y contains the most significant digits
48947db96d56Sopenharmony_ci         * of v, y/1000 <= v < (y+1)/1000 and abs(z - log(v)) < 10**-2. */
48957db96d56Sopenharmony_ci        v.exp = -a_digits;
48967db96d56Sopenharmony_ci        t = a_exp + a_digits;
48977db96d56Sopenharmony_ci        mpd_set_negative(z);
48987db96d56Sopenharmony_ci    }
48997db96d56Sopenharmony_ci
49007db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
49017db96d56Sopenharmony_ci    mpd_maxcontext(&varcontext);
49027db96d56Sopenharmony_ci    varcontext.round = MPD_ROUND_TRUNC;
49037db96d56Sopenharmony_ci
49047db96d56Sopenharmony_ci    maxprec = ctx->prec + 2;
49057db96d56Sopenharmony_ci    if (t == 0 && (x <= 15 || x >= 800)) {
49067db96d56Sopenharmony_ci        /* 0.900 <= v <= 1.15: Estimate the magnitude of the logarithm.
49077db96d56Sopenharmony_ci         * If ln(v) will underflow, skip the loop. Otherwise, adjust the
49087db96d56Sopenharmony_ci         * precision upwards in order to obtain a sufficient number of
49097db96d56Sopenharmony_ci         * significant digits.
49107db96d56Sopenharmony_ci         *
49117db96d56Sopenharmony_ci         *   Case v > 1:
49127db96d56Sopenharmony_ci         *      abs((v-1)/10) < abs((v-1)/v) < abs(ln(v)) < abs(v-1)
49137db96d56Sopenharmony_ci         *   Case v < 1:
49147db96d56Sopenharmony_ci         *      abs(v-1) < abs(ln(v)) < abs((v-1)/v) < abs((v-1)*10)
49157db96d56Sopenharmony_ci         */
49167db96d56Sopenharmony_ci        int cmp = _mpd_cmp(&v, &one);
49177db96d56Sopenharmony_ci
49187db96d56Sopenharmony_ci        /* Upper bound (assume v > 1): abs(v-1), unrounded */
49197db96d56Sopenharmony_ci        _mpd_qsub(&tmp, &v, &one, &maxcontext, &maxcontext.status);
49207db96d56Sopenharmony_ci        if (maxcontext.status & MPD_Errors) {
49217db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Malloc_error, status);
49227db96d56Sopenharmony_ci            goto finish;
49237db96d56Sopenharmony_ci        }
49247db96d56Sopenharmony_ci
49257db96d56Sopenharmony_ci        if (cmp < 0) {
49267db96d56Sopenharmony_ci            /* v < 1: abs((v-1)*10) */
49277db96d56Sopenharmony_ci            tmp.exp += 1;
49287db96d56Sopenharmony_ci        }
49297db96d56Sopenharmony_ci        if (mpd_adjexp(&tmp) < mpd_etiny(ctx)) {
49307db96d56Sopenharmony_ci            /* The upper bound is less than etiny: Underflow to zero */
49317db96d56Sopenharmony_ci            _settriple(result, (cmp<0), 1, mpd_etiny(ctx)-1);
49327db96d56Sopenharmony_ci            goto finish;
49337db96d56Sopenharmony_ci        }
49347db96d56Sopenharmony_ci        /* Lower bound: abs((v-1)/10) or abs(v-1) */
49357db96d56Sopenharmony_ci        tmp.exp -= 1;
49367db96d56Sopenharmony_ci        if (mpd_adjexp(&tmp) < 0) {
49377db96d56Sopenharmony_ci            /* Absolute error of the loop: abs(z - log(v)) < 10**-p. If
49387db96d56Sopenharmony_ci             * p = ctx->prec+2-adjexp(lower), then the relative error of
49397db96d56Sopenharmony_ci             * the result is (using 10**adjexp(x) <= abs(x)):
49407db96d56Sopenharmony_ci             *
49417db96d56Sopenharmony_ci             *   abs(z - log(v)) / abs(log(v)) < 10**-p / abs(log(v))
49427db96d56Sopenharmony_ci             *                                 <= 10**(-ctx->prec-2)
49437db96d56Sopenharmony_ci             */
49447db96d56Sopenharmony_ci            maxprec = maxprec - mpd_adjexp(&tmp);
49457db96d56Sopenharmony_ci        }
49467db96d56Sopenharmony_ci    }
49477db96d56Sopenharmony_ci
49487db96d56Sopenharmony_ci    i = ln_schedule_prec(klist, maxprec, 2);
49497db96d56Sopenharmony_ci    for (; i >= 0; i--) {
49507db96d56Sopenharmony_ci        varcontext.prec = 2*klist[i]+3;
49517db96d56Sopenharmony_ci        z->flags ^= MPD_NEG;
49527db96d56Sopenharmony_ci        _mpd_qexp(&tmp, z, &varcontext, status);
49537db96d56Sopenharmony_ci        z->flags ^= MPD_NEG;
49547db96d56Sopenharmony_ci
49557db96d56Sopenharmony_ci        if (v.digits > varcontext.prec) {
49567db96d56Sopenharmony_ci            shift = v.digits - varcontext.prec;
49577db96d56Sopenharmony_ci            mpd_qshiftr(&vtmp, &v, shift, status);
49587db96d56Sopenharmony_ci            vtmp.exp += shift;
49597db96d56Sopenharmony_ci            mpd_qmul(&tmp, &vtmp, &tmp, &varcontext, status);
49607db96d56Sopenharmony_ci        }
49617db96d56Sopenharmony_ci        else {
49627db96d56Sopenharmony_ci            mpd_qmul(&tmp, &v, &tmp, &varcontext, status);
49637db96d56Sopenharmony_ci        }
49647db96d56Sopenharmony_ci
49657db96d56Sopenharmony_ci        mpd_qsub(&tmp, &tmp, &one, &maxcontext, status);
49667db96d56Sopenharmony_ci        mpd_qadd(z, z, &tmp, &maxcontext, status);
49677db96d56Sopenharmony_ci        if (mpd_isspecial(z)) {
49687db96d56Sopenharmony_ci            break;
49697db96d56Sopenharmony_ci        }
49707db96d56Sopenharmony_ci    }
49717db96d56Sopenharmony_ci
49727db96d56Sopenharmony_ci    /*
49737db96d56Sopenharmony_ci     * Case t == 0:
49747db96d56Sopenharmony_ci     *    t * log(10) == 0, the result does not change and the analysis
49757db96d56Sopenharmony_ci     *    above applies. If v < 0.900 or v > 1.15, the relative error is
49767db96d56Sopenharmony_ci     *    less than 10**(-ctx.prec-1).
49777db96d56Sopenharmony_ci     * Case t != 0:
49787db96d56Sopenharmony_ci     *      z := approx(log(v))
49797db96d56Sopenharmony_ci     *      y := approx(log(10))
49807db96d56Sopenharmony_ci     *      p := maxprec = ctx->prec + 2
49817db96d56Sopenharmony_ci     *   Absolute errors:
49827db96d56Sopenharmony_ci     *      1) abs(z - log(v)) < 10**-p
49837db96d56Sopenharmony_ci     *      2) abs(y - log(10)) < 10**-p
49847db96d56Sopenharmony_ci     *   The multiplication is exact, so:
49857db96d56Sopenharmony_ci     *      3) abs(t*y - t*log(10)) < t*10**-p
49867db96d56Sopenharmony_ci     *   The sum is exact, so:
49877db96d56Sopenharmony_ci     *      4) abs((z + t*y) - (log(v) + t*log(10))) < (abs(t) + 1) * 10**-p
49887db96d56Sopenharmony_ci     *   Bounds for log(v) and log(10):
49897db96d56Sopenharmony_ci     *      5) -7/10 < log(v) < 17/10
49907db96d56Sopenharmony_ci     *      6) 23/10 < log(10) < 24/10
49917db96d56Sopenharmony_ci     *   Using 4), 5), 6) and t != 0, the relative error is:
49927db96d56Sopenharmony_ci     *
49937db96d56Sopenharmony_ci     *      7) relerr < ((abs(t) + 1)*10**-p) / abs(log(v) + t*log(10))
49947db96d56Sopenharmony_ci     *                < 0.5 * 10**(-p + 1) = 0.5 * 10**(-ctx->prec-1)
49957db96d56Sopenharmony_ci     */
49967db96d56Sopenharmony_ci    mpd_qln10(&v, maxprec+1, status);
49977db96d56Sopenharmony_ci    mpd_qmul_ssize(&tmp, &v, t, &maxcontext, status);
49987db96d56Sopenharmony_ci    mpd_qadd(result, &tmp, z, &maxcontext, status);
49997db96d56Sopenharmony_ci
50007db96d56Sopenharmony_ci
50017db96d56Sopenharmony_cifinish:
50027db96d56Sopenharmony_ci    *status |= (MPD_Inexact|MPD_Rounded);
50037db96d56Sopenharmony_ci    mpd_del(&v);
50047db96d56Sopenharmony_ci    mpd_del(&vtmp);
50057db96d56Sopenharmony_ci    mpd_del(&tmp);
50067db96d56Sopenharmony_ci}
50077db96d56Sopenharmony_ci
50087db96d56Sopenharmony_ci/* ln(a) */
50097db96d56Sopenharmony_civoid
50107db96d56Sopenharmony_cimpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
50117db96d56Sopenharmony_ci        uint32_t *status)
50127db96d56Sopenharmony_ci{
50137db96d56Sopenharmony_ci    mpd_context_t workctx;
50147db96d56Sopenharmony_ci    mpd_ssize_t adjexp, t;
50157db96d56Sopenharmony_ci
50167db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
50177db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
50187db96d56Sopenharmony_ci            return;
50197db96d56Sopenharmony_ci        }
50207db96d56Sopenharmony_ci        if (mpd_isnegative(a)) {
50217db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
50227db96d56Sopenharmony_ci            return;
50237db96d56Sopenharmony_ci        }
50247db96d56Sopenharmony_ci        mpd_setspecial(result, MPD_POS, MPD_INF);
50257db96d56Sopenharmony_ci        return;
50267db96d56Sopenharmony_ci    }
50277db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
50287db96d56Sopenharmony_ci        mpd_setspecial(result, MPD_NEG, MPD_INF);
50297db96d56Sopenharmony_ci        return;
50307db96d56Sopenharmony_ci    }
50317db96d56Sopenharmony_ci    if (mpd_isnegative(a)) {
50327db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
50337db96d56Sopenharmony_ci        return;
50347db96d56Sopenharmony_ci    }
50357db96d56Sopenharmony_ci    if (_mpd_cmp(a, &one) == 0) {
50367db96d56Sopenharmony_ci        _settriple(result, MPD_POS, 0, 0);
50377db96d56Sopenharmony_ci        return;
50387db96d56Sopenharmony_ci    }
50397db96d56Sopenharmony_ci    /*
50407db96d56Sopenharmony_ci     * Check if the result will overflow (0 < x, x != 1):
50417db96d56Sopenharmony_ci     *   1) log10(x) < 0 iff adjexp(x) < 0
50427db96d56Sopenharmony_ci     *   2) 0 < x /\ x <= y ==> adjexp(x) <= adjexp(y)
50437db96d56Sopenharmony_ci     *   3) 0 < x /\ x != 1 ==> 2 * abs(log10(x)) < abs(log(x))
50447db96d56Sopenharmony_ci     *   4) adjexp(x) <= log10(x) < adjexp(x) + 1
50457db96d56Sopenharmony_ci     *
50467db96d56Sopenharmony_ci     * Case adjexp(x) >= 0:
50477db96d56Sopenharmony_ci     *   5) 2 * adjexp(x) < abs(log(x))
50487db96d56Sopenharmony_ci     *   Case adjexp(x) > 0:
50497db96d56Sopenharmony_ci     *     6) adjexp(2 * adjexp(x)) <= adjexp(abs(log(x)))
50507db96d56Sopenharmony_ci     *   Case adjexp(x) == 0:
50517db96d56Sopenharmony_ci     *     mpd_exp_digits(t)-1 == 0 <= emax (the shortcut is not triggered)
50527db96d56Sopenharmony_ci     *
50537db96d56Sopenharmony_ci     * Case adjexp(x) < 0:
50547db96d56Sopenharmony_ci     *   7) 2 * (-adjexp(x) - 1) < abs(log(x))
50557db96d56Sopenharmony_ci     *   Case adjexp(x) < -1:
50567db96d56Sopenharmony_ci     *     8) adjexp(2 * (-adjexp(x) - 1)) <= adjexp(abs(log(x)))
50577db96d56Sopenharmony_ci     *   Case adjexp(x) == -1:
50587db96d56Sopenharmony_ci     *     mpd_exp_digits(t)-1 == 0 <= emax (the shortcut is not triggered)
50597db96d56Sopenharmony_ci     */
50607db96d56Sopenharmony_ci    adjexp = mpd_adjexp(a);
50617db96d56Sopenharmony_ci    t = (adjexp < 0) ? -adjexp-1 : adjexp;
50627db96d56Sopenharmony_ci    t *= 2;
50637db96d56Sopenharmony_ci    if (mpd_exp_digits(t)-1 > ctx->emax) {
50647db96d56Sopenharmony_ci        *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
50657db96d56Sopenharmony_ci        mpd_setspecial(result, (adjexp<0), MPD_INF);
50667db96d56Sopenharmony_ci        return;
50677db96d56Sopenharmony_ci    }
50687db96d56Sopenharmony_ci
50697db96d56Sopenharmony_ci    workctx = *ctx;
50707db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_HALF_EVEN;
50717db96d56Sopenharmony_ci
50727db96d56Sopenharmony_ci    if (ctx->allcr) {
50737db96d56Sopenharmony_ci        MPD_NEW_STATIC(t1, 0,0,0,0);
50747db96d56Sopenharmony_ci        MPD_NEW_STATIC(t2, 0,0,0,0);
50757db96d56Sopenharmony_ci        MPD_NEW_STATIC(ulp, 0,0,0,0);
50767db96d56Sopenharmony_ci        MPD_NEW_STATIC(aa, 0,0,0,0);
50777db96d56Sopenharmony_ci        mpd_ssize_t prec;
50787db96d56Sopenharmony_ci
50797db96d56Sopenharmony_ci        if (result == a) {
50807db96d56Sopenharmony_ci            if (!mpd_qcopy(&aa, a, status)) {
50817db96d56Sopenharmony_ci                mpd_seterror(result, MPD_Malloc_error, status);
50827db96d56Sopenharmony_ci                return;
50837db96d56Sopenharmony_ci            }
50847db96d56Sopenharmony_ci            a = &aa;
50857db96d56Sopenharmony_ci        }
50867db96d56Sopenharmony_ci
50877db96d56Sopenharmony_ci        workctx.clamp = 0;
50887db96d56Sopenharmony_ci        prec = ctx->prec + 3;
50897db96d56Sopenharmony_ci        while (1) {
50907db96d56Sopenharmony_ci            workctx.prec = prec;
50917db96d56Sopenharmony_ci            _mpd_qln(result, a, &workctx, status);
50927db96d56Sopenharmony_ci            _ssettriple(&ulp, MPD_POS, 1,
50937db96d56Sopenharmony_ci                        result->exp + result->digits-workctx.prec);
50947db96d56Sopenharmony_ci
50957db96d56Sopenharmony_ci            workctx.prec = ctx->prec;
50967db96d56Sopenharmony_ci            mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
50977db96d56Sopenharmony_ci            mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
50987db96d56Sopenharmony_ci            if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
50997db96d56Sopenharmony_ci                mpd_qcmp(&t1, &t2, status) == 0) {
51007db96d56Sopenharmony_ci                workctx.clamp = ctx->clamp;
51017db96d56Sopenharmony_ci                mpd_check_underflow(result, &workctx, status);
51027db96d56Sopenharmony_ci                mpd_qfinalize(result, &workctx, status);
51037db96d56Sopenharmony_ci                break;
51047db96d56Sopenharmony_ci            }
51057db96d56Sopenharmony_ci            prec += MPD_RDIGITS;
51067db96d56Sopenharmony_ci        }
51077db96d56Sopenharmony_ci        mpd_del(&t1);
51087db96d56Sopenharmony_ci        mpd_del(&t2);
51097db96d56Sopenharmony_ci        mpd_del(&ulp);
51107db96d56Sopenharmony_ci        mpd_del(&aa);
51117db96d56Sopenharmony_ci    }
51127db96d56Sopenharmony_ci    else {
51137db96d56Sopenharmony_ci        _mpd_qln(result, a, &workctx, status);
51147db96d56Sopenharmony_ci        mpd_check_underflow(result, &workctx, status);
51157db96d56Sopenharmony_ci        mpd_qfinalize(result, &workctx, status);
51167db96d56Sopenharmony_ci    }
51177db96d56Sopenharmony_ci}
51187db96d56Sopenharmony_ci
51197db96d56Sopenharmony_ci/*
51207db96d56Sopenharmony_ci * Internal log10() function that does not check for specials, zero or one.
51217db96d56Sopenharmony_ci * Case SKIP_FINALIZE:
51227db96d56Sopenharmony_ci *   Relative error: abs(result - log10(a)) < 0.1 * 10**-prec * abs(log10(a))
51237db96d56Sopenharmony_ci * Case DO_FINALIZE:
51247db96d56Sopenharmony_ci *   Ulp error: abs(result - log10(a)) < ulp(log10(a))
51257db96d56Sopenharmony_ci */
51267db96d56Sopenharmony_cienum {SKIP_FINALIZE, DO_FINALIZE};
51277db96d56Sopenharmony_cistatic void
51287db96d56Sopenharmony_ci_mpd_qlog10(int action, mpd_t *result, const mpd_t *a,
51297db96d56Sopenharmony_ci            const mpd_context_t *ctx, uint32_t *status)
51307db96d56Sopenharmony_ci{
51317db96d56Sopenharmony_ci    mpd_context_t workctx;
51327db96d56Sopenharmony_ci    MPD_NEW_STATIC(ln10,0,0,0,0);
51337db96d56Sopenharmony_ci
51347db96d56Sopenharmony_ci    mpd_maxcontext(&workctx);
51357db96d56Sopenharmony_ci    workctx.prec = ctx->prec + 3;
51367db96d56Sopenharmony_ci    /* relative error: 0.1 * 10**(-p-3). The specific underflow shortcut
51377db96d56Sopenharmony_ci     * in _mpd_qln() does not change the final result. */
51387db96d56Sopenharmony_ci    _mpd_qln(result, a, &workctx, status);
51397db96d56Sopenharmony_ci    /* relative error: 5 * 10**(-p-3) */
51407db96d56Sopenharmony_ci    mpd_qln10(&ln10, workctx.prec, status);
51417db96d56Sopenharmony_ci
51427db96d56Sopenharmony_ci    if (action == DO_FINALIZE) {
51437db96d56Sopenharmony_ci        workctx = *ctx;
51447db96d56Sopenharmony_ci        workctx.round = MPD_ROUND_HALF_EVEN;
51457db96d56Sopenharmony_ci    }
51467db96d56Sopenharmony_ci    /* SKIP_FINALIZE: relative error: 5 * 10**(-p-3) */
51477db96d56Sopenharmony_ci    _mpd_qdiv(NO_IDEAL_EXP, result, result, &ln10, &workctx, status);
51487db96d56Sopenharmony_ci
51497db96d56Sopenharmony_ci    mpd_del(&ln10);
51507db96d56Sopenharmony_ci}
51517db96d56Sopenharmony_ci
51527db96d56Sopenharmony_ci/* log10(a) */
51537db96d56Sopenharmony_civoid
51547db96d56Sopenharmony_cimpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
51557db96d56Sopenharmony_ci           uint32_t *status)
51567db96d56Sopenharmony_ci{
51577db96d56Sopenharmony_ci    mpd_context_t workctx;
51587db96d56Sopenharmony_ci    mpd_ssize_t adjexp, t;
51597db96d56Sopenharmony_ci
51607db96d56Sopenharmony_ci    workctx = *ctx;
51617db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_HALF_EVEN;
51627db96d56Sopenharmony_ci
51637db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
51647db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
51657db96d56Sopenharmony_ci            return;
51667db96d56Sopenharmony_ci        }
51677db96d56Sopenharmony_ci        if (mpd_isnegative(a)) {
51687db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
51697db96d56Sopenharmony_ci            return;
51707db96d56Sopenharmony_ci        }
51717db96d56Sopenharmony_ci        mpd_setspecial(result, MPD_POS, MPD_INF);
51727db96d56Sopenharmony_ci        return;
51737db96d56Sopenharmony_ci    }
51747db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
51757db96d56Sopenharmony_ci        mpd_setspecial(result, MPD_NEG, MPD_INF);
51767db96d56Sopenharmony_ci        return;
51777db96d56Sopenharmony_ci    }
51787db96d56Sopenharmony_ci    if (mpd_isnegative(a)) {
51797db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
51807db96d56Sopenharmony_ci        return;
51817db96d56Sopenharmony_ci    }
51827db96d56Sopenharmony_ci    if (mpd_coeff_ispow10(a)) {
51837db96d56Sopenharmony_ci        uint8_t sign = 0;
51847db96d56Sopenharmony_ci        adjexp = mpd_adjexp(a);
51857db96d56Sopenharmony_ci        if (adjexp < 0) {
51867db96d56Sopenharmony_ci            sign = 1;
51877db96d56Sopenharmony_ci            adjexp = -adjexp;
51887db96d56Sopenharmony_ci        }
51897db96d56Sopenharmony_ci        _settriple(result, sign, adjexp, 0);
51907db96d56Sopenharmony_ci        mpd_qfinalize(result, &workctx, status);
51917db96d56Sopenharmony_ci        return;
51927db96d56Sopenharmony_ci    }
51937db96d56Sopenharmony_ci    /*
51947db96d56Sopenharmony_ci     * Check if the result will overflow (0 < x, x != 1):
51957db96d56Sopenharmony_ci     *   1) log10(x) < 0 iff adjexp(x) < 0
51967db96d56Sopenharmony_ci     *   2) 0 < x /\ x <= y ==> adjexp(x) <= adjexp(y)
51977db96d56Sopenharmony_ci     *   3) adjexp(x) <= log10(x) < adjexp(x) + 1
51987db96d56Sopenharmony_ci     *
51997db96d56Sopenharmony_ci     * Case adjexp(x) >= 0:
52007db96d56Sopenharmony_ci     *   4) adjexp(x) <= abs(log10(x))
52017db96d56Sopenharmony_ci     *   Case adjexp(x) > 0:
52027db96d56Sopenharmony_ci     *     5) adjexp(adjexp(x)) <= adjexp(abs(log10(x)))
52037db96d56Sopenharmony_ci     *   Case adjexp(x) == 0:
52047db96d56Sopenharmony_ci     *     mpd_exp_digits(t)-1 == 0 <= emax (the shortcut is not triggered)
52057db96d56Sopenharmony_ci     *
52067db96d56Sopenharmony_ci     * Case adjexp(x) < 0:
52077db96d56Sopenharmony_ci     *   6) -adjexp(x) - 1 < abs(log10(x))
52087db96d56Sopenharmony_ci     *   Case adjexp(x) < -1:
52097db96d56Sopenharmony_ci     *     7) adjexp(-adjexp(x) - 1) <= adjexp(abs(log(x)))
52107db96d56Sopenharmony_ci     *   Case adjexp(x) == -1:
52117db96d56Sopenharmony_ci     *     mpd_exp_digits(t)-1 == 0 <= emax (the shortcut is not triggered)
52127db96d56Sopenharmony_ci     */
52137db96d56Sopenharmony_ci    adjexp = mpd_adjexp(a);
52147db96d56Sopenharmony_ci    t = (adjexp < 0) ? -adjexp-1 : adjexp;
52157db96d56Sopenharmony_ci    if (mpd_exp_digits(t)-1 > ctx->emax) {
52167db96d56Sopenharmony_ci        *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
52177db96d56Sopenharmony_ci        mpd_setspecial(result, (adjexp<0), MPD_INF);
52187db96d56Sopenharmony_ci        return;
52197db96d56Sopenharmony_ci    }
52207db96d56Sopenharmony_ci
52217db96d56Sopenharmony_ci    if (ctx->allcr) {
52227db96d56Sopenharmony_ci        MPD_NEW_STATIC(t1, 0,0,0,0);
52237db96d56Sopenharmony_ci        MPD_NEW_STATIC(t2, 0,0,0,0);
52247db96d56Sopenharmony_ci        MPD_NEW_STATIC(ulp, 0,0,0,0);
52257db96d56Sopenharmony_ci        MPD_NEW_STATIC(aa, 0,0,0,0);
52267db96d56Sopenharmony_ci        mpd_ssize_t prec;
52277db96d56Sopenharmony_ci
52287db96d56Sopenharmony_ci        if (result == a) {
52297db96d56Sopenharmony_ci            if (!mpd_qcopy(&aa, a, status)) {
52307db96d56Sopenharmony_ci                mpd_seterror(result, MPD_Malloc_error, status);
52317db96d56Sopenharmony_ci                return;
52327db96d56Sopenharmony_ci            }
52337db96d56Sopenharmony_ci            a = &aa;
52347db96d56Sopenharmony_ci        }
52357db96d56Sopenharmony_ci
52367db96d56Sopenharmony_ci        workctx.clamp = 0;
52377db96d56Sopenharmony_ci        prec = ctx->prec + 3;
52387db96d56Sopenharmony_ci        while (1) {
52397db96d56Sopenharmony_ci            workctx.prec = prec;
52407db96d56Sopenharmony_ci            _mpd_qlog10(SKIP_FINALIZE, result, a, &workctx, status);
52417db96d56Sopenharmony_ci            _ssettriple(&ulp, MPD_POS, 1,
52427db96d56Sopenharmony_ci                        result->exp + result->digits-workctx.prec);
52437db96d56Sopenharmony_ci
52447db96d56Sopenharmony_ci            workctx.prec = ctx->prec;
52457db96d56Sopenharmony_ci            mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
52467db96d56Sopenharmony_ci            mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
52477db96d56Sopenharmony_ci            if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
52487db96d56Sopenharmony_ci                mpd_qcmp(&t1, &t2, status) == 0) {
52497db96d56Sopenharmony_ci                workctx.clamp = ctx->clamp;
52507db96d56Sopenharmony_ci                mpd_check_underflow(result, &workctx, status);
52517db96d56Sopenharmony_ci                mpd_qfinalize(result, &workctx, status);
52527db96d56Sopenharmony_ci                break;
52537db96d56Sopenharmony_ci            }
52547db96d56Sopenharmony_ci            prec += MPD_RDIGITS;
52557db96d56Sopenharmony_ci        }
52567db96d56Sopenharmony_ci        mpd_del(&t1);
52577db96d56Sopenharmony_ci        mpd_del(&t2);
52587db96d56Sopenharmony_ci        mpd_del(&ulp);
52597db96d56Sopenharmony_ci        mpd_del(&aa);
52607db96d56Sopenharmony_ci    }
52617db96d56Sopenharmony_ci    else {
52627db96d56Sopenharmony_ci        _mpd_qlog10(DO_FINALIZE, result, a, &workctx, status);
52637db96d56Sopenharmony_ci        mpd_check_underflow(result, &workctx, status);
52647db96d56Sopenharmony_ci    }
52657db96d56Sopenharmony_ci}
52667db96d56Sopenharmony_ci
52677db96d56Sopenharmony_ci/*
52687db96d56Sopenharmony_ci * Maximum of the two operands. Attention: If one operand is a quiet NaN and the
52697db96d56Sopenharmony_ci * other is numeric, the numeric operand is returned. This may not be what one
52707db96d56Sopenharmony_ci * expects.
52717db96d56Sopenharmony_ci */
52727db96d56Sopenharmony_civoid
52737db96d56Sopenharmony_cimpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b,
52747db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
52757db96d56Sopenharmony_ci{
52767db96d56Sopenharmony_ci    int c;
52777db96d56Sopenharmony_ci
52787db96d56Sopenharmony_ci    if (mpd_isqnan(a) && !mpd_isnan(b)) {
52797db96d56Sopenharmony_ci        mpd_qcopy(result, b, status);
52807db96d56Sopenharmony_ci    }
52817db96d56Sopenharmony_ci    else if (mpd_isqnan(b) && !mpd_isnan(a)) {
52827db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
52837db96d56Sopenharmony_ci    }
52847db96d56Sopenharmony_ci    else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
52857db96d56Sopenharmony_ci        return;
52867db96d56Sopenharmony_ci    }
52877db96d56Sopenharmony_ci    else {
52887db96d56Sopenharmony_ci        c = _mpd_cmp(a, b);
52897db96d56Sopenharmony_ci        if (c == 0) {
52907db96d56Sopenharmony_ci            c = _mpd_cmp_numequal(a, b);
52917db96d56Sopenharmony_ci        }
52927db96d56Sopenharmony_ci
52937db96d56Sopenharmony_ci        if (c < 0) {
52947db96d56Sopenharmony_ci            mpd_qcopy(result, b, status);
52957db96d56Sopenharmony_ci        }
52967db96d56Sopenharmony_ci        else {
52977db96d56Sopenharmony_ci            mpd_qcopy(result, a, status);
52987db96d56Sopenharmony_ci        }
52997db96d56Sopenharmony_ci    }
53007db96d56Sopenharmony_ci
53017db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
53027db96d56Sopenharmony_ci}
53037db96d56Sopenharmony_ci
53047db96d56Sopenharmony_ci/*
53057db96d56Sopenharmony_ci * Maximum magnitude: Same as mpd_max(), but compares the operands with their
53067db96d56Sopenharmony_ci * sign ignored.
53077db96d56Sopenharmony_ci */
53087db96d56Sopenharmony_civoid
53097db96d56Sopenharmony_cimpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b,
53107db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
53117db96d56Sopenharmony_ci{
53127db96d56Sopenharmony_ci    int c;
53137db96d56Sopenharmony_ci
53147db96d56Sopenharmony_ci    if (mpd_isqnan(a) && !mpd_isnan(b)) {
53157db96d56Sopenharmony_ci        mpd_qcopy(result, b, status);
53167db96d56Sopenharmony_ci    }
53177db96d56Sopenharmony_ci    else if (mpd_isqnan(b) && !mpd_isnan(a)) {
53187db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
53197db96d56Sopenharmony_ci    }
53207db96d56Sopenharmony_ci    else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
53217db96d56Sopenharmony_ci        return;
53227db96d56Sopenharmony_ci    }
53237db96d56Sopenharmony_ci    else {
53247db96d56Sopenharmony_ci        c = _mpd_cmp_abs(a, b);
53257db96d56Sopenharmony_ci        if (c == 0) {
53267db96d56Sopenharmony_ci            c = _mpd_cmp_numequal(a, b);
53277db96d56Sopenharmony_ci        }
53287db96d56Sopenharmony_ci
53297db96d56Sopenharmony_ci        if (c < 0) {
53307db96d56Sopenharmony_ci            mpd_qcopy(result, b, status);
53317db96d56Sopenharmony_ci        }
53327db96d56Sopenharmony_ci        else {
53337db96d56Sopenharmony_ci            mpd_qcopy(result, a, status);
53347db96d56Sopenharmony_ci        }
53357db96d56Sopenharmony_ci    }
53367db96d56Sopenharmony_ci
53377db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
53387db96d56Sopenharmony_ci}
53397db96d56Sopenharmony_ci
53407db96d56Sopenharmony_ci/*
53417db96d56Sopenharmony_ci * Minimum of the two operands. Attention: If one operand is a quiet NaN and the
53427db96d56Sopenharmony_ci * other is numeric, the numeric operand is returned. This may not be what one
53437db96d56Sopenharmony_ci * expects.
53447db96d56Sopenharmony_ci */
53457db96d56Sopenharmony_civoid
53467db96d56Sopenharmony_cimpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b,
53477db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
53487db96d56Sopenharmony_ci{
53497db96d56Sopenharmony_ci    int c;
53507db96d56Sopenharmony_ci
53517db96d56Sopenharmony_ci    if (mpd_isqnan(a) && !mpd_isnan(b)) {
53527db96d56Sopenharmony_ci        mpd_qcopy(result, b, status);
53537db96d56Sopenharmony_ci    }
53547db96d56Sopenharmony_ci    else if (mpd_isqnan(b) && !mpd_isnan(a)) {
53557db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
53567db96d56Sopenharmony_ci    }
53577db96d56Sopenharmony_ci    else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
53587db96d56Sopenharmony_ci        return;
53597db96d56Sopenharmony_ci    }
53607db96d56Sopenharmony_ci    else {
53617db96d56Sopenharmony_ci        c = _mpd_cmp(a, b);
53627db96d56Sopenharmony_ci        if (c == 0) {
53637db96d56Sopenharmony_ci            c = _mpd_cmp_numequal(a, b);
53647db96d56Sopenharmony_ci        }
53657db96d56Sopenharmony_ci
53667db96d56Sopenharmony_ci        if (c < 0) {
53677db96d56Sopenharmony_ci            mpd_qcopy(result, a, status);
53687db96d56Sopenharmony_ci        }
53697db96d56Sopenharmony_ci        else {
53707db96d56Sopenharmony_ci            mpd_qcopy(result, b, status);
53717db96d56Sopenharmony_ci        }
53727db96d56Sopenharmony_ci    }
53737db96d56Sopenharmony_ci
53747db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
53757db96d56Sopenharmony_ci}
53767db96d56Sopenharmony_ci
53777db96d56Sopenharmony_ci/*
53787db96d56Sopenharmony_ci * Minimum magnitude: Same as mpd_min(), but compares the operands with their
53797db96d56Sopenharmony_ci * sign ignored.
53807db96d56Sopenharmony_ci */
53817db96d56Sopenharmony_civoid
53827db96d56Sopenharmony_cimpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b,
53837db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
53847db96d56Sopenharmony_ci{
53857db96d56Sopenharmony_ci    int c;
53867db96d56Sopenharmony_ci
53877db96d56Sopenharmony_ci    if (mpd_isqnan(a) && !mpd_isnan(b)) {
53887db96d56Sopenharmony_ci        mpd_qcopy(result, b, status);
53897db96d56Sopenharmony_ci    }
53907db96d56Sopenharmony_ci    else if (mpd_isqnan(b) && !mpd_isnan(a)) {
53917db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
53927db96d56Sopenharmony_ci    }
53937db96d56Sopenharmony_ci    else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
53947db96d56Sopenharmony_ci        return;
53957db96d56Sopenharmony_ci    }
53967db96d56Sopenharmony_ci    else {
53977db96d56Sopenharmony_ci        c = _mpd_cmp_abs(a, b);
53987db96d56Sopenharmony_ci        if (c == 0) {
53997db96d56Sopenharmony_ci            c = _mpd_cmp_numequal(a, b);
54007db96d56Sopenharmony_ci        }
54017db96d56Sopenharmony_ci
54027db96d56Sopenharmony_ci        if (c < 0) {
54037db96d56Sopenharmony_ci            mpd_qcopy(result, a, status);
54047db96d56Sopenharmony_ci        }
54057db96d56Sopenharmony_ci        else {
54067db96d56Sopenharmony_ci            mpd_qcopy(result, b, status);
54077db96d56Sopenharmony_ci        }
54087db96d56Sopenharmony_ci    }
54097db96d56Sopenharmony_ci
54107db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
54117db96d56Sopenharmony_ci}
54127db96d56Sopenharmony_ci
54137db96d56Sopenharmony_ci/* Minimum space needed for the result array in _karatsuba_rec(). */
54147db96d56Sopenharmony_cistatic inline mpd_size_t
54157db96d56Sopenharmony_ci_kmul_resultsize(mpd_size_t la, mpd_size_t lb)
54167db96d56Sopenharmony_ci{
54177db96d56Sopenharmony_ci    mpd_size_t n, m;
54187db96d56Sopenharmony_ci
54197db96d56Sopenharmony_ci    n = add_size_t(la, lb);
54207db96d56Sopenharmony_ci    n = add_size_t(n, 1);
54217db96d56Sopenharmony_ci
54227db96d56Sopenharmony_ci    m = (la+1)/2 + 1;
54237db96d56Sopenharmony_ci    m = mul_size_t(m, 3);
54247db96d56Sopenharmony_ci
54257db96d56Sopenharmony_ci    return (m > n) ? m : n;
54267db96d56Sopenharmony_ci}
54277db96d56Sopenharmony_ci
54287db96d56Sopenharmony_ci/* Work space needed in _karatsuba_rec(). lim >= 4 */
54297db96d56Sopenharmony_cistatic inline mpd_size_t
54307db96d56Sopenharmony_ci_kmul_worksize(mpd_size_t n, mpd_size_t lim)
54317db96d56Sopenharmony_ci{
54327db96d56Sopenharmony_ci    mpd_size_t m;
54337db96d56Sopenharmony_ci
54347db96d56Sopenharmony_ci    if (n <= lim) {
54357db96d56Sopenharmony_ci        return 0;
54367db96d56Sopenharmony_ci    }
54377db96d56Sopenharmony_ci
54387db96d56Sopenharmony_ci    m = (n+1)/2 + 1;
54397db96d56Sopenharmony_ci
54407db96d56Sopenharmony_ci    return add_size_t(mul_size_t(m, 2), _kmul_worksize(m, lim));
54417db96d56Sopenharmony_ci}
54427db96d56Sopenharmony_ci
54437db96d56Sopenharmony_ci
54447db96d56Sopenharmony_ci#define MPD_KARATSUBA_BASECASE 16  /* must be >= 4 */
54457db96d56Sopenharmony_ci
54467db96d56Sopenharmony_ci/*
54477db96d56Sopenharmony_ci * Add the product of a and b to c.
54487db96d56Sopenharmony_ci * c must be _kmul_resultsize(la, lb) in size.
54497db96d56Sopenharmony_ci * w is used as a work array and must be _kmul_worksize(a, lim) in size.
54507db96d56Sopenharmony_ci * Roman E. Maeder, Storage Allocation for the Karatsuba Integer Multiplication
54517db96d56Sopenharmony_ci * Algorithm. In "Design and implementation of symbolic computation systems",
54527db96d56Sopenharmony_ci * Springer, 1993, ISBN 354057235X, 9783540572350.
54537db96d56Sopenharmony_ci */
54547db96d56Sopenharmony_cistatic void
54557db96d56Sopenharmony_ci_karatsuba_rec(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b,
54567db96d56Sopenharmony_ci               mpd_uint_t *w, mpd_size_t la, mpd_size_t lb)
54577db96d56Sopenharmony_ci{
54587db96d56Sopenharmony_ci    mpd_size_t m, lt;
54597db96d56Sopenharmony_ci
54607db96d56Sopenharmony_ci    assert(la >= lb && lb > 0);
54617db96d56Sopenharmony_ci    assert(la <= MPD_KARATSUBA_BASECASE || w != NULL);
54627db96d56Sopenharmony_ci
54637db96d56Sopenharmony_ci    if (la <= MPD_KARATSUBA_BASECASE) {
54647db96d56Sopenharmony_ci        _mpd_basemul(c, a, b, la, lb);
54657db96d56Sopenharmony_ci        return;
54667db96d56Sopenharmony_ci    }
54677db96d56Sopenharmony_ci
54687db96d56Sopenharmony_ci    m = (la+1)/2;  /* ceil(la/2) */
54697db96d56Sopenharmony_ci
54707db96d56Sopenharmony_ci    /* lb <= m < la */
54717db96d56Sopenharmony_ci    if (lb <= m) {
54727db96d56Sopenharmony_ci
54737db96d56Sopenharmony_ci        /* lb can now be larger than la-m */
54747db96d56Sopenharmony_ci        if (lb > la-m) {
54757db96d56Sopenharmony_ci            lt = lb + lb + 1;       /* space needed for result array */
54767db96d56Sopenharmony_ci            mpd_uint_zero(w, lt);   /* clear result array */
54777db96d56Sopenharmony_ci            _karatsuba_rec(w, b, a+m, w+lt, lb, la-m); /* b*ah */
54787db96d56Sopenharmony_ci        }
54797db96d56Sopenharmony_ci        else {
54807db96d56Sopenharmony_ci            lt = (la-m) + (la-m) + 1;  /* space needed for result array */
54817db96d56Sopenharmony_ci            mpd_uint_zero(w, lt);      /* clear result array */
54827db96d56Sopenharmony_ci            _karatsuba_rec(w, a+m, b, w+lt, la-m, lb); /* ah*b */
54837db96d56Sopenharmony_ci        }
54847db96d56Sopenharmony_ci        _mpd_baseaddto(c+m, w, (la-m)+lb);      /* add ah*b*B**m */
54857db96d56Sopenharmony_ci
54867db96d56Sopenharmony_ci        lt = m + m + 1;         /* space needed for the result array */
54877db96d56Sopenharmony_ci        mpd_uint_zero(w, lt);   /* clear result array */
54887db96d56Sopenharmony_ci        _karatsuba_rec(w, a, b, w+lt, m, lb);  /* al*b */
54897db96d56Sopenharmony_ci        _mpd_baseaddto(c, w, m+lb);    /* add al*b */
54907db96d56Sopenharmony_ci
54917db96d56Sopenharmony_ci        return;
54927db96d56Sopenharmony_ci    }
54937db96d56Sopenharmony_ci
54947db96d56Sopenharmony_ci    /* la >= lb > m */
54957db96d56Sopenharmony_ci    memcpy(w, a, m * sizeof *w);
54967db96d56Sopenharmony_ci    w[m] = 0;
54977db96d56Sopenharmony_ci    _mpd_baseaddto(w, a+m, la-m);
54987db96d56Sopenharmony_ci
54997db96d56Sopenharmony_ci    memcpy(w+(m+1), b, m * sizeof *w);
55007db96d56Sopenharmony_ci    w[m+1+m] = 0;
55017db96d56Sopenharmony_ci    _mpd_baseaddto(w+(m+1), b+m, lb-m);
55027db96d56Sopenharmony_ci
55037db96d56Sopenharmony_ci    _karatsuba_rec(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1);
55047db96d56Sopenharmony_ci
55057db96d56Sopenharmony_ci    lt = (la-m) + (la-m) + 1;
55067db96d56Sopenharmony_ci    mpd_uint_zero(w, lt);
55077db96d56Sopenharmony_ci
55087db96d56Sopenharmony_ci    _karatsuba_rec(w, a+m, b+m, w+lt, la-m, lb-m);
55097db96d56Sopenharmony_ci
55107db96d56Sopenharmony_ci    _mpd_baseaddto(c+2*m, w, (la-m) + (lb-m));
55117db96d56Sopenharmony_ci    _mpd_basesubfrom(c+m, w, (la-m) + (lb-m));
55127db96d56Sopenharmony_ci
55137db96d56Sopenharmony_ci    lt = m + m + 1;
55147db96d56Sopenharmony_ci    mpd_uint_zero(w, lt);
55157db96d56Sopenharmony_ci
55167db96d56Sopenharmony_ci    _karatsuba_rec(w, a, b, w+lt, m, m);
55177db96d56Sopenharmony_ci    _mpd_baseaddto(c, w, m+m);
55187db96d56Sopenharmony_ci    _mpd_basesubfrom(c+m, w, m+m);
55197db96d56Sopenharmony_ci
55207db96d56Sopenharmony_ci    return;
55217db96d56Sopenharmony_ci}
55227db96d56Sopenharmony_ci
55237db96d56Sopenharmony_ci/*
55247db96d56Sopenharmony_ci * Multiply u and v, using Karatsuba multiplication. Returns a pointer
55257db96d56Sopenharmony_ci * to the result or NULL in case of failure (malloc error).
55267db96d56Sopenharmony_ci * Conditions: ulen >= vlen, ulen >= 4
55277db96d56Sopenharmony_ci */
55287db96d56Sopenharmony_cistatic mpd_uint_t *
55297db96d56Sopenharmony_ci_mpd_kmul(const mpd_uint_t *u, const mpd_uint_t *v,
55307db96d56Sopenharmony_ci          mpd_size_t ulen, mpd_size_t vlen,
55317db96d56Sopenharmony_ci          mpd_size_t *rsize)
55327db96d56Sopenharmony_ci{
55337db96d56Sopenharmony_ci    mpd_uint_t *result = NULL, *w = NULL;
55347db96d56Sopenharmony_ci    mpd_size_t m;
55357db96d56Sopenharmony_ci
55367db96d56Sopenharmony_ci    assert(ulen >= 4);
55377db96d56Sopenharmony_ci    assert(ulen >= vlen);
55387db96d56Sopenharmony_ci
55397db96d56Sopenharmony_ci    *rsize = _kmul_resultsize(ulen, vlen);
55407db96d56Sopenharmony_ci    if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) {
55417db96d56Sopenharmony_ci        return NULL;
55427db96d56Sopenharmony_ci    }
55437db96d56Sopenharmony_ci
55447db96d56Sopenharmony_ci    m = _kmul_worksize(ulen, MPD_KARATSUBA_BASECASE);
55457db96d56Sopenharmony_ci    if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) {
55467db96d56Sopenharmony_ci        mpd_free(result);
55477db96d56Sopenharmony_ci        return NULL;
55487db96d56Sopenharmony_ci    }
55497db96d56Sopenharmony_ci
55507db96d56Sopenharmony_ci    _karatsuba_rec(result, u, v, w, ulen, vlen);
55517db96d56Sopenharmony_ci
55527db96d56Sopenharmony_ci
55537db96d56Sopenharmony_ci    if (w) mpd_free(w);
55547db96d56Sopenharmony_ci    return result;
55557db96d56Sopenharmony_ci}
55567db96d56Sopenharmony_ci
55577db96d56Sopenharmony_ci
55587db96d56Sopenharmony_ci/*
55597db96d56Sopenharmony_ci * Determine the minimum length for the number theoretic transform. Valid
55607db96d56Sopenharmony_ci * transform lengths are 2**n or 3*2**n, where 2**n <= MPD_MAXTRANSFORM_2N.
55617db96d56Sopenharmony_ci * The function finds the shortest length m such that rsize <= m.
55627db96d56Sopenharmony_ci */
55637db96d56Sopenharmony_cistatic inline mpd_size_t
55647db96d56Sopenharmony_ci_mpd_get_transform_len(mpd_size_t rsize)
55657db96d56Sopenharmony_ci{
55667db96d56Sopenharmony_ci    mpd_size_t log2rsize;
55677db96d56Sopenharmony_ci    mpd_size_t x, step;
55687db96d56Sopenharmony_ci
55697db96d56Sopenharmony_ci    assert(rsize >= 4);
55707db96d56Sopenharmony_ci    log2rsize = mpd_bsr(rsize);
55717db96d56Sopenharmony_ci
55727db96d56Sopenharmony_ci    if (rsize <= 1024) {
55737db96d56Sopenharmony_ci        /* 2**n is faster in this range. */
55747db96d56Sopenharmony_ci        x = ((mpd_size_t)1)<<log2rsize;
55757db96d56Sopenharmony_ci        return (rsize == x) ? x : x<<1;
55767db96d56Sopenharmony_ci    }
55777db96d56Sopenharmony_ci    else if (rsize <= MPD_MAXTRANSFORM_2N) {
55787db96d56Sopenharmony_ci        x = ((mpd_size_t)1)<<log2rsize;
55797db96d56Sopenharmony_ci        if (rsize == x) return x;
55807db96d56Sopenharmony_ci        step = x>>1;
55817db96d56Sopenharmony_ci        x += step;
55827db96d56Sopenharmony_ci        return (rsize <= x) ? x : x + step;
55837db96d56Sopenharmony_ci    }
55847db96d56Sopenharmony_ci    else if (rsize <= MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2) {
55857db96d56Sopenharmony_ci        return MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2;
55867db96d56Sopenharmony_ci    }
55877db96d56Sopenharmony_ci    else if (rsize <= 3*MPD_MAXTRANSFORM_2N) {
55887db96d56Sopenharmony_ci        return 3*MPD_MAXTRANSFORM_2N;
55897db96d56Sopenharmony_ci    }
55907db96d56Sopenharmony_ci    else {
55917db96d56Sopenharmony_ci        return MPD_SIZE_MAX;
55927db96d56Sopenharmony_ci    }
55937db96d56Sopenharmony_ci}
55947db96d56Sopenharmony_ci
55957db96d56Sopenharmony_ci#ifdef PPRO
55967db96d56Sopenharmony_ci#ifndef _MSC_VER
55977db96d56Sopenharmony_cistatic inline unsigned short
55987db96d56Sopenharmony_ci_mpd_get_control87(void)
55997db96d56Sopenharmony_ci{
56007db96d56Sopenharmony_ci    unsigned short cw;
56017db96d56Sopenharmony_ci
56027db96d56Sopenharmony_ci    __asm__ __volatile__ ("fnstcw %0" : "=m" (cw));
56037db96d56Sopenharmony_ci    return cw;
56047db96d56Sopenharmony_ci}
56057db96d56Sopenharmony_ci
56067db96d56Sopenharmony_cistatic inline void
56077db96d56Sopenharmony_ci_mpd_set_control87(unsigned short cw)
56087db96d56Sopenharmony_ci{
56097db96d56Sopenharmony_ci    __asm__ __volatile__ ("fldcw %0" : : "m" (cw));
56107db96d56Sopenharmony_ci}
56117db96d56Sopenharmony_ci#endif
56127db96d56Sopenharmony_ci
56137db96d56Sopenharmony_cistatic unsigned int
56147db96d56Sopenharmony_cimpd_set_fenv(void)
56157db96d56Sopenharmony_ci{
56167db96d56Sopenharmony_ci    unsigned int cw;
56177db96d56Sopenharmony_ci#ifdef _MSC_VER
56187db96d56Sopenharmony_ci    unsigned int flags =
56197db96d56Sopenharmony_ci        _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFLOW|
56207db96d56Sopenharmony_ci        _EM_UNDERFLOW|_EM_INEXACT|_RC_CHOP|_PC_64;
56217db96d56Sopenharmony_ci    unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC;
56227db96d56Sopenharmony_ci    unsigned int dummy;
56237db96d56Sopenharmony_ci
56247db96d56Sopenharmony_ci    __control87_2(0, 0, &cw, NULL);
56257db96d56Sopenharmony_ci    __control87_2(flags, mask, &dummy, NULL);
56267db96d56Sopenharmony_ci#else
56277db96d56Sopenharmony_ci    cw = _mpd_get_control87();
56287db96d56Sopenharmony_ci    _mpd_set_control87(cw|0xF3F);
56297db96d56Sopenharmony_ci#endif
56307db96d56Sopenharmony_ci    return cw;
56317db96d56Sopenharmony_ci}
56327db96d56Sopenharmony_ci
56337db96d56Sopenharmony_cistatic void
56347db96d56Sopenharmony_cimpd_restore_fenv(unsigned int cw)
56357db96d56Sopenharmony_ci{
56367db96d56Sopenharmony_ci#ifdef _MSC_VER
56377db96d56Sopenharmony_ci    unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC;
56387db96d56Sopenharmony_ci    unsigned int dummy;
56397db96d56Sopenharmony_ci
56407db96d56Sopenharmony_ci    __control87_2(cw, mask, &dummy, NULL);
56417db96d56Sopenharmony_ci#else
56427db96d56Sopenharmony_ci    _mpd_set_control87((unsigned short)cw);
56437db96d56Sopenharmony_ci#endif
56447db96d56Sopenharmony_ci}
56457db96d56Sopenharmony_ci#endif /* PPRO */
56467db96d56Sopenharmony_ci
56477db96d56Sopenharmony_ci/*
56487db96d56Sopenharmony_ci * Multiply u and v, using the fast number theoretic transform. Returns
56497db96d56Sopenharmony_ci * a pointer to the result or NULL in case of failure (malloc error).
56507db96d56Sopenharmony_ci */
56517db96d56Sopenharmony_cistatic mpd_uint_t *
56527db96d56Sopenharmony_ci_mpd_fntmul(const mpd_uint_t *u, const mpd_uint_t *v,
56537db96d56Sopenharmony_ci            mpd_size_t ulen, mpd_size_t vlen,
56547db96d56Sopenharmony_ci            mpd_size_t *rsize)
56557db96d56Sopenharmony_ci{
56567db96d56Sopenharmony_ci    mpd_uint_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *vtmp = NULL;
56577db96d56Sopenharmony_ci    mpd_size_t n;
56587db96d56Sopenharmony_ci
56597db96d56Sopenharmony_ci#ifdef PPRO
56607db96d56Sopenharmony_ci    unsigned int cw;
56617db96d56Sopenharmony_ci    cw = mpd_set_fenv();
56627db96d56Sopenharmony_ci#endif
56637db96d56Sopenharmony_ci
56647db96d56Sopenharmony_ci    *rsize = add_size_t(ulen, vlen);
56657db96d56Sopenharmony_ci    if ((n = _mpd_get_transform_len(*rsize)) == MPD_SIZE_MAX) {
56667db96d56Sopenharmony_ci        goto malloc_error;
56677db96d56Sopenharmony_ci    }
56687db96d56Sopenharmony_ci
56697db96d56Sopenharmony_ci    if ((c1 = mpd_calloc(n, sizeof *c1)) == NULL) {
56707db96d56Sopenharmony_ci        goto malloc_error;
56717db96d56Sopenharmony_ci    }
56727db96d56Sopenharmony_ci    if ((c2 = mpd_calloc(n, sizeof *c2)) == NULL) {
56737db96d56Sopenharmony_ci        goto malloc_error;
56747db96d56Sopenharmony_ci    }
56757db96d56Sopenharmony_ci    if ((c3 = mpd_calloc(n, sizeof *c3)) == NULL) {
56767db96d56Sopenharmony_ci        goto malloc_error;
56777db96d56Sopenharmony_ci    }
56787db96d56Sopenharmony_ci
56797db96d56Sopenharmony_ci    memcpy(c1, u, ulen * (sizeof *c1));
56807db96d56Sopenharmony_ci    memcpy(c2, u, ulen * (sizeof *c2));
56817db96d56Sopenharmony_ci    memcpy(c3, u, ulen * (sizeof *c3));
56827db96d56Sopenharmony_ci
56837db96d56Sopenharmony_ci    if (u == v) {
56847db96d56Sopenharmony_ci        if (!fnt_autoconvolute(c1, n, P1) ||
56857db96d56Sopenharmony_ci            !fnt_autoconvolute(c2, n, P2) ||
56867db96d56Sopenharmony_ci            !fnt_autoconvolute(c3, n, P3)) {
56877db96d56Sopenharmony_ci            goto malloc_error;
56887db96d56Sopenharmony_ci        }
56897db96d56Sopenharmony_ci    }
56907db96d56Sopenharmony_ci    else {
56917db96d56Sopenharmony_ci        if ((vtmp = mpd_calloc(n, sizeof *vtmp)) == NULL) {
56927db96d56Sopenharmony_ci            goto malloc_error;
56937db96d56Sopenharmony_ci        }
56947db96d56Sopenharmony_ci
56957db96d56Sopenharmony_ci        memcpy(vtmp, v, vlen * (sizeof *vtmp));
56967db96d56Sopenharmony_ci        if (!fnt_convolute(c1, vtmp, n, P1)) {
56977db96d56Sopenharmony_ci            mpd_free(vtmp);
56987db96d56Sopenharmony_ci            goto malloc_error;
56997db96d56Sopenharmony_ci        }
57007db96d56Sopenharmony_ci
57017db96d56Sopenharmony_ci        memcpy(vtmp, v, vlen * (sizeof *vtmp));
57027db96d56Sopenharmony_ci        mpd_uint_zero(vtmp+vlen, n-vlen);
57037db96d56Sopenharmony_ci        if (!fnt_convolute(c2, vtmp, n, P2)) {
57047db96d56Sopenharmony_ci            mpd_free(vtmp);
57057db96d56Sopenharmony_ci            goto malloc_error;
57067db96d56Sopenharmony_ci        }
57077db96d56Sopenharmony_ci
57087db96d56Sopenharmony_ci        memcpy(vtmp, v, vlen * (sizeof *vtmp));
57097db96d56Sopenharmony_ci        mpd_uint_zero(vtmp+vlen, n-vlen);
57107db96d56Sopenharmony_ci        if (!fnt_convolute(c3, vtmp, n, P3)) {
57117db96d56Sopenharmony_ci            mpd_free(vtmp);
57127db96d56Sopenharmony_ci            goto malloc_error;
57137db96d56Sopenharmony_ci        }
57147db96d56Sopenharmony_ci
57157db96d56Sopenharmony_ci        mpd_free(vtmp);
57167db96d56Sopenharmony_ci    }
57177db96d56Sopenharmony_ci
57187db96d56Sopenharmony_ci    crt3(c1, c2, c3, *rsize);
57197db96d56Sopenharmony_ci
57207db96d56Sopenharmony_ciout:
57217db96d56Sopenharmony_ci#ifdef PPRO
57227db96d56Sopenharmony_ci    mpd_restore_fenv(cw);
57237db96d56Sopenharmony_ci#endif
57247db96d56Sopenharmony_ci    if (c2) mpd_free(c2);
57257db96d56Sopenharmony_ci    if (c3) mpd_free(c3);
57267db96d56Sopenharmony_ci    return c1;
57277db96d56Sopenharmony_ci
57287db96d56Sopenharmony_cimalloc_error:
57297db96d56Sopenharmony_ci    if (c1) mpd_free(c1);
57307db96d56Sopenharmony_ci    c1 = NULL;
57317db96d56Sopenharmony_ci    goto out;
57327db96d56Sopenharmony_ci}
57337db96d56Sopenharmony_ci
57347db96d56Sopenharmony_ci
57357db96d56Sopenharmony_ci/*
57367db96d56Sopenharmony_ci * Karatsuba multiplication with FNT/basemul as the base case.
57377db96d56Sopenharmony_ci */
57387db96d56Sopenharmony_cistatic int
57397db96d56Sopenharmony_ci_karatsuba_rec_fnt(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b,
57407db96d56Sopenharmony_ci                   mpd_uint_t *w, mpd_size_t la, mpd_size_t lb)
57417db96d56Sopenharmony_ci{
57427db96d56Sopenharmony_ci    mpd_size_t m, lt;
57437db96d56Sopenharmony_ci
57447db96d56Sopenharmony_ci    assert(la >= lb && lb > 0);
57457db96d56Sopenharmony_ci    assert(la <= 3*(MPD_MAXTRANSFORM_2N/2) || w != NULL);
57467db96d56Sopenharmony_ci
57477db96d56Sopenharmony_ci    if (la <= 3*(MPD_MAXTRANSFORM_2N/2)) {
57487db96d56Sopenharmony_ci
57497db96d56Sopenharmony_ci        if (lb <= 192) {
57507db96d56Sopenharmony_ci            _mpd_basemul(c, b, a, lb, la);
57517db96d56Sopenharmony_ci        }
57527db96d56Sopenharmony_ci        else {
57537db96d56Sopenharmony_ci            mpd_uint_t *result;
57547db96d56Sopenharmony_ci            mpd_size_t dummy;
57557db96d56Sopenharmony_ci
57567db96d56Sopenharmony_ci            if ((result = _mpd_fntmul(a, b, la, lb, &dummy)) == NULL) {
57577db96d56Sopenharmony_ci                return 0;
57587db96d56Sopenharmony_ci            }
57597db96d56Sopenharmony_ci            memcpy(c, result, (la+lb) * (sizeof *result));
57607db96d56Sopenharmony_ci            mpd_free(result);
57617db96d56Sopenharmony_ci        }
57627db96d56Sopenharmony_ci        return 1;
57637db96d56Sopenharmony_ci    }
57647db96d56Sopenharmony_ci
57657db96d56Sopenharmony_ci    m = (la+1)/2;  /* ceil(la/2) */
57667db96d56Sopenharmony_ci
57677db96d56Sopenharmony_ci    /* lb <= m < la */
57687db96d56Sopenharmony_ci    if (lb <= m) {
57697db96d56Sopenharmony_ci
57707db96d56Sopenharmony_ci        /* lb can now be larger than la-m */
57717db96d56Sopenharmony_ci        if (lb > la-m) {
57727db96d56Sopenharmony_ci            lt = lb + lb + 1;       /* space needed for result array */
57737db96d56Sopenharmony_ci            mpd_uint_zero(w, lt);   /* clear result array */
57747db96d56Sopenharmony_ci            if (!_karatsuba_rec_fnt(w, b, a+m, w+lt, lb, la-m)) { /* b*ah */
57757db96d56Sopenharmony_ci                return 0; /* GCOV_UNLIKELY */
57767db96d56Sopenharmony_ci            }
57777db96d56Sopenharmony_ci        }
57787db96d56Sopenharmony_ci        else {
57797db96d56Sopenharmony_ci            lt = (la-m) + (la-m) + 1;  /* space needed for result array */
57807db96d56Sopenharmony_ci            mpd_uint_zero(w, lt);      /* clear result array */
57817db96d56Sopenharmony_ci            if (!_karatsuba_rec_fnt(w, a+m, b, w+lt, la-m, lb)) { /* ah*b */
57827db96d56Sopenharmony_ci                return 0; /* GCOV_UNLIKELY */
57837db96d56Sopenharmony_ci            }
57847db96d56Sopenharmony_ci        }
57857db96d56Sopenharmony_ci        _mpd_baseaddto(c+m, w, (la-m)+lb); /* add ah*b*B**m */
57867db96d56Sopenharmony_ci
57877db96d56Sopenharmony_ci        lt = m + m + 1;         /* space needed for the result array */
57887db96d56Sopenharmony_ci        mpd_uint_zero(w, lt);   /* clear result array */
57897db96d56Sopenharmony_ci        if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, lb)) {  /* al*b */
57907db96d56Sopenharmony_ci            return 0; /* GCOV_UNLIKELY */
57917db96d56Sopenharmony_ci        }
57927db96d56Sopenharmony_ci        _mpd_baseaddto(c, w, m+lb);       /* add al*b */
57937db96d56Sopenharmony_ci
57947db96d56Sopenharmony_ci        return 1;
57957db96d56Sopenharmony_ci    }
57967db96d56Sopenharmony_ci
57977db96d56Sopenharmony_ci    /* la >= lb > m */
57987db96d56Sopenharmony_ci    memcpy(w, a, m * sizeof *w);
57997db96d56Sopenharmony_ci    w[m] = 0;
58007db96d56Sopenharmony_ci    _mpd_baseaddto(w, a+m, la-m);
58017db96d56Sopenharmony_ci
58027db96d56Sopenharmony_ci    memcpy(w+(m+1), b, m * sizeof *w);
58037db96d56Sopenharmony_ci    w[m+1+m] = 0;
58047db96d56Sopenharmony_ci    _mpd_baseaddto(w+(m+1), b+m, lb-m);
58057db96d56Sopenharmony_ci
58067db96d56Sopenharmony_ci    if (!_karatsuba_rec_fnt(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1)) {
58077db96d56Sopenharmony_ci        return 0; /* GCOV_UNLIKELY */
58087db96d56Sopenharmony_ci    }
58097db96d56Sopenharmony_ci
58107db96d56Sopenharmony_ci    lt = (la-m) + (la-m) + 1;
58117db96d56Sopenharmony_ci    mpd_uint_zero(w, lt);
58127db96d56Sopenharmony_ci
58137db96d56Sopenharmony_ci    if (!_karatsuba_rec_fnt(w, a+m, b+m, w+lt, la-m, lb-m)) {
58147db96d56Sopenharmony_ci        return 0; /* GCOV_UNLIKELY */
58157db96d56Sopenharmony_ci    }
58167db96d56Sopenharmony_ci
58177db96d56Sopenharmony_ci    _mpd_baseaddto(c+2*m, w, (la-m) + (lb-m));
58187db96d56Sopenharmony_ci    _mpd_basesubfrom(c+m, w, (la-m) + (lb-m));
58197db96d56Sopenharmony_ci
58207db96d56Sopenharmony_ci    lt = m + m + 1;
58217db96d56Sopenharmony_ci    mpd_uint_zero(w, lt);
58227db96d56Sopenharmony_ci
58237db96d56Sopenharmony_ci    if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, m)) {
58247db96d56Sopenharmony_ci        return 0; /* GCOV_UNLIKELY */
58257db96d56Sopenharmony_ci    }
58267db96d56Sopenharmony_ci    _mpd_baseaddto(c, w, m+m);
58277db96d56Sopenharmony_ci    _mpd_basesubfrom(c+m, w, m+m);
58287db96d56Sopenharmony_ci
58297db96d56Sopenharmony_ci    return 1;
58307db96d56Sopenharmony_ci}
58317db96d56Sopenharmony_ci
58327db96d56Sopenharmony_ci/*
58337db96d56Sopenharmony_ci * Multiply u and v, using Karatsuba multiplication with the FNT as the
58347db96d56Sopenharmony_ci * base case. Returns a pointer to the result or NULL in case of failure
58357db96d56Sopenharmony_ci * (malloc error). Conditions: ulen >= vlen, ulen >= 4.
58367db96d56Sopenharmony_ci */
58377db96d56Sopenharmony_cistatic mpd_uint_t *
58387db96d56Sopenharmony_ci_mpd_kmul_fnt(const mpd_uint_t *u, const mpd_uint_t *v,
58397db96d56Sopenharmony_ci              mpd_size_t ulen, mpd_size_t vlen,
58407db96d56Sopenharmony_ci              mpd_size_t *rsize)
58417db96d56Sopenharmony_ci{
58427db96d56Sopenharmony_ci    mpd_uint_t *result = NULL, *w = NULL;
58437db96d56Sopenharmony_ci    mpd_size_t m;
58447db96d56Sopenharmony_ci
58457db96d56Sopenharmony_ci    assert(ulen >= 4);
58467db96d56Sopenharmony_ci    assert(ulen >= vlen);
58477db96d56Sopenharmony_ci
58487db96d56Sopenharmony_ci    *rsize = _kmul_resultsize(ulen, vlen);
58497db96d56Sopenharmony_ci    if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) {
58507db96d56Sopenharmony_ci        return NULL;
58517db96d56Sopenharmony_ci    }
58527db96d56Sopenharmony_ci
58537db96d56Sopenharmony_ci    m = _kmul_worksize(ulen, 3*(MPD_MAXTRANSFORM_2N/2));
58547db96d56Sopenharmony_ci    if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) {
58557db96d56Sopenharmony_ci        mpd_free(result); /* GCOV_UNLIKELY */
58567db96d56Sopenharmony_ci        return NULL; /* GCOV_UNLIKELY */
58577db96d56Sopenharmony_ci    }
58587db96d56Sopenharmony_ci
58597db96d56Sopenharmony_ci    if (!_karatsuba_rec_fnt(result, u, v, w, ulen, vlen)) {
58607db96d56Sopenharmony_ci        mpd_free(result);
58617db96d56Sopenharmony_ci        result = NULL;
58627db96d56Sopenharmony_ci    }
58637db96d56Sopenharmony_ci
58647db96d56Sopenharmony_ci
58657db96d56Sopenharmony_ci    if (w) mpd_free(w);
58667db96d56Sopenharmony_ci    return result;
58677db96d56Sopenharmony_ci}
58687db96d56Sopenharmony_ci
58697db96d56Sopenharmony_ci
58707db96d56Sopenharmony_ci/* Deal with the special cases of multiplying infinities. */
58717db96d56Sopenharmony_cistatic void
58727db96d56Sopenharmony_ci_mpd_qmul_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status)
58737db96d56Sopenharmony_ci{
58747db96d56Sopenharmony_ci    if (mpd_isinfinite(a)) {
58757db96d56Sopenharmony_ci        if (mpd_iszero(b)) {
58767db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
58777db96d56Sopenharmony_ci        }
58787db96d56Sopenharmony_ci        else {
58797db96d56Sopenharmony_ci            mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
58807db96d56Sopenharmony_ci        }
58817db96d56Sopenharmony_ci        return;
58827db96d56Sopenharmony_ci    }
58837db96d56Sopenharmony_ci    assert(mpd_isinfinite(b));
58847db96d56Sopenharmony_ci    if (mpd_iszero(a)) {
58857db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
58867db96d56Sopenharmony_ci    }
58877db96d56Sopenharmony_ci    else {
58887db96d56Sopenharmony_ci        mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
58897db96d56Sopenharmony_ci    }
58907db96d56Sopenharmony_ci}
58917db96d56Sopenharmony_ci
58927db96d56Sopenharmony_ci/*
58937db96d56Sopenharmony_ci * Internal function: Multiply a and b. _mpd_qmul deals with specials but
58947db96d56Sopenharmony_ci * does NOT finalize the result. This is for use in mpd_fma().
58957db96d56Sopenharmony_ci */
58967db96d56Sopenharmony_cistatic inline void
58977db96d56Sopenharmony_ci_mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
58987db96d56Sopenharmony_ci          const mpd_context_t *ctx, uint32_t *status)
58997db96d56Sopenharmony_ci{
59007db96d56Sopenharmony_ci    const mpd_t *big = a, *small = b;
59017db96d56Sopenharmony_ci    mpd_uint_t *rdata = NULL;
59027db96d56Sopenharmony_ci    mpd_uint_t rbuf[MPD_MINALLOC_MAX];
59037db96d56Sopenharmony_ci    mpd_size_t rsize, i;
59047db96d56Sopenharmony_ci
59057db96d56Sopenharmony_ci
59067db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
59077db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
59087db96d56Sopenharmony_ci            return;
59097db96d56Sopenharmony_ci        }
59107db96d56Sopenharmony_ci        _mpd_qmul_inf(result, a, b, status);
59117db96d56Sopenharmony_ci        return;
59127db96d56Sopenharmony_ci    }
59137db96d56Sopenharmony_ci
59147db96d56Sopenharmony_ci    if (small->len > big->len) {
59157db96d56Sopenharmony_ci        _mpd_ptrswap(&big, &small);
59167db96d56Sopenharmony_ci    }
59177db96d56Sopenharmony_ci
59187db96d56Sopenharmony_ci    rsize = big->len + small->len;
59197db96d56Sopenharmony_ci
59207db96d56Sopenharmony_ci    if (big->len == 1) {
59217db96d56Sopenharmony_ci        _mpd_singlemul(result->data, big->data[0], small->data[0]);
59227db96d56Sopenharmony_ci        goto finish;
59237db96d56Sopenharmony_ci    }
59247db96d56Sopenharmony_ci    if (rsize <= (mpd_size_t)MPD_MINALLOC_MAX) {
59257db96d56Sopenharmony_ci        if (big->len == 2) {
59267db96d56Sopenharmony_ci            _mpd_mul_2_le2(rbuf, big->data, small->data, small->len);
59277db96d56Sopenharmony_ci        }
59287db96d56Sopenharmony_ci        else {
59297db96d56Sopenharmony_ci            mpd_uint_zero(rbuf, rsize);
59307db96d56Sopenharmony_ci            if (small->len == 1) {
59317db96d56Sopenharmony_ci                _mpd_shortmul(rbuf, big->data, big->len, small->data[0]);
59327db96d56Sopenharmony_ci            }
59337db96d56Sopenharmony_ci            else {
59347db96d56Sopenharmony_ci                _mpd_basemul(rbuf, small->data, big->data, small->len, big->len);
59357db96d56Sopenharmony_ci            }
59367db96d56Sopenharmony_ci        }
59377db96d56Sopenharmony_ci        if (!mpd_qresize(result, rsize, status)) {
59387db96d56Sopenharmony_ci            return;
59397db96d56Sopenharmony_ci        }
59407db96d56Sopenharmony_ci        for(i = 0; i < rsize; i++) {
59417db96d56Sopenharmony_ci            result->data[i] = rbuf[i];
59427db96d56Sopenharmony_ci        }
59437db96d56Sopenharmony_ci        goto finish;
59447db96d56Sopenharmony_ci    }
59457db96d56Sopenharmony_ci
59467db96d56Sopenharmony_ci
59477db96d56Sopenharmony_ci    if (small->len <= 256) {
59487db96d56Sopenharmony_ci        rdata = mpd_calloc(rsize, sizeof *rdata);
59497db96d56Sopenharmony_ci        if (rdata != NULL) {
59507db96d56Sopenharmony_ci            if (small->len == 1) {
59517db96d56Sopenharmony_ci                _mpd_shortmul(rdata, big->data, big->len, small->data[0]);
59527db96d56Sopenharmony_ci            }
59537db96d56Sopenharmony_ci            else {
59547db96d56Sopenharmony_ci                _mpd_basemul(rdata, small->data, big->data, small->len, big->len);
59557db96d56Sopenharmony_ci            }
59567db96d56Sopenharmony_ci        }
59577db96d56Sopenharmony_ci    }
59587db96d56Sopenharmony_ci    else if (rsize <= 1024) {
59597db96d56Sopenharmony_ci        rdata = _mpd_kmul(big->data, small->data, big->len, small->len, &rsize);
59607db96d56Sopenharmony_ci    }
59617db96d56Sopenharmony_ci    else if (rsize <= 3*MPD_MAXTRANSFORM_2N) {
59627db96d56Sopenharmony_ci        rdata = _mpd_fntmul(big->data, small->data, big->len, small->len, &rsize);
59637db96d56Sopenharmony_ci    }
59647db96d56Sopenharmony_ci    else {
59657db96d56Sopenharmony_ci        rdata = _mpd_kmul_fnt(big->data, small->data, big->len, small->len, &rsize);
59667db96d56Sopenharmony_ci    }
59677db96d56Sopenharmony_ci
59687db96d56Sopenharmony_ci    if (rdata == NULL) {
59697db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Malloc_error, status);
59707db96d56Sopenharmony_ci        return;
59717db96d56Sopenharmony_ci    }
59727db96d56Sopenharmony_ci
59737db96d56Sopenharmony_ci    if (mpd_isdynamic_data(result)) {
59747db96d56Sopenharmony_ci        mpd_free(result->data);
59757db96d56Sopenharmony_ci    }
59767db96d56Sopenharmony_ci    result->data = rdata;
59777db96d56Sopenharmony_ci    result->alloc = rsize;
59787db96d56Sopenharmony_ci    mpd_set_dynamic_data(result);
59797db96d56Sopenharmony_ci
59807db96d56Sopenharmony_ci
59817db96d56Sopenharmony_cifinish:
59827db96d56Sopenharmony_ci    mpd_set_flags(result, mpd_sign(a)^mpd_sign(b));
59837db96d56Sopenharmony_ci    result->exp = big->exp + small->exp;
59847db96d56Sopenharmony_ci    result->len = _mpd_real_size(result->data, rsize);
59857db96d56Sopenharmony_ci    /* resize to smaller cannot fail */
59867db96d56Sopenharmony_ci    mpd_qresize(result, result->len, status);
59877db96d56Sopenharmony_ci    mpd_setdigits(result);
59887db96d56Sopenharmony_ci}
59897db96d56Sopenharmony_ci
59907db96d56Sopenharmony_ci/* Multiply a and b. */
59917db96d56Sopenharmony_civoid
59927db96d56Sopenharmony_cimpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
59937db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
59947db96d56Sopenharmony_ci{
59957db96d56Sopenharmony_ci    _mpd_qmul(result, a, b, ctx, status);
59967db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
59977db96d56Sopenharmony_ci}
59987db96d56Sopenharmony_ci
59997db96d56Sopenharmony_ci/* Multiply a and b. Set NaN/Invalid_operation if the result is inexact. */
60007db96d56Sopenharmony_cistatic void
60017db96d56Sopenharmony_ci_mpd_qmul_exact(mpd_t *result, const mpd_t *a, const mpd_t *b,
60027db96d56Sopenharmony_ci                const mpd_context_t *ctx, uint32_t *status)
60037db96d56Sopenharmony_ci{
60047db96d56Sopenharmony_ci    uint32_t workstatus = 0;
60057db96d56Sopenharmony_ci
60067db96d56Sopenharmony_ci    mpd_qmul(result, a, b, ctx, &workstatus);
60077db96d56Sopenharmony_ci    *status |= workstatus;
60087db96d56Sopenharmony_ci    if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
60097db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
60107db96d56Sopenharmony_ci    }
60117db96d56Sopenharmony_ci}
60127db96d56Sopenharmony_ci
60137db96d56Sopenharmony_ci/* Multiply decimal and mpd_ssize_t. */
60147db96d56Sopenharmony_civoid
60157db96d56Sopenharmony_cimpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b,
60167db96d56Sopenharmony_ci               const mpd_context_t *ctx, uint32_t *status)
60177db96d56Sopenharmony_ci{
60187db96d56Sopenharmony_ci    mpd_context_t maxcontext;
60197db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
60207db96d56Sopenharmony_ci
60217db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
60227db96d56Sopenharmony_ci    mpd_qsset_ssize(&bb, b, &maxcontext, status);
60237db96d56Sopenharmony_ci    mpd_qmul(result, a, &bb, ctx, status);
60247db96d56Sopenharmony_ci    mpd_del(&bb);
60257db96d56Sopenharmony_ci}
60267db96d56Sopenharmony_ci
60277db96d56Sopenharmony_ci/* Multiply decimal and mpd_uint_t. */
60287db96d56Sopenharmony_civoid
60297db96d56Sopenharmony_cimpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b,
60307db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
60317db96d56Sopenharmony_ci{
60327db96d56Sopenharmony_ci    mpd_context_t maxcontext;
60337db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
60347db96d56Sopenharmony_ci
60357db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
60367db96d56Sopenharmony_ci    mpd_qsset_uint(&bb, b, &maxcontext, status);
60377db96d56Sopenharmony_ci    mpd_qmul(result, a, &bb, ctx, status);
60387db96d56Sopenharmony_ci    mpd_del(&bb);
60397db96d56Sopenharmony_ci}
60407db96d56Sopenharmony_ci
60417db96d56Sopenharmony_civoid
60427db96d56Sopenharmony_cimpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b,
60437db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
60447db96d56Sopenharmony_ci{
60457db96d56Sopenharmony_ci    mpd_qmul_ssize(result, a, b, ctx, status);
60467db96d56Sopenharmony_ci}
60477db96d56Sopenharmony_ci
60487db96d56Sopenharmony_civoid
60497db96d56Sopenharmony_cimpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b,
60507db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
60517db96d56Sopenharmony_ci{
60527db96d56Sopenharmony_ci    mpd_qmul_uint(result, a, b, ctx, status);
60537db96d56Sopenharmony_ci}
60547db96d56Sopenharmony_ci
60557db96d56Sopenharmony_ci#ifdef CONFIG_64
60567db96d56Sopenharmony_civoid
60577db96d56Sopenharmony_cimpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b,
60587db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
60597db96d56Sopenharmony_ci{
60607db96d56Sopenharmony_ci    mpd_qmul_ssize(result, a, b, ctx, status);
60617db96d56Sopenharmony_ci}
60627db96d56Sopenharmony_ci
60637db96d56Sopenharmony_civoid
60647db96d56Sopenharmony_cimpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b,
60657db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
60667db96d56Sopenharmony_ci{
60677db96d56Sopenharmony_ci    mpd_qmul_uint(result, a, b, ctx, status);
60687db96d56Sopenharmony_ci}
60697db96d56Sopenharmony_ci#elif !defined(LEGACY_COMPILER)
60707db96d56Sopenharmony_ci/* Multiply decimal and int64_t. */
60717db96d56Sopenharmony_civoid
60727db96d56Sopenharmony_cimpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b,
60737db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
60747db96d56Sopenharmony_ci{
60757db96d56Sopenharmony_ci    mpd_context_t maxcontext;
60767db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
60777db96d56Sopenharmony_ci
60787db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
60797db96d56Sopenharmony_ci    mpd_qset_i64(&bb, b, &maxcontext, status);
60807db96d56Sopenharmony_ci    mpd_qmul(result, a, &bb, ctx, status);
60817db96d56Sopenharmony_ci    mpd_del(&bb);
60827db96d56Sopenharmony_ci}
60837db96d56Sopenharmony_ci
60847db96d56Sopenharmony_ci/* Multiply decimal and uint64_t. */
60857db96d56Sopenharmony_civoid
60867db96d56Sopenharmony_cimpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b,
60877db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
60887db96d56Sopenharmony_ci{
60897db96d56Sopenharmony_ci    mpd_context_t maxcontext;
60907db96d56Sopenharmony_ci    MPD_NEW_STATIC(bb,0,0,0,0);
60917db96d56Sopenharmony_ci
60927db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
60937db96d56Sopenharmony_ci    mpd_qset_u64(&bb, b, &maxcontext, status);
60947db96d56Sopenharmony_ci    mpd_qmul(result, a, &bb, ctx, status);
60957db96d56Sopenharmony_ci    mpd_del(&bb);
60967db96d56Sopenharmony_ci}
60977db96d56Sopenharmony_ci#endif
60987db96d56Sopenharmony_ci
60997db96d56Sopenharmony_ci/* Like the minus operator. */
61007db96d56Sopenharmony_civoid
61017db96d56Sopenharmony_cimpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
61027db96d56Sopenharmony_ci           uint32_t *status)
61037db96d56Sopenharmony_ci{
61047db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
61057db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
61067db96d56Sopenharmony_ci            return;
61077db96d56Sopenharmony_ci        }
61087db96d56Sopenharmony_ci    }
61097db96d56Sopenharmony_ci
61107db96d56Sopenharmony_ci    if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) {
61117db96d56Sopenharmony_ci        mpd_qcopy_abs(result, a, status);
61127db96d56Sopenharmony_ci    }
61137db96d56Sopenharmony_ci    else {
61147db96d56Sopenharmony_ci        mpd_qcopy_negate(result, a, status);
61157db96d56Sopenharmony_ci    }
61167db96d56Sopenharmony_ci
61177db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
61187db96d56Sopenharmony_ci}
61197db96d56Sopenharmony_ci
61207db96d56Sopenharmony_ci/* Like the plus operator. */
61217db96d56Sopenharmony_civoid
61227db96d56Sopenharmony_cimpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
61237db96d56Sopenharmony_ci          uint32_t *status)
61247db96d56Sopenharmony_ci{
61257db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
61267db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
61277db96d56Sopenharmony_ci            return;
61287db96d56Sopenharmony_ci        }
61297db96d56Sopenharmony_ci    }
61307db96d56Sopenharmony_ci
61317db96d56Sopenharmony_ci    if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) {
61327db96d56Sopenharmony_ci        mpd_qcopy_abs(result, a, status);
61337db96d56Sopenharmony_ci    }
61347db96d56Sopenharmony_ci    else {
61357db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
61367db96d56Sopenharmony_ci    }
61377db96d56Sopenharmony_ci
61387db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
61397db96d56Sopenharmony_ci}
61407db96d56Sopenharmony_ci
61417db96d56Sopenharmony_ci/* The largest representable number that is smaller than the operand. */
61427db96d56Sopenharmony_civoid
61437db96d56Sopenharmony_cimpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
61447db96d56Sopenharmony_ci                uint32_t *status)
61457db96d56Sopenharmony_ci{
61467db96d56Sopenharmony_ci    mpd_context_t workctx;
61477db96d56Sopenharmony_ci    MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1);
61487db96d56Sopenharmony_ci
61497db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
61507db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
61517db96d56Sopenharmony_ci            return;
61527db96d56Sopenharmony_ci        }
61537db96d56Sopenharmony_ci
61547db96d56Sopenharmony_ci        assert(mpd_isinfinite(a));
61557db96d56Sopenharmony_ci        if (mpd_isnegative(a)) {
61567db96d56Sopenharmony_ci            mpd_qcopy(result, a, status);
61577db96d56Sopenharmony_ci            return;
61587db96d56Sopenharmony_ci        }
61597db96d56Sopenharmony_ci        else {
61607db96d56Sopenharmony_ci            mpd_clear_flags(result);
61617db96d56Sopenharmony_ci            mpd_qmaxcoeff(result, ctx, status);
61627db96d56Sopenharmony_ci            if (mpd_isnan(result)) {
61637db96d56Sopenharmony_ci                return;
61647db96d56Sopenharmony_ci            }
61657db96d56Sopenharmony_ci            result->exp = mpd_etop(ctx);
61667db96d56Sopenharmony_ci            return;
61677db96d56Sopenharmony_ci        }
61687db96d56Sopenharmony_ci    }
61697db96d56Sopenharmony_ci
61707db96d56Sopenharmony_ci    mpd_workcontext(&workctx, ctx);
61717db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_FLOOR;
61727db96d56Sopenharmony_ci
61737db96d56Sopenharmony_ci    if (!mpd_qcopy(result, a, status)) {
61747db96d56Sopenharmony_ci        return;
61757db96d56Sopenharmony_ci    }
61767db96d56Sopenharmony_ci
61777db96d56Sopenharmony_ci    mpd_qfinalize(result, &workctx, &workctx.status);
61787db96d56Sopenharmony_ci    if (workctx.status&(MPD_Inexact|MPD_Errors)) {
61797db96d56Sopenharmony_ci        *status |= (workctx.status&MPD_Errors);
61807db96d56Sopenharmony_ci        return;
61817db96d56Sopenharmony_ci    }
61827db96d56Sopenharmony_ci
61837db96d56Sopenharmony_ci    workctx.status = 0;
61847db96d56Sopenharmony_ci    mpd_qsub(result, a, &tiny, &workctx, &workctx.status);
61857db96d56Sopenharmony_ci    *status |= (workctx.status&MPD_Errors);
61867db96d56Sopenharmony_ci}
61877db96d56Sopenharmony_ci
61887db96d56Sopenharmony_ci/* The smallest representable number that is larger than the operand. */
61897db96d56Sopenharmony_civoid
61907db96d56Sopenharmony_cimpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
61917db96d56Sopenharmony_ci               uint32_t *status)
61927db96d56Sopenharmony_ci{
61937db96d56Sopenharmony_ci    mpd_context_t workctx;
61947db96d56Sopenharmony_ci    MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1);
61957db96d56Sopenharmony_ci
61967db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
61977db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
61987db96d56Sopenharmony_ci            return;
61997db96d56Sopenharmony_ci        }
62007db96d56Sopenharmony_ci
62017db96d56Sopenharmony_ci        assert(mpd_isinfinite(a));
62027db96d56Sopenharmony_ci        if (mpd_ispositive(a)) {
62037db96d56Sopenharmony_ci            mpd_qcopy(result, a, status);
62047db96d56Sopenharmony_ci        }
62057db96d56Sopenharmony_ci        else {
62067db96d56Sopenharmony_ci            mpd_clear_flags(result);
62077db96d56Sopenharmony_ci            mpd_qmaxcoeff(result, ctx, status);
62087db96d56Sopenharmony_ci            if (mpd_isnan(result)) {
62097db96d56Sopenharmony_ci                return;
62107db96d56Sopenharmony_ci            }
62117db96d56Sopenharmony_ci            mpd_set_flags(result, MPD_NEG);
62127db96d56Sopenharmony_ci            result->exp = mpd_etop(ctx);
62137db96d56Sopenharmony_ci        }
62147db96d56Sopenharmony_ci        return;
62157db96d56Sopenharmony_ci    }
62167db96d56Sopenharmony_ci
62177db96d56Sopenharmony_ci    mpd_workcontext(&workctx, ctx);
62187db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_CEILING;
62197db96d56Sopenharmony_ci
62207db96d56Sopenharmony_ci    if (!mpd_qcopy(result, a, status)) {
62217db96d56Sopenharmony_ci        return;
62227db96d56Sopenharmony_ci    }
62237db96d56Sopenharmony_ci
62247db96d56Sopenharmony_ci    mpd_qfinalize(result, &workctx, &workctx.status);
62257db96d56Sopenharmony_ci    if (workctx.status & (MPD_Inexact|MPD_Errors)) {
62267db96d56Sopenharmony_ci        *status |= (workctx.status&MPD_Errors);
62277db96d56Sopenharmony_ci        return;
62287db96d56Sopenharmony_ci    }
62297db96d56Sopenharmony_ci
62307db96d56Sopenharmony_ci    workctx.status = 0;
62317db96d56Sopenharmony_ci    mpd_qadd(result, a, &tiny, &workctx, &workctx.status);
62327db96d56Sopenharmony_ci    *status |= (workctx.status&MPD_Errors);
62337db96d56Sopenharmony_ci}
62347db96d56Sopenharmony_ci
62357db96d56Sopenharmony_ci/*
62367db96d56Sopenharmony_ci * The number closest to the first operand that is in the direction towards
62377db96d56Sopenharmony_ci * the second operand.
62387db96d56Sopenharmony_ci */
62397db96d56Sopenharmony_civoid
62407db96d56Sopenharmony_cimpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b,
62417db96d56Sopenharmony_ci                 const mpd_context_t *ctx, uint32_t *status)
62427db96d56Sopenharmony_ci{
62437db96d56Sopenharmony_ci    int c;
62447db96d56Sopenharmony_ci
62457db96d56Sopenharmony_ci    if (mpd_qcheck_nans(result, a, b, ctx, status)) {
62467db96d56Sopenharmony_ci        return;
62477db96d56Sopenharmony_ci    }
62487db96d56Sopenharmony_ci
62497db96d56Sopenharmony_ci    c = _mpd_cmp(a, b);
62507db96d56Sopenharmony_ci    if (c == 0) {
62517db96d56Sopenharmony_ci        mpd_qcopy_sign(result, a, b, status);
62527db96d56Sopenharmony_ci        return;
62537db96d56Sopenharmony_ci    }
62547db96d56Sopenharmony_ci
62557db96d56Sopenharmony_ci    if (c < 0) {
62567db96d56Sopenharmony_ci        mpd_qnext_plus(result, a, ctx, status);
62577db96d56Sopenharmony_ci    }
62587db96d56Sopenharmony_ci    else {
62597db96d56Sopenharmony_ci        mpd_qnext_minus(result, a, ctx, status);
62607db96d56Sopenharmony_ci    }
62617db96d56Sopenharmony_ci
62627db96d56Sopenharmony_ci    if (mpd_isinfinite(result)) {
62637db96d56Sopenharmony_ci        *status |= (MPD_Overflow|MPD_Rounded|MPD_Inexact);
62647db96d56Sopenharmony_ci    }
62657db96d56Sopenharmony_ci    else if (mpd_adjexp(result) < ctx->emin) {
62667db96d56Sopenharmony_ci        *status |= (MPD_Underflow|MPD_Subnormal|MPD_Rounded|MPD_Inexact);
62677db96d56Sopenharmony_ci        if (mpd_iszero(result)) {
62687db96d56Sopenharmony_ci            *status |= MPD_Clamped;
62697db96d56Sopenharmony_ci        }
62707db96d56Sopenharmony_ci    }
62717db96d56Sopenharmony_ci}
62727db96d56Sopenharmony_ci
62737db96d56Sopenharmony_ci/*
62747db96d56Sopenharmony_ci * Internal function: Integer power with mpd_uint_t exponent. The function
62757db96d56Sopenharmony_ci * can fail with MPD_Malloc_error.
62767db96d56Sopenharmony_ci *
62777db96d56Sopenharmony_ci * The error is equal to the error incurred in k-1 multiplications. Assuming
62787db96d56Sopenharmony_ci * the upper bound for the relative error in each operation:
62797db96d56Sopenharmony_ci *
62807db96d56Sopenharmony_ci *   abs(err) = 5 * 10**-prec
62817db96d56Sopenharmony_ci *   result = x**k * (1 + err)**(k-1)
62827db96d56Sopenharmony_ci */
62837db96d56Sopenharmony_cistatic inline void
62847db96d56Sopenharmony_ci_mpd_qpow_uint(mpd_t *result, const mpd_t *base, mpd_uint_t exp,
62857db96d56Sopenharmony_ci               uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status)
62867db96d56Sopenharmony_ci{
62877db96d56Sopenharmony_ci    uint32_t workstatus = 0;
62887db96d56Sopenharmony_ci    mpd_uint_t n;
62897db96d56Sopenharmony_ci
62907db96d56Sopenharmony_ci    if (exp == 0) {
62917db96d56Sopenharmony_ci        _settriple(result, resultsign, 1, 0); /* GCOV_NOT_REACHED */
62927db96d56Sopenharmony_ci        return; /* GCOV_NOT_REACHED */
62937db96d56Sopenharmony_ci    }
62947db96d56Sopenharmony_ci
62957db96d56Sopenharmony_ci    if (!mpd_qcopy(result, base, status)) {
62967db96d56Sopenharmony_ci        return;
62977db96d56Sopenharmony_ci    }
62987db96d56Sopenharmony_ci
62997db96d56Sopenharmony_ci    n = mpd_bits[mpd_bsr(exp)];
63007db96d56Sopenharmony_ci    while (n >>= 1) {
63017db96d56Sopenharmony_ci        mpd_qmul(result, result, result, ctx, &workstatus);
63027db96d56Sopenharmony_ci        if (exp & n) {
63037db96d56Sopenharmony_ci            mpd_qmul(result, result, base, ctx, &workstatus);
63047db96d56Sopenharmony_ci        }
63057db96d56Sopenharmony_ci        if (mpd_isspecial(result) ||
63067db96d56Sopenharmony_ci            (mpd_iszerocoeff(result) && (workstatus & MPD_Clamped))) {
63077db96d56Sopenharmony_ci            break;
63087db96d56Sopenharmony_ci        }
63097db96d56Sopenharmony_ci    }
63107db96d56Sopenharmony_ci
63117db96d56Sopenharmony_ci    *status |= workstatus;
63127db96d56Sopenharmony_ci    mpd_set_sign(result, resultsign);
63137db96d56Sopenharmony_ci}
63147db96d56Sopenharmony_ci
63157db96d56Sopenharmony_ci/*
63167db96d56Sopenharmony_ci * Internal function: Integer power with mpd_t exponent, tbase and texp
63177db96d56Sopenharmony_ci * are modified!! Function can fail with MPD_Malloc_error.
63187db96d56Sopenharmony_ci *
63197db96d56Sopenharmony_ci * The error is equal to the error incurred in k multiplications. Assuming
63207db96d56Sopenharmony_ci * the upper bound for the relative error in each operation:
63217db96d56Sopenharmony_ci *
63227db96d56Sopenharmony_ci *   abs(err) = 5 * 10**-prec
63237db96d56Sopenharmony_ci *   result = x**k * (1 + err)**k
63247db96d56Sopenharmony_ci */
63257db96d56Sopenharmony_cistatic inline void
63267db96d56Sopenharmony_ci_mpd_qpow_mpd(mpd_t *result, mpd_t *tbase, mpd_t *texp, uint8_t resultsign,
63277db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
63287db96d56Sopenharmony_ci{
63297db96d56Sopenharmony_ci    uint32_t workstatus = 0;
63307db96d56Sopenharmony_ci    mpd_context_t maxctx;
63317db96d56Sopenharmony_ci    MPD_NEW_CONST(two,0,0,1,1,1,2);
63327db96d56Sopenharmony_ci
63337db96d56Sopenharmony_ci
63347db96d56Sopenharmony_ci    mpd_maxcontext(&maxctx);
63357db96d56Sopenharmony_ci
63367db96d56Sopenharmony_ci    /* resize to smaller cannot fail */
63377db96d56Sopenharmony_ci    mpd_qcopy(result, &one, status);
63387db96d56Sopenharmony_ci
63397db96d56Sopenharmony_ci    while (!mpd_iszero(texp)) {
63407db96d56Sopenharmony_ci        if (mpd_isodd(texp)) {
63417db96d56Sopenharmony_ci            mpd_qmul(result, result, tbase, ctx, &workstatus);
63427db96d56Sopenharmony_ci            *status |= workstatus;
63437db96d56Sopenharmony_ci            if (mpd_isspecial(result) ||
63447db96d56Sopenharmony_ci                (mpd_iszerocoeff(result) && (workstatus & MPD_Clamped))) {
63457db96d56Sopenharmony_ci                break;
63467db96d56Sopenharmony_ci            }
63477db96d56Sopenharmony_ci        }
63487db96d56Sopenharmony_ci        mpd_qmul(tbase, tbase, tbase, ctx, &workstatus);
63497db96d56Sopenharmony_ci        mpd_qdivint(texp, texp, &two, &maxctx, &workstatus);
63507db96d56Sopenharmony_ci        if (mpd_isnan(tbase) || mpd_isnan(texp)) {
63517db96d56Sopenharmony_ci            mpd_seterror(result, workstatus&MPD_Errors, status);
63527db96d56Sopenharmony_ci            return;
63537db96d56Sopenharmony_ci        }
63547db96d56Sopenharmony_ci    }
63557db96d56Sopenharmony_ci    mpd_set_sign(result, resultsign);
63567db96d56Sopenharmony_ci}
63577db96d56Sopenharmony_ci
63587db96d56Sopenharmony_ci/*
63597db96d56Sopenharmony_ci * The power function for integer exponents. Relative error _before_ the
63607db96d56Sopenharmony_ci * final rounding to prec:
63617db96d56Sopenharmony_ci *   abs(result - base**exp) < 0.1 * 10**-prec * abs(base**exp)
63627db96d56Sopenharmony_ci */
63637db96d56Sopenharmony_cistatic void
63647db96d56Sopenharmony_ci_mpd_qpow_int(mpd_t *result, const mpd_t *base, const mpd_t *exp,
63657db96d56Sopenharmony_ci              uint8_t resultsign,
63667db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
63677db96d56Sopenharmony_ci{
63687db96d56Sopenharmony_ci    mpd_context_t workctx;
63697db96d56Sopenharmony_ci    MPD_NEW_STATIC(tbase,0,0,0,0);
63707db96d56Sopenharmony_ci    MPD_NEW_STATIC(texp,0,0,0,0);
63717db96d56Sopenharmony_ci    mpd_uint_t n;
63727db96d56Sopenharmony_ci
63737db96d56Sopenharmony_ci
63747db96d56Sopenharmony_ci    mpd_workcontext(&workctx, ctx);
63757db96d56Sopenharmony_ci    workctx.prec += (exp->digits + exp->exp + 2);
63767db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_HALF_EVEN;
63777db96d56Sopenharmony_ci    workctx.clamp = 0;
63787db96d56Sopenharmony_ci    if (mpd_isnegative(exp)) {
63797db96d56Sopenharmony_ci        uint32_t workstatus = 0;
63807db96d56Sopenharmony_ci        workctx.prec += 1;
63817db96d56Sopenharmony_ci        mpd_qdiv(&tbase, &one, base, &workctx, &workstatus);
63827db96d56Sopenharmony_ci        *status |= workstatus;
63837db96d56Sopenharmony_ci        if (workstatus&MPD_Errors) {
63847db96d56Sopenharmony_ci            mpd_setspecial(result, MPD_POS, MPD_NAN);
63857db96d56Sopenharmony_ci            goto finish;
63867db96d56Sopenharmony_ci        }
63877db96d56Sopenharmony_ci    }
63887db96d56Sopenharmony_ci    else {
63897db96d56Sopenharmony_ci        if (!mpd_qcopy(&tbase, base, status)) {
63907db96d56Sopenharmony_ci            mpd_setspecial(result, MPD_POS, MPD_NAN);
63917db96d56Sopenharmony_ci            goto finish;
63927db96d56Sopenharmony_ci        }
63937db96d56Sopenharmony_ci    }
63947db96d56Sopenharmony_ci
63957db96d56Sopenharmony_ci    n = mpd_qabs_uint(exp, &workctx.status);
63967db96d56Sopenharmony_ci    if (workctx.status&MPD_Invalid_operation) {
63977db96d56Sopenharmony_ci        if (!mpd_qcopy(&texp, exp, status)) {
63987db96d56Sopenharmony_ci            mpd_setspecial(result, MPD_POS, MPD_NAN); /* GCOV_UNLIKELY */
63997db96d56Sopenharmony_ci            goto finish; /* GCOV_UNLIKELY */
64007db96d56Sopenharmony_ci        }
64017db96d56Sopenharmony_ci        _mpd_qpow_mpd(result, &tbase, &texp, resultsign, &workctx, status);
64027db96d56Sopenharmony_ci    }
64037db96d56Sopenharmony_ci    else {
64047db96d56Sopenharmony_ci        _mpd_qpow_uint(result, &tbase, n, resultsign, &workctx, status);
64057db96d56Sopenharmony_ci    }
64067db96d56Sopenharmony_ci
64077db96d56Sopenharmony_ci    if (mpd_isinfinite(result)) {
64087db96d56Sopenharmony_ci        /* for ROUND_DOWN, ROUND_FLOOR, etc. */
64097db96d56Sopenharmony_ci        _settriple(result, resultsign, 1, MPD_EXP_INF);
64107db96d56Sopenharmony_ci    }
64117db96d56Sopenharmony_ci
64127db96d56Sopenharmony_cifinish:
64137db96d56Sopenharmony_ci    mpd_del(&tbase);
64147db96d56Sopenharmony_ci    mpd_del(&texp);
64157db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
64167db96d56Sopenharmony_ci}
64177db96d56Sopenharmony_ci
64187db96d56Sopenharmony_ci/*
64197db96d56Sopenharmony_ci * If the exponent is infinite and base equals one, the result is one
64207db96d56Sopenharmony_ci * with a coefficient of length prec. Otherwise, result is undefined.
64217db96d56Sopenharmony_ci * Return the value of the comparison against one.
64227db96d56Sopenharmony_ci */
64237db96d56Sopenharmony_cistatic int
64247db96d56Sopenharmony_ci_qcheck_pow_one_inf(mpd_t *result, const mpd_t *base, uint8_t resultsign,
64257db96d56Sopenharmony_ci                    const mpd_context_t *ctx, uint32_t *status)
64267db96d56Sopenharmony_ci{
64277db96d56Sopenharmony_ci    mpd_ssize_t shift;
64287db96d56Sopenharmony_ci    int cmp;
64297db96d56Sopenharmony_ci
64307db96d56Sopenharmony_ci    if ((cmp = _mpd_cmp(base, &one)) == 0) {
64317db96d56Sopenharmony_ci        shift = ctx->prec-1;
64327db96d56Sopenharmony_ci        mpd_qshiftl(result, &one, shift, status);
64337db96d56Sopenharmony_ci        result->exp = -shift;
64347db96d56Sopenharmony_ci        mpd_set_flags(result, resultsign);
64357db96d56Sopenharmony_ci        *status |= (MPD_Inexact|MPD_Rounded);
64367db96d56Sopenharmony_ci    }
64377db96d56Sopenharmony_ci
64387db96d56Sopenharmony_ci    return cmp;
64397db96d56Sopenharmony_ci}
64407db96d56Sopenharmony_ci
64417db96d56Sopenharmony_ci/*
64427db96d56Sopenharmony_ci * If abs(base) equals one, calculate the correct power of one result.
64437db96d56Sopenharmony_ci * Otherwise, result is undefined. Return the value of the comparison
64447db96d56Sopenharmony_ci * against 1.
64457db96d56Sopenharmony_ci *
64467db96d56Sopenharmony_ci * This is an internal function that does not check for specials.
64477db96d56Sopenharmony_ci */
64487db96d56Sopenharmony_cistatic int
64497db96d56Sopenharmony_ci_qcheck_pow_one(mpd_t *result, const mpd_t *base, const mpd_t *exp,
64507db96d56Sopenharmony_ci                uint8_t resultsign,
64517db96d56Sopenharmony_ci                const mpd_context_t *ctx, uint32_t *status)
64527db96d56Sopenharmony_ci{
64537db96d56Sopenharmony_ci    uint32_t workstatus = 0;
64547db96d56Sopenharmony_ci    mpd_ssize_t shift;
64557db96d56Sopenharmony_ci    int cmp;
64567db96d56Sopenharmony_ci
64577db96d56Sopenharmony_ci    if ((cmp = _mpd_cmp_abs(base, &one)) == 0) {
64587db96d56Sopenharmony_ci        if (_mpd_isint(exp)) {
64597db96d56Sopenharmony_ci            if (mpd_isnegative(exp)) {
64607db96d56Sopenharmony_ci                _settriple(result, resultsign, 1, 0);
64617db96d56Sopenharmony_ci                return 0;
64627db96d56Sopenharmony_ci            }
64637db96d56Sopenharmony_ci            /* 1.000**3 = 1.000000000 */
64647db96d56Sopenharmony_ci            mpd_qmul_ssize(result, exp, -base->exp, ctx, &workstatus);
64657db96d56Sopenharmony_ci            if (workstatus&MPD_Errors) {
64667db96d56Sopenharmony_ci                *status |= (workstatus&MPD_Errors);
64677db96d56Sopenharmony_ci                return 0;
64687db96d56Sopenharmony_ci            }
64697db96d56Sopenharmony_ci            /* digits-1 after exponentiation */
64707db96d56Sopenharmony_ci            shift = mpd_qget_ssize(result, &workstatus);
64717db96d56Sopenharmony_ci            /* shift is MPD_SSIZE_MAX if result is too large */
64727db96d56Sopenharmony_ci            if (shift > ctx->prec-1) {
64737db96d56Sopenharmony_ci                shift = ctx->prec-1;
64747db96d56Sopenharmony_ci                *status |= MPD_Rounded;
64757db96d56Sopenharmony_ci            }
64767db96d56Sopenharmony_ci        }
64777db96d56Sopenharmony_ci        else if (mpd_ispositive(base)) {
64787db96d56Sopenharmony_ci            shift = ctx->prec-1;
64797db96d56Sopenharmony_ci            *status |= (MPD_Inexact|MPD_Rounded);
64807db96d56Sopenharmony_ci        }
64817db96d56Sopenharmony_ci        else {
64827db96d56Sopenharmony_ci            return -2; /* GCOV_NOT_REACHED */
64837db96d56Sopenharmony_ci        }
64847db96d56Sopenharmony_ci        if (!mpd_qshiftl(result, &one, shift, status)) {
64857db96d56Sopenharmony_ci            return 0;
64867db96d56Sopenharmony_ci        }
64877db96d56Sopenharmony_ci        result->exp = -shift;
64887db96d56Sopenharmony_ci        mpd_set_flags(result, resultsign);
64897db96d56Sopenharmony_ci    }
64907db96d56Sopenharmony_ci
64917db96d56Sopenharmony_ci    return cmp;
64927db96d56Sopenharmony_ci}
64937db96d56Sopenharmony_ci
64947db96d56Sopenharmony_ci/*
64957db96d56Sopenharmony_ci * Detect certain over/underflow of x**y.
64967db96d56Sopenharmony_ci * ACL2 proof: pow-bounds.lisp.
64977db96d56Sopenharmony_ci *
64987db96d56Sopenharmony_ci *   Symbols:
64997db96d56Sopenharmony_ci *
65007db96d56Sopenharmony_ci *     e: EXP_INF or EXP_CLAMP
65017db96d56Sopenharmony_ci *     x: base
65027db96d56Sopenharmony_ci *     y: exponent
65037db96d56Sopenharmony_ci *
65047db96d56Sopenharmony_ci *     omega(e) = log10(abs(e))
65057db96d56Sopenharmony_ci *     zeta(x)  = log10(abs(log10(x)))
65067db96d56Sopenharmony_ci *     theta(y) = log10(abs(y))
65077db96d56Sopenharmony_ci *
65087db96d56Sopenharmony_ci *   Upper and lower bounds:
65097db96d56Sopenharmony_ci *
65107db96d56Sopenharmony_ci *     ub_omega(e) = ceil(log10(abs(e)))
65117db96d56Sopenharmony_ci *     lb_theta(y) = floor(log10(abs(y)))
65127db96d56Sopenharmony_ci *
65137db96d56Sopenharmony_ci *                  | floor(log10(floor(abs(log10(x))))) if x < 1/10 or x >= 10
65147db96d56Sopenharmony_ci *     lb_zeta(x) = | floor(log10(abs(x-1)/10)) if 1/10 <= x < 1
65157db96d56Sopenharmony_ci *                  | floor(log10(abs((x-1)/100))) if 1 < x < 10
65167db96d56Sopenharmony_ci *
65177db96d56Sopenharmony_ci *   ub_omega(e) and lb_theta(y) are obviously upper and lower bounds
65187db96d56Sopenharmony_ci *   for omega(e) and theta(y).
65197db96d56Sopenharmony_ci *
65207db96d56Sopenharmony_ci *   lb_zeta is a lower bound for zeta(x):
65217db96d56Sopenharmony_ci *
65227db96d56Sopenharmony_ci *     x < 1/10 or x >= 10:
65237db96d56Sopenharmony_ci *
65247db96d56Sopenharmony_ci *       abs(log10(x)) >= 1, so the outer log10 is well defined. Since log10
65257db96d56Sopenharmony_ci *       is strictly increasing, the end result is a lower bound.
65267db96d56Sopenharmony_ci *
65277db96d56Sopenharmony_ci *     1/10 <= x < 1:
65287db96d56Sopenharmony_ci *
65297db96d56Sopenharmony_ci *       We use: log10(x) <= (x-1)/log(10)
65307db96d56Sopenharmony_ci *               abs(log10(x)) >= abs(x-1)/log(10)
65317db96d56Sopenharmony_ci *               abs(log10(x)) >= abs(x-1)/10
65327db96d56Sopenharmony_ci *
65337db96d56Sopenharmony_ci *     1 < x < 10:
65347db96d56Sopenharmony_ci *
65357db96d56Sopenharmony_ci *       We use: (x-1)/(x*log(10)) < log10(x)
65367db96d56Sopenharmony_ci *               abs((x-1)/100) < abs(log10(x))
65377db96d56Sopenharmony_ci *
65387db96d56Sopenharmony_ci *       XXX: abs((x-1)/10) would work, need ACL2 proof.
65397db96d56Sopenharmony_ci *
65407db96d56Sopenharmony_ci *
65417db96d56Sopenharmony_ci *   Let (0 < x < 1 and y < 0) or (x > 1 and y > 0).                  (H1)
65427db96d56Sopenharmony_ci *   Let ub_omega(exp_inf) < lb_zeta(x) + lb_theta(y)                 (H2)
65437db96d56Sopenharmony_ci *
65447db96d56Sopenharmony_ci *   Then:
65457db96d56Sopenharmony_ci *       log10(abs(exp_inf)) < log10(abs(log10(x))) + log10(abs(y)).   (1)
65467db96d56Sopenharmony_ci *                   exp_inf < log10(x) * y                            (2)
65477db96d56Sopenharmony_ci *               10**exp_inf < x**y                                    (3)
65487db96d56Sopenharmony_ci *
65497db96d56Sopenharmony_ci *   Let (0 < x < 1 and y > 0) or (x > 1 and y < 0).                  (H3)
65507db96d56Sopenharmony_ci *   Let ub_omega(exp_clamp) < lb_zeta(x) + lb_theta(y)               (H4)
65517db96d56Sopenharmony_ci *
65527db96d56Sopenharmony_ci *   Then:
65537db96d56Sopenharmony_ci *     log10(abs(exp_clamp)) < log10(abs(log10(x))) + log10(abs(y)).   (4)
65547db96d56Sopenharmony_ci *              log10(x) * y < exp_clamp                               (5)
65557db96d56Sopenharmony_ci *                      x**y < 10**exp_clamp                           (6)
65567db96d56Sopenharmony_ci *
65577db96d56Sopenharmony_ci */
65587db96d56Sopenharmony_cistatic mpd_ssize_t
65597db96d56Sopenharmony_ci_lower_bound_zeta(const mpd_t *x, uint32_t *status)
65607db96d56Sopenharmony_ci{
65617db96d56Sopenharmony_ci    mpd_context_t maxctx;
65627db96d56Sopenharmony_ci    MPD_NEW_STATIC(scratch,0,0,0,0);
65637db96d56Sopenharmony_ci    mpd_ssize_t t, u;
65647db96d56Sopenharmony_ci
65657db96d56Sopenharmony_ci    t = mpd_adjexp(x);
65667db96d56Sopenharmony_ci    if (t > 0) {
65677db96d56Sopenharmony_ci        /* x >= 10 -> floor(log10(floor(abs(log10(x))))) */
65687db96d56Sopenharmony_ci        return mpd_exp_digits(t) - 1;
65697db96d56Sopenharmony_ci    }
65707db96d56Sopenharmony_ci    else if (t < -1) {
65717db96d56Sopenharmony_ci        /* x < 1/10 -> floor(log10(floor(abs(log10(x))))) */
65727db96d56Sopenharmony_ci        return mpd_exp_digits(t+1) - 1;
65737db96d56Sopenharmony_ci    }
65747db96d56Sopenharmony_ci    else {
65757db96d56Sopenharmony_ci        mpd_maxcontext(&maxctx);
65767db96d56Sopenharmony_ci        mpd_qsub(&scratch, x, &one, &maxctx, status);
65777db96d56Sopenharmony_ci        if (mpd_isspecial(&scratch)) {
65787db96d56Sopenharmony_ci            mpd_del(&scratch);
65797db96d56Sopenharmony_ci            return MPD_SSIZE_MAX;
65807db96d56Sopenharmony_ci        }
65817db96d56Sopenharmony_ci        u = mpd_adjexp(&scratch);
65827db96d56Sopenharmony_ci        mpd_del(&scratch);
65837db96d56Sopenharmony_ci
65847db96d56Sopenharmony_ci        /* t == -1, 1/10 <= x < 1 -> floor(log10(abs(x-1)/10))
65857db96d56Sopenharmony_ci         * t == 0,  1 < x < 10    -> floor(log10(abs(x-1)/100)) */
65867db96d56Sopenharmony_ci        return (t == 0) ? u-2 : u-1;
65877db96d56Sopenharmony_ci    }
65887db96d56Sopenharmony_ci}
65897db96d56Sopenharmony_ci
65907db96d56Sopenharmony_ci/*
65917db96d56Sopenharmony_ci * Detect cases of certain overflow/underflow in the power function.
65927db96d56Sopenharmony_ci * Assumptions: x != 1, y != 0. The proof above is for positive x.
65937db96d56Sopenharmony_ci * If x is negative and y is an odd integer, x**y == -(abs(x)**y),
65947db96d56Sopenharmony_ci * so the analysis does not change.
65957db96d56Sopenharmony_ci */
65967db96d56Sopenharmony_cistatic int
65977db96d56Sopenharmony_ci_qcheck_pow_bounds(mpd_t *result, const mpd_t *x, const mpd_t *y,
65987db96d56Sopenharmony_ci                   uint8_t resultsign,
65997db96d56Sopenharmony_ci                   const mpd_context_t *ctx, uint32_t *status)
66007db96d56Sopenharmony_ci{
66017db96d56Sopenharmony_ci    MPD_NEW_SHARED(abs_x, x);
66027db96d56Sopenharmony_ci    mpd_ssize_t ub_omega, lb_zeta, lb_theta;
66037db96d56Sopenharmony_ci    uint8_t sign;
66047db96d56Sopenharmony_ci
66057db96d56Sopenharmony_ci    mpd_set_positive(&abs_x);
66067db96d56Sopenharmony_ci
66077db96d56Sopenharmony_ci    lb_theta = mpd_adjexp(y);
66087db96d56Sopenharmony_ci    lb_zeta = _lower_bound_zeta(&abs_x, status);
66097db96d56Sopenharmony_ci    if (lb_zeta == MPD_SSIZE_MAX) {
66107db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Malloc_error, status);
66117db96d56Sopenharmony_ci        return 1;
66127db96d56Sopenharmony_ci    }
66137db96d56Sopenharmony_ci
66147db96d56Sopenharmony_ci    sign = (mpd_adjexp(&abs_x) < 0) ^ mpd_sign(y);
66157db96d56Sopenharmony_ci    if (sign == 0) {
66167db96d56Sopenharmony_ci        /* (0 < |x| < 1 and y < 0) or (|x| > 1 and y > 0) */
66177db96d56Sopenharmony_ci        ub_omega = mpd_exp_digits(ctx->emax);
66187db96d56Sopenharmony_ci        if (ub_omega < lb_zeta + lb_theta) {
66197db96d56Sopenharmony_ci            _settriple(result, resultsign, 1, MPD_EXP_INF);
66207db96d56Sopenharmony_ci            mpd_qfinalize(result, ctx, status);
66217db96d56Sopenharmony_ci            return 1;
66227db96d56Sopenharmony_ci        }
66237db96d56Sopenharmony_ci    }
66247db96d56Sopenharmony_ci    else {
66257db96d56Sopenharmony_ci        /* (0 < |x| < 1 and y > 0) or (|x| > 1 and y < 0). */
66267db96d56Sopenharmony_ci        ub_omega = mpd_exp_digits(mpd_etiny(ctx));
66277db96d56Sopenharmony_ci        if (ub_omega < lb_zeta + lb_theta) {
66287db96d56Sopenharmony_ci            _settriple(result, resultsign, 1, mpd_etiny(ctx)-1);
66297db96d56Sopenharmony_ci            mpd_qfinalize(result, ctx, status);
66307db96d56Sopenharmony_ci            return 1;
66317db96d56Sopenharmony_ci        }
66327db96d56Sopenharmony_ci    }
66337db96d56Sopenharmony_ci
66347db96d56Sopenharmony_ci    return 0;
66357db96d56Sopenharmony_ci}
66367db96d56Sopenharmony_ci
66377db96d56Sopenharmony_ci/*
66387db96d56Sopenharmony_ci * TODO: Implement algorithm for computing exact powers from decimal.py.
66397db96d56Sopenharmony_ci * In order to prevent infinite loops, this has to be called before
66407db96d56Sopenharmony_ci * using Ziv's strategy for correct rounding.
66417db96d56Sopenharmony_ci */
66427db96d56Sopenharmony_ci/*
66437db96d56Sopenharmony_cistatic int
66447db96d56Sopenharmony_ci_mpd_qpow_exact(mpd_t *result, const mpd_t *base, const mpd_t *exp,
66457db96d56Sopenharmony_ci                const mpd_context_t *ctx, uint32_t *status)
66467db96d56Sopenharmony_ci{
66477db96d56Sopenharmony_ci    return 0;
66487db96d56Sopenharmony_ci}
66497db96d56Sopenharmony_ci*/
66507db96d56Sopenharmony_ci
66517db96d56Sopenharmony_ci/*
66527db96d56Sopenharmony_ci * The power function for real exponents.
66537db96d56Sopenharmony_ci *   Relative error: abs(result - e**y) < e**y * 1/5 * 10**(-prec - 1)
66547db96d56Sopenharmony_ci */
66557db96d56Sopenharmony_cistatic void
66567db96d56Sopenharmony_ci_mpd_qpow_real(mpd_t *result, const mpd_t *base, const mpd_t *exp,
66577db96d56Sopenharmony_ci               const mpd_context_t *ctx, uint32_t *status)
66587db96d56Sopenharmony_ci{
66597db96d56Sopenharmony_ci    mpd_context_t workctx;
66607db96d56Sopenharmony_ci    MPD_NEW_STATIC(texp,0,0,0,0);
66617db96d56Sopenharmony_ci
66627db96d56Sopenharmony_ci    if (!mpd_qcopy(&texp, exp, status)) {
66637db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Malloc_error, status);
66647db96d56Sopenharmony_ci        return;
66657db96d56Sopenharmony_ci    }
66667db96d56Sopenharmony_ci
66677db96d56Sopenharmony_ci    mpd_maxcontext(&workctx);
66687db96d56Sopenharmony_ci    workctx.prec = (base->digits > ctx->prec) ? base->digits : ctx->prec;
66697db96d56Sopenharmony_ci    workctx.prec += (4 + MPD_EXPDIGITS);
66707db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_HALF_EVEN;
66717db96d56Sopenharmony_ci    workctx.allcr = ctx->allcr;
66727db96d56Sopenharmony_ci
66737db96d56Sopenharmony_ci    /*
66747db96d56Sopenharmony_ci     * extra := MPD_EXPDIGITS = MPD_EXP_MAX_T
66757db96d56Sopenharmony_ci     * wp := prec + 4 + extra
66767db96d56Sopenharmony_ci     * abs(err) < 5 * 10**-wp
66777db96d56Sopenharmony_ci     * y := log(base) * exp
66787db96d56Sopenharmony_ci     * Calculate:
66797db96d56Sopenharmony_ci     *   1)   e**(y * (1 + err)**2) * (1 + err)
66807db96d56Sopenharmony_ci     *      = e**y * e**(y * (2*err + err**2)) * (1 + err)
66817db96d56Sopenharmony_ci     *        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66827db96d56Sopenharmony_ci     * Relative error of the underlined term:
66837db96d56Sopenharmony_ci     *   2) abs(e**(y * (2*err + err**2)) - 1)
66847db96d56Sopenharmony_ci     * Case abs(y) >= 10**extra:
66857db96d56Sopenharmony_ci     *   3) adjexp(y)+1 > log10(abs(y)) >= extra
66867db96d56Sopenharmony_ci     *   This triggers the Overflow/Underflow shortcut in _mpd_qexp(),
66877db96d56Sopenharmony_ci     *   so no further analysis is necessary.
66887db96d56Sopenharmony_ci     * Case abs(y) < 10**extra:
66897db96d56Sopenharmony_ci     *   4) abs(y * (2*err + err**2)) < 1/5 * 10**(-prec - 2)
66907db96d56Sopenharmony_ci     *   Use (see _mpd_qexp):
66917db96d56Sopenharmony_ci     *     5) abs(x) <= 9/10 * 10**-p ==> abs(e**x - 1) < 10**-p
66927db96d56Sopenharmony_ci     *   With 2), 4) and 5):
66937db96d56Sopenharmony_ci     *     6) abs(e**(y * (2*err + err**2)) - 1) < 10**(-prec - 2)
66947db96d56Sopenharmony_ci     *   The complete relative error of 1) is:
66957db96d56Sopenharmony_ci     *     7) abs(result - e**y) < e**y * 1/5 * 10**(-prec - 1)
66967db96d56Sopenharmony_ci     */
66977db96d56Sopenharmony_ci    mpd_qln(result, base, &workctx, &workctx.status);
66987db96d56Sopenharmony_ci    mpd_qmul(result, result, &texp, &workctx, &workctx.status);
66997db96d56Sopenharmony_ci    mpd_qexp(result, result, &workctx, status);
67007db96d56Sopenharmony_ci
67017db96d56Sopenharmony_ci    mpd_del(&texp);
67027db96d56Sopenharmony_ci    *status |= (workctx.status&MPD_Errors);
67037db96d56Sopenharmony_ci    *status |= (MPD_Inexact|MPD_Rounded);
67047db96d56Sopenharmony_ci}
67057db96d56Sopenharmony_ci
67067db96d56Sopenharmony_ci/* The power function: base**exp */
67077db96d56Sopenharmony_civoid
67087db96d56Sopenharmony_cimpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp,
67097db96d56Sopenharmony_ci         const mpd_context_t *ctx, uint32_t *status)
67107db96d56Sopenharmony_ci{
67117db96d56Sopenharmony_ci    uint8_t resultsign = 0;
67127db96d56Sopenharmony_ci    int intexp = 0;
67137db96d56Sopenharmony_ci    int cmp;
67147db96d56Sopenharmony_ci
67157db96d56Sopenharmony_ci    if (mpd_isspecial(base) || mpd_isspecial(exp)) {
67167db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, base, exp, ctx, status)) {
67177db96d56Sopenharmony_ci            return;
67187db96d56Sopenharmony_ci        }
67197db96d56Sopenharmony_ci    }
67207db96d56Sopenharmony_ci    if (mpd_isinteger(exp)) {
67217db96d56Sopenharmony_ci        intexp = 1;
67227db96d56Sopenharmony_ci        resultsign = mpd_isnegative(base) && mpd_isodd(exp);
67237db96d56Sopenharmony_ci    }
67247db96d56Sopenharmony_ci
67257db96d56Sopenharmony_ci    if (mpd_iszero(base)) {
67267db96d56Sopenharmony_ci        if (mpd_iszero(exp)) {
67277db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
67287db96d56Sopenharmony_ci        }
67297db96d56Sopenharmony_ci        else if (mpd_isnegative(exp)) {
67307db96d56Sopenharmony_ci            mpd_setspecial(result, resultsign, MPD_INF);
67317db96d56Sopenharmony_ci        }
67327db96d56Sopenharmony_ci        else {
67337db96d56Sopenharmony_ci            _settriple(result, resultsign, 0, 0);
67347db96d56Sopenharmony_ci        }
67357db96d56Sopenharmony_ci        return;
67367db96d56Sopenharmony_ci    }
67377db96d56Sopenharmony_ci    if (mpd_isnegative(base)) {
67387db96d56Sopenharmony_ci        if (!intexp || mpd_isinfinite(exp)) {
67397db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
67407db96d56Sopenharmony_ci            return;
67417db96d56Sopenharmony_ci        }
67427db96d56Sopenharmony_ci    }
67437db96d56Sopenharmony_ci    if (mpd_isinfinite(exp)) {
67447db96d56Sopenharmony_ci        /* power of one */
67457db96d56Sopenharmony_ci        cmp = _qcheck_pow_one_inf(result, base, resultsign, ctx, status);
67467db96d56Sopenharmony_ci        if (cmp == 0) {
67477db96d56Sopenharmony_ci            return;
67487db96d56Sopenharmony_ci        }
67497db96d56Sopenharmony_ci        else {
67507db96d56Sopenharmony_ci            cmp *= mpd_arith_sign(exp);
67517db96d56Sopenharmony_ci            if (cmp < 0) {
67527db96d56Sopenharmony_ci                _settriple(result, resultsign, 0, 0);
67537db96d56Sopenharmony_ci            }
67547db96d56Sopenharmony_ci            else {
67557db96d56Sopenharmony_ci                mpd_setspecial(result, resultsign, MPD_INF);
67567db96d56Sopenharmony_ci            }
67577db96d56Sopenharmony_ci        }
67587db96d56Sopenharmony_ci        return;
67597db96d56Sopenharmony_ci    }
67607db96d56Sopenharmony_ci    if (mpd_isinfinite(base)) {
67617db96d56Sopenharmony_ci        if (mpd_iszero(exp)) {
67627db96d56Sopenharmony_ci            _settriple(result, resultsign, 1, 0);
67637db96d56Sopenharmony_ci        }
67647db96d56Sopenharmony_ci        else if (mpd_isnegative(exp)) {
67657db96d56Sopenharmony_ci            _settriple(result, resultsign, 0, 0);
67667db96d56Sopenharmony_ci        }
67677db96d56Sopenharmony_ci        else {
67687db96d56Sopenharmony_ci            mpd_setspecial(result, resultsign, MPD_INF);
67697db96d56Sopenharmony_ci        }
67707db96d56Sopenharmony_ci        return;
67717db96d56Sopenharmony_ci    }
67727db96d56Sopenharmony_ci    if (mpd_iszero(exp)) {
67737db96d56Sopenharmony_ci        _settriple(result, resultsign, 1, 0);
67747db96d56Sopenharmony_ci        return;
67757db96d56Sopenharmony_ci    }
67767db96d56Sopenharmony_ci    if (_qcheck_pow_one(result, base, exp, resultsign, ctx, status) == 0) {
67777db96d56Sopenharmony_ci        return;
67787db96d56Sopenharmony_ci    }
67797db96d56Sopenharmony_ci    if (_qcheck_pow_bounds(result, base, exp, resultsign, ctx, status)) {
67807db96d56Sopenharmony_ci        return;
67817db96d56Sopenharmony_ci    }
67827db96d56Sopenharmony_ci
67837db96d56Sopenharmony_ci    if (intexp) {
67847db96d56Sopenharmony_ci        _mpd_qpow_int(result, base, exp, resultsign, ctx, status);
67857db96d56Sopenharmony_ci    }
67867db96d56Sopenharmony_ci    else {
67877db96d56Sopenharmony_ci        _mpd_qpow_real(result, base, exp, ctx, status);
67887db96d56Sopenharmony_ci        if (!mpd_isspecial(result) && _mpd_cmp(result, &one) == 0) {
67897db96d56Sopenharmony_ci            mpd_ssize_t shift = ctx->prec-1;
67907db96d56Sopenharmony_ci            mpd_qshiftl(result, &one, shift, status);
67917db96d56Sopenharmony_ci            result->exp = -shift;
67927db96d56Sopenharmony_ci        }
67937db96d56Sopenharmony_ci        if (mpd_isinfinite(result)) {
67947db96d56Sopenharmony_ci            /* for ROUND_DOWN, ROUND_FLOOR, etc. */
67957db96d56Sopenharmony_ci            _settriple(result, MPD_POS, 1, MPD_EXP_INF);
67967db96d56Sopenharmony_ci        }
67977db96d56Sopenharmony_ci        mpd_qfinalize(result, ctx, status);
67987db96d56Sopenharmony_ci    }
67997db96d56Sopenharmony_ci}
68007db96d56Sopenharmony_ci
68017db96d56Sopenharmony_ci/*
68027db96d56Sopenharmony_ci * Internal function: Integer powmod with mpd_uint_t exponent, base is modified!
68037db96d56Sopenharmony_ci * Function can fail with MPD_Malloc_error.
68047db96d56Sopenharmony_ci */
68057db96d56Sopenharmony_cistatic inline void
68067db96d56Sopenharmony_ci_mpd_qpowmod_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp,
68077db96d56Sopenharmony_ci                  const mpd_t *mod, uint32_t *status)
68087db96d56Sopenharmony_ci{
68097db96d56Sopenharmony_ci    mpd_context_t maxcontext;
68107db96d56Sopenharmony_ci
68117db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
68127db96d56Sopenharmony_ci
68137db96d56Sopenharmony_ci    /* resize to smaller cannot fail */
68147db96d56Sopenharmony_ci    mpd_qcopy(result, &one, status);
68157db96d56Sopenharmony_ci
68167db96d56Sopenharmony_ci    while (exp > 0) {
68177db96d56Sopenharmony_ci        if (exp & 1) {
68187db96d56Sopenharmony_ci            _mpd_qmul_exact(result, result, base, &maxcontext, status);
68197db96d56Sopenharmony_ci            mpd_qrem(result, result, mod, &maxcontext, status);
68207db96d56Sopenharmony_ci        }
68217db96d56Sopenharmony_ci        _mpd_qmul_exact(base, base, base, &maxcontext, status);
68227db96d56Sopenharmony_ci        mpd_qrem(base, base, mod, &maxcontext, status);
68237db96d56Sopenharmony_ci        exp >>= 1;
68247db96d56Sopenharmony_ci    }
68257db96d56Sopenharmony_ci}
68267db96d56Sopenharmony_ci
68277db96d56Sopenharmony_ci/* The powmod function: (base**exp) % mod */
68287db96d56Sopenharmony_civoid
68297db96d56Sopenharmony_cimpd_qpowmod(mpd_t *result, const mpd_t *base, const mpd_t *exp,
68307db96d56Sopenharmony_ci            const mpd_t *mod,
68317db96d56Sopenharmony_ci            const mpd_context_t *ctx, uint32_t *status)
68327db96d56Sopenharmony_ci{
68337db96d56Sopenharmony_ci    mpd_context_t maxcontext;
68347db96d56Sopenharmony_ci    MPD_NEW_STATIC(tbase,0,0,0,0);
68357db96d56Sopenharmony_ci    MPD_NEW_STATIC(texp,0,0,0,0);
68367db96d56Sopenharmony_ci    MPD_NEW_STATIC(tmod,0,0,0,0);
68377db96d56Sopenharmony_ci    MPD_NEW_STATIC(tmp,0,0,0,0);
68387db96d56Sopenharmony_ci    MPD_NEW_CONST(two,0,0,1,1,1,2);
68397db96d56Sopenharmony_ci    mpd_ssize_t tbase_exp, texp_exp;
68407db96d56Sopenharmony_ci    mpd_ssize_t i;
68417db96d56Sopenharmony_ci    mpd_t t;
68427db96d56Sopenharmony_ci    mpd_uint_t r;
68437db96d56Sopenharmony_ci    uint8_t sign;
68447db96d56Sopenharmony_ci
68457db96d56Sopenharmony_ci
68467db96d56Sopenharmony_ci    if (mpd_isspecial(base) || mpd_isspecial(exp) || mpd_isspecial(mod)) {
68477db96d56Sopenharmony_ci        if (mpd_qcheck_3nans(result, base, exp, mod, ctx, status)) {
68487db96d56Sopenharmony_ci            return;
68497db96d56Sopenharmony_ci        }
68507db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
68517db96d56Sopenharmony_ci        return;
68527db96d56Sopenharmony_ci    }
68537db96d56Sopenharmony_ci
68547db96d56Sopenharmony_ci
68557db96d56Sopenharmony_ci    if (!_mpd_isint(base) || !_mpd_isint(exp) || !_mpd_isint(mod)) {
68567db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
68577db96d56Sopenharmony_ci        return;
68587db96d56Sopenharmony_ci    }
68597db96d56Sopenharmony_ci    if (mpd_iszerocoeff(mod)) {
68607db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
68617db96d56Sopenharmony_ci        return;
68627db96d56Sopenharmony_ci    }
68637db96d56Sopenharmony_ci    if (mod->digits+mod->exp > ctx->prec) {
68647db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
68657db96d56Sopenharmony_ci        return;
68667db96d56Sopenharmony_ci    }
68677db96d56Sopenharmony_ci
68687db96d56Sopenharmony_ci    sign = (mpd_isnegative(base)) && (mpd_isodd(exp));
68697db96d56Sopenharmony_ci    if (mpd_iszerocoeff(exp)) {
68707db96d56Sopenharmony_ci        if (mpd_iszerocoeff(base)) {
68717db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
68727db96d56Sopenharmony_ci            return;
68737db96d56Sopenharmony_ci        }
68747db96d56Sopenharmony_ci        r = (_mpd_cmp_abs(mod, &one)==0) ? 0 : 1;
68757db96d56Sopenharmony_ci        _settriple(result, sign, r, 0);
68767db96d56Sopenharmony_ci        return;
68777db96d56Sopenharmony_ci    }
68787db96d56Sopenharmony_ci    if (mpd_isnegative(exp)) {
68797db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
68807db96d56Sopenharmony_ci        return;
68817db96d56Sopenharmony_ci    }
68827db96d56Sopenharmony_ci    if (mpd_iszerocoeff(base)) {
68837db96d56Sopenharmony_ci        _settriple(result, sign, 0, 0);
68847db96d56Sopenharmony_ci        return;
68857db96d56Sopenharmony_ci    }
68867db96d56Sopenharmony_ci
68877db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
68887db96d56Sopenharmony_ci
68897db96d56Sopenharmony_ci    mpd_qrescale(&tmod, mod, 0, &maxcontext, &maxcontext.status);
68907db96d56Sopenharmony_ci    if (maxcontext.status&MPD_Errors) {
68917db96d56Sopenharmony_ci        mpd_seterror(result, maxcontext.status&MPD_Errors, status);
68927db96d56Sopenharmony_ci        goto out;
68937db96d56Sopenharmony_ci    }
68947db96d56Sopenharmony_ci    maxcontext.status = 0;
68957db96d56Sopenharmony_ci    mpd_set_positive(&tmod);
68967db96d56Sopenharmony_ci
68977db96d56Sopenharmony_ci    mpd_qround_to_int(&tbase, base, &maxcontext, status);
68987db96d56Sopenharmony_ci    mpd_set_positive(&tbase);
68997db96d56Sopenharmony_ci    tbase_exp = tbase.exp;
69007db96d56Sopenharmony_ci    tbase.exp = 0;
69017db96d56Sopenharmony_ci
69027db96d56Sopenharmony_ci    mpd_qround_to_int(&texp, exp, &maxcontext, status);
69037db96d56Sopenharmony_ci    texp_exp = texp.exp;
69047db96d56Sopenharmony_ci    texp.exp = 0;
69057db96d56Sopenharmony_ci
69067db96d56Sopenharmony_ci    /* base = (base.int % modulo * pow(10, base.exp, modulo)) % modulo */
69077db96d56Sopenharmony_ci    mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
69087db96d56Sopenharmony_ci    mpd_qshiftl(result, &one, tbase_exp, status);
69097db96d56Sopenharmony_ci    mpd_qrem(result, result, &tmod, &maxcontext, status);
69107db96d56Sopenharmony_ci    _mpd_qmul_exact(&tbase, &tbase, result, &maxcontext, status);
69117db96d56Sopenharmony_ci    mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
69127db96d56Sopenharmony_ci    if (mpd_isspecial(&tbase) ||
69137db96d56Sopenharmony_ci        mpd_isspecial(&texp) ||
69147db96d56Sopenharmony_ci        mpd_isspecial(&tmod)) {
69157db96d56Sopenharmony_ci        goto mpd_errors;
69167db96d56Sopenharmony_ci    }
69177db96d56Sopenharmony_ci
69187db96d56Sopenharmony_ci    for (i = 0; i < texp_exp; i++) {
69197db96d56Sopenharmony_ci        _mpd_qpowmod_uint(&tmp, &tbase, 10, &tmod, status);
69207db96d56Sopenharmony_ci        t = tmp;
69217db96d56Sopenharmony_ci        tmp = tbase;
69227db96d56Sopenharmony_ci        tbase = t;
69237db96d56Sopenharmony_ci    }
69247db96d56Sopenharmony_ci    if (mpd_isspecial(&tbase)) {
69257db96d56Sopenharmony_ci        goto mpd_errors; /* GCOV_UNLIKELY */
69267db96d56Sopenharmony_ci    }
69277db96d56Sopenharmony_ci
69287db96d56Sopenharmony_ci    /* resize to smaller cannot fail */
69297db96d56Sopenharmony_ci    mpd_qcopy(result, &one, status);
69307db96d56Sopenharmony_ci    while (mpd_isfinite(&texp) && !mpd_iszero(&texp)) {
69317db96d56Sopenharmony_ci        if (mpd_isodd(&texp)) {
69327db96d56Sopenharmony_ci            _mpd_qmul_exact(result, result, &tbase, &maxcontext, status);
69337db96d56Sopenharmony_ci            mpd_qrem(result, result, &tmod, &maxcontext, status);
69347db96d56Sopenharmony_ci        }
69357db96d56Sopenharmony_ci        _mpd_qmul_exact(&tbase, &tbase, &tbase, &maxcontext, status);
69367db96d56Sopenharmony_ci        mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
69377db96d56Sopenharmony_ci        mpd_qdivint(&texp, &texp, &two, &maxcontext, status);
69387db96d56Sopenharmony_ci    }
69397db96d56Sopenharmony_ci    if (mpd_isspecial(&texp) || mpd_isspecial(&tbase) ||
69407db96d56Sopenharmony_ci        mpd_isspecial(&tmod) || mpd_isspecial(result)) {
69417db96d56Sopenharmony_ci        /* MPD_Malloc_error */
69427db96d56Sopenharmony_ci        goto mpd_errors;
69437db96d56Sopenharmony_ci    }
69447db96d56Sopenharmony_ci    else {
69457db96d56Sopenharmony_ci        mpd_set_sign(result, sign);
69467db96d56Sopenharmony_ci    }
69477db96d56Sopenharmony_ci
69487db96d56Sopenharmony_ciout:
69497db96d56Sopenharmony_ci    mpd_del(&tbase);
69507db96d56Sopenharmony_ci    mpd_del(&texp);
69517db96d56Sopenharmony_ci    mpd_del(&tmod);
69527db96d56Sopenharmony_ci    mpd_del(&tmp);
69537db96d56Sopenharmony_ci    return;
69547db96d56Sopenharmony_ci
69557db96d56Sopenharmony_cimpd_errors:
69567db96d56Sopenharmony_ci    mpd_setspecial(result, MPD_POS, MPD_NAN);
69577db96d56Sopenharmony_ci    goto out;
69587db96d56Sopenharmony_ci}
69597db96d56Sopenharmony_ci
69607db96d56Sopenharmony_civoid
69617db96d56Sopenharmony_cimpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b,
69627db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
69637db96d56Sopenharmony_ci{
69647db96d56Sopenharmony_ci    uint32_t workstatus = 0;
69657db96d56Sopenharmony_ci    mpd_ssize_t b_exp = b->exp;
69667db96d56Sopenharmony_ci    mpd_ssize_t expdiff, shift;
69677db96d56Sopenharmony_ci    mpd_uint_t rnd;
69687db96d56Sopenharmony_ci
69697db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
69707db96d56Sopenharmony_ci        if (mpd_qcheck_nans(result, a, b, ctx, status)) {
69717db96d56Sopenharmony_ci            return;
69727db96d56Sopenharmony_ci        }
69737db96d56Sopenharmony_ci        if (mpd_isinfinite(a) && mpd_isinfinite(b)) {
69747db96d56Sopenharmony_ci            mpd_qcopy(result, a, status);
69757db96d56Sopenharmony_ci            return;
69767db96d56Sopenharmony_ci        }
69777db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
69787db96d56Sopenharmony_ci        return;
69797db96d56Sopenharmony_ci    }
69807db96d56Sopenharmony_ci
69817db96d56Sopenharmony_ci    if (b->exp > ctx->emax || b->exp < mpd_etiny(ctx)) {
69827db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
69837db96d56Sopenharmony_ci        return;
69847db96d56Sopenharmony_ci    }
69857db96d56Sopenharmony_ci
69867db96d56Sopenharmony_ci    if (mpd_iszero(a)) {
69877db96d56Sopenharmony_ci        _settriple(result, mpd_sign(a), 0, b->exp);
69887db96d56Sopenharmony_ci        mpd_qfinalize(result, ctx, status);
69897db96d56Sopenharmony_ci        return;
69907db96d56Sopenharmony_ci    }
69917db96d56Sopenharmony_ci
69927db96d56Sopenharmony_ci
69937db96d56Sopenharmony_ci    expdiff = a->exp - b->exp;
69947db96d56Sopenharmony_ci    if (a->digits + expdiff > ctx->prec) {
69957db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
69967db96d56Sopenharmony_ci        return;
69977db96d56Sopenharmony_ci    }
69987db96d56Sopenharmony_ci
69997db96d56Sopenharmony_ci    if (expdiff >= 0) {
70007db96d56Sopenharmony_ci        shift = expdiff;
70017db96d56Sopenharmony_ci        if (!mpd_qshiftl(result, a, shift, status)) {
70027db96d56Sopenharmony_ci            return;
70037db96d56Sopenharmony_ci        }
70047db96d56Sopenharmony_ci        result->exp = b_exp;
70057db96d56Sopenharmony_ci    }
70067db96d56Sopenharmony_ci    else {
70077db96d56Sopenharmony_ci        /* At this point expdiff < 0 and a->digits+expdiff <= prec,
70087db96d56Sopenharmony_ci         * so the shift before an increment will fit in prec. */
70097db96d56Sopenharmony_ci        shift = -expdiff;
70107db96d56Sopenharmony_ci        rnd = mpd_qshiftr(result, a, shift, status);
70117db96d56Sopenharmony_ci        if (rnd == MPD_UINT_MAX) {
70127db96d56Sopenharmony_ci            return;
70137db96d56Sopenharmony_ci        }
70147db96d56Sopenharmony_ci        result->exp = b_exp;
70157db96d56Sopenharmony_ci        if (!_mpd_apply_round_fit(result, rnd, ctx, status)) {
70167db96d56Sopenharmony_ci            return;
70177db96d56Sopenharmony_ci        }
70187db96d56Sopenharmony_ci        workstatus |= MPD_Rounded;
70197db96d56Sopenharmony_ci        if (rnd) {
70207db96d56Sopenharmony_ci            workstatus |= MPD_Inexact;
70217db96d56Sopenharmony_ci        }
70227db96d56Sopenharmony_ci    }
70237db96d56Sopenharmony_ci
70247db96d56Sopenharmony_ci    if (mpd_adjexp(result) > ctx->emax ||
70257db96d56Sopenharmony_ci        mpd_adjexp(result) < mpd_etiny(ctx)) {
70267db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
70277db96d56Sopenharmony_ci        return;
70287db96d56Sopenharmony_ci    }
70297db96d56Sopenharmony_ci
70307db96d56Sopenharmony_ci    *status |= workstatus;
70317db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
70327db96d56Sopenharmony_ci}
70337db96d56Sopenharmony_ci
70347db96d56Sopenharmony_civoid
70357db96d56Sopenharmony_cimpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
70367db96d56Sopenharmony_ci            uint32_t *status)
70377db96d56Sopenharmony_ci{
70387db96d56Sopenharmony_ci    mpd_ssize_t shift, maxexp, maxshift;
70397db96d56Sopenharmony_ci    uint8_t sign_a = mpd_sign(a);
70407db96d56Sopenharmony_ci
70417db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
70427db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
70437db96d56Sopenharmony_ci            return;
70447db96d56Sopenharmony_ci        }
70457db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
70467db96d56Sopenharmony_ci        return;
70477db96d56Sopenharmony_ci    }
70487db96d56Sopenharmony_ci
70497db96d56Sopenharmony_ci    if (!mpd_qcopy(result, a, status)) {
70507db96d56Sopenharmony_ci        return;
70517db96d56Sopenharmony_ci    }
70527db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
70537db96d56Sopenharmony_ci    if (mpd_isspecial(result)) {
70547db96d56Sopenharmony_ci        return;
70557db96d56Sopenharmony_ci    }
70567db96d56Sopenharmony_ci    if (mpd_iszero(result)) {
70577db96d56Sopenharmony_ci        _settriple(result, sign_a, 0, 0);
70587db96d56Sopenharmony_ci        return;
70597db96d56Sopenharmony_ci    }
70607db96d56Sopenharmony_ci
70617db96d56Sopenharmony_ci    shift = mpd_trail_zeros(result);
70627db96d56Sopenharmony_ci    maxexp = (ctx->clamp) ? mpd_etop(ctx) : ctx->emax;
70637db96d56Sopenharmony_ci    /* After the finalizing above result->exp <= maxexp. */
70647db96d56Sopenharmony_ci    maxshift = maxexp - result->exp;
70657db96d56Sopenharmony_ci    shift = (shift > maxshift) ? maxshift : shift;
70667db96d56Sopenharmony_ci
70677db96d56Sopenharmony_ci    mpd_qshiftr_inplace(result, shift);
70687db96d56Sopenharmony_ci    result->exp += shift;
70697db96d56Sopenharmony_ci}
70707db96d56Sopenharmony_ci
70717db96d56Sopenharmony_civoid
70727db96d56Sopenharmony_cimpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx,
70737db96d56Sopenharmony_ci         uint32_t *status)
70747db96d56Sopenharmony_ci{
70757db96d56Sopenharmony_ci    MPD_NEW_STATIC(q,0,0,0,0);
70767db96d56Sopenharmony_ci
70777db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
70787db96d56Sopenharmony_ci        if (mpd_qcheck_nans(r, a, b, ctx, status)) {
70797db96d56Sopenharmony_ci            return;
70807db96d56Sopenharmony_ci        }
70817db96d56Sopenharmony_ci        if (mpd_isinfinite(a)) {
70827db96d56Sopenharmony_ci            mpd_seterror(r, MPD_Invalid_operation, status);
70837db96d56Sopenharmony_ci            return;
70847db96d56Sopenharmony_ci        }
70857db96d56Sopenharmony_ci        if (mpd_isinfinite(b)) {
70867db96d56Sopenharmony_ci            mpd_qcopy(r, a, status);
70877db96d56Sopenharmony_ci            mpd_qfinalize(r, ctx, status);
70887db96d56Sopenharmony_ci            return;
70897db96d56Sopenharmony_ci        }
70907db96d56Sopenharmony_ci        /* debug */
70917db96d56Sopenharmony_ci        abort(); /* GCOV_NOT_REACHED */
70927db96d56Sopenharmony_ci    }
70937db96d56Sopenharmony_ci    if (mpd_iszerocoeff(b)) {
70947db96d56Sopenharmony_ci        if (mpd_iszerocoeff(a)) {
70957db96d56Sopenharmony_ci            mpd_seterror(r, MPD_Division_undefined, status);
70967db96d56Sopenharmony_ci        }
70977db96d56Sopenharmony_ci        else {
70987db96d56Sopenharmony_ci            mpd_seterror(r, MPD_Invalid_operation, status);
70997db96d56Sopenharmony_ci        }
71007db96d56Sopenharmony_ci        return;
71017db96d56Sopenharmony_ci    }
71027db96d56Sopenharmony_ci
71037db96d56Sopenharmony_ci    _mpd_qdivmod(&q, r, a, b, ctx, status);
71047db96d56Sopenharmony_ci    mpd_del(&q);
71057db96d56Sopenharmony_ci    mpd_qfinalize(r, ctx, status);
71067db96d56Sopenharmony_ci}
71077db96d56Sopenharmony_ci
71087db96d56Sopenharmony_civoid
71097db96d56Sopenharmony_cimpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b,
71107db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
71117db96d56Sopenharmony_ci{
71127db96d56Sopenharmony_ci    mpd_context_t workctx;
71137db96d56Sopenharmony_ci    MPD_NEW_STATIC(btmp,0,0,0,0);
71147db96d56Sopenharmony_ci    MPD_NEW_STATIC(q,0,0,0,0);
71157db96d56Sopenharmony_ci    mpd_ssize_t expdiff, qdigits;
71167db96d56Sopenharmony_ci    int cmp, isodd, allnine;
71177db96d56Sopenharmony_ci
71187db96d56Sopenharmony_ci    assert(r != NULL); /* annotation for scan-build */
71197db96d56Sopenharmony_ci
71207db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
71217db96d56Sopenharmony_ci        if (mpd_qcheck_nans(r, a, b, ctx, status)) {
71227db96d56Sopenharmony_ci            return;
71237db96d56Sopenharmony_ci        }
71247db96d56Sopenharmony_ci        if (mpd_isinfinite(a)) {
71257db96d56Sopenharmony_ci            mpd_seterror(r, MPD_Invalid_operation, status);
71267db96d56Sopenharmony_ci            return;
71277db96d56Sopenharmony_ci        }
71287db96d56Sopenharmony_ci        if (mpd_isinfinite(b)) {
71297db96d56Sopenharmony_ci            mpd_qcopy(r, a, status);
71307db96d56Sopenharmony_ci            mpd_qfinalize(r, ctx, status);
71317db96d56Sopenharmony_ci            return;
71327db96d56Sopenharmony_ci        }
71337db96d56Sopenharmony_ci        /* debug */
71347db96d56Sopenharmony_ci        abort(); /* GCOV_NOT_REACHED */
71357db96d56Sopenharmony_ci    }
71367db96d56Sopenharmony_ci    if (mpd_iszerocoeff(b)) {
71377db96d56Sopenharmony_ci        if (mpd_iszerocoeff(a)) {
71387db96d56Sopenharmony_ci            mpd_seterror(r,  MPD_Division_undefined, status);
71397db96d56Sopenharmony_ci        }
71407db96d56Sopenharmony_ci        else {
71417db96d56Sopenharmony_ci            mpd_seterror(r,  MPD_Invalid_operation, status);
71427db96d56Sopenharmony_ci        }
71437db96d56Sopenharmony_ci        return;
71447db96d56Sopenharmony_ci    }
71457db96d56Sopenharmony_ci
71467db96d56Sopenharmony_ci    if (r == b) {
71477db96d56Sopenharmony_ci        if (!mpd_qcopy(&btmp, b, status)) {
71487db96d56Sopenharmony_ci            mpd_seterror(r, MPD_Malloc_error, status);
71497db96d56Sopenharmony_ci            return;
71507db96d56Sopenharmony_ci        }
71517db96d56Sopenharmony_ci        b = &btmp;
71527db96d56Sopenharmony_ci    }
71537db96d56Sopenharmony_ci
71547db96d56Sopenharmony_ci    _mpd_qdivmod(&q, r, a, b, ctx, status);
71557db96d56Sopenharmony_ci    if (mpd_isnan(&q) || mpd_isnan(r)) {
71567db96d56Sopenharmony_ci        goto finish;
71577db96d56Sopenharmony_ci    }
71587db96d56Sopenharmony_ci    if (mpd_iszerocoeff(r)) {
71597db96d56Sopenharmony_ci        goto finish;
71607db96d56Sopenharmony_ci    }
71617db96d56Sopenharmony_ci
71627db96d56Sopenharmony_ci    expdiff = mpd_adjexp(b) - mpd_adjexp(r);
71637db96d56Sopenharmony_ci    if (-1 <= expdiff && expdiff <= 1) {
71647db96d56Sopenharmony_ci
71657db96d56Sopenharmony_ci        allnine = mpd_coeff_isallnine(&q);
71667db96d56Sopenharmony_ci        qdigits = q.digits;
71677db96d56Sopenharmony_ci        isodd = mpd_isodd(&q);
71687db96d56Sopenharmony_ci
71697db96d56Sopenharmony_ci        mpd_maxcontext(&workctx);
71707db96d56Sopenharmony_ci        if (mpd_sign(a) == mpd_sign(b)) {
71717db96d56Sopenharmony_ci            /* sign(r) == sign(b) */
71727db96d56Sopenharmony_ci            _mpd_qsub(&q, r, b, &workctx, &workctx.status);
71737db96d56Sopenharmony_ci        }
71747db96d56Sopenharmony_ci        else {
71757db96d56Sopenharmony_ci            /* sign(r) != sign(b) */
71767db96d56Sopenharmony_ci            _mpd_qadd(&q, r, b, &workctx, &workctx.status);
71777db96d56Sopenharmony_ci        }
71787db96d56Sopenharmony_ci
71797db96d56Sopenharmony_ci        if (workctx.status&MPD_Errors) {
71807db96d56Sopenharmony_ci            mpd_seterror(r, workctx.status&MPD_Errors, status);
71817db96d56Sopenharmony_ci            goto finish;
71827db96d56Sopenharmony_ci        }
71837db96d56Sopenharmony_ci
71847db96d56Sopenharmony_ci        cmp = _mpd_cmp_abs(&q, r);
71857db96d56Sopenharmony_ci        if (cmp < 0 || (cmp == 0 && isodd)) {
71867db96d56Sopenharmony_ci            /* abs(r) > abs(b)/2 or abs(r) == abs(b)/2 and isodd(quotient) */
71877db96d56Sopenharmony_ci            if (allnine && qdigits == ctx->prec) {
71887db96d56Sopenharmony_ci                /* abs(quotient) + 1 == 10**prec */
71897db96d56Sopenharmony_ci                mpd_seterror(r, MPD_Division_impossible, status);
71907db96d56Sopenharmony_ci                goto finish;
71917db96d56Sopenharmony_ci            }
71927db96d56Sopenharmony_ci            mpd_qcopy(r, &q, status);
71937db96d56Sopenharmony_ci        }
71947db96d56Sopenharmony_ci    }
71957db96d56Sopenharmony_ci
71967db96d56Sopenharmony_ci
71977db96d56Sopenharmony_cifinish:
71987db96d56Sopenharmony_ci    mpd_del(&btmp);
71997db96d56Sopenharmony_ci    mpd_del(&q);
72007db96d56Sopenharmony_ci    mpd_qfinalize(r, ctx, status);
72017db96d56Sopenharmony_ci}
72027db96d56Sopenharmony_ci
72037db96d56Sopenharmony_cistatic void
72047db96d56Sopenharmony_ci_mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
72057db96d56Sopenharmony_ci              const mpd_context_t *ctx, uint32_t *status)
72067db96d56Sopenharmony_ci{
72077db96d56Sopenharmony_ci    mpd_ssize_t expdiff, shift;
72087db96d56Sopenharmony_ci    mpd_uint_t rnd;
72097db96d56Sopenharmony_ci
72107db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
72117db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
72127db96d56Sopenharmony_ci        return;
72137db96d56Sopenharmony_ci    }
72147db96d56Sopenharmony_ci
72157db96d56Sopenharmony_ci    if (mpd_iszero(a)) {
72167db96d56Sopenharmony_ci        _settriple(result, mpd_sign(a), 0, exp);
72177db96d56Sopenharmony_ci        return;
72187db96d56Sopenharmony_ci    }
72197db96d56Sopenharmony_ci
72207db96d56Sopenharmony_ci    expdiff = a->exp - exp;
72217db96d56Sopenharmony_ci    if (expdiff >= 0) {
72227db96d56Sopenharmony_ci        shift = expdiff;
72237db96d56Sopenharmony_ci        if (a->digits + shift > MPD_MAX_PREC+1) {
72247db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
72257db96d56Sopenharmony_ci            return;
72267db96d56Sopenharmony_ci        }
72277db96d56Sopenharmony_ci        if (!mpd_qshiftl(result, a, shift, status)) {
72287db96d56Sopenharmony_ci            return;
72297db96d56Sopenharmony_ci        }
72307db96d56Sopenharmony_ci        result->exp = exp;
72317db96d56Sopenharmony_ci    }
72327db96d56Sopenharmony_ci    else {
72337db96d56Sopenharmony_ci        shift = -expdiff;
72347db96d56Sopenharmony_ci        rnd = mpd_qshiftr(result, a, shift, status);
72357db96d56Sopenharmony_ci        if (rnd == MPD_UINT_MAX) {
72367db96d56Sopenharmony_ci            return;
72377db96d56Sopenharmony_ci        }
72387db96d56Sopenharmony_ci        result->exp = exp;
72397db96d56Sopenharmony_ci        _mpd_apply_round_excess(result, rnd, ctx, status);
72407db96d56Sopenharmony_ci        *status |= MPD_Rounded;
72417db96d56Sopenharmony_ci        if (rnd) {
72427db96d56Sopenharmony_ci            *status |= MPD_Inexact;
72437db96d56Sopenharmony_ci        }
72447db96d56Sopenharmony_ci    }
72457db96d56Sopenharmony_ci
72467db96d56Sopenharmony_ci    if (mpd_issubnormal(result, ctx)) {
72477db96d56Sopenharmony_ci        *status |= MPD_Subnormal;
72487db96d56Sopenharmony_ci    }
72497db96d56Sopenharmony_ci}
72507db96d56Sopenharmony_ci
72517db96d56Sopenharmony_ci/*
72527db96d56Sopenharmony_ci * Rescale a number so that it has exponent 'exp'. Does not regard context
72537db96d56Sopenharmony_ci * precision, emax, emin, but uses the rounding mode. Special numbers are
72547db96d56Sopenharmony_ci * quietly copied. Restrictions:
72557db96d56Sopenharmony_ci *
72567db96d56Sopenharmony_ci *     MPD_MIN_ETINY <= exp <= MPD_MAX_EMAX+1
72577db96d56Sopenharmony_ci *     result->digits <= MPD_MAX_PREC+1
72587db96d56Sopenharmony_ci */
72597db96d56Sopenharmony_civoid
72607db96d56Sopenharmony_cimpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
72617db96d56Sopenharmony_ci             const mpd_context_t *ctx, uint32_t *status)
72627db96d56Sopenharmony_ci{
72637db96d56Sopenharmony_ci    if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY) {
72647db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
72657db96d56Sopenharmony_ci        return;
72667db96d56Sopenharmony_ci    }
72677db96d56Sopenharmony_ci
72687db96d56Sopenharmony_ci    _mpd_qrescale(result, a, exp, ctx, status);
72697db96d56Sopenharmony_ci}
72707db96d56Sopenharmony_ci
72717db96d56Sopenharmony_ci/*
72727db96d56Sopenharmony_ci * Same as mpd_qrescale, but with relaxed restrictions. The result of this
72737db96d56Sopenharmony_ci * function should only be used for formatting a number and never as input
72747db96d56Sopenharmony_ci * for other operations.
72757db96d56Sopenharmony_ci *
72767db96d56Sopenharmony_ci *     MPD_MIN_ETINY-MPD_MAX_PREC <= exp <= MPD_MAX_EMAX+1
72777db96d56Sopenharmony_ci *     result->digits <= MPD_MAX_PREC+1
72787db96d56Sopenharmony_ci */
72797db96d56Sopenharmony_civoid
72807db96d56Sopenharmony_cimpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
72817db96d56Sopenharmony_ci                 const mpd_context_t *ctx, uint32_t *status)
72827db96d56Sopenharmony_ci{
72837db96d56Sopenharmony_ci    if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY-MPD_MAX_PREC) {
72847db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
72857db96d56Sopenharmony_ci        return;
72867db96d56Sopenharmony_ci    }
72877db96d56Sopenharmony_ci
72887db96d56Sopenharmony_ci    _mpd_qrescale(result, a, exp, ctx, status);
72897db96d56Sopenharmony_ci}
72907db96d56Sopenharmony_ci
72917db96d56Sopenharmony_ci/* Round to an integer according to 'action' and ctx->round. */
72927db96d56Sopenharmony_cienum {TO_INT_EXACT, TO_INT_SILENT, TO_INT_TRUNC};
72937db96d56Sopenharmony_cistatic void
72947db96d56Sopenharmony_ci_mpd_qround_to_integral(int action, mpd_t *result, const mpd_t *a,
72957db96d56Sopenharmony_ci                        const mpd_context_t *ctx, uint32_t *status)
72967db96d56Sopenharmony_ci{
72977db96d56Sopenharmony_ci    mpd_uint_t rnd;
72987db96d56Sopenharmony_ci
72997db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
73007db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
73017db96d56Sopenharmony_ci            return;
73027db96d56Sopenharmony_ci        }
73037db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
73047db96d56Sopenharmony_ci        return;
73057db96d56Sopenharmony_ci    }
73067db96d56Sopenharmony_ci    if (a->exp >= 0) {
73077db96d56Sopenharmony_ci        mpd_qcopy(result, a, status);
73087db96d56Sopenharmony_ci        return;
73097db96d56Sopenharmony_ci    }
73107db96d56Sopenharmony_ci    if (mpd_iszerocoeff(a)) {
73117db96d56Sopenharmony_ci        _settriple(result, mpd_sign(a), 0, 0);
73127db96d56Sopenharmony_ci        return;
73137db96d56Sopenharmony_ci    }
73147db96d56Sopenharmony_ci
73157db96d56Sopenharmony_ci    rnd = mpd_qshiftr(result, a, -a->exp, status);
73167db96d56Sopenharmony_ci    if (rnd == MPD_UINT_MAX) {
73177db96d56Sopenharmony_ci        return;
73187db96d56Sopenharmony_ci    }
73197db96d56Sopenharmony_ci    result->exp = 0;
73207db96d56Sopenharmony_ci
73217db96d56Sopenharmony_ci    if (action == TO_INT_EXACT || action == TO_INT_SILENT) {
73227db96d56Sopenharmony_ci        _mpd_apply_round_excess(result, rnd, ctx, status);
73237db96d56Sopenharmony_ci        if (action == TO_INT_EXACT) {
73247db96d56Sopenharmony_ci            *status |= MPD_Rounded;
73257db96d56Sopenharmony_ci            if (rnd) {
73267db96d56Sopenharmony_ci                *status |= MPD_Inexact;
73277db96d56Sopenharmony_ci            }
73287db96d56Sopenharmony_ci        }
73297db96d56Sopenharmony_ci    }
73307db96d56Sopenharmony_ci}
73317db96d56Sopenharmony_ci
73327db96d56Sopenharmony_civoid
73337db96d56Sopenharmony_cimpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
73347db96d56Sopenharmony_ci                   uint32_t *status)
73357db96d56Sopenharmony_ci{
73367db96d56Sopenharmony_ci    (void)_mpd_qround_to_integral(TO_INT_EXACT, result, a, ctx, status);
73377db96d56Sopenharmony_ci}
73387db96d56Sopenharmony_ci
73397db96d56Sopenharmony_civoid
73407db96d56Sopenharmony_cimpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
73417db96d56Sopenharmony_ci                  uint32_t *status)
73427db96d56Sopenharmony_ci{
73437db96d56Sopenharmony_ci    (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, ctx, status);
73447db96d56Sopenharmony_ci}
73457db96d56Sopenharmony_ci
73467db96d56Sopenharmony_civoid
73477db96d56Sopenharmony_cimpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
73487db96d56Sopenharmony_ci           uint32_t *status)
73497db96d56Sopenharmony_ci{
73507db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
73517db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
73527db96d56Sopenharmony_ci        return;
73537db96d56Sopenharmony_ci    }
73547db96d56Sopenharmony_ci
73557db96d56Sopenharmony_ci    (void)_mpd_qround_to_integral(TO_INT_TRUNC, result, a, ctx, status);
73567db96d56Sopenharmony_ci}
73577db96d56Sopenharmony_ci
73587db96d56Sopenharmony_civoid
73597db96d56Sopenharmony_cimpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
73607db96d56Sopenharmony_ci           uint32_t *status)
73617db96d56Sopenharmony_ci{
73627db96d56Sopenharmony_ci    mpd_context_t workctx = *ctx;
73637db96d56Sopenharmony_ci
73647db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
73657db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
73667db96d56Sopenharmony_ci        return;
73677db96d56Sopenharmony_ci    }
73687db96d56Sopenharmony_ci
73697db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_FLOOR;
73707db96d56Sopenharmony_ci    (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a,
73717db96d56Sopenharmony_ci                                  &workctx, status);
73727db96d56Sopenharmony_ci}
73737db96d56Sopenharmony_ci
73747db96d56Sopenharmony_civoid
73757db96d56Sopenharmony_cimpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
73767db96d56Sopenharmony_ci          uint32_t *status)
73777db96d56Sopenharmony_ci{
73787db96d56Sopenharmony_ci    mpd_context_t workctx = *ctx;
73797db96d56Sopenharmony_ci
73807db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
73817db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
73827db96d56Sopenharmony_ci        return;
73837db96d56Sopenharmony_ci    }
73847db96d56Sopenharmony_ci
73857db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_CEILING;
73867db96d56Sopenharmony_ci    (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a,
73877db96d56Sopenharmony_ci                                  &workctx, status);
73887db96d56Sopenharmony_ci}
73897db96d56Sopenharmony_ci
73907db96d56Sopenharmony_ciint
73917db96d56Sopenharmony_cimpd_same_quantum(const mpd_t *a, const mpd_t *b)
73927db96d56Sopenharmony_ci{
73937db96d56Sopenharmony_ci    if (mpd_isspecial(a) || mpd_isspecial(b)) {
73947db96d56Sopenharmony_ci        return ((mpd_isnan(a) && mpd_isnan(b)) ||
73957db96d56Sopenharmony_ci                (mpd_isinfinite(a) && mpd_isinfinite(b)));
73967db96d56Sopenharmony_ci    }
73977db96d56Sopenharmony_ci
73987db96d56Sopenharmony_ci    return a->exp == b->exp;
73997db96d56Sopenharmony_ci}
74007db96d56Sopenharmony_ci
74017db96d56Sopenharmony_ci/* Schedule the increase in precision for the Newton iteration. */
74027db96d56Sopenharmony_cistatic inline int
74037db96d56Sopenharmony_cirecpr_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2],
74047db96d56Sopenharmony_ci                    mpd_ssize_t maxprec, mpd_ssize_t initprec)
74057db96d56Sopenharmony_ci{
74067db96d56Sopenharmony_ci    mpd_ssize_t k;
74077db96d56Sopenharmony_ci    int i;
74087db96d56Sopenharmony_ci
74097db96d56Sopenharmony_ci    assert(maxprec > 0 && initprec > 0);
74107db96d56Sopenharmony_ci    if (maxprec <= initprec) return -1;
74117db96d56Sopenharmony_ci
74127db96d56Sopenharmony_ci    i = 0; k = maxprec;
74137db96d56Sopenharmony_ci    do {
74147db96d56Sopenharmony_ci        k = (k+1) / 2;
74157db96d56Sopenharmony_ci        klist[i++] = k;
74167db96d56Sopenharmony_ci    } while (k > initprec);
74177db96d56Sopenharmony_ci
74187db96d56Sopenharmony_ci    return i-1;
74197db96d56Sopenharmony_ci}
74207db96d56Sopenharmony_ci
74217db96d56Sopenharmony_ci/*
74227db96d56Sopenharmony_ci * Initial approximation for the reciprocal:
74237db96d56Sopenharmony_ci *    k_0 := MPD_RDIGITS-2
74247db96d56Sopenharmony_ci *    z_0 := 10**(-k_0) * floor(10**(2*k_0 + 2) / floor(v * 10**(k_0 + 2)))
74257db96d56Sopenharmony_ci * Absolute error:
74267db96d56Sopenharmony_ci *    |1/v - z_0| < 10**(-k_0)
74277db96d56Sopenharmony_ci * ACL2 proof: maxerror-inverse-approx
74287db96d56Sopenharmony_ci */
74297db96d56Sopenharmony_cistatic void
74307db96d56Sopenharmony_ci_mpd_qreciprocal_approx(mpd_t *z, const mpd_t *v, uint32_t *status)
74317db96d56Sopenharmony_ci{
74327db96d56Sopenharmony_ci    mpd_uint_t p10data[2] = {0, mpd_pow10[MPD_RDIGITS-2]};
74337db96d56Sopenharmony_ci    mpd_uint_t dummy, word;
74347db96d56Sopenharmony_ci    int n;
74357db96d56Sopenharmony_ci
74367db96d56Sopenharmony_ci    assert(v->exp == -v->digits);
74377db96d56Sopenharmony_ci
74387db96d56Sopenharmony_ci    _mpd_get_msdigits(&dummy, &word, v, MPD_RDIGITS);
74397db96d56Sopenharmony_ci    n = mpd_word_digits(word);
74407db96d56Sopenharmony_ci    word *= mpd_pow10[MPD_RDIGITS-n];
74417db96d56Sopenharmony_ci
74427db96d56Sopenharmony_ci    mpd_qresize(z, 2, status);
74437db96d56Sopenharmony_ci    (void)_mpd_shortdiv(z->data, p10data, 2, word);
74447db96d56Sopenharmony_ci
74457db96d56Sopenharmony_ci    mpd_clear_flags(z);
74467db96d56Sopenharmony_ci    z->exp = -(MPD_RDIGITS-2);
74477db96d56Sopenharmony_ci    z->len = (z->data[1] == 0) ? 1 : 2;
74487db96d56Sopenharmony_ci    mpd_setdigits(z);
74497db96d56Sopenharmony_ci}
74507db96d56Sopenharmony_ci
74517db96d56Sopenharmony_ci/*
74527db96d56Sopenharmony_ci * Reciprocal, calculated with Newton's Method. Assumption: result != a.
74537db96d56Sopenharmony_ci * NOTE: The comments in the function show that certain operations are
74547db96d56Sopenharmony_ci * exact. The proof for the maximum error is too long to fit in here.
74557db96d56Sopenharmony_ci * ACL2 proof: maxerror-inverse-complete
74567db96d56Sopenharmony_ci */
74577db96d56Sopenharmony_cistatic void
74587db96d56Sopenharmony_ci_mpd_qreciprocal(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
74597db96d56Sopenharmony_ci                 uint32_t *status)
74607db96d56Sopenharmony_ci{
74617db96d56Sopenharmony_ci    mpd_context_t varcontext, maxcontext;
74627db96d56Sopenharmony_ci    mpd_t *z = result;         /* current approximation */
74637db96d56Sopenharmony_ci    mpd_t *v;                  /* a, normalized to a number between 0.1 and 1 */
74647db96d56Sopenharmony_ci    MPD_NEW_SHARED(vtmp, a);   /* v shares data with a */
74657db96d56Sopenharmony_ci    MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */
74667db96d56Sopenharmony_ci    MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */
74677db96d56Sopenharmony_ci    MPD_NEW_CONST(two,0,0,1,1,1,2); /* const 2 */
74687db96d56Sopenharmony_ci    mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
74697db96d56Sopenharmony_ci    mpd_ssize_t adj, maxprec, initprec;
74707db96d56Sopenharmony_ci    uint8_t sign = mpd_sign(a);
74717db96d56Sopenharmony_ci    int i;
74727db96d56Sopenharmony_ci
74737db96d56Sopenharmony_ci    assert(result != a);
74747db96d56Sopenharmony_ci
74757db96d56Sopenharmony_ci    v = &vtmp;
74767db96d56Sopenharmony_ci    mpd_clear_flags(v);
74777db96d56Sopenharmony_ci    adj = v->digits + v->exp;
74787db96d56Sopenharmony_ci    v->exp = -v->digits;
74797db96d56Sopenharmony_ci
74807db96d56Sopenharmony_ci    /* Initial approximation */
74817db96d56Sopenharmony_ci    _mpd_qreciprocal_approx(z, v, status);
74827db96d56Sopenharmony_ci
74837db96d56Sopenharmony_ci    mpd_maxcontext(&varcontext);
74847db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
74857db96d56Sopenharmony_ci    varcontext.round = maxcontext.round = MPD_ROUND_TRUNC;
74867db96d56Sopenharmony_ci    varcontext.emax = maxcontext.emax = MPD_MAX_EMAX + 100;
74877db96d56Sopenharmony_ci    varcontext.emin = maxcontext.emin = MPD_MIN_EMIN - 100;
74887db96d56Sopenharmony_ci    maxcontext.prec = MPD_MAX_PREC + 100;
74897db96d56Sopenharmony_ci
74907db96d56Sopenharmony_ci    maxprec = ctx->prec;
74917db96d56Sopenharmony_ci    maxprec += 2;
74927db96d56Sopenharmony_ci    initprec = MPD_RDIGITS-3;
74937db96d56Sopenharmony_ci
74947db96d56Sopenharmony_ci    i = recpr_schedule_prec(klist, maxprec, initprec);
74957db96d56Sopenharmony_ci    for (; i >= 0; i--) {
74967db96d56Sopenharmony_ci         /* Loop invariant: z->digits <= klist[i]+7 */
74977db96d56Sopenharmony_ci         /* Let s := z**2, exact result */
74987db96d56Sopenharmony_ci        _mpd_qmul_exact(&s, z, z, &maxcontext, status);
74997db96d56Sopenharmony_ci        varcontext.prec = 2*klist[i] + 5;
75007db96d56Sopenharmony_ci        if (v->digits > varcontext.prec) {
75017db96d56Sopenharmony_ci            /* Let t := v, truncated to n >= 2*k+5 fraction digits */
75027db96d56Sopenharmony_ci            mpd_qshiftr(&t, v, v->digits-varcontext.prec, status);
75037db96d56Sopenharmony_ci            t.exp = -varcontext.prec;
75047db96d56Sopenharmony_ci            /* Let t := trunc(v)*s, truncated to n >= 2*k+1 fraction digits */
75057db96d56Sopenharmony_ci            mpd_qmul(&t, &t, &s, &varcontext, status);
75067db96d56Sopenharmony_ci        }
75077db96d56Sopenharmony_ci        else { /* v->digits <= 2*k+5 */
75087db96d56Sopenharmony_ci            /* Let t := v*s, truncated to n >= 2*k+1 fraction digits */
75097db96d56Sopenharmony_ci            mpd_qmul(&t, v, &s, &varcontext, status);
75107db96d56Sopenharmony_ci        }
75117db96d56Sopenharmony_ci        /* Let s := 2*z, exact result */
75127db96d56Sopenharmony_ci        _mpd_qmul_exact(&s, z, &two, &maxcontext, status);
75137db96d56Sopenharmony_ci        /* s.digits < t.digits <= 2*k+5, |adjexp(s)-adjexp(t)| <= 1,
75147db96d56Sopenharmony_ci         * so the subtraction generates at most 2*k+6 <= klist[i+1]+7
75157db96d56Sopenharmony_ci         * digits. The loop invariant is preserved. */
75167db96d56Sopenharmony_ci        _mpd_qsub_exact(z, &s, &t, &maxcontext, status);
75177db96d56Sopenharmony_ci    }
75187db96d56Sopenharmony_ci
75197db96d56Sopenharmony_ci    if (!mpd_isspecial(z)) {
75207db96d56Sopenharmony_ci        z->exp -= adj;
75217db96d56Sopenharmony_ci        mpd_set_flags(z, sign);
75227db96d56Sopenharmony_ci    }
75237db96d56Sopenharmony_ci
75247db96d56Sopenharmony_ci    mpd_del(&s);
75257db96d56Sopenharmony_ci    mpd_del(&t);
75267db96d56Sopenharmony_ci    mpd_qfinalize(z, ctx, status);
75277db96d56Sopenharmony_ci}
75287db96d56Sopenharmony_ci
75297db96d56Sopenharmony_ci/*
75307db96d56Sopenharmony_ci * Internal function for large numbers:
75317db96d56Sopenharmony_ci *
75327db96d56Sopenharmony_ci *     q, r = divmod(coeff(a), coeff(b))
75337db96d56Sopenharmony_ci *
75347db96d56Sopenharmony_ci * Strategy: Multiply the dividend by the reciprocal of the divisor. The
75357db96d56Sopenharmony_ci * inexact result is fixed by a small loop, using at most one iteration.
75367db96d56Sopenharmony_ci *
75377db96d56Sopenharmony_ci * ACL2 proofs:
75387db96d56Sopenharmony_ci * ------------
75397db96d56Sopenharmony_ci *    1) q is a natural number.  (ndivmod-quotient-natp)
75407db96d56Sopenharmony_ci *    2) r is a natural number.  (ndivmod-remainder-natp)
75417db96d56Sopenharmony_ci *    3) a = q * b + r           (ndivmod-q*b+r==a)
75427db96d56Sopenharmony_ci *    4) r < b                   (ndivmod-remainder-<-b)
75437db96d56Sopenharmony_ci */
75447db96d56Sopenharmony_cistatic void
75457db96d56Sopenharmony_ci_mpd_base_ndivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
75467db96d56Sopenharmony_ci                  uint32_t *status)
75477db96d56Sopenharmony_ci{
75487db96d56Sopenharmony_ci    mpd_context_t workctx;
75497db96d56Sopenharmony_ci    mpd_t *qq = q, *rr = r;
75507db96d56Sopenharmony_ci    mpd_t aa, bb;
75517db96d56Sopenharmony_ci    int k;
75527db96d56Sopenharmony_ci
75537db96d56Sopenharmony_ci    _mpd_copy_shared(&aa, a);
75547db96d56Sopenharmony_ci    _mpd_copy_shared(&bb, b);
75557db96d56Sopenharmony_ci
75567db96d56Sopenharmony_ci    mpd_set_positive(&aa);
75577db96d56Sopenharmony_ci    mpd_set_positive(&bb);
75587db96d56Sopenharmony_ci    aa.exp = 0;
75597db96d56Sopenharmony_ci    bb.exp = 0;
75607db96d56Sopenharmony_ci
75617db96d56Sopenharmony_ci    if (q == a || q == b) {
75627db96d56Sopenharmony_ci        if ((qq = mpd_qnew()) == NULL) {
75637db96d56Sopenharmony_ci            *status |= MPD_Malloc_error;
75647db96d56Sopenharmony_ci            goto nanresult;
75657db96d56Sopenharmony_ci        }
75667db96d56Sopenharmony_ci    }
75677db96d56Sopenharmony_ci    if (r == a || r == b) {
75687db96d56Sopenharmony_ci        if ((rr = mpd_qnew()) == NULL) {
75697db96d56Sopenharmony_ci            *status |= MPD_Malloc_error;
75707db96d56Sopenharmony_ci            goto nanresult;
75717db96d56Sopenharmony_ci        }
75727db96d56Sopenharmony_ci    }
75737db96d56Sopenharmony_ci
75747db96d56Sopenharmony_ci    mpd_maxcontext(&workctx);
75757db96d56Sopenharmony_ci
75767db96d56Sopenharmony_ci    /* Let prec := adigits - bdigits + 4 */
75777db96d56Sopenharmony_ci    workctx.prec = a->digits - b->digits + 1 + 3;
75787db96d56Sopenharmony_ci    if (a->digits > MPD_MAX_PREC || workctx.prec > MPD_MAX_PREC) {
75797db96d56Sopenharmony_ci        *status |= MPD_Division_impossible;
75807db96d56Sopenharmony_ci        goto nanresult;
75817db96d56Sopenharmony_ci    }
75827db96d56Sopenharmony_ci
75837db96d56Sopenharmony_ci    /* Let x := _mpd_qreciprocal(b, prec)
75847db96d56Sopenharmony_ci     * Then x is bounded by:
75857db96d56Sopenharmony_ci     *    1) 1/b - 10**(-prec - bdigits) < x < 1/b + 10**(-prec - bdigits)
75867db96d56Sopenharmony_ci     *    2) 1/b - 10**(-adigits - 4) < x < 1/b + 10**(-adigits - 4)
75877db96d56Sopenharmony_ci     */
75887db96d56Sopenharmony_ci    _mpd_qreciprocal(rr, &bb, &workctx, &workctx.status);
75897db96d56Sopenharmony_ci
75907db96d56Sopenharmony_ci    /* Get an estimate for the quotient. Let q := a * x
75917db96d56Sopenharmony_ci     * Then q is bounded by:
75927db96d56Sopenharmony_ci     *    3) a/b - 10**-4 < q < a/b + 10**-4
75937db96d56Sopenharmony_ci     */
75947db96d56Sopenharmony_ci    _mpd_qmul(qq, &aa, rr, &workctx, &workctx.status);
75957db96d56Sopenharmony_ci    /* Truncate q to an integer:
75967db96d56Sopenharmony_ci     *    4) a/b - 2 < trunc(q) < a/b + 1
75977db96d56Sopenharmony_ci     */
75987db96d56Sopenharmony_ci    mpd_qtrunc(qq, qq, &workctx, &workctx.status);
75997db96d56Sopenharmony_ci
76007db96d56Sopenharmony_ci    workctx.prec = aa.digits + 3;
76017db96d56Sopenharmony_ci    workctx.emax = MPD_MAX_EMAX + 3;
76027db96d56Sopenharmony_ci    workctx.emin = MPD_MIN_EMIN - 3;
76037db96d56Sopenharmony_ci    /* Multiply the estimate for q by b:
76047db96d56Sopenharmony_ci     *    5) a - 2 * b < trunc(q) * b < a + b
76057db96d56Sopenharmony_ci     */
76067db96d56Sopenharmony_ci    _mpd_qmul(rr, &bb, qq, &workctx, &workctx.status);
76077db96d56Sopenharmony_ci    /* Get the estimate for r such that a = q * b + r. */
76087db96d56Sopenharmony_ci    _mpd_qsub_exact(rr, &aa, rr, &workctx, &workctx.status);
76097db96d56Sopenharmony_ci
76107db96d56Sopenharmony_ci    /* Fix the result. At this point -b < r < 2*b, so the correction loop
76117db96d56Sopenharmony_ci       takes at most one iteration. */
76127db96d56Sopenharmony_ci    for (k = 0;; k++) {
76137db96d56Sopenharmony_ci        if (mpd_isspecial(qq) || mpd_isspecial(rr)) {
76147db96d56Sopenharmony_ci            *status |= (workctx.status&MPD_Errors);
76157db96d56Sopenharmony_ci            goto nanresult;
76167db96d56Sopenharmony_ci        }
76177db96d56Sopenharmony_ci        if (k > 2) { /* Allow two iterations despite the proof. */
76187db96d56Sopenharmony_ci            mpd_err_warn("libmpdec: internal error in "       /* GCOV_NOT_REACHED */
76197db96d56Sopenharmony_ci                         "_mpd_base_ndivmod: please report"); /* GCOV_NOT_REACHED */
76207db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;                 /* GCOV_NOT_REACHED */
76217db96d56Sopenharmony_ci            goto nanresult;                                   /* GCOV_NOT_REACHED */
76227db96d56Sopenharmony_ci        }
76237db96d56Sopenharmony_ci        /* r < 0 */
76247db96d56Sopenharmony_ci        else if (_mpd_cmp(&zero, rr) == 1) {
76257db96d56Sopenharmony_ci            _mpd_qadd_exact(rr, rr, &bb, &workctx, &workctx.status);
76267db96d56Sopenharmony_ci            _mpd_qadd_exact(qq, qq, &minus_one, &workctx, &workctx.status);
76277db96d56Sopenharmony_ci        }
76287db96d56Sopenharmony_ci        /* 0 <= r < b */
76297db96d56Sopenharmony_ci        else if (_mpd_cmp(rr, &bb) == -1) {
76307db96d56Sopenharmony_ci            break;
76317db96d56Sopenharmony_ci        }
76327db96d56Sopenharmony_ci        /* r >= b */
76337db96d56Sopenharmony_ci        else {
76347db96d56Sopenharmony_ci            _mpd_qsub_exact(rr, rr, &bb, &workctx, &workctx.status);
76357db96d56Sopenharmony_ci            _mpd_qadd_exact(qq, qq, &one, &workctx, &workctx.status);
76367db96d56Sopenharmony_ci        }
76377db96d56Sopenharmony_ci    }
76387db96d56Sopenharmony_ci
76397db96d56Sopenharmony_ci    if (qq != q) {
76407db96d56Sopenharmony_ci        if (!mpd_qcopy(q, qq, status)) {
76417db96d56Sopenharmony_ci            goto nanresult; /* GCOV_UNLIKELY */
76427db96d56Sopenharmony_ci        }
76437db96d56Sopenharmony_ci        mpd_del(qq);
76447db96d56Sopenharmony_ci    }
76457db96d56Sopenharmony_ci    if (rr != r) {
76467db96d56Sopenharmony_ci        if (!mpd_qcopy(r, rr, status)) {
76477db96d56Sopenharmony_ci            goto nanresult; /* GCOV_UNLIKELY */
76487db96d56Sopenharmony_ci        }
76497db96d56Sopenharmony_ci        mpd_del(rr);
76507db96d56Sopenharmony_ci    }
76517db96d56Sopenharmony_ci
76527db96d56Sopenharmony_ci    *status |= (workctx.status&MPD_Errors);
76537db96d56Sopenharmony_ci    return;
76547db96d56Sopenharmony_ci
76557db96d56Sopenharmony_ci
76567db96d56Sopenharmony_cinanresult:
76577db96d56Sopenharmony_ci    if (qq && qq != q) mpd_del(qq);
76587db96d56Sopenharmony_ci    if (rr && rr != r) mpd_del(rr);
76597db96d56Sopenharmony_ci    mpd_setspecial(q, MPD_POS, MPD_NAN);
76607db96d56Sopenharmony_ci    mpd_setspecial(r, MPD_POS, MPD_NAN);
76617db96d56Sopenharmony_ci}
76627db96d56Sopenharmony_ci
76637db96d56Sopenharmony_ci/* LIBMPDEC_ONLY */
76647db96d56Sopenharmony_ci/*
76657db96d56Sopenharmony_ci * Schedule the optimal precision increase for the Newton iteration.
76667db96d56Sopenharmony_ci *   v := input operand
76677db96d56Sopenharmony_ci *   z_0 := initial approximation
76687db96d56Sopenharmony_ci *   initprec := natural number such that abs(sqrt(v) - z_0) < 10**-initprec
76697db96d56Sopenharmony_ci *   maxprec := target precision
76707db96d56Sopenharmony_ci *
76717db96d56Sopenharmony_ci * For convenience the output klist contains the elements in reverse order:
76727db96d56Sopenharmony_ci *   klist := [k_n-1, ..., k_0], where
76737db96d56Sopenharmony_ci *     1) k_0 <= initprec and
76747db96d56Sopenharmony_ci *     2) abs(sqrt(v) - result) < 10**(-2*k_n-1 + 2) <= 10**-maxprec.
76757db96d56Sopenharmony_ci */
76767db96d56Sopenharmony_cistatic inline int
76777db96d56Sopenharmony_ciinvroot_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2],
76787db96d56Sopenharmony_ci                      mpd_ssize_t maxprec, mpd_ssize_t initprec)
76797db96d56Sopenharmony_ci{
76807db96d56Sopenharmony_ci    mpd_ssize_t k;
76817db96d56Sopenharmony_ci    int i;
76827db96d56Sopenharmony_ci
76837db96d56Sopenharmony_ci    assert(maxprec >= 3 && initprec >= 3);
76847db96d56Sopenharmony_ci    if (maxprec <= initprec) return -1;
76857db96d56Sopenharmony_ci
76867db96d56Sopenharmony_ci    i = 0; k = maxprec;
76877db96d56Sopenharmony_ci    do {
76887db96d56Sopenharmony_ci        k = (k+3) / 2;
76897db96d56Sopenharmony_ci        klist[i++] = k;
76907db96d56Sopenharmony_ci    } while (k > initprec);
76917db96d56Sopenharmony_ci
76927db96d56Sopenharmony_ci    return i-1;
76937db96d56Sopenharmony_ci}
76947db96d56Sopenharmony_ci
76957db96d56Sopenharmony_ci/*
76967db96d56Sopenharmony_ci * Initial approximation for the inverse square root function.
76977db96d56Sopenharmony_ci *   Input:
76987db96d56Sopenharmony_ci *     v := rational number, with 1 <= v < 100
76997db96d56Sopenharmony_ci *     vhat := floor(v * 10**6)
77007db96d56Sopenharmony_ci *   Output:
77017db96d56Sopenharmony_ci *     z := approximation to 1/sqrt(v), such that abs(z - 1/sqrt(v)) < 10**-3.
77027db96d56Sopenharmony_ci */
77037db96d56Sopenharmony_cistatic inline void
77047db96d56Sopenharmony_ci_invroot_init_approx(mpd_t *z, mpd_uint_t vhat)
77057db96d56Sopenharmony_ci{
77067db96d56Sopenharmony_ci    mpd_uint_t lo = 1000;
77077db96d56Sopenharmony_ci    mpd_uint_t hi = 10000;
77087db96d56Sopenharmony_ci    mpd_uint_t a, sq;
77097db96d56Sopenharmony_ci
77107db96d56Sopenharmony_ci    assert(lo*lo <= vhat && vhat < (hi+1)*(hi+1));
77117db96d56Sopenharmony_ci
77127db96d56Sopenharmony_ci    for(;;) {
77137db96d56Sopenharmony_ci        a = (lo + hi) / 2;
77147db96d56Sopenharmony_ci        sq = a * a;
77157db96d56Sopenharmony_ci        if (vhat >= sq) {
77167db96d56Sopenharmony_ci            if (vhat < sq + 2*a + 1) {
77177db96d56Sopenharmony_ci                break;
77187db96d56Sopenharmony_ci            }
77197db96d56Sopenharmony_ci            lo = a + 1;
77207db96d56Sopenharmony_ci        }
77217db96d56Sopenharmony_ci        else {
77227db96d56Sopenharmony_ci            hi = a - 1;
77237db96d56Sopenharmony_ci        }
77247db96d56Sopenharmony_ci    }
77257db96d56Sopenharmony_ci
77267db96d56Sopenharmony_ci    /*
77277db96d56Sopenharmony_ci     * After the binary search we have:
77287db96d56Sopenharmony_ci     *  1) a**2 <= floor(v * 10**6) < (a + 1)**2
77297db96d56Sopenharmony_ci     * This implies:
77307db96d56Sopenharmony_ci     *  2) a**2 <= v * 10**6 < (a + 1)**2
77317db96d56Sopenharmony_ci     *  3) a <= sqrt(v) * 10**3 < a + 1
77327db96d56Sopenharmony_ci     * Since 10**3 <= a:
77337db96d56Sopenharmony_ci     *  4) 0 <= 10**prec/a - 1/sqrt(v) < 10**-prec
77347db96d56Sopenharmony_ci     * We have:
77357db96d56Sopenharmony_ci     *  5) 10**3/a - 10**-3 < floor(10**9/a) * 10**-6 <= 10**3/a
77367db96d56Sopenharmony_ci     * Merging 4) and 5):
77377db96d56Sopenharmony_ci     *  6) abs(floor(10**9/a) * 10**-6 - 1/sqrt(v)) < 10**-3
77387db96d56Sopenharmony_ci     */
77397db96d56Sopenharmony_ci    mpd_minalloc(z);
77407db96d56Sopenharmony_ci    mpd_clear_flags(z);
77417db96d56Sopenharmony_ci    z->data[0] = 1000000000UL / a;
77427db96d56Sopenharmony_ci    z->len = 1;
77437db96d56Sopenharmony_ci    z->exp = -6;
77447db96d56Sopenharmony_ci    mpd_setdigits(z);
77457db96d56Sopenharmony_ci}
77467db96d56Sopenharmony_ci
77477db96d56Sopenharmony_ci/*
77487db96d56Sopenharmony_ci * Set 'result' to 1/sqrt(a).
77497db96d56Sopenharmony_ci *   Relative error: abs(result - 1/sqrt(a)) < 10**-prec * 1/sqrt(a)
77507db96d56Sopenharmony_ci */
77517db96d56Sopenharmony_cistatic void
77527db96d56Sopenharmony_ci_mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
77537db96d56Sopenharmony_ci              uint32_t *status)
77547db96d56Sopenharmony_ci{
77557db96d56Sopenharmony_ci    uint32_t workstatus = 0;
77567db96d56Sopenharmony_ci    mpd_context_t varcontext, maxcontext;
77577db96d56Sopenharmony_ci    mpd_t *z = result;         /* current approximation */
77587db96d56Sopenharmony_ci    mpd_t *v;                  /* a, normalized to a number between 1 and 100 */
77597db96d56Sopenharmony_ci    MPD_NEW_SHARED(vtmp, a);   /* by default v will share data with a */
77607db96d56Sopenharmony_ci    MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */
77617db96d56Sopenharmony_ci    MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */
77627db96d56Sopenharmony_ci    MPD_NEW_CONST(one_half,0,-1,1,1,1,5);
77637db96d56Sopenharmony_ci    MPD_NEW_CONST(three,0,0,1,1,1,3);
77647db96d56Sopenharmony_ci    mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
77657db96d56Sopenharmony_ci    mpd_ssize_t ideal_exp, shift;
77667db96d56Sopenharmony_ci    mpd_ssize_t adj, tz;
77677db96d56Sopenharmony_ci    mpd_ssize_t maxprec, fracdigits;
77687db96d56Sopenharmony_ci    mpd_uint_t vhat, dummy;
77697db96d56Sopenharmony_ci    int i, n;
77707db96d56Sopenharmony_ci
77717db96d56Sopenharmony_ci
77727db96d56Sopenharmony_ci    ideal_exp = -(a->exp - (a->exp & 1)) / 2;
77737db96d56Sopenharmony_ci
77747db96d56Sopenharmony_ci    v = &vtmp;
77757db96d56Sopenharmony_ci    if (result == a) {
77767db96d56Sopenharmony_ci        if ((v = mpd_qncopy(a)) == NULL) {
77777db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Malloc_error, status);
77787db96d56Sopenharmony_ci            return;
77797db96d56Sopenharmony_ci        }
77807db96d56Sopenharmony_ci    }
77817db96d56Sopenharmony_ci
77827db96d56Sopenharmony_ci    /* normalize a to 1 <= v < 100 */
77837db96d56Sopenharmony_ci    if ((v->digits+v->exp) & 1) {
77847db96d56Sopenharmony_ci        fracdigits = v->digits - 1;
77857db96d56Sopenharmony_ci        v->exp = -fracdigits;
77867db96d56Sopenharmony_ci        n = (v->digits > 7) ? 7 : (int)v->digits;
77877db96d56Sopenharmony_ci        /* Let vhat := floor(v * 10**(2*initprec)) */
77887db96d56Sopenharmony_ci        _mpd_get_msdigits(&dummy, &vhat, v, n);
77897db96d56Sopenharmony_ci        if (n < 7) {
77907db96d56Sopenharmony_ci            vhat *= mpd_pow10[7-n];
77917db96d56Sopenharmony_ci        }
77927db96d56Sopenharmony_ci    }
77937db96d56Sopenharmony_ci    else {
77947db96d56Sopenharmony_ci        fracdigits = v->digits - 2;
77957db96d56Sopenharmony_ci        v->exp = -fracdigits;
77967db96d56Sopenharmony_ci        n = (v->digits > 8) ? 8 : (int)v->digits;
77977db96d56Sopenharmony_ci        /* Let vhat := floor(v * 10**(2*initprec)) */
77987db96d56Sopenharmony_ci        _mpd_get_msdigits(&dummy, &vhat, v, n);
77997db96d56Sopenharmony_ci        if (n < 8) {
78007db96d56Sopenharmony_ci            vhat *= mpd_pow10[8-n];
78017db96d56Sopenharmony_ci        }
78027db96d56Sopenharmony_ci    }
78037db96d56Sopenharmony_ci    adj = (a->exp-v->exp) / 2;
78047db96d56Sopenharmony_ci
78057db96d56Sopenharmony_ci    /* initial approximation */
78067db96d56Sopenharmony_ci    _invroot_init_approx(z, vhat);
78077db96d56Sopenharmony_ci
78087db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
78097db96d56Sopenharmony_ci    mpd_maxcontext(&varcontext);
78107db96d56Sopenharmony_ci    varcontext.round = MPD_ROUND_TRUNC;
78117db96d56Sopenharmony_ci    maxprec = ctx->prec + 1;
78127db96d56Sopenharmony_ci
78137db96d56Sopenharmony_ci    /* initprec == 3 */
78147db96d56Sopenharmony_ci    i = invroot_schedule_prec(klist, maxprec, 3);
78157db96d56Sopenharmony_ci    for (; i >= 0; i--) {
78167db96d56Sopenharmony_ci        varcontext.prec = 2*klist[i]+2;
78177db96d56Sopenharmony_ci        mpd_qmul(&s, z, z, &maxcontext, &workstatus);
78187db96d56Sopenharmony_ci        if (v->digits > varcontext.prec) {
78197db96d56Sopenharmony_ci            shift = v->digits - varcontext.prec;
78207db96d56Sopenharmony_ci            mpd_qshiftr(&t, v, shift, &workstatus);
78217db96d56Sopenharmony_ci            t.exp += shift;
78227db96d56Sopenharmony_ci            mpd_qmul(&t, &t, &s, &varcontext, &workstatus);
78237db96d56Sopenharmony_ci        }
78247db96d56Sopenharmony_ci        else {
78257db96d56Sopenharmony_ci            mpd_qmul(&t, v, &s, &varcontext, &workstatus);
78267db96d56Sopenharmony_ci        }
78277db96d56Sopenharmony_ci        mpd_qsub(&t, &three, &t, &maxcontext, &workstatus);
78287db96d56Sopenharmony_ci        mpd_qmul(z, z, &t, &varcontext, &workstatus);
78297db96d56Sopenharmony_ci        mpd_qmul(z, z, &one_half, &maxcontext, &workstatus);
78307db96d56Sopenharmony_ci    }
78317db96d56Sopenharmony_ci
78327db96d56Sopenharmony_ci    z->exp -= adj;
78337db96d56Sopenharmony_ci
78347db96d56Sopenharmony_ci    tz = mpd_trail_zeros(result);
78357db96d56Sopenharmony_ci    shift = ideal_exp - result->exp;
78367db96d56Sopenharmony_ci    shift = (tz > shift) ? shift : tz;
78377db96d56Sopenharmony_ci    if (shift > 0) {
78387db96d56Sopenharmony_ci        mpd_qshiftr_inplace(result, shift);
78397db96d56Sopenharmony_ci        result->exp += shift;
78407db96d56Sopenharmony_ci    }
78417db96d56Sopenharmony_ci
78427db96d56Sopenharmony_ci
78437db96d56Sopenharmony_ci    mpd_del(&s);
78447db96d56Sopenharmony_ci    mpd_del(&t);
78457db96d56Sopenharmony_ci    if (v != &vtmp) mpd_del(v);
78467db96d56Sopenharmony_ci    *status |= (workstatus&MPD_Errors);
78477db96d56Sopenharmony_ci    *status |= (MPD_Rounded|MPD_Inexact);
78487db96d56Sopenharmony_ci}
78497db96d56Sopenharmony_ci
78507db96d56Sopenharmony_civoid
78517db96d56Sopenharmony_cimpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
78527db96d56Sopenharmony_ci             uint32_t *status)
78537db96d56Sopenharmony_ci{
78547db96d56Sopenharmony_ci    mpd_context_t workctx;
78557db96d56Sopenharmony_ci
78567db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
78577db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
78587db96d56Sopenharmony_ci            return;
78597db96d56Sopenharmony_ci        }
78607db96d56Sopenharmony_ci        if (mpd_isnegative(a)) {
78617db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
78627db96d56Sopenharmony_ci            return;
78637db96d56Sopenharmony_ci        }
78647db96d56Sopenharmony_ci        /* positive infinity */
78657db96d56Sopenharmony_ci        _settriple(result, MPD_POS, 0, mpd_etiny(ctx));
78667db96d56Sopenharmony_ci        *status |= MPD_Clamped;
78677db96d56Sopenharmony_ci        return;
78687db96d56Sopenharmony_ci    }
78697db96d56Sopenharmony_ci    if (mpd_iszero(a)) {
78707db96d56Sopenharmony_ci        mpd_setspecial(result, mpd_sign(a), MPD_INF);
78717db96d56Sopenharmony_ci        *status |= MPD_Division_by_zero;
78727db96d56Sopenharmony_ci        return;
78737db96d56Sopenharmony_ci    }
78747db96d56Sopenharmony_ci    if (mpd_isnegative(a)) {
78757db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
78767db96d56Sopenharmony_ci        return;
78777db96d56Sopenharmony_ci    }
78787db96d56Sopenharmony_ci
78797db96d56Sopenharmony_ci    workctx = *ctx;
78807db96d56Sopenharmony_ci    workctx.prec += 2;
78817db96d56Sopenharmony_ci    workctx.round = MPD_ROUND_HALF_EVEN;
78827db96d56Sopenharmony_ci    _mpd_qinvroot(result, a, &workctx, status);
78837db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
78847db96d56Sopenharmony_ci}
78857db96d56Sopenharmony_ci/* END LIBMPDEC_ONLY */
78867db96d56Sopenharmony_ci
78877db96d56Sopenharmony_ci/* Algorithm from decimal.py */
78887db96d56Sopenharmony_cistatic void
78897db96d56Sopenharmony_ci_mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
78907db96d56Sopenharmony_ci           uint32_t *status)
78917db96d56Sopenharmony_ci{
78927db96d56Sopenharmony_ci    mpd_context_t maxcontext;
78937db96d56Sopenharmony_ci    MPD_NEW_STATIC(c,0,0,0,0);
78947db96d56Sopenharmony_ci    MPD_NEW_STATIC(q,0,0,0,0);
78957db96d56Sopenharmony_ci    MPD_NEW_STATIC(r,0,0,0,0);
78967db96d56Sopenharmony_ci    MPD_NEW_CONST(two,0,0,1,1,1,2);
78977db96d56Sopenharmony_ci    mpd_ssize_t prec, ideal_exp;
78987db96d56Sopenharmony_ci    mpd_ssize_t l, shift;
78997db96d56Sopenharmony_ci    int exact = 0;
79007db96d56Sopenharmony_ci
79017db96d56Sopenharmony_ci
79027db96d56Sopenharmony_ci    ideal_exp = (a->exp - (a->exp & 1)) / 2;
79037db96d56Sopenharmony_ci
79047db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
79057db96d56Sopenharmony_ci        if (mpd_qcheck_nan(result, a, ctx, status)) {
79067db96d56Sopenharmony_ci            return;
79077db96d56Sopenharmony_ci        }
79087db96d56Sopenharmony_ci        if (mpd_isnegative(a)) {
79097db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Invalid_operation, status);
79107db96d56Sopenharmony_ci            return;
79117db96d56Sopenharmony_ci        }
79127db96d56Sopenharmony_ci        mpd_setspecial(result, MPD_POS, MPD_INF);
79137db96d56Sopenharmony_ci        return;
79147db96d56Sopenharmony_ci    }
79157db96d56Sopenharmony_ci    if (mpd_iszero(a)) {
79167db96d56Sopenharmony_ci        _settriple(result, mpd_sign(a), 0, ideal_exp);
79177db96d56Sopenharmony_ci        mpd_qfinalize(result, ctx, status);
79187db96d56Sopenharmony_ci        return;
79197db96d56Sopenharmony_ci    }
79207db96d56Sopenharmony_ci    if (mpd_isnegative(a)) {
79217db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
79227db96d56Sopenharmony_ci        return;
79237db96d56Sopenharmony_ci    }
79247db96d56Sopenharmony_ci
79257db96d56Sopenharmony_ci    mpd_maxcontext(&maxcontext);
79267db96d56Sopenharmony_ci    prec = ctx->prec + 1;
79277db96d56Sopenharmony_ci
79287db96d56Sopenharmony_ci    if (!mpd_qcopy(&c, a, status)) {
79297db96d56Sopenharmony_ci        goto malloc_error;
79307db96d56Sopenharmony_ci    }
79317db96d56Sopenharmony_ci    c.exp = 0;
79327db96d56Sopenharmony_ci
79337db96d56Sopenharmony_ci    if (a->exp & 1) {
79347db96d56Sopenharmony_ci        if (!mpd_qshiftl(&c, &c, 1, status)) {
79357db96d56Sopenharmony_ci            goto malloc_error;
79367db96d56Sopenharmony_ci        }
79377db96d56Sopenharmony_ci        l = (a->digits >> 1) + 1;
79387db96d56Sopenharmony_ci    }
79397db96d56Sopenharmony_ci    else {
79407db96d56Sopenharmony_ci        l = (a->digits + 1) >> 1;
79417db96d56Sopenharmony_ci    }
79427db96d56Sopenharmony_ci
79437db96d56Sopenharmony_ci    shift = prec - l;
79447db96d56Sopenharmony_ci    if (shift >= 0) {
79457db96d56Sopenharmony_ci        if (!mpd_qshiftl(&c, &c, 2*shift, status)) {
79467db96d56Sopenharmony_ci            goto malloc_error;
79477db96d56Sopenharmony_ci        }
79487db96d56Sopenharmony_ci        exact = 1;
79497db96d56Sopenharmony_ci    }
79507db96d56Sopenharmony_ci    else {
79517db96d56Sopenharmony_ci        exact = !mpd_qshiftr_inplace(&c, -2*shift);
79527db96d56Sopenharmony_ci    }
79537db96d56Sopenharmony_ci
79547db96d56Sopenharmony_ci    ideal_exp -= shift;
79557db96d56Sopenharmony_ci
79567db96d56Sopenharmony_ci    /* find result = floor(sqrt(c)) using Newton's method */
79577db96d56Sopenharmony_ci    if (!mpd_qshiftl(result, &one, prec, status)) {
79587db96d56Sopenharmony_ci        goto malloc_error;
79597db96d56Sopenharmony_ci    }
79607db96d56Sopenharmony_ci
79617db96d56Sopenharmony_ci    while (1) {
79627db96d56Sopenharmony_ci        _mpd_qdivmod(&q, &r, &c, result, &maxcontext, &maxcontext.status);
79637db96d56Sopenharmony_ci        if (mpd_isspecial(result) || mpd_isspecial(&q)) {
79647db96d56Sopenharmony_ci            mpd_seterror(result, maxcontext.status&MPD_Errors, status);
79657db96d56Sopenharmony_ci            goto out;
79667db96d56Sopenharmony_ci        }
79677db96d56Sopenharmony_ci        if (_mpd_cmp(result, &q) <= 0) {
79687db96d56Sopenharmony_ci            break;
79697db96d56Sopenharmony_ci        }
79707db96d56Sopenharmony_ci        _mpd_qadd_exact(result, result, &q, &maxcontext, &maxcontext.status);
79717db96d56Sopenharmony_ci        if (mpd_isspecial(result)) {
79727db96d56Sopenharmony_ci            mpd_seterror(result, maxcontext.status&MPD_Errors, status);
79737db96d56Sopenharmony_ci            goto out;
79747db96d56Sopenharmony_ci        }
79757db96d56Sopenharmony_ci        _mpd_qdivmod(result, &r, result, &two, &maxcontext, &maxcontext.status);
79767db96d56Sopenharmony_ci    }
79777db96d56Sopenharmony_ci
79787db96d56Sopenharmony_ci    if (exact) {
79797db96d56Sopenharmony_ci        _mpd_qmul_exact(&r, result, result, &maxcontext, &maxcontext.status);
79807db96d56Sopenharmony_ci        if (mpd_isspecial(&r)) {
79817db96d56Sopenharmony_ci            mpd_seterror(result, maxcontext.status&MPD_Errors, status);
79827db96d56Sopenharmony_ci            goto out;
79837db96d56Sopenharmony_ci        }
79847db96d56Sopenharmony_ci        exact = (_mpd_cmp(&r, &c) == 0);
79857db96d56Sopenharmony_ci    }
79867db96d56Sopenharmony_ci
79877db96d56Sopenharmony_ci    if (exact) {
79887db96d56Sopenharmony_ci        if (shift >= 0) {
79897db96d56Sopenharmony_ci            mpd_qshiftr_inplace(result, shift);
79907db96d56Sopenharmony_ci        }
79917db96d56Sopenharmony_ci        else {
79927db96d56Sopenharmony_ci            if (!mpd_qshiftl(result, result, -shift, status)) {
79937db96d56Sopenharmony_ci                goto malloc_error;
79947db96d56Sopenharmony_ci            }
79957db96d56Sopenharmony_ci        }
79967db96d56Sopenharmony_ci        ideal_exp += shift;
79977db96d56Sopenharmony_ci    }
79987db96d56Sopenharmony_ci    else {
79997db96d56Sopenharmony_ci        int lsd = (int)mpd_lsd(result->data[0]);
80007db96d56Sopenharmony_ci        if (lsd == 0 || lsd == 5) {
80017db96d56Sopenharmony_ci            result->data[0] += 1;
80027db96d56Sopenharmony_ci        }
80037db96d56Sopenharmony_ci    }
80047db96d56Sopenharmony_ci
80057db96d56Sopenharmony_ci    result->exp = ideal_exp;
80067db96d56Sopenharmony_ci
80077db96d56Sopenharmony_ci
80087db96d56Sopenharmony_ciout:
80097db96d56Sopenharmony_ci    mpd_del(&c);
80107db96d56Sopenharmony_ci    mpd_del(&q);
80117db96d56Sopenharmony_ci    mpd_del(&r);
80127db96d56Sopenharmony_ci    maxcontext = *ctx;
80137db96d56Sopenharmony_ci    maxcontext.round = MPD_ROUND_HALF_EVEN;
80147db96d56Sopenharmony_ci    mpd_qfinalize(result, &maxcontext, status);
80157db96d56Sopenharmony_ci    return;
80167db96d56Sopenharmony_ci
80177db96d56Sopenharmony_cimalloc_error:
80187db96d56Sopenharmony_ci    mpd_seterror(result, MPD_Malloc_error, status);
80197db96d56Sopenharmony_ci    goto out;
80207db96d56Sopenharmony_ci}
80217db96d56Sopenharmony_ci
80227db96d56Sopenharmony_civoid
80237db96d56Sopenharmony_cimpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
80247db96d56Sopenharmony_ci          uint32_t *status)
80257db96d56Sopenharmony_ci{
80267db96d56Sopenharmony_ci    MPD_NEW_STATIC(aa,0,0,0,0);
80277db96d56Sopenharmony_ci    uint32_t xstatus = 0;
80287db96d56Sopenharmony_ci
80297db96d56Sopenharmony_ci    if (result == a) {
80307db96d56Sopenharmony_ci        if (!mpd_qcopy(&aa, a, status)) {
80317db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Malloc_error, status);
80327db96d56Sopenharmony_ci            goto out;
80337db96d56Sopenharmony_ci        }
80347db96d56Sopenharmony_ci        a = &aa;
80357db96d56Sopenharmony_ci    }
80367db96d56Sopenharmony_ci
80377db96d56Sopenharmony_ci    _mpd_qsqrt(result, a, ctx, &xstatus);
80387db96d56Sopenharmony_ci
80397db96d56Sopenharmony_ci    if (xstatus & (MPD_Malloc_error|MPD_Division_impossible)) {
80407db96d56Sopenharmony_ci        /* The above conditions can occur at very high context precisions
80417db96d56Sopenharmony_ci         * if intermediate values get too large. Retry the operation with
80427db96d56Sopenharmony_ci         * a lower context precision in case the result is exact.
80437db96d56Sopenharmony_ci         *
80447db96d56Sopenharmony_ci         * If the result is exact, an upper bound for the number of digits
80457db96d56Sopenharmony_ci         * is the number of digits in the input.
80467db96d56Sopenharmony_ci         *
80477db96d56Sopenharmony_ci         * NOTE: sqrt(40e9) = 2.0e+5 /\ digits(40e9) = digits(2.0e+5) = 2
80487db96d56Sopenharmony_ci         */
80497db96d56Sopenharmony_ci        uint32_t ystatus = 0;
80507db96d56Sopenharmony_ci        mpd_context_t workctx = *ctx;
80517db96d56Sopenharmony_ci
80527db96d56Sopenharmony_ci        workctx.prec = a->digits;
80537db96d56Sopenharmony_ci        if (workctx.prec >= ctx->prec) {
80547db96d56Sopenharmony_ci            *status |= (xstatus|MPD_Errors);
80557db96d56Sopenharmony_ci            goto out; /* No point in repeating this, keep the original error. */
80567db96d56Sopenharmony_ci        }
80577db96d56Sopenharmony_ci
80587db96d56Sopenharmony_ci        _mpd_qsqrt(result, a, &workctx, &ystatus);
80597db96d56Sopenharmony_ci        if (ystatus != 0) {
80607db96d56Sopenharmony_ci            ystatus = *status | ((xstatus|ystatus)&MPD_Errors);
80617db96d56Sopenharmony_ci            mpd_seterror(result, ystatus, status);
80627db96d56Sopenharmony_ci        }
80637db96d56Sopenharmony_ci    }
80647db96d56Sopenharmony_ci    else {
80657db96d56Sopenharmony_ci        *status |= xstatus;
80667db96d56Sopenharmony_ci    }
80677db96d56Sopenharmony_ci
80687db96d56Sopenharmony_ciout:
80697db96d56Sopenharmony_ci    mpd_del(&aa);
80707db96d56Sopenharmony_ci}
80717db96d56Sopenharmony_ci
80727db96d56Sopenharmony_ci
80737db96d56Sopenharmony_ci/******************************************************************************/
80747db96d56Sopenharmony_ci/*                              Base conversions                              */
80757db96d56Sopenharmony_ci/******************************************************************************/
80767db96d56Sopenharmony_ci
80777db96d56Sopenharmony_ci/* Space needed to represent an integer mpd_t in base 'base'. */
80787db96d56Sopenharmony_cisize_t
80797db96d56Sopenharmony_cimpd_sizeinbase(const mpd_t *a, uint32_t base)
80807db96d56Sopenharmony_ci{
80817db96d56Sopenharmony_ci    double x;
80827db96d56Sopenharmony_ci    size_t digits;
80837db96d56Sopenharmony_ci    double upper_bound;
80847db96d56Sopenharmony_ci
80857db96d56Sopenharmony_ci    assert(mpd_isinteger(a));
80867db96d56Sopenharmony_ci    assert(base >= 2);
80877db96d56Sopenharmony_ci
80887db96d56Sopenharmony_ci    if (mpd_iszero(a)) {
80897db96d56Sopenharmony_ci        return 1;
80907db96d56Sopenharmony_ci    }
80917db96d56Sopenharmony_ci
80927db96d56Sopenharmony_ci    digits = a->digits+a->exp;
80937db96d56Sopenharmony_ci
80947db96d56Sopenharmony_ci#ifdef CONFIG_64
80957db96d56Sopenharmony_ci    /* ceil(2711437152599294 / log10(2)) + 4 == 2**53 */
80967db96d56Sopenharmony_ci    if (digits > 2711437152599294ULL) {
80977db96d56Sopenharmony_ci        return SIZE_MAX;
80987db96d56Sopenharmony_ci    }
80997db96d56Sopenharmony_ci
81007db96d56Sopenharmony_ci    upper_bound = (double)((1ULL<<53)-1);
81017db96d56Sopenharmony_ci#else
81027db96d56Sopenharmony_ci    upper_bound = (double)(SIZE_MAX-1);
81037db96d56Sopenharmony_ci#endif
81047db96d56Sopenharmony_ci
81057db96d56Sopenharmony_ci    x = (double)digits / log10(base);
81067db96d56Sopenharmony_ci    return (x > upper_bound) ? SIZE_MAX : (size_t)x + 1;
81077db96d56Sopenharmony_ci}
81087db96d56Sopenharmony_ci
81097db96d56Sopenharmony_ci/* Space needed to import a base 'base' integer of length 'srclen'. */
81107db96d56Sopenharmony_cistatic mpd_ssize_t
81117db96d56Sopenharmony_ci_mpd_importsize(size_t srclen, uint32_t base)
81127db96d56Sopenharmony_ci{
81137db96d56Sopenharmony_ci    double x;
81147db96d56Sopenharmony_ci    double upper_bound;
81157db96d56Sopenharmony_ci
81167db96d56Sopenharmony_ci    assert(srclen > 0);
81177db96d56Sopenharmony_ci    assert(base >= 2);
81187db96d56Sopenharmony_ci
81197db96d56Sopenharmony_ci#if SIZE_MAX == UINT64_MAX
81207db96d56Sopenharmony_ci    if (srclen > (1ULL<<53)) {
81217db96d56Sopenharmony_ci        return MPD_SSIZE_MAX;
81227db96d56Sopenharmony_ci    }
81237db96d56Sopenharmony_ci
81247db96d56Sopenharmony_ci    assert((1ULL<<53) <= MPD_MAXIMPORT);
81257db96d56Sopenharmony_ci    upper_bound = (double)((1ULL<<53)-1);
81267db96d56Sopenharmony_ci#else
81277db96d56Sopenharmony_ci    upper_bound = MPD_MAXIMPORT-1;
81287db96d56Sopenharmony_ci#endif
81297db96d56Sopenharmony_ci
81307db96d56Sopenharmony_ci    x = (double)srclen * (log10(base)/MPD_RDIGITS);
81317db96d56Sopenharmony_ci    return (x > upper_bound) ? MPD_SSIZE_MAX : (mpd_ssize_t)x + 1;
81327db96d56Sopenharmony_ci}
81337db96d56Sopenharmony_ci
81347db96d56Sopenharmony_cistatic uint8_t
81357db96d56Sopenharmony_cimpd_resize_u16(uint16_t **w, size_t nmemb)
81367db96d56Sopenharmony_ci{
81377db96d56Sopenharmony_ci    uint8_t err = 0;
81387db96d56Sopenharmony_ci    *w = mpd_realloc(*w, nmemb, sizeof **w, &err);
81397db96d56Sopenharmony_ci    return !err;
81407db96d56Sopenharmony_ci}
81417db96d56Sopenharmony_ci
81427db96d56Sopenharmony_cistatic uint8_t
81437db96d56Sopenharmony_cimpd_resize_u32(uint32_t **w, size_t nmemb)
81447db96d56Sopenharmony_ci{
81457db96d56Sopenharmony_ci    uint8_t err = 0;
81467db96d56Sopenharmony_ci    *w = mpd_realloc(*w, nmemb, sizeof **w, &err);
81477db96d56Sopenharmony_ci    return !err;
81487db96d56Sopenharmony_ci}
81497db96d56Sopenharmony_ci
81507db96d56Sopenharmony_cistatic size_t
81517db96d56Sopenharmony_ci_baseconv_to_u16(uint16_t **w, size_t wlen, mpd_uint_t wbase,
81527db96d56Sopenharmony_ci                 mpd_uint_t *u, mpd_ssize_t ulen)
81537db96d56Sopenharmony_ci{
81547db96d56Sopenharmony_ci    size_t n = 0;
81557db96d56Sopenharmony_ci
81567db96d56Sopenharmony_ci    assert(wlen > 0 && ulen > 0);
81577db96d56Sopenharmony_ci    assert(wbase <= (1U<<16));
81587db96d56Sopenharmony_ci
81597db96d56Sopenharmony_ci    do {
81607db96d56Sopenharmony_ci        if (n >= wlen) {
81617db96d56Sopenharmony_ci            if (!mpd_resize_u16(w, n+1)) {
81627db96d56Sopenharmony_ci                return SIZE_MAX;
81637db96d56Sopenharmony_ci            }
81647db96d56Sopenharmony_ci            wlen = n+1;
81657db96d56Sopenharmony_ci        }
81667db96d56Sopenharmony_ci        (*w)[n++] = (uint16_t)_mpd_shortdiv(u, u, ulen, wbase);
81677db96d56Sopenharmony_ci        /* ulen is at least 1. u[ulen-1] can only be zero if ulen == 1. */
81687db96d56Sopenharmony_ci        ulen = _mpd_real_size(u, ulen);
81697db96d56Sopenharmony_ci
81707db96d56Sopenharmony_ci    } while (u[ulen-1] != 0);
81717db96d56Sopenharmony_ci
81727db96d56Sopenharmony_ci    return n;
81737db96d56Sopenharmony_ci}
81747db96d56Sopenharmony_ci
81757db96d56Sopenharmony_cistatic size_t
81767db96d56Sopenharmony_ci_coeff_from_u16(mpd_t *w, mpd_ssize_t wlen,
81777db96d56Sopenharmony_ci                const mpd_uint_t *u, size_t ulen, uint32_t ubase,
81787db96d56Sopenharmony_ci                uint32_t *status)
81797db96d56Sopenharmony_ci{
81807db96d56Sopenharmony_ci    mpd_ssize_t n = 0;
81817db96d56Sopenharmony_ci    mpd_uint_t carry;
81827db96d56Sopenharmony_ci
81837db96d56Sopenharmony_ci    assert(wlen > 0 && ulen > 0);
81847db96d56Sopenharmony_ci    assert(ubase <= (1U<<16));
81857db96d56Sopenharmony_ci
81867db96d56Sopenharmony_ci    w->data[n++] = u[--ulen];
81877db96d56Sopenharmony_ci    while (--ulen != SIZE_MAX) {
81887db96d56Sopenharmony_ci        carry = _mpd_shortmul_c(w->data, w->data, n, ubase);
81897db96d56Sopenharmony_ci        if (carry) {
81907db96d56Sopenharmony_ci            if (n >= wlen) {
81917db96d56Sopenharmony_ci                if (!mpd_qresize(w, n+1, status)) {
81927db96d56Sopenharmony_ci                    return SIZE_MAX;
81937db96d56Sopenharmony_ci                }
81947db96d56Sopenharmony_ci                wlen = n+1;
81957db96d56Sopenharmony_ci            }
81967db96d56Sopenharmony_ci            w->data[n++] = carry;
81977db96d56Sopenharmony_ci        }
81987db96d56Sopenharmony_ci        carry = _mpd_shortadd(w->data, n, u[ulen]);
81997db96d56Sopenharmony_ci        if (carry) {
82007db96d56Sopenharmony_ci            if (n >= wlen) {
82017db96d56Sopenharmony_ci                if (!mpd_qresize(w, n+1, status)) {
82027db96d56Sopenharmony_ci                    return SIZE_MAX;
82037db96d56Sopenharmony_ci                }
82047db96d56Sopenharmony_ci                wlen = n+1;
82057db96d56Sopenharmony_ci            }
82067db96d56Sopenharmony_ci            w->data[n++] = carry;
82077db96d56Sopenharmony_ci        }
82087db96d56Sopenharmony_ci    }
82097db96d56Sopenharmony_ci
82107db96d56Sopenharmony_ci    return n;
82117db96d56Sopenharmony_ci}
82127db96d56Sopenharmony_ci
82137db96d56Sopenharmony_ci/* target base wbase < source base ubase */
82147db96d56Sopenharmony_cistatic size_t
82157db96d56Sopenharmony_ci_baseconv_to_smaller(uint32_t **w, size_t wlen, uint32_t wbase,
82167db96d56Sopenharmony_ci                     mpd_uint_t *u, mpd_ssize_t ulen, mpd_uint_t ubase)
82177db96d56Sopenharmony_ci{
82187db96d56Sopenharmony_ci    size_t n = 0;
82197db96d56Sopenharmony_ci
82207db96d56Sopenharmony_ci    assert(wlen > 0 && ulen > 0);
82217db96d56Sopenharmony_ci    assert(wbase < ubase);
82227db96d56Sopenharmony_ci
82237db96d56Sopenharmony_ci    do {
82247db96d56Sopenharmony_ci        if (n >= wlen) {
82257db96d56Sopenharmony_ci            if (!mpd_resize_u32(w, n+1)) {
82267db96d56Sopenharmony_ci                return SIZE_MAX;
82277db96d56Sopenharmony_ci            }
82287db96d56Sopenharmony_ci            wlen = n+1;
82297db96d56Sopenharmony_ci        }
82307db96d56Sopenharmony_ci        (*w)[n++] = (uint32_t)_mpd_shortdiv_b(u, u, ulen, wbase, ubase);
82317db96d56Sopenharmony_ci        /* ulen is at least 1. u[ulen-1] can only be zero if ulen == 1. */
82327db96d56Sopenharmony_ci        ulen = _mpd_real_size(u, ulen);
82337db96d56Sopenharmony_ci
82347db96d56Sopenharmony_ci    } while (u[ulen-1] != 0);
82357db96d56Sopenharmony_ci
82367db96d56Sopenharmony_ci    return n;
82377db96d56Sopenharmony_ci}
82387db96d56Sopenharmony_ci
82397db96d56Sopenharmony_ci#ifdef CONFIG_32
82407db96d56Sopenharmony_ci/* target base 'wbase' == source base 'ubase' */
82417db96d56Sopenharmony_cistatic size_t
82427db96d56Sopenharmony_ci_copy_equal_base(uint32_t **w, size_t wlen,
82437db96d56Sopenharmony_ci                 const uint32_t *u, size_t ulen)
82447db96d56Sopenharmony_ci{
82457db96d56Sopenharmony_ci    if (wlen < ulen) {
82467db96d56Sopenharmony_ci        if (!mpd_resize_u32(w, ulen)) {
82477db96d56Sopenharmony_ci            return SIZE_MAX;
82487db96d56Sopenharmony_ci        }
82497db96d56Sopenharmony_ci    }
82507db96d56Sopenharmony_ci
82517db96d56Sopenharmony_ci    memcpy(*w, u, ulen * (sizeof **w));
82527db96d56Sopenharmony_ci    return ulen;
82537db96d56Sopenharmony_ci}
82547db96d56Sopenharmony_ci
82557db96d56Sopenharmony_ci/* target base 'wbase' > source base 'ubase' */
82567db96d56Sopenharmony_cistatic size_t
82577db96d56Sopenharmony_ci_baseconv_to_larger(uint32_t **w, size_t wlen, mpd_uint_t wbase,
82587db96d56Sopenharmony_ci                    const mpd_uint_t *u, size_t ulen, mpd_uint_t ubase)
82597db96d56Sopenharmony_ci{
82607db96d56Sopenharmony_ci    size_t n = 0;
82617db96d56Sopenharmony_ci    mpd_uint_t carry;
82627db96d56Sopenharmony_ci
82637db96d56Sopenharmony_ci    assert(wlen > 0 && ulen > 0);
82647db96d56Sopenharmony_ci    assert(ubase < wbase);
82657db96d56Sopenharmony_ci
82667db96d56Sopenharmony_ci    (*w)[n++] = u[--ulen];
82677db96d56Sopenharmony_ci    while (--ulen != SIZE_MAX) {
82687db96d56Sopenharmony_ci        carry = _mpd_shortmul_b(*w, *w, n, ubase, wbase);
82697db96d56Sopenharmony_ci        if (carry) {
82707db96d56Sopenharmony_ci            if (n >= wlen) {
82717db96d56Sopenharmony_ci                if (!mpd_resize_u32(w, n+1)) {
82727db96d56Sopenharmony_ci                    return SIZE_MAX;
82737db96d56Sopenharmony_ci                }
82747db96d56Sopenharmony_ci                wlen = n+1;
82757db96d56Sopenharmony_ci            }
82767db96d56Sopenharmony_ci            (*w)[n++] = carry;
82777db96d56Sopenharmony_ci        }
82787db96d56Sopenharmony_ci        carry = _mpd_shortadd_b(*w, n, u[ulen], wbase);
82797db96d56Sopenharmony_ci        if (carry) {
82807db96d56Sopenharmony_ci            if (n >= wlen) {
82817db96d56Sopenharmony_ci                if (!mpd_resize_u32(w, n+1)) {
82827db96d56Sopenharmony_ci                    return SIZE_MAX;
82837db96d56Sopenharmony_ci                }
82847db96d56Sopenharmony_ci                wlen = n+1;
82857db96d56Sopenharmony_ci            }
82867db96d56Sopenharmony_ci            (*w)[n++] = carry;
82877db96d56Sopenharmony_ci        }
82887db96d56Sopenharmony_ci    }
82897db96d56Sopenharmony_ci
82907db96d56Sopenharmony_ci    return n;
82917db96d56Sopenharmony_ci}
82927db96d56Sopenharmony_ci
82937db96d56Sopenharmony_ci/* target base wbase < source base ubase */
82947db96d56Sopenharmony_cistatic size_t
82957db96d56Sopenharmony_ci_coeff_from_larger_base(mpd_t *w, size_t wlen, mpd_uint_t wbase,
82967db96d56Sopenharmony_ci                        mpd_uint_t *u, mpd_ssize_t ulen, mpd_uint_t ubase,
82977db96d56Sopenharmony_ci                        uint32_t *status)
82987db96d56Sopenharmony_ci{
82997db96d56Sopenharmony_ci    size_t n = 0;
83007db96d56Sopenharmony_ci
83017db96d56Sopenharmony_ci    assert(wlen > 0 && ulen > 0);
83027db96d56Sopenharmony_ci    assert(wbase < ubase);
83037db96d56Sopenharmony_ci
83047db96d56Sopenharmony_ci    do {
83057db96d56Sopenharmony_ci        if (n >= wlen) {
83067db96d56Sopenharmony_ci            if (!mpd_qresize(w, n+1, status)) {
83077db96d56Sopenharmony_ci                return SIZE_MAX;
83087db96d56Sopenharmony_ci            }
83097db96d56Sopenharmony_ci            wlen = n+1;
83107db96d56Sopenharmony_ci        }
83117db96d56Sopenharmony_ci        w->data[n++] = (uint32_t)_mpd_shortdiv_b(u, u, ulen, wbase, ubase);
83127db96d56Sopenharmony_ci        /* ulen is at least 1. u[ulen-1] can only be zero if ulen == 1. */
83137db96d56Sopenharmony_ci        ulen = _mpd_real_size(u, ulen);
83147db96d56Sopenharmony_ci
83157db96d56Sopenharmony_ci    } while (u[ulen-1] != 0);
83167db96d56Sopenharmony_ci
83177db96d56Sopenharmony_ci    return n;
83187db96d56Sopenharmony_ci}
83197db96d56Sopenharmony_ci#endif
83207db96d56Sopenharmony_ci
83217db96d56Sopenharmony_ci/* target base 'wbase' > source base 'ubase' */
83227db96d56Sopenharmony_cistatic size_t
83237db96d56Sopenharmony_ci_coeff_from_smaller_base(mpd_t *w, mpd_ssize_t wlen, mpd_uint_t wbase,
83247db96d56Sopenharmony_ci                         const uint32_t *u, size_t ulen, mpd_uint_t ubase,
83257db96d56Sopenharmony_ci                         uint32_t *status)
83267db96d56Sopenharmony_ci{
83277db96d56Sopenharmony_ci    mpd_ssize_t n = 0;
83287db96d56Sopenharmony_ci    mpd_uint_t carry;
83297db96d56Sopenharmony_ci
83307db96d56Sopenharmony_ci    assert(wlen > 0 && ulen > 0);
83317db96d56Sopenharmony_ci    assert(wbase > ubase);
83327db96d56Sopenharmony_ci
83337db96d56Sopenharmony_ci    w->data[n++] = u[--ulen];
83347db96d56Sopenharmony_ci    while (--ulen != SIZE_MAX) {
83357db96d56Sopenharmony_ci        carry = _mpd_shortmul_b(w->data, w->data, n, ubase, wbase);
83367db96d56Sopenharmony_ci        if (carry) {
83377db96d56Sopenharmony_ci            if (n >= wlen) {
83387db96d56Sopenharmony_ci                if (!mpd_qresize(w, n+1, status)) {
83397db96d56Sopenharmony_ci                    return SIZE_MAX;
83407db96d56Sopenharmony_ci                }
83417db96d56Sopenharmony_ci                wlen = n+1;
83427db96d56Sopenharmony_ci            }
83437db96d56Sopenharmony_ci            w->data[n++] = carry;
83447db96d56Sopenharmony_ci        }
83457db96d56Sopenharmony_ci        carry = _mpd_shortadd_b(w->data, n, u[ulen], wbase);
83467db96d56Sopenharmony_ci        if (carry) {
83477db96d56Sopenharmony_ci            if (n >= wlen) {
83487db96d56Sopenharmony_ci                if (!mpd_qresize(w, n+1, status)) {
83497db96d56Sopenharmony_ci                    return SIZE_MAX;
83507db96d56Sopenharmony_ci                }
83517db96d56Sopenharmony_ci                wlen = n+1;
83527db96d56Sopenharmony_ci            }
83537db96d56Sopenharmony_ci            w->data[n++] = carry;
83547db96d56Sopenharmony_ci        }
83557db96d56Sopenharmony_ci    }
83567db96d56Sopenharmony_ci
83577db96d56Sopenharmony_ci    return n;
83587db96d56Sopenharmony_ci}
83597db96d56Sopenharmony_ci
83607db96d56Sopenharmony_ci/*
83617db96d56Sopenharmony_ci * Convert an integer mpd_t to a multiprecision integer with base <= 2**16.
83627db96d56Sopenharmony_ci * The least significant word of the result is (*rdata)[0].
83637db96d56Sopenharmony_ci *
83647db96d56Sopenharmony_ci * If rdata is NULL, space is allocated by the function and rlen is irrelevant.
83657db96d56Sopenharmony_ci * In case of an error any allocated storage is freed and rdata is set back to
83667db96d56Sopenharmony_ci * NULL.
83677db96d56Sopenharmony_ci *
83687db96d56Sopenharmony_ci * If rdata is non-NULL, it MUST be allocated by one of libmpdec's allocation
83697db96d56Sopenharmony_ci * functions and rlen MUST be correct. If necessary, the function will resize
83707db96d56Sopenharmony_ci * rdata. In case of an error the caller must free rdata.
83717db96d56Sopenharmony_ci *
83727db96d56Sopenharmony_ci * Return value: In case of success, the exact length of rdata, SIZE_MAX
83737db96d56Sopenharmony_ci * otherwise.
83747db96d56Sopenharmony_ci */
83757db96d56Sopenharmony_cisize_t
83767db96d56Sopenharmony_cimpd_qexport_u16(uint16_t **rdata, size_t rlen, uint32_t rbase,
83777db96d56Sopenharmony_ci                const mpd_t *src, uint32_t *status)
83787db96d56Sopenharmony_ci{
83797db96d56Sopenharmony_ci    MPD_NEW_STATIC(tsrc,0,0,0,0);
83807db96d56Sopenharmony_ci    int alloc = 0; /* rdata == NULL */
83817db96d56Sopenharmony_ci    size_t n;
83827db96d56Sopenharmony_ci
83837db96d56Sopenharmony_ci    assert(rbase <= (1U<<16));
83847db96d56Sopenharmony_ci
83857db96d56Sopenharmony_ci    if (mpd_isspecial(src) || !_mpd_isint(src)) {
83867db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
83877db96d56Sopenharmony_ci        return SIZE_MAX;
83887db96d56Sopenharmony_ci    }
83897db96d56Sopenharmony_ci
83907db96d56Sopenharmony_ci    if (*rdata == NULL) {
83917db96d56Sopenharmony_ci        rlen = mpd_sizeinbase(src, rbase);
83927db96d56Sopenharmony_ci        if (rlen == SIZE_MAX) {
83937db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
83947db96d56Sopenharmony_ci            return SIZE_MAX;
83957db96d56Sopenharmony_ci        }
83967db96d56Sopenharmony_ci        *rdata = mpd_alloc(rlen, sizeof **rdata);
83977db96d56Sopenharmony_ci        if (*rdata == NULL) {
83987db96d56Sopenharmony_ci            goto malloc_error;
83997db96d56Sopenharmony_ci        }
84007db96d56Sopenharmony_ci        alloc = 1;
84017db96d56Sopenharmony_ci    }
84027db96d56Sopenharmony_ci
84037db96d56Sopenharmony_ci    if (mpd_iszero(src)) {
84047db96d56Sopenharmony_ci        **rdata = 0;
84057db96d56Sopenharmony_ci        return 1;
84067db96d56Sopenharmony_ci    }
84077db96d56Sopenharmony_ci
84087db96d56Sopenharmony_ci    if (src->exp >= 0) {
84097db96d56Sopenharmony_ci        if (!mpd_qshiftl(&tsrc, src, src->exp, status)) {
84107db96d56Sopenharmony_ci            goto malloc_error;
84117db96d56Sopenharmony_ci        }
84127db96d56Sopenharmony_ci    }
84137db96d56Sopenharmony_ci    else {
84147db96d56Sopenharmony_ci        if (mpd_qshiftr(&tsrc, src, -src->exp, status) == MPD_UINT_MAX) {
84157db96d56Sopenharmony_ci            goto malloc_error;
84167db96d56Sopenharmony_ci        }
84177db96d56Sopenharmony_ci    }
84187db96d56Sopenharmony_ci
84197db96d56Sopenharmony_ci    n = _baseconv_to_u16(rdata, rlen, rbase, tsrc.data, tsrc.len);
84207db96d56Sopenharmony_ci    if (n == SIZE_MAX) {
84217db96d56Sopenharmony_ci        goto malloc_error;
84227db96d56Sopenharmony_ci    }
84237db96d56Sopenharmony_ci
84247db96d56Sopenharmony_ci
84257db96d56Sopenharmony_ciout:
84267db96d56Sopenharmony_ci    mpd_del(&tsrc);
84277db96d56Sopenharmony_ci    return n;
84287db96d56Sopenharmony_ci
84297db96d56Sopenharmony_cimalloc_error:
84307db96d56Sopenharmony_ci    if (alloc) {
84317db96d56Sopenharmony_ci        mpd_free(*rdata);
84327db96d56Sopenharmony_ci        *rdata = NULL;
84337db96d56Sopenharmony_ci    }
84347db96d56Sopenharmony_ci    n = SIZE_MAX;
84357db96d56Sopenharmony_ci    *status |= MPD_Malloc_error;
84367db96d56Sopenharmony_ci    goto out;
84377db96d56Sopenharmony_ci}
84387db96d56Sopenharmony_ci
84397db96d56Sopenharmony_ci/*
84407db96d56Sopenharmony_ci * Convert an integer mpd_t to a multiprecision integer with base<=UINT32_MAX.
84417db96d56Sopenharmony_ci * The least significant word of the result is (*rdata)[0].
84427db96d56Sopenharmony_ci *
84437db96d56Sopenharmony_ci * If rdata is NULL, space is allocated by the function and rlen is irrelevant.
84447db96d56Sopenharmony_ci * In case of an error any allocated storage is freed and rdata is set back to
84457db96d56Sopenharmony_ci * NULL.
84467db96d56Sopenharmony_ci *
84477db96d56Sopenharmony_ci * If rdata is non-NULL, it MUST be allocated by one of libmpdec's allocation
84487db96d56Sopenharmony_ci * functions and rlen MUST be correct. If necessary, the function will resize
84497db96d56Sopenharmony_ci * rdata. In case of an error the caller must free rdata.
84507db96d56Sopenharmony_ci *
84517db96d56Sopenharmony_ci * Return value: In case of success, the exact length of rdata, SIZE_MAX
84527db96d56Sopenharmony_ci * otherwise.
84537db96d56Sopenharmony_ci */
84547db96d56Sopenharmony_cisize_t
84557db96d56Sopenharmony_cimpd_qexport_u32(uint32_t **rdata, size_t rlen, uint32_t rbase,
84567db96d56Sopenharmony_ci                const mpd_t *src, uint32_t *status)
84577db96d56Sopenharmony_ci{
84587db96d56Sopenharmony_ci    MPD_NEW_STATIC(tsrc,0,0,0,0);
84597db96d56Sopenharmony_ci    int alloc = 0; /* rdata == NULL */
84607db96d56Sopenharmony_ci    size_t n;
84617db96d56Sopenharmony_ci
84627db96d56Sopenharmony_ci    if (mpd_isspecial(src) || !_mpd_isint(src)) {
84637db96d56Sopenharmony_ci        *status |= MPD_Invalid_operation;
84647db96d56Sopenharmony_ci        return SIZE_MAX;
84657db96d56Sopenharmony_ci    }
84667db96d56Sopenharmony_ci
84677db96d56Sopenharmony_ci    if (*rdata == NULL) {
84687db96d56Sopenharmony_ci        rlen = mpd_sizeinbase(src, rbase);
84697db96d56Sopenharmony_ci        if (rlen == SIZE_MAX) {
84707db96d56Sopenharmony_ci            *status |= MPD_Invalid_operation;
84717db96d56Sopenharmony_ci            return SIZE_MAX;
84727db96d56Sopenharmony_ci        }
84737db96d56Sopenharmony_ci        *rdata = mpd_alloc(rlen, sizeof **rdata);
84747db96d56Sopenharmony_ci        if (*rdata == NULL) {
84757db96d56Sopenharmony_ci            goto malloc_error;
84767db96d56Sopenharmony_ci        }
84777db96d56Sopenharmony_ci        alloc = 1;
84787db96d56Sopenharmony_ci    }
84797db96d56Sopenharmony_ci
84807db96d56Sopenharmony_ci    if (mpd_iszero(src)) {
84817db96d56Sopenharmony_ci        **rdata = 0;
84827db96d56Sopenharmony_ci        return 1;
84837db96d56Sopenharmony_ci    }
84847db96d56Sopenharmony_ci
84857db96d56Sopenharmony_ci    if (src->exp >= 0) {
84867db96d56Sopenharmony_ci        if (!mpd_qshiftl(&tsrc, src, src->exp, status)) {
84877db96d56Sopenharmony_ci            goto malloc_error;
84887db96d56Sopenharmony_ci        }
84897db96d56Sopenharmony_ci    }
84907db96d56Sopenharmony_ci    else {
84917db96d56Sopenharmony_ci        if (mpd_qshiftr(&tsrc, src, -src->exp, status) == MPD_UINT_MAX) {
84927db96d56Sopenharmony_ci            goto malloc_error;
84937db96d56Sopenharmony_ci        }
84947db96d56Sopenharmony_ci    }
84957db96d56Sopenharmony_ci
84967db96d56Sopenharmony_ci#ifdef CONFIG_64
84977db96d56Sopenharmony_ci    n = _baseconv_to_smaller(rdata, rlen, rbase,
84987db96d56Sopenharmony_ci                             tsrc.data, tsrc.len, MPD_RADIX);
84997db96d56Sopenharmony_ci#else
85007db96d56Sopenharmony_ci    if (rbase == MPD_RADIX) {
85017db96d56Sopenharmony_ci        n = _copy_equal_base(rdata, rlen, tsrc.data, tsrc.len);
85027db96d56Sopenharmony_ci    }
85037db96d56Sopenharmony_ci    else if (rbase < MPD_RADIX) {
85047db96d56Sopenharmony_ci        n = _baseconv_to_smaller(rdata, rlen, rbase,
85057db96d56Sopenharmony_ci                                 tsrc.data, tsrc.len, MPD_RADIX);
85067db96d56Sopenharmony_ci    }
85077db96d56Sopenharmony_ci    else {
85087db96d56Sopenharmony_ci        n = _baseconv_to_larger(rdata, rlen, rbase,
85097db96d56Sopenharmony_ci                                tsrc.data, tsrc.len, MPD_RADIX);
85107db96d56Sopenharmony_ci    }
85117db96d56Sopenharmony_ci#endif
85127db96d56Sopenharmony_ci
85137db96d56Sopenharmony_ci    if (n == SIZE_MAX) {
85147db96d56Sopenharmony_ci        goto malloc_error;
85157db96d56Sopenharmony_ci    }
85167db96d56Sopenharmony_ci
85177db96d56Sopenharmony_ci
85187db96d56Sopenharmony_ciout:
85197db96d56Sopenharmony_ci    mpd_del(&tsrc);
85207db96d56Sopenharmony_ci    return n;
85217db96d56Sopenharmony_ci
85227db96d56Sopenharmony_cimalloc_error:
85237db96d56Sopenharmony_ci    if (alloc) {
85247db96d56Sopenharmony_ci        mpd_free(*rdata);
85257db96d56Sopenharmony_ci        *rdata = NULL;
85267db96d56Sopenharmony_ci    }
85277db96d56Sopenharmony_ci    n = SIZE_MAX;
85287db96d56Sopenharmony_ci    *status |= MPD_Malloc_error;
85297db96d56Sopenharmony_ci    goto out;
85307db96d56Sopenharmony_ci}
85317db96d56Sopenharmony_ci
85327db96d56Sopenharmony_ci
85337db96d56Sopenharmony_ci/*
85347db96d56Sopenharmony_ci * Converts a multiprecision integer with base <= UINT16_MAX+1 to an mpd_t.
85357db96d56Sopenharmony_ci * The least significant word of the source is srcdata[0].
85367db96d56Sopenharmony_ci */
85377db96d56Sopenharmony_civoid
85387db96d56Sopenharmony_cimpd_qimport_u16(mpd_t *result,
85397db96d56Sopenharmony_ci                const uint16_t *srcdata, size_t srclen,
85407db96d56Sopenharmony_ci                uint8_t srcsign, uint32_t srcbase,
85417db96d56Sopenharmony_ci                const mpd_context_t *ctx, uint32_t *status)
85427db96d56Sopenharmony_ci{
85437db96d56Sopenharmony_ci    mpd_uint_t *usrc; /* uint16_t src copied to an mpd_uint_t array */
85447db96d56Sopenharmony_ci    mpd_ssize_t rlen; /* length of the result */
85457db96d56Sopenharmony_ci    size_t n;
85467db96d56Sopenharmony_ci
85477db96d56Sopenharmony_ci    assert(srclen > 0);
85487db96d56Sopenharmony_ci    assert(srcbase <= (1U<<16));
85497db96d56Sopenharmony_ci
85507db96d56Sopenharmony_ci    rlen = _mpd_importsize(srclen, srcbase);
85517db96d56Sopenharmony_ci    if (rlen == MPD_SSIZE_MAX) {
85527db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
85537db96d56Sopenharmony_ci        return;
85547db96d56Sopenharmony_ci    }
85557db96d56Sopenharmony_ci
85567db96d56Sopenharmony_ci    usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc);
85577db96d56Sopenharmony_ci    if (usrc == NULL) {
85587db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Malloc_error, status);
85597db96d56Sopenharmony_ci        return;
85607db96d56Sopenharmony_ci    }
85617db96d56Sopenharmony_ci    for (n = 0; n < srclen; n++) {
85627db96d56Sopenharmony_ci        usrc[n] = srcdata[n];
85637db96d56Sopenharmony_ci    }
85647db96d56Sopenharmony_ci
85657db96d56Sopenharmony_ci    if (!mpd_qresize(result, rlen, status)) {
85667db96d56Sopenharmony_ci        goto finish;
85677db96d56Sopenharmony_ci    }
85687db96d56Sopenharmony_ci
85697db96d56Sopenharmony_ci    n = _coeff_from_u16(result, rlen, usrc, srclen, srcbase, status);
85707db96d56Sopenharmony_ci    if (n == SIZE_MAX) {
85717db96d56Sopenharmony_ci        goto finish;
85727db96d56Sopenharmony_ci    }
85737db96d56Sopenharmony_ci
85747db96d56Sopenharmony_ci    mpd_set_flags(result, srcsign);
85757db96d56Sopenharmony_ci    result->exp = 0;
85767db96d56Sopenharmony_ci    result->len = n;
85777db96d56Sopenharmony_ci    mpd_setdigits(result);
85787db96d56Sopenharmony_ci
85797db96d56Sopenharmony_ci    mpd_qresize(result, result->len, status);
85807db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
85817db96d56Sopenharmony_ci
85827db96d56Sopenharmony_ci
85837db96d56Sopenharmony_cifinish:
85847db96d56Sopenharmony_ci    mpd_free(usrc);
85857db96d56Sopenharmony_ci}
85867db96d56Sopenharmony_ci
85877db96d56Sopenharmony_ci/*
85887db96d56Sopenharmony_ci * Converts a multiprecision integer with base <= UINT32_MAX to an mpd_t.
85897db96d56Sopenharmony_ci * The least significant word of the source is srcdata[0].
85907db96d56Sopenharmony_ci */
85917db96d56Sopenharmony_civoid
85927db96d56Sopenharmony_cimpd_qimport_u32(mpd_t *result,
85937db96d56Sopenharmony_ci                const uint32_t *srcdata, size_t srclen,
85947db96d56Sopenharmony_ci                uint8_t srcsign, uint32_t srcbase,
85957db96d56Sopenharmony_ci                const mpd_context_t *ctx, uint32_t *status)
85967db96d56Sopenharmony_ci{
85977db96d56Sopenharmony_ci    mpd_ssize_t rlen; /* length of the result */
85987db96d56Sopenharmony_ci    size_t n;
85997db96d56Sopenharmony_ci
86007db96d56Sopenharmony_ci    assert(srclen > 0);
86017db96d56Sopenharmony_ci
86027db96d56Sopenharmony_ci    rlen = _mpd_importsize(srclen, srcbase);
86037db96d56Sopenharmony_ci    if (rlen == MPD_SSIZE_MAX) {
86047db96d56Sopenharmony_ci        mpd_seterror(result, MPD_Invalid_operation, status);
86057db96d56Sopenharmony_ci        return;
86067db96d56Sopenharmony_ci    }
86077db96d56Sopenharmony_ci
86087db96d56Sopenharmony_ci    if (!mpd_qresize(result, rlen, status)) {
86097db96d56Sopenharmony_ci        return;
86107db96d56Sopenharmony_ci    }
86117db96d56Sopenharmony_ci
86127db96d56Sopenharmony_ci#ifdef CONFIG_64
86137db96d56Sopenharmony_ci    n = _coeff_from_smaller_base(result, rlen, MPD_RADIX,
86147db96d56Sopenharmony_ci                                 srcdata, srclen, srcbase,
86157db96d56Sopenharmony_ci                                 status);
86167db96d56Sopenharmony_ci#else
86177db96d56Sopenharmony_ci    if (srcbase == MPD_RADIX) {
86187db96d56Sopenharmony_ci        if (!mpd_qresize(result, srclen, status)) {
86197db96d56Sopenharmony_ci            return;
86207db96d56Sopenharmony_ci        }
86217db96d56Sopenharmony_ci        memcpy(result->data, srcdata, srclen * (sizeof *srcdata));
86227db96d56Sopenharmony_ci        n = srclen;
86237db96d56Sopenharmony_ci    }
86247db96d56Sopenharmony_ci    else if (srcbase < MPD_RADIX) {
86257db96d56Sopenharmony_ci        n = _coeff_from_smaller_base(result, rlen, MPD_RADIX,
86267db96d56Sopenharmony_ci                                     srcdata, srclen, srcbase,
86277db96d56Sopenharmony_ci                                     status);
86287db96d56Sopenharmony_ci    }
86297db96d56Sopenharmony_ci    else {
86307db96d56Sopenharmony_ci        mpd_uint_t *usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc);
86317db96d56Sopenharmony_ci        if (usrc == NULL) {
86327db96d56Sopenharmony_ci            mpd_seterror(result, MPD_Malloc_error, status);
86337db96d56Sopenharmony_ci            return;
86347db96d56Sopenharmony_ci        }
86357db96d56Sopenharmony_ci        for (n = 0; n < srclen; n++) {
86367db96d56Sopenharmony_ci            usrc[n] = srcdata[n];
86377db96d56Sopenharmony_ci        }
86387db96d56Sopenharmony_ci
86397db96d56Sopenharmony_ci        n = _coeff_from_larger_base(result, rlen, MPD_RADIX,
86407db96d56Sopenharmony_ci                                    usrc, (mpd_ssize_t)srclen, srcbase,
86417db96d56Sopenharmony_ci                                    status);
86427db96d56Sopenharmony_ci        mpd_free(usrc);
86437db96d56Sopenharmony_ci    }
86447db96d56Sopenharmony_ci#endif
86457db96d56Sopenharmony_ci
86467db96d56Sopenharmony_ci    if (n == SIZE_MAX) {
86477db96d56Sopenharmony_ci        return;
86487db96d56Sopenharmony_ci    }
86497db96d56Sopenharmony_ci
86507db96d56Sopenharmony_ci    mpd_set_flags(result, srcsign);
86517db96d56Sopenharmony_ci    result->exp = 0;
86527db96d56Sopenharmony_ci    result->len = n;
86537db96d56Sopenharmony_ci    mpd_setdigits(result);
86547db96d56Sopenharmony_ci
86557db96d56Sopenharmony_ci    mpd_qresize(result, result->len, status);
86567db96d56Sopenharmony_ci    mpd_qfinalize(result, ctx, status);
86577db96d56Sopenharmony_ci}
86587db96d56Sopenharmony_ci
86597db96d56Sopenharmony_ci
86607db96d56Sopenharmony_ci/******************************************************************************/
86617db96d56Sopenharmony_ci/*                                From triple                                 */
86627db96d56Sopenharmony_ci/******************************************************************************/
86637db96d56Sopenharmony_ci
86647db96d56Sopenharmony_ci#if defined(CONFIG_64) && defined(__SIZEOF_INT128__)
86657db96d56Sopenharmony_cistatic mpd_ssize_t
86667db96d56Sopenharmony_ci_set_coeff(uint64_t data[3], uint64_t hi, uint64_t lo)
86677db96d56Sopenharmony_ci{
86687db96d56Sopenharmony_ci    __uint128_t d = ((__uint128_t)hi << 64) + lo;
86697db96d56Sopenharmony_ci    __uint128_t q, r;
86707db96d56Sopenharmony_ci
86717db96d56Sopenharmony_ci    q = d / MPD_RADIX;
86727db96d56Sopenharmony_ci    r = d % MPD_RADIX;
86737db96d56Sopenharmony_ci    data[0] = (uint64_t)r;
86747db96d56Sopenharmony_ci    d = q;
86757db96d56Sopenharmony_ci
86767db96d56Sopenharmony_ci    q = d / MPD_RADIX;
86777db96d56Sopenharmony_ci    r = d % MPD_RADIX;
86787db96d56Sopenharmony_ci    data[1] = (uint64_t)r;
86797db96d56Sopenharmony_ci    d = q;
86807db96d56Sopenharmony_ci
86817db96d56Sopenharmony_ci    q = d / MPD_RADIX;
86827db96d56Sopenharmony_ci    r = d % MPD_RADIX;
86837db96d56Sopenharmony_ci    data[2] = (uint64_t)r;
86847db96d56Sopenharmony_ci
86857db96d56Sopenharmony_ci    if (q != 0) {
86867db96d56Sopenharmony_ci        abort(); /* GCOV_NOT_REACHED */
86877db96d56Sopenharmony_ci    }
86887db96d56Sopenharmony_ci
86897db96d56Sopenharmony_ci    return data[2] != 0 ? 3 : (data[1] != 0 ? 2 : 1);
86907db96d56Sopenharmony_ci}
86917db96d56Sopenharmony_ci#else
86927db96d56Sopenharmony_cistatic size_t
86937db96d56Sopenharmony_ci_uint_from_u16(mpd_uint_t *w, mpd_ssize_t wlen, const uint16_t *u, size_t ulen)
86947db96d56Sopenharmony_ci{
86957db96d56Sopenharmony_ci    const mpd_uint_t ubase = 1U<<16;
86967db96d56Sopenharmony_ci    mpd_ssize_t n = 0;
86977db96d56Sopenharmony_ci    mpd_uint_t carry;
86987db96d56Sopenharmony_ci
86997db96d56Sopenharmony_ci    assert(wlen > 0 && ulen > 0);
87007db96d56Sopenharmony_ci
87017db96d56Sopenharmony_ci    w[n++] = u[--ulen];
87027db96d56Sopenharmony_ci    while (--ulen != SIZE_MAX) {
87037db96d56Sopenharmony_ci        carry = _mpd_shortmul_c(w, w, n, ubase);
87047db96d56Sopenharmony_ci        if (carry) {
87057db96d56Sopenharmony_ci            if (n >= wlen) {
87067db96d56Sopenharmony_ci                abort();  /* GCOV_NOT_REACHED */
87077db96d56Sopenharmony_ci            }
87087db96d56Sopenharmony_ci            w[n++] = carry;
87097db96d56Sopenharmony_ci        }
87107db96d56Sopenharmony_ci        carry = _mpd_shortadd(w, n, u[ulen]);
87117db96d56Sopenharmony_ci        if (carry) {
87127db96d56Sopenharmony_ci            if (n >= wlen) {
87137db96d56Sopenharmony_ci                abort();  /* GCOV_NOT_REACHED */
87147db96d56Sopenharmony_ci            }
87157db96d56Sopenharmony_ci            w[n++] = carry;
87167db96d56Sopenharmony_ci        }
87177db96d56Sopenharmony_ci    }
87187db96d56Sopenharmony_ci
87197db96d56Sopenharmony_ci    return n;
87207db96d56Sopenharmony_ci}
87217db96d56Sopenharmony_ci
87227db96d56Sopenharmony_cistatic mpd_ssize_t
87237db96d56Sopenharmony_ci_set_coeff(mpd_uint_t *data, mpd_ssize_t len, uint64_t hi, uint64_t lo)
87247db96d56Sopenharmony_ci{
87257db96d56Sopenharmony_ci    uint16_t u16[8] = {0};
87267db96d56Sopenharmony_ci
87277db96d56Sopenharmony_ci    u16[7] = (uint16_t)((hi & 0xFFFF000000000000ULL) >> 48);
87287db96d56Sopenharmony_ci    u16[6] = (uint16_t)((hi & 0x0000FFFF00000000ULL) >> 32);
87297db96d56Sopenharmony_ci    u16[5] = (uint16_t)((hi & 0x00000000FFFF0000ULL) >> 16);
87307db96d56Sopenharmony_ci    u16[4] = (uint16_t) (hi & 0x000000000000FFFFULL);
87317db96d56Sopenharmony_ci
87327db96d56Sopenharmony_ci    u16[3] = (uint16_t)((lo & 0xFFFF000000000000ULL) >> 48);
87337db96d56Sopenharmony_ci    u16[2] = (uint16_t)((lo & 0x0000FFFF00000000ULL) >> 32);
87347db96d56Sopenharmony_ci    u16[1] = (uint16_t)((lo & 0x00000000FFFF0000ULL) >> 16);
87357db96d56Sopenharmony_ci    u16[0] = (uint16_t) (lo & 0x000000000000FFFFULL);
87367db96d56Sopenharmony_ci
87377db96d56Sopenharmony_ci    return (mpd_ssize_t)_uint_from_u16(data, len, u16, 8);
87387db96d56Sopenharmony_ci}
87397db96d56Sopenharmony_ci#endif
87407db96d56Sopenharmony_ci
87417db96d56Sopenharmony_cistatic int
87427db96d56Sopenharmony_ci_set_uint128_coeff_exp(mpd_t *result, uint64_t hi, uint64_t lo, mpd_ssize_t exp)
87437db96d56Sopenharmony_ci{
87447db96d56Sopenharmony_ci    mpd_uint_t data[5] = {0};
87457db96d56Sopenharmony_ci    uint32_t status = 0;
87467db96d56Sopenharmony_ci    mpd_ssize_t len;
87477db96d56Sopenharmony_ci
87487db96d56Sopenharmony_ci#if defined(CONFIG_64) && defined(__SIZEOF_INT128__)
87497db96d56Sopenharmony_ci    len = _set_coeff(data, hi, lo);
87507db96d56Sopenharmony_ci#else
87517db96d56Sopenharmony_ci    len = _set_coeff(data, 5, hi, lo);
87527db96d56Sopenharmony_ci#endif
87537db96d56Sopenharmony_ci
87547db96d56Sopenharmony_ci    if (!mpd_qresize(result, len, &status)) {
87557db96d56Sopenharmony_ci        return -1;
87567db96d56Sopenharmony_ci    }
87577db96d56Sopenharmony_ci
87587db96d56Sopenharmony_ci    for (mpd_ssize_t i = 0; i < len; i++) {
87597db96d56Sopenharmony_ci        result->data[i] = data[i];
87607db96d56Sopenharmony_ci    }
87617db96d56Sopenharmony_ci
87627db96d56Sopenharmony_ci    result->exp = exp;
87637db96d56Sopenharmony_ci    result->len = len;
87647db96d56Sopenharmony_ci    mpd_setdigits(result);
87657db96d56Sopenharmony_ci
87667db96d56Sopenharmony_ci    return 0;
87677db96d56Sopenharmony_ci}
87687db96d56Sopenharmony_ci
87697db96d56Sopenharmony_ciint
87707db96d56Sopenharmony_cimpd_from_uint128_triple(mpd_t *result, const mpd_uint128_triple_t *triple, uint32_t *status)
87717db96d56Sopenharmony_ci{
87727db96d56Sopenharmony_ci    static const mpd_context_t maxcontext = {
87737db96d56Sopenharmony_ci     .prec=MPD_MAX_PREC,
87747db96d56Sopenharmony_ci     .emax=MPD_MAX_EMAX,
87757db96d56Sopenharmony_ci     .emin=MPD_MIN_EMIN,
87767db96d56Sopenharmony_ci     .round=MPD_ROUND_HALF_EVEN,
87777db96d56Sopenharmony_ci     .traps=MPD_Traps,
87787db96d56Sopenharmony_ci     .status=0,
87797db96d56Sopenharmony_ci     .newtrap=0,
87807db96d56Sopenharmony_ci     .clamp=0,
87817db96d56Sopenharmony_ci     .allcr=1,
87827db96d56Sopenharmony_ci    };
87837db96d56Sopenharmony_ci    const enum mpd_triple_class tag = triple->tag;
87847db96d56Sopenharmony_ci    const uint8_t sign = triple->sign;
87857db96d56Sopenharmony_ci    const uint64_t hi = triple->hi;
87867db96d56Sopenharmony_ci    const uint64_t lo = triple->lo;
87877db96d56Sopenharmony_ci    mpd_ssize_t exp;
87887db96d56Sopenharmony_ci
87897db96d56Sopenharmony_ci#ifdef CONFIG_32
87907db96d56Sopenharmony_ci    if (triple->exp < MPD_SSIZE_MIN || triple->exp > MPD_SSIZE_MAX) {
87917db96d56Sopenharmony_ci        goto conversion_error;
87927db96d56Sopenharmony_ci    }
87937db96d56Sopenharmony_ci#endif
87947db96d56Sopenharmony_ci    exp = (mpd_ssize_t)triple->exp;
87957db96d56Sopenharmony_ci
87967db96d56Sopenharmony_ci    switch (tag) {
87977db96d56Sopenharmony_ci    case MPD_TRIPLE_QNAN: case MPD_TRIPLE_SNAN: {
87987db96d56Sopenharmony_ci        if (sign > 1 || exp != 0) {
87997db96d56Sopenharmony_ci            goto conversion_error;
88007db96d56Sopenharmony_ci        }
88017db96d56Sopenharmony_ci
88027db96d56Sopenharmony_ci        const uint8_t flags = tag == MPD_TRIPLE_QNAN ? MPD_NAN : MPD_SNAN;
88037db96d56Sopenharmony_ci        mpd_setspecial(result, sign, flags);
88047db96d56Sopenharmony_ci
88057db96d56Sopenharmony_ci        if (hi == 0 && lo == 0) {  /* no payload */
88067db96d56Sopenharmony_ci            return 0;
88077db96d56Sopenharmony_ci        }
88087db96d56Sopenharmony_ci
88097db96d56Sopenharmony_ci        if (_set_uint128_coeff_exp(result, hi, lo, exp) < 0) {
88107db96d56Sopenharmony_ci            goto malloc_error;
88117db96d56Sopenharmony_ci        }
88127db96d56Sopenharmony_ci
88137db96d56Sopenharmony_ci        return 0;
88147db96d56Sopenharmony_ci    }
88157db96d56Sopenharmony_ci
88167db96d56Sopenharmony_ci    case MPD_TRIPLE_INF: {
88177db96d56Sopenharmony_ci        if (sign > 1 || hi != 0 || lo != 0 || exp != 0) {
88187db96d56Sopenharmony_ci            goto conversion_error;
88197db96d56Sopenharmony_ci        }
88207db96d56Sopenharmony_ci
88217db96d56Sopenharmony_ci        mpd_setspecial(result, sign, MPD_INF);
88227db96d56Sopenharmony_ci
88237db96d56Sopenharmony_ci        return 0;
88247db96d56Sopenharmony_ci    }
88257db96d56Sopenharmony_ci
88267db96d56Sopenharmony_ci    case MPD_TRIPLE_NORMAL: {
88277db96d56Sopenharmony_ci        if (sign > 1) {
88287db96d56Sopenharmony_ci            goto conversion_error;
88297db96d56Sopenharmony_ci        }
88307db96d56Sopenharmony_ci
88317db96d56Sopenharmony_ci        const uint8_t flags = sign ? MPD_NEG : MPD_POS;
88327db96d56Sopenharmony_ci        mpd_set_flags(result, flags);
88337db96d56Sopenharmony_ci
88347db96d56Sopenharmony_ci        if (exp > MPD_EXP_INF) {
88357db96d56Sopenharmony_ci            exp = MPD_EXP_INF;
88367db96d56Sopenharmony_ci        }
88377db96d56Sopenharmony_ci        if (exp == MPD_SSIZE_MIN) {
88387db96d56Sopenharmony_ci            exp = MPD_SSIZE_MIN+1;
88397db96d56Sopenharmony_ci        }
88407db96d56Sopenharmony_ci
88417db96d56Sopenharmony_ci        if (_set_uint128_coeff_exp(result, hi, lo, exp) < 0) {
88427db96d56Sopenharmony_ci            goto malloc_error;
88437db96d56Sopenharmony_ci        }
88447db96d56Sopenharmony_ci
88457db96d56Sopenharmony_ci        uint32_t workstatus = 0;
88467db96d56Sopenharmony_ci        mpd_qfinalize(result, &maxcontext, &workstatus);
88477db96d56Sopenharmony_ci        if (workstatus & (MPD_Inexact|MPD_Rounded|MPD_Clamped)) {
88487db96d56Sopenharmony_ci            goto conversion_error;
88497db96d56Sopenharmony_ci        }
88507db96d56Sopenharmony_ci
88517db96d56Sopenharmony_ci        return 0;
88527db96d56Sopenharmony_ci    }
88537db96d56Sopenharmony_ci
88547db96d56Sopenharmony_ci    default:
88557db96d56Sopenharmony_ci        goto conversion_error;
88567db96d56Sopenharmony_ci    }
88577db96d56Sopenharmony_ci
88587db96d56Sopenharmony_ciconversion_error:
88597db96d56Sopenharmony_ci    mpd_seterror(result, MPD_Conversion_syntax, status);
88607db96d56Sopenharmony_ci    return -1;
88617db96d56Sopenharmony_ci
88627db96d56Sopenharmony_cimalloc_error:
88637db96d56Sopenharmony_ci    mpd_seterror(result, MPD_Malloc_error, status);
88647db96d56Sopenharmony_ci    return -1;
88657db96d56Sopenharmony_ci}
88667db96d56Sopenharmony_ci
88677db96d56Sopenharmony_ci
88687db96d56Sopenharmony_ci/******************************************************************************/
88697db96d56Sopenharmony_ci/*                                  As triple                                 */
88707db96d56Sopenharmony_ci/******************************************************************************/
88717db96d56Sopenharmony_ci
88727db96d56Sopenharmony_ci#if defined(CONFIG_64) && defined(__SIZEOF_INT128__)
88737db96d56Sopenharmony_cistatic void
88747db96d56Sopenharmony_ci_get_coeff(uint64_t *hi, uint64_t *lo, const mpd_t *a)
88757db96d56Sopenharmony_ci{
88767db96d56Sopenharmony_ci    __uint128_t u128 = 0;
88777db96d56Sopenharmony_ci
88787db96d56Sopenharmony_ci    switch (a->len) {
88797db96d56Sopenharmony_ci    case 3:
88807db96d56Sopenharmony_ci        u128 = a->data[2]; /* fall through */
88817db96d56Sopenharmony_ci    case 2:
88827db96d56Sopenharmony_ci        u128 = u128 * MPD_RADIX + a->data[1]; /* fall through */
88837db96d56Sopenharmony_ci    case 1:
88847db96d56Sopenharmony_ci        u128 = u128 * MPD_RADIX + a->data[0];
88857db96d56Sopenharmony_ci        break;
88867db96d56Sopenharmony_ci    default:
88877db96d56Sopenharmony_ci        abort(); /* GCOV_NOT_REACHED */
88887db96d56Sopenharmony_ci    }
88897db96d56Sopenharmony_ci
88907db96d56Sopenharmony_ci    *hi = u128 >> 64;
88917db96d56Sopenharmony_ci    *lo = (uint64_t)u128;
88927db96d56Sopenharmony_ci}
88937db96d56Sopenharmony_ci#else
88947db96d56Sopenharmony_cistatic size_t
88957db96d56Sopenharmony_ci_uint_to_u16(uint16_t w[8], mpd_uint_t *u, mpd_ssize_t ulen)
88967db96d56Sopenharmony_ci{
88977db96d56Sopenharmony_ci    const mpd_uint_t wbase = 1U<<16;
88987db96d56Sopenharmony_ci    size_t n = 0;
88997db96d56Sopenharmony_ci
89007db96d56Sopenharmony_ci    assert(ulen > 0);
89017db96d56Sopenharmony_ci
89027db96d56Sopenharmony_ci    do {
89037db96d56Sopenharmony_ci        if (n >= 8) {
89047db96d56Sopenharmony_ci            abort();  /* GCOV_NOT_REACHED */
89057db96d56Sopenharmony_ci        }
89067db96d56Sopenharmony_ci        w[n++] = (uint16_t)_mpd_shortdiv(u, u, ulen, wbase);
89077db96d56Sopenharmony_ci        /* ulen is at least 1. u[ulen-1] can only be zero if ulen == 1. */
89087db96d56Sopenharmony_ci        ulen = _mpd_real_size(u, ulen);
89097db96d56Sopenharmony_ci
89107db96d56Sopenharmony_ci    } while (u[ulen-1] != 0);
89117db96d56Sopenharmony_ci
89127db96d56Sopenharmony_ci    return n;
89137db96d56Sopenharmony_ci}
89147db96d56Sopenharmony_ci
89157db96d56Sopenharmony_cistatic void
89167db96d56Sopenharmony_ci_get_coeff(uint64_t *hi, uint64_t *lo, const mpd_t *a)
89177db96d56Sopenharmony_ci{
89187db96d56Sopenharmony_ci    uint16_t u16[8] = {0};
89197db96d56Sopenharmony_ci    mpd_uint_t data[5] = {0};
89207db96d56Sopenharmony_ci
89217db96d56Sopenharmony_ci    switch (a->len) {
89227db96d56Sopenharmony_ci    case 5:
89237db96d56Sopenharmony_ci        data[4] = a->data[4]; /* fall through */
89247db96d56Sopenharmony_ci    case 4:
89257db96d56Sopenharmony_ci        data[3] = a->data[3]; /* fall through */
89267db96d56Sopenharmony_ci    case 3:
89277db96d56Sopenharmony_ci        data[2] = a->data[2]; /* fall through */
89287db96d56Sopenharmony_ci    case 2:
89297db96d56Sopenharmony_ci        data[1] = a->data[1]; /* fall through */
89307db96d56Sopenharmony_ci    case 1:
89317db96d56Sopenharmony_ci        data[0] = a->data[0];
89327db96d56Sopenharmony_ci        break;
89337db96d56Sopenharmony_ci    default:
89347db96d56Sopenharmony_ci        abort();  /* GCOV_NOT_REACHED */
89357db96d56Sopenharmony_ci    }
89367db96d56Sopenharmony_ci
89377db96d56Sopenharmony_ci    _uint_to_u16(u16, data, a->len);
89387db96d56Sopenharmony_ci
89397db96d56Sopenharmony_ci    *hi = (uint64_t)u16[7] << 48;
89407db96d56Sopenharmony_ci    *hi |= (uint64_t)u16[6] << 32;
89417db96d56Sopenharmony_ci    *hi |= (uint64_t)u16[5] << 16;
89427db96d56Sopenharmony_ci    *hi |= (uint64_t)u16[4];
89437db96d56Sopenharmony_ci
89447db96d56Sopenharmony_ci    *lo = (uint64_t)u16[3] << 48;
89457db96d56Sopenharmony_ci    *lo |= (uint64_t)u16[2] << 32;
89467db96d56Sopenharmony_ci    *lo |= (uint64_t)u16[1] << 16;
89477db96d56Sopenharmony_ci    *lo |= (uint64_t)u16[0];
89487db96d56Sopenharmony_ci}
89497db96d56Sopenharmony_ci#endif
89507db96d56Sopenharmony_ci
89517db96d56Sopenharmony_cistatic enum mpd_triple_class
89527db96d56Sopenharmony_ci_coeff_as_uint128(uint64_t *hi, uint64_t *lo, const mpd_t *a)
89537db96d56Sopenharmony_ci{
89547db96d56Sopenharmony_ci#ifdef CONFIG_64
89557db96d56Sopenharmony_ci    static mpd_uint_t uint128_max_data[3] = { 3374607431768211455ULL, 4028236692093846346ULL, 3ULL };
89567db96d56Sopenharmony_ci    static const mpd_t uint128_max = { MPD_STATIC|MPD_CONST_DATA, 0, 39, 3, 3, uint128_max_data };
89577db96d56Sopenharmony_ci#else
89587db96d56Sopenharmony_ci    static mpd_uint_t uint128_max_data[5] = { 768211455U, 374607431U, 938463463U, 282366920U, 340U };
89597db96d56Sopenharmony_ci    static const mpd_t uint128_max = { MPD_STATIC|MPD_CONST_DATA, 0, 39, 5, 5, uint128_max_data };
89607db96d56Sopenharmony_ci#endif
89617db96d56Sopenharmony_ci    enum mpd_triple_class ret = MPD_TRIPLE_NORMAL;
89627db96d56Sopenharmony_ci    uint32_t status = 0;
89637db96d56Sopenharmony_ci    mpd_t coeff;
89647db96d56Sopenharmony_ci
89657db96d56Sopenharmony_ci    *hi = *lo = 0ULL;
89667db96d56Sopenharmony_ci
89677db96d56Sopenharmony_ci    if (mpd_isspecial(a)) {
89687db96d56Sopenharmony_ci        if (mpd_isinfinite(a)) {
89697db96d56Sopenharmony_ci            return MPD_TRIPLE_INF;
89707db96d56Sopenharmony_ci        }
89717db96d56Sopenharmony_ci
89727db96d56Sopenharmony_ci        ret = mpd_isqnan(a) ? MPD_TRIPLE_QNAN : MPD_TRIPLE_SNAN;
89737db96d56Sopenharmony_ci        if (a->len == 0) { /* no payload */
89747db96d56Sopenharmony_ci            return ret;
89757db96d56Sopenharmony_ci        }
89767db96d56Sopenharmony_ci    }
89777db96d56Sopenharmony_ci    else if (mpd_iszero(a)) {
89787db96d56Sopenharmony_ci        return ret;
89797db96d56Sopenharmony_ci    }
89807db96d56Sopenharmony_ci
89817db96d56Sopenharmony_ci    _mpd_copy_shared(&coeff, a);
89827db96d56Sopenharmony_ci    mpd_set_flags(&coeff, 0);
89837db96d56Sopenharmony_ci    coeff.exp = 0;
89847db96d56Sopenharmony_ci
89857db96d56Sopenharmony_ci    if (mpd_qcmp(&coeff, &uint128_max, &status) > 0) {
89867db96d56Sopenharmony_ci        return MPD_TRIPLE_ERROR;
89877db96d56Sopenharmony_ci    }
89887db96d56Sopenharmony_ci
89897db96d56Sopenharmony_ci    _get_coeff(hi, lo, &coeff);
89907db96d56Sopenharmony_ci    return ret;
89917db96d56Sopenharmony_ci}
89927db96d56Sopenharmony_ci
89937db96d56Sopenharmony_cimpd_uint128_triple_t
89947db96d56Sopenharmony_cimpd_as_uint128_triple(const mpd_t *a)
89957db96d56Sopenharmony_ci{
89967db96d56Sopenharmony_ci    mpd_uint128_triple_t triple = { MPD_TRIPLE_ERROR, 0, 0, 0, 0 };
89977db96d56Sopenharmony_ci
89987db96d56Sopenharmony_ci    triple.tag = _coeff_as_uint128(&triple.hi, &triple.lo, a);
89997db96d56Sopenharmony_ci    if (triple.tag == MPD_TRIPLE_ERROR) {
90007db96d56Sopenharmony_ci        return triple;
90017db96d56Sopenharmony_ci    }
90027db96d56Sopenharmony_ci
90037db96d56Sopenharmony_ci    triple.sign = !!mpd_isnegative(a);
90047db96d56Sopenharmony_ci    if (triple.tag == MPD_TRIPLE_NORMAL) {
90057db96d56Sopenharmony_ci        triple.exp = a->exp;
90067db96d56Sopenharmony_ci    }
90077db96d56Sopenharmony_ci
90087db96d56Sopenharmony_ci    return triple;
90097db96d56Sopenharmony_ci}
9010