mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-01-01 03:12:18 +08:00
implemented multiplication of integer by power of 10
This commit is contained in:
parent
0a9257e825
commit
7b8f04500a
@ -45,6 +45,28 @@ FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
|||||||
from_chars_advanced(UC const *first, UC const *last, T &value,
|
from_chars_advanced(UC const *first, UC const *last, T &value,
|
||||||
parse_options_t<UC> options) noexcept;
|
parse_options_t<UC> options) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function multiplies an integer number by a power of 10 and returns
|
||||||
|
* the result as a double precision floating-point value that is correctly
|
||||||
|
* rounded. The resulting floating-point value is the closest floating-point
|
||||||
|
* value, using the "round to nearest, tie to even" convention for values that
|
||||||
|
* would otherwise fall right in-between two values. That is, we provide exact
|
||||||
|
* conversion according to the IEEE standard.
|
||||||
|
*
|
||||||
|
* On overflow infinity is returned, on underflow 0 is returned.
|
||||||
|
*
|
||||||
|
* The implementation does not throw and does not allocate memory (e.g., with
|
||||||
|
* `new` or `malloc`).
|
||||||
|
*/
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
|
typename std::enable_if<is_supported_float_type<double>::value, double>::type
|
||||||
|
multiply_integer_and_power_of_10(uint64_t mantissa,
|
||||||
|
int decimal_exponent) noexcept;
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
|
typename std::enable_if<is_supported_float_type<double>::value, double>::type
|
||||||
|
multiply_integer_and_power_of_10(int64_t mantissa,
|
||||||
|
int decimal_exponent) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* from_chars for integer types.
|
* from_chars for integer types.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -188,32 +188,17 @@ from_chars(UC const *first, UC const *last, T &value,
|
|||||||
parse_options_t<UC>(fmt));
|
parse_options_t<UC>(fmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
template <typename T>
|
||||||
* This function overload takes parsed_number_string_t structure that is created
|
FASTFLOAT_CONSTEXPR20 bool
|
||||||
* and populated either by from_chars_advanced function taking chars range and
|
clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative,
|
||||||
* parsing options or other parsing custom function implemented by user.
|
T &value) noexcept {
|
||||||
*/
|
|
||||||
template <typename T, typename UC>
|
|
||||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
|
||||||
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
|
||||||
|
|
||||||
static_assert(is_supported_float_type<T>::value,
|
|
||||||
"only some floating-point types are supported");
|
|
||||||
static_assert(is_supported_char_type<UC>::value,
|
|
||||||
"only char, wchar_t, char16_t and char32_t are supported");
|
|
||||||
|
|
||||||
from_chars_result_t<UC> answer;
|
|
||||||
|
|
||||||
answer.ec = std::errc(); // be optimistic
|
|
||||||
answer.ptr = pns.lastmatch;
|
|
||||||
// The implementation of the Clinger's fast path is convoluted because
|
// The implementation of the Clinger's fast path is convoluted because
|
||||||
// we want round-to-nearest in all cases, irrespective of the rounding mode
|
// we want round-to-nearest in all cases, irrespective of the rounding mode
|
||||||
// selected on the thread.
|
// selected on the thread.
|
||||||
// We proceed optimistically, assuming that detail::rounds_to_nearest()
|
// We proceed optimistically, assuming that detail::rounds_to_nearest()
|
||||||
// returns true.
|
// returns true.
|
||||||
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
|
if (binary_format<T>::min_exponent_fast_path() <= exponent &&
|
||||||
pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
|
exponent <= binary_format<T>::max_exponent_fast_path()) {
|
||||||
!pns.too_many_digits) {
|
|
||||||
// Unfortunately, the conventional Clinger's fast path is only possible
|
// Unfortunately, the conventional Clinger's fast path is only possible
|
||||||
// when the system rounds to the nearest float.
|
// when the system rounds to the nearest float.
|
||||||
//
|
//
|
||||||
@ -224,41 +209,64 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
|||||||
if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
|
if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
|
||||||
// We have that fegetround() == FE_TONEAREST.
|
// We have that fegetround() == FE_TONEAREST.
|
||||||
// Next is Clinger's fast path.
|
// Next is Clinger's fast path.
|
||||||
if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
|
if (mantissa <= binary_format<T>::max_mantissa_fast_path()) {
|
||||||
value = T(pns.mantissa);
|
value = T(mantissa);
|
||||||
if (pns.exponent < 0) {
|
if (exponent < 0) {
|
||||||
value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
|
value = value / binary_format<T>::exact_power_of_ten(-exponent);
|
||||||
} else {
|
} else {
|
||||||
value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
|
value = value * binary_format<T>::exact_power_of_ten(exponent);
|
||||||
}
|
}
|
||||||
if (pns.negative) {
|
if (is_negative) {
|
||||||
value = -value;
|
value = -value;
|
||||||
}
|
}
|
||||||
return answer;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We do not have that fegetround() == FE_TONEAREST.
|
// We do not have that fegetround() == FE_TONEAREST.
|
||||||
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
|
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
|
||||||
// proposal
|
// proposal
|
||||||
if (pns.exponent >= 0 &&
|
if (exponent >= 0 &&
|
||||||
pns.mantissa <=
|
mantissa <= binary_format<T>::max_mantissa_fast_path(exponent)) {
|
||||||
binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
|
|
||||||
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
|
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
|
||||||
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
||||||
if (pns.mantissa == 0) {
|
if (mantissa == 0) {
|
||||||
value = pns.negative ? T(-0.) : T(0.);
|
value = is_negative ? T(-0.) : T(0.);
|
||||||
return answer;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
value = T(pns.mantissa) *
|
value = T(mantissa) * binary_format<T>::exact_power_of_ten(exponent);
|
||||||
binary_format<T>::exact_power_of_ten(pns.exponent);
|
if (is_negative) {
|
||||||
if (pns.negative) {
|
|
||||||
value = -value;
|
value = -value;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function overload takes parsed_number_string_t structure that is created
|
||||||
|
* and populated either by from_chars_advanced function taking chars range and
|
||||||
|
* parsing options or other parsing custom function implemented by user.
|
||||||
|
*/
|
||||||
|
template <typename T, typename UC>
|
||||||
|
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||||
|
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
||||||
|
static_assert(is_supported_float_type<T>::value,
|
||||||
|
"only some floating-point types are supported");
|
||||||
|
static_assert(is_supported_char_type<UC>::value,
|
||||||
|
"only char, wchar_t, char16_t and char32_t are supported");
|
||||||
|
|
||||||
|
from_chars_result_t<UC> answer;
|
||||||
|
|
||||||
|
answer.ec = std::errc(); // be optimistic
|
||||||
|
answer.ptr = pns.lastmatch;
|
||||||
|
|
||||||
|
if (!pns.too_many_digits &&
|
||||||
|
clinger_fast_path_impl(pns.mantissa, pns.exponent, pns.negative, value))
|
||||||
return answer;
|
return answer;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
adjusted_mantissa am =
|
adjusted_mantissa am =
|
||||||
compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
|
compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
|
||||||
if (pns.too_many_digits && am.power2 >= 0) {
|
if (pns.too_many_digits && am.power2 >= 0) {
|
||||||
@ -336,6 +344,54 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
|
|||||||
return from_chars_advanced(first, last, value, options);
|
return from_chars_advanced(first, last, value, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
|
typename std::enable_if<is_supported_float_type<double>::value, double>::type
|
||||||
|
multiply_integer_and_power_of_10(uint64_t mantissa,
|
||||||
|
int decimal_exponent) noexcept {
|
||||||
|
double value;
|
||||||
|
if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value))
|
||||||
|
return value;
|
||||||
|
|
||||||
|
adjusted_mantissa am =
|
||||||
|
compute_float<binary_format<double>>(decimal_exponent, mantissa);
|
||||||
|
to_float(false, am, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
|
typename std::enable_if<is_supported_float_type<double>::value, double>::type
|
||||||
|
multiply_integer_and_power_of_10(int64_t mantissa,
|
||||||
|
int decimal_exponent) noexcept {
|
||||||
|
const bool is_negative = mantissa < 0;
|
||||||
|
const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa);
|
||||||
|
|
||||||
|
double value;
|
||||||
|
if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value))
|
||||||
|
return value;
|
||||||
|
|
||||||
|
adjusted_mantissa am =
|
||||||
|
compute_float<binary_format<double>>(decimal_exponent, m);
|
||||||
|
to_float(is_negative, am, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following overloads are here to avoid surprising ambiguity for int,
|
||||||
|
// unsigned, etc.
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
|
typename std::enable_if<is_supported_float_type<double>::value, double>::type
|
||||||
|
multiply_integer_and_power_of_10(unsigned mantissa,
|
||||||
|
int decimal_exponent) noexcept {
|
||||||
|
return multiply_integer_and_power_of_10(static_cast<uint64_t>(mantissa),
|
||||||
|
decimal_exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
|
typename std::enable_if<is_supported_float_type<double>::value, double>::type
|
||||||
|
multiply_integer_and_power_of_10(int mantissa, int decimal_exponent) noexcept {
|
||||||
|
return multiply_integer_and_power_of_10(static_cast<int64_t>(mantissa),
|
||||||
|
decimal_exponent);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename UC>
|
template <typename T, typename UC>
|
||||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||||
from_chars_int_advanced(UC const *first, UC const *last, T &value,
|
from_chars_int_advanced(UC const *first, UC const *last, T &value,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user