in cpp/src/arrow/vendored/double-conversion/string-to-double.cc [257:417]
static double RadixStringToIeee(Iterator* current,
Iterator end,
bool sign,
uc16 separator,
bool parse_as_hex_float,
bool allow_trailing_junk,
double junk_string_value,
bool read_as_double,
bool* result_is_junk) {
DOUBLE_CONVERSION_ASSERT(*current != end);
DOUBLE_CONVERSION_ASSERT(!parse_as_hex_float ||
IsHexFloatString(*current, end, separator, allow_trailing_junk));
const int kDoubleSize = Double::kSignificandSize;
const int kSingleSize = Single::kSignificandSize;
const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize;
*result_is_junk = true;
int64_t number = 0;
int exponent = 0;
const int radix = (1 << radix_log_2);
// Whether we have encountered a '.' and are parsing the decimal digits.
// Only relevant if parse_as_hex_float is true.
bool post_decimal = false;
// Skip leading 0s.
while (**current == '0') {
if (Advance(current, separator, radix, end)) {
*result_is_junk = false;
return SignedZero(sign);
}
}
while (true) {
int digit;
if (IsDecimalDigitForRadix(**current, radix)) {
digit = static_cast<char>(**current) - '0';
if (post_decimal) exponent -= radix_log_2;
} else if (IsCharacterDigitForRadix(**current, radix, 'a')) {
digit = static_cast<char>(**current) - 'a' + 10;
if (post_decimal) exponent -= radix_log_2;
} else if (IsCharacterDigitForRadix(**current, radix, 'A')) {
digit = static_cast<char>(**current) - 'A' + 10;
if (post_decimal) exponent -= radix_log_2;
} else if (parse_as_hex_float && **current == '.') {
post_decimal = true;
Advance(current, separator, radix, end);
DOUBLE_CONVERSION_ASSERT(*current != end);
continue;
} else if (parse_as_hex_float && (**current == 'p' || **current == 'P')) {
break;
} else {
if (allow_trailing_junk || !AdvanceToNonspace(current, end)) {
break;
} else {
return junk_string_value;
}
}
number = number * radix + digit;
int overflow = static_cast<int>(number >> kSignificandSize);
if (overflow != 0) {
// Overflow occurred. Need to determine which direction to round the
// result.
int overflow_bits_count = 1;
while (overflow > 1) {
overflow_bits_count++;
overflow >>= 1;
}
int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
number >>= overflow_bits_count;
exponent += overflow_bits_count;
bool zero_tail = true;
for (;;) {
if (Advance(current, separator, radix, end)) break;
if (parse_as_hex_float && **current == '.') {
// Just run over the '.'. We are just trying to see whether there is
// a non-zero digit somewhere.
Advance(current, separator, radix, end);
DOUBLE_CONVERSION_ASSERT(*current != end);
post_decimal = true;
}
if (!isDigit(**current, radix)) break;
zero_tail = zero_tail && **current == '0';
if (!post_decimal) exponent += radix_log_2;
}
if (!parse_as_hex_float &&
!allow_trailing_junk &&
AdvanceToNonspace(current, end)) {
return junk_string_value;
}
int middle_value = (1 << (overflow_bits_count - 1));
if (dropped_bits > middle_value) {
number++; // Rounding up.
} else if (dropped_bits == middle_value) {
// Rounding to even to consistency with decimals: half-way case rounds
// up if significant part is odd and down otherwise.
if ((number & 1) != 0 || !zero_tail) {
number++; // Rounding up.
}
}
// Rounding up may cause overflow.
if ((number & ((int64_t)1 << kSignificandSize)) != 0) {
exponent++;
number >>= 1;
}
break;
}
if (Advance(current, separator, radix, end)) break;
}
DOUBLE_CONVERSION_ASSERT(number < ((int64_t)1 << kSignificandSize));
DOUBLE_CONVERSION_ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
*result_is_junk = false;
if (parse_as_hex_float) {
DOUBLE_CONVERSION_ASSERT(**current == 'p' || **current == 'P');
Advance(current, separator, radix, end);
DOUBLE_CONVERSION_ASSERT(*current != end);
bool is_negative = false;
if (**current == '+') {
Advance(current, separator, radix, end);
DOUBLE_CONVERSION_ASSERT(*current != end);
} else if (**current == '-') {
is_negative = true;
Advance(current, separator, radix, end);
DOUBLE_CONVERSION_ASSERT(*current != end);
}
int written_exponent = 0;
while (IsDecimalDigitForRadix(**current, 10)) {
// No need to read exponents if they are too big. That could potentially overflow
// the `written_exponent` variable.
if (abs(written_exponent) <= 100 * Double::kMaxExponent) {
written_exponent = 10 * written_exponent + **current - '0';
}
if (Advance(current, separator, radix, end)) break;
}
if (is_negative) written_exponent = -written_exponent;
exponent += written_exponent;
}
if (exponent == 0 || number == 0) {
if (sign) {
if (number == 0) return -0.0;
number = -number;
}
return static_cast<double>(number);
}
DOUBLE_CONVERSION_ASSERT(number != 0);
double result = Double(DiyFp(number, exponent)).value();
return sign ? -result : result;
}