Skip to content

Commit 7b8f045

Browse files
committed
implemented multiplication of integer by power of 10
1 parent 0a9257e commit 7b8f045

File tree

2 files changed

+116
-38
lines changed

2 files changed

+116
-38
lines changed

include/fast_float/fast_float.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,28 @@ FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
4545
from_chars_advanced(UC const *first, UC const *last, T &value,
4646
parse_options_t<UC> options) noexcept;
4747

48+
/**
49+
* This function multiplies an integer number by a power of 10 and returns
50+
* the result as a double precision floating-point value that is correctly
51+
* rounded. The resulting floating-point value is the closest floating-point
52+
* value, using the "round to nearest, tie to even" convention for values that
53+
* would otherwise fall right in-between two values. That is, we provide exact
54+
* conversion according to the IEEE standard.
55+
*
56+
* On overflow infinity is returned, on underflow 0 is returned.
57+
*
58+
* The implementation does not throw and does not allocate memory (e.g., with
59+
* `new` or `malloc`).
60+
*/
61+
FASTFLOAT_CONSTEXPR20
62+
typename std::enable_if<is_supported_float_type<double>::value, double>::type
63+
multiply_integer_and_power_of_10(uint64_t mantissa,
64+
int decimal_exponent) noexcept;
65+
FASTFLOAT_CONSTEXPR20
66+
typename std::enable_if<is_supported_float_type<double>::value, double>::type
67+
multiply_integer_and_power_of_10(int64_t mantissa,
68+
int decimal_exponent) noexcept;
69+
4870
/**
4971
* from_chars for integer types.
5072
*/

include/fast_float/parse_number.h

Lines changed: 94 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -188,32 +188,17 @@ from_chars(UC const *first, UC const *last, T &value,
188188
parse_options_t<UC>(fmt));
189189
}
190190

191-
/**
192-
* This function overload takes parsed_number_string_t structure that is created
193-
* and populated either by from_chars_advanced function taking chars range and
194-
* parsing options or other parsing custom function implemented by user.
195-
*/
196-
template <typename T, typename UC>
197-
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
198-
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
199-
200-
static_assert(is_supported_float_type<T>::value,
201-
"only some floating-point types are supported");
202-
static_assert(is_supported_char_type<UC>::value,
203-
"only char, wchar_t, char16_t and char32_t are supported");
204-
205-
from_chars_result_t<UC> answer;
206-
207-
answer.ec = std::errc(); // be optimistic
208-
answer.ptr = pns.lastmatch;
191+
template <typename T>
192+
FASTFLOAT_CONSTEXPR20 bool
193+
clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative,
194+
T &value) noexcept {
209195
// The implementation of the Clinger's fast path is convoluted because
210196
// we want round-to-nearest in all cases, irrespective of the rounding mode
211197
// selected on the thread.
212198
// We proceed optimistically, assuming that detail::rounds_to_nearest()
213199
// returns true.
214-
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent &&
215-
pns.exponent <= binary_format<T>::max_exponent_fast_path() &&
216-
!pns.too_many_digits) {
200+
if (binary_format<T>::min_exponent_fast_path() <= exponent &&
201+
exponent <= binary_format<T>::max_exponent_fast_path()) {
217202
// Unfortunately, the conventional Clinger's fast path is only possible
218203
// when the system rounds to the nearest float.
219204
//
@@ -224,41 +209,64 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
224209
if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
225210
// We have that fegetround() == FE_TONEAREST.
226211
// Next is Clinger's fast path.
227-
if (pns.mantissa <= binary_format<T>::max_mantissa_fast_path()) {
228-
value = T(pns.mantissa);
229-
if (pns.exponent < 0) {
230-
value = value / binary_format<T>::exact_power_of_ten(-pns.exponent);
212+
if (mantissa <= binary_format<T>::max_mantissa_fast_path()) {
213+
value = T(mantissa);
214+
if (exponent < 0) {
215+
value = value / binary_format<T>::exact_power_of_ten(-exponent);
231216
} else {
232-
value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
217+
value = value * binary_format<T>::exact_power_of_ten(exponent);
233218
}
234-
if (pns.negative) {
219+
if (is_negative) {
235220
value = -value;
236221
}
237-
return answer;
222+
return true;
238223
}
239224
} else {
240225
// We do not have that fegetround() == FE_TONEAREST.
241226
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
242227
// proposal
243-
if (pns.exponent >= 0 &&
244-
pns.mantissa <=
245-
binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
228+
if (exponent >= 0 &&
229+
mantissa <= binary_format<T>::max_mantissa_fast_path(exponent)) {
246230
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
247231
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
248-
if (pns.mantissa == 0) {
249-
value = pns.negative ? T(-0.) : T(0.);
250-
return answer;
232+
if (mantissa == 0) {
233+
value = is_negative ? T(-0.) : T(0.);
234+
return true;
251235
}
252236
#endif
253-
value = T(pns.mantissa) *
254-
binary_format<T>::exact_power_of_ten(pns.exponent);
255-
if (pns.negative) {
237+
value = T(mantissa) * binary_format<T>::exact_power_of_ten(exponent);
238+
if (is_negative) {
256239
value = -value;
257240
}
258-
return answer;
241+
return true;
259242
}
260243
}
261244
}
245+
return false;
246+
}
247+
248+
/**
249+
* This function overload takes parsed_number_string_t structure that is created
250+
* and populated either by from_chars_advanced function taking chars range and
251+
* parsing options or other parsing custom function implemented by user.
252+
*/
253+
template <typename T, typename UC>
254+
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
255+
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
256+
static_assert(is_supported_float_type<T>::value,
257+
"only some floating-point types are supported");
258+
static_assert(is_supported_char_type<UC>::value,
259+
"only char, wchar_t, char16_t and char32_t are supported");
260+
261+
from_chars_result_t<UC> answer;
262+
263+
answer.ec = std::errc(); // be optimistic
264+
answer.ptr = pns.lastmatch;
265+
266+
if (!pns.too_many_digits &&
267+
clinger_fast_path_impl(pns.mantissa, pns.exponent, pns.negative, value))
268+
return answer;
269+
262270
adjusted_mantissa am =
263271
compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
264272
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 {
336344
return from_chars_advanced(first, last, value, options);
337345
}
338346

347+
FASTFLOAT_CONSTEXPR20
348+
typename std::enable_if<is_supported_float_type<double>::value, double>::type
349+
multiply_integer_and_power_of_10(uint64_t mantissa,
350+
int decimal_exponent) noexcept {
351+
double value;
352+
if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value))
353+
return value;
354+
355+
adjusted_mantissa am =
356+
compute_float<binary_format<double>>(decimal_exponent, mantissa);
357+
to_float(false, am, value);
358+
return value;
359+
}
360+
361+
FASTFLOAT_CONSTEXPR20
362+
typename std::enable_if<is_supported_float_type<double>::value, double>::type
363+
multiply_integer_and_power_of_10(int64_t mantissa,
364+
int decimal_exponent) noexcept {
365+
const bool is_negative = mantissa < 0;
366+
const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa);
367+
368+
double value;
369+
if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value))
370+
return value;
371+
372+
adjusted_mantissa am =
373+
compute_float<binary_format<double>>(decimal_exponent, m);
374+
to_float(is_negative, am, value);
375+
return value;
376+
}
377+
378+
// the following overloads are here to avoid surprising ambiguity for int,
379+
// unsigned, etc.
380+
FASTFLOAT_CONSTEXPR20
381+
typename std::enable_if<is_supported_float_type<double>::value, double>::type
382+
multiply_integer_and_power_of_10(unsigned mantissa,
383+
int decimal_exponent) noexcept {
384+
return multiply_integer_and_power_of_10(static_cast<uint64_t>(mantissa),
385+
decimal_exponent);
386+
}
387+
388+
FASTFLOAT_CONSTEXPR20
389+
typename std::enable_if<is_supported_float_type<double>::value, double>::type
390+
multiply_integer_and_power_of_10(int mantissa, int decimal_exponent) noexcept {
391+
return multiply_integer_and_power_of_10(static_cast<int64_t>(mantissa),
392+
decimal_exponent);
393+
}
394+
339395
template <typename T, typename UC>
340396
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
341397
from_chars_int_advanced(UC const *first, UC const *last, T &value,

0 commit comments

Comments
 (0)