//
// cfout.cpp
//
//      Copyright (c) Microsoft Corporation. All rights reserved.
//
// Floating point binary to decimal conversion routines
//
#include <corecrt_internal_fltintrn.h>
#include <corecrt_internal_big_integer.h>
#include <fenv.h>
#include <string.h>



using namespace __crt_strtox;

namespace
{
    class scoped_fp_state_reset
    {
    public:

        scoped_fp_state_reset() throw()
        {
            // The calls to feholdexcept and fesetenv are relatively expensive,
            // so we only call them if there are any unmasked exceptions.
            fegetenv(&_environment);
            if ((_environment._Fe_ctl & FE_ALL_EXCEPT) == FE_ALL_EXCEPT)
            {
                _requires_reset = false;
            }
            else
            {
                feholdexcept(&_environment);
                _requires_reset = true;
            }
        }

        ~scoped_fp_state_reset() throw()
        {
            if (_requires_reset)
            {
                fesetenv(&_environment);
            }
        }

    private:

        scoped_fp_state_reset(scoped_fp_state_reset const&);
        scoped_fp_state_reset& operator=(scoped_fp_state_reset const&);

        fenv_t _environment;
        bool   _requires_reset;
    };
}



// This function converts a finite, positive floating point value into its
// decimal representation.  The decimal mantissa and exponent are returned
// via the out parameters.  If the value is zero, negative, infinity, or nan,
// the behavior is undefined.
//
// This function is based on the digit generation algorithm described in the
// paper "Printing floating point numbers quickly and accurately," by Robert G.
// Burger and R. Kent Dybvig, from ACM SIGPLAN 1996 Conference on Programming
// Language Design and Implementation, June 1996.  This function deviates from
// that algorithm in its termination conditions:  the Burger-Dybvig algorithm
// terminates when it runs out of significant digits; this function continues
// generating digits, even if they are insignificant (this allows us to print
// large, exactly representable values exactly, e.g. large powers of two).
//
// This function stops generating digits when the first of the following
// conditions is true:  [1] the mantissa buffer is exhausted, [2] sufficient
// digits have been generated for a %f specifier with the requested precision,
// or [3] all remaining digits are known to be zero.
template <typename FloatingType>
__forceinline static void __cdecl convert_to_fos_high_precision(
    FloatingType const value,
    uint32_t     const precision,
    int*         const exponent,
    char*        const mantissa_buffer,
    size_t       const mantissa_buffer_count
    ) throw()
{
    using floating_traits = __acrt_floating_type_traits<FloatingType>;
    using components_type = typename floating_traits::components_type;

    _ASSERTE(mantissa_buffer_count > 0);

    components_type const& value_components = reinterpret_cast<components_type const&>(value);

    // Special handling is required for denormal values:  because the implicit
    // high order bit is a zero, not a one, we need to [1] not set that bit when
    // we expand the mantissa, and [2] increment the exponent to account for the
    // extra shift.
    bool const is_denormal = value_components._exponent == 0;

    uint64_t const mantissa_adjustment = is_denormal
        ? 0
        : static_cast<uint64_t>(1) << (floating_traits::mantissa_bits - 1);

    int32_t const exponent_adjustment = is_denormal
        ? 2
        : 1;

    // f and e are the unbiased mantissa and exponent, respectively.  (Where one-
    // -letter variable names are used, they match the same variables from the
    // Burger-Dybvig paper.)
    uint64_t const f = value_components._mantissa + mantissa_adjustment;
    int32_t  const e =
        static_cast<int32_t>(value_components._exponent) -
        floating_traits::exponent_bias -
        floating_traits::mantissa_bits +
        exponent_adjustment;

    // k is the decimal exponent, such that the resulting decimal number is of
    // the form 0.mmmmm * 10^k, where mmmm are the mantissa digits we generate.
    // Note that the use of log10 here may not give the correct result:  it may
    // be off by one, e.g. as is the case for powers of ten (log10(100) is two,
    // but the correct value of k for 100 is 3).  We detect off-by-one errors
    // later and correct for them.
    int32_t k = static_cast<int32_t>(ceil(log10(value)));
    if (k == INT32_MAX || k == INT32_MIN)
    {
        _ASSERTE(("unexpected input value; log10 failed", 0));
        k = 0;
    }

    // The floating point number is represented as a fraction, r / s.  The
    // initialization of these two values is as described in the Burger-Dybvig
    // paper.
    big_integer r = make_big_integer(f);
    big_integer s{};

    if (e >= 0)
    {
        if (r != make_big_integer_power_of_two(floating_traits::mantissa_bits - 1))
        {
            shift_left(r, e + 1);   // f * b^e * 2
            s = make_big_integer(2); // 2
        }
        else
        {
            shift_left(r, e + 2);   // f * b^(e+1) * 2
            s = make_big_integer(4); // b * 2
        }
    }
    else
    {
        if (e == floating_traits::minimum_binary_exponent ||
            r != make_big_integer_power_of_two(floating_traits::mantissa_bits - 1))
        {
            shift_left(r, 1);                          // f * 2
            s = make_big_integer_power_of_two(-e + 1); // b^-e * 2
        }
        else
        {
            shift_left(r, 2);                          // f * b * 2
            s = make_big_integer_power_of_two(-e + 2); // b^(-e+1) * 2
        }
    }

    if (k >= 0)
    {
        multiply_by_power_of_ten(s, k);
    }
    else
    {
        multiply_by_power_of_ten(r, -k);
    }

    char* mantissa_it = mantissa_buffer;

    // Perform a trial digit generation to handle off-by-one errors in the
    // computation of 'k':  There are three possible cases, which we handle
    // in turn:
    multiply(r, 10);
    uint32_t const initial_digit = static_cast<uint32_t>(divide(r, s));

    // If the initial digit was computed as 10, k is too small.  We increment k
    // and adjust s as if it had been computed with the correct k above.  We
    // then treat the digit as a one, which is what it would have been extracted
    // as had k, r, and s been correct to begin with.
    if (initial_digit == 10)
    {
        ++k;
        *mantissa_it++ = '1';
        multiply(s, 10);
    }
    // If the initial digit is zero, k is too large.  We decrement k and ignore
    // the zero that we read (the next digit that we read will be the "real"
    // initial digit.
    else if (initial_digit == 0)
    {
        --k;
    }
    // Otherwise, k was correct and the digit we read was the actual initial
    // digit of the number; just store it.
    else
    {
        *mantissa_it++ = static_cast<char>('0' + initial_digit);
    }

    *exponent = k; // k is now correct; store it for our caller

    uint32_t const required_digits = k >= 0 && precision <= INT_MAX
        ? k + precision
        : precision;

    char* const mantissa_last = mantissa_buffer + __min(mantissa_buffer_count - 1, required_digits);
    for (;;)
    {
        if (mantissa_it == mantissa_last)
        {
            break;
        }

        if (is_zero(r))
        {
            break;
        }

        // To reduce the number of expensive high precision division operations,
        // we generate multiple digits per iteration.  Our quotient type is a
        // uint32_t, and the largest power of ten representable by a uint32_t is
        // 10^9, so we generate nine digits per iteration.
        uint32_t const digits_per_iteration            = 9;
        uint32_t const digits_per_iteration_multiplier = 1000 * 1000 * 1000;

        multiply(r, digits_per_iteration_multiplier);
        uint32_t quotient = static_cast<uint32_t>(divide(r, s));

        _ASSERTE(quotient < digits_per_iteration_multiplier);

        // Decompose the quotient into its nine component digits by repeatedly
        // dividing by ten.  This generates digits in reverse order.
        #pragma warning(suppress: 6293) // For-loop counts down from minimum
        for (uint32_t i = digits_per_iteration - 1; i != static_cast<uint32_t>(-1); --i)
        {
            char const d = static_cast<char>('0' + quotient % 10);
            quotient /= 10;

            // We may not have room in the mantissa buffer for all of the digits;
            // ignore the ones for which we do not have room:
            if (static_cast<uint32_t>(mantissa_last - mantissa_it) < i)
            {
                continue;
            }

            mantissa_it[i] = d;
        }

        mantissa_it += __min(digits_per_iteration, mantissa_last - mantissa_it);
    }

    *mantissa_it = '\0';
}

extern "C" void __cdecl __acrt_fltout(
    _CRT_DOUBLE       value,
    unsigned    const precision,
    STRFLT      const flt,
    char*       const result,
    size_t      const result_count
    )
{
    using floating_traits = __acrt_floating_type_traits<double>;
    using components_type = floating_traits::components_type;

    scoped_fp_state_reset const reset_fp_state;

    components_type& components = reinterpret_cast<components_type&>(value);

    flt->sign     = components._sign == 1 ? '-' : ' ';
    flt->mantissa = result;

    bool const value_is_zero = components._exponent == 0 && components._mantissa == 0;
    if (value_is_zero)
    {
        flt->decpt = 0;
        _ERRCHECK(strcpy_s(result, result_count, "0"));
        return;
    }

    // Handle special cases:
    __acrt_fp_class const classification = __acrt_fp_classify(value.x);
    if (classification != __acrt_fp_class::finite)
    {
        flt->decpt = 1;
    }

    switch (classification)
    {
    case __acrt_fp_class::infinity:      _ERRCHECK(strcpy_s(result, result_count, "1#INF" )); return;
    case __acrt_fp_class::quiet_nan:     _ERRCHECK(strcpy_s(result, result_count, "1#QNAN")); return;
    case __acrt_fp_class::signaling_nan: _ERRCHECK(strcpy_s(result, result_count, "1#SNAN")); return;
    case __acrt_fp_class::indeterminate: _ERRCHECK(strcpy_s(result, result_count, "1#IND" )); return;
    }

    // Make the number positive before we pass it to the digit generator:
    components._sign = 0;

    // The digit generator produces a truncated sequence of digits.  To allow
    // our caller to correctly round the mantissa, we need to generate an extra
    // digit.
    convert_to_fos_high_precision(value.x, precision + 1, &flt->decpt, result, result_count);
}
