// Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // common _[FL]Dtento functionality #include "xmath.hpp" #if !defined(MRTDLL) extern "C" { #endif // defined(MRTDLL) // macros #define ACSIZE 4 // size of extended-precision accumulators #define BIAS (ACSIZE * (FBITS / 2)) // avoid denorms for finite values #define FRAC_BITS_2 (FRAC_BITS * FRAC_BITS) #if FBITS == 53 #define FRAC_BITS 67108864.0L // 2^26 static const FTYPE tenth[] = { // 53-bit: 0.100000 static_cast(FLIT(6710886.0) / FRAC_BITS), static_cast(FLIT(26843545.0) / FRAC_BITS_2), static_cast(FLIT(40265318.0) / FRAC_BITS_2 / FRAC_BITS), static_cast(FLIT(26843545.0) / FRAC_BITS_2 / FRAC_BITS_2), }; #elif FBITS == 24 #define FRAC_BITS 4096.0L // 2^12 static const FTYPE tenth[] = { // 24-bit: 0.100000 static_cast(FLIT(409.0) / FRAC_BITS), static_cast(FLIT(2457.0) / FRAC_BITS_2), static_cast(FLIT(2457.0) / FRAC_BITS_2 / FRAC_BITS), static_cast(FLIT(2457.0) / FRAC_BITS_2 / FRAC_BITS_2), }; #else // ^^^ FBITS == 24 / FBITS != 24 && FBITS != 53 vvv #error Unexpected value for FBITS #endif // ^^^ FBITS != 24 && FBITS != 53 ^^^ FTYPE FNAME(Dtento)(FTYPE* xpx, long n, int* perr) noexcept { // compute *px * 10**n FTYPE xpf[ACSIZE]; FTYPE x; if (n == 0 || xpx[0] == FLIT(0.0)) { return FNAME(Xp_getw)(xpx, ACSIZE); } if (0 < n) { FNAME(Xp_setw)(xpf, ACSIZE, 10.0); // factor = 10 } else { // scale down n = -n; FNAME(Xp_movx)(xpf, ACSIZE, tenth); // factor = 1/10 FNAME(Xp_ldexpx)(xpx, ACSIZE, BIAS); // scale up x } for (;;) { // multiply as needed by 10^(2^n) FTYPE xpt[ACSIZE * 2]; FTYPE xpw[ACSIZE]; if (n & 1) { FNAME(Xp_mulx)(xpx, ACSIZE, xpf, ACSIZE, xpt); } n >>= 1; if (n == 0) { break; } FNAME(Xp_movx)(xpw, ACSIZE, xpf); FNAME(Xp_mulx)(xpf, ACSIZE, xpw, ACSIZE, xpt); // square 10^n } if (xpf[0] < FLIT(1.0)) { FNAME(Xp_ldexpx)(xpx, ACSIZE, -BIAS); // scale down result } x = FNAME(Xp_getw)(xpx, ACSIZE); if (x == FLIT(0.0) || x == FCONST(Inf) || x == -FCONST(Inf)) { // report error and set errno errno = ERANGE; if (perr != nullptr) { *perr |= 1; } } return x; } #if !defined(MRTDLL) } // extern "C" #endif // !defined(MRTDLL)