mfbt/double-conversion/double-conversion.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright 2010 the V8 project authors. All rights reserved.
michael@0 2 // Redistribution and use in source and binary forms, with or without
michael@0 3 // modification, are permitted provided that the following conditions are
michael@0 4 // met:
michael@0 5 //
michael@0 6 // * Redistributions of source code must retain the above copyright
michael@0 7 // notice, this list of conditions and the following disclaimer.
michael@0 8 // * Redistributions in binary form must reproduce the above
michael@0 9 // copyright notice, this list of conditions and the following
michael@0 10 // disclaimer in the documentation and/or other materials provided
michael@0 11 // with the distribution.
michael@0 12 // * Neither the name of Google Inc. nor the names of its
michael@0 13 // contributors may be used to endorse or promote products derived
michael@0 14 // from this software without specific prior written permission.
michael@0 15 //
michael@0 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 27
michael@0 28 #include <limits.h>
michael@0 29 #include <math.h>
michael@0 30
michael@0 31 #include "double-conversion.h"
michael@0 32
michael@0 33 #include "bignum-dtoa.h"
michael@0 34 #include "fast-dtoa.h"
michael@0 35 #include "fixed-dtoa.h"
michael@0 36 #include "ieee.h"
michael@0 37 #include "strtod.h"
michael@0 38 #include "utils.h"
michael@0 39
michael@0 40 namespace double_conversion {
michael@0 41
michael@0 42 const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {
michael@0 43 int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
michael@0 44 static DoubleToStringConverter converter(flags,
michael@0 45 "Infinity",
michael@0 46 "NaN",
michael@0 47 'e',
michael@0 48 -6, 21,
michael@0 49 6, 0);
michael@0 50 return converter;
michael@0 51 }
michael@0 52
michael@0 53
michael@0 54 bool DoubleToStringConverter::HandleSpecialValues(
michael@0 55 double value,
michael@0 56 StringBuilder* result_builder) const {
michael@0 57 Double double_inspect(value);
michael@0 58 if (double_inspect.IsInfinite()) {
michael@0 59 if (infinity_symbol_ == NULL) return false;
michael@0 60 if (value < 0) {
michael@0 61 result_builder->AddCharacter('-');
michael@0 62 }
michael@0 63 result_builder->AddString(infinity_symbol_);
michael@0 64 return true;
michael@0 65 }
michael@0 66 if (double_inspect.IsNan()) {
michael@0 67 if (nan_symbol_ == NULL) return false;
michael@0 68 result_builder->AddString(nan_symbol_);
michael@0 69 return true;
michael@0 70 }
michael@0 71 return false;
michael@0 72 }
michael@0 73
michael@0 74
michael@0 75 void DoubleToStringConverter::CreateExponentialRepresentation(
michael@0 76 const char* decimal_digits,
michael@0 77 int length,
michael@0 78 int exponent,
michael@0 79 StringBuilder* result_builder) const {
michael@0 80 ASSERT(length != 0);
michael@0 81 result_builder->AddCharacter(decimal_digits[0]);
michael@0 82 if (length != 1) {
michael@0 83 result_builder->AddCharacter('.');
michael@0 84 result_builder->AddSubstring(&decimal_digits[1], length-1);
michael@0 85 }
michael@0 86 result_builder->AddCharacter(exponent_character_);
michael@0 87 if (exponent < 0) {
michael@0 88 result_builder->AddCharacter('-');
michael@0 89 exponent = -exponent;
michael@0 90 } else {
michael@0 91 if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
michael@0 92 result_builder->AddCharacter('+');
michael@0 93 }
michael@0 94 }
michael@0 95 if (exponent == 0) {
michael@0 96 result_builder->AddCharacter('0');
michael@0 97 return;
michael@0 98 }
michael@0 99 ASSERT(exponent < 1e4);
michael@0 100 const int kMaxExponentLength = 5;
michael@0 101 char buffer[kMaxExponentLength + 1];
michael@0 102 buffer[kMaxExponentLength] = '\0';
michael@0 103 int first_char_pos = kMaxExponentLength;
michael@0 104 while (exponent > 0) {
michael@0 105 buffer[--first_char_pos] = '0' + (exponent % 10);
michael@0 106 exponent /= 10;
michael@0 107 }
michael@0 108 result_builder->AddSubstring(&buffer[first_char_pos],
michael@0 109 kMaxExponentLength - first_char_pos);
michael@0 110 }
michael@0 111
michael@0 112
michael@0 113 void DoubleToStringConverter::CreateDecimalRepresentation(
michael@0 114 const char* decimal_digits,
michael@0 115 int length,
michael@0 116 int decimal_point,
michael@0 117 int digits_after_point,
michael@0 118 StringBuilder* result_builder) const {
michael@0 119 // Create a representation that is padded with zeros if needed.
michael@0 120 if (decimal_point <= 0) {
michael@0 121 // "0.00000decimal_rep".
michael@0 122 result_builder->AddCharacter('0');
michael@0 123 if (digits_after_point > 0) {
michael@0 124 result_builder->AddCharacter('.');
michael@0 125 result_builder->AddPadding('0', -decimal_point);
michael@0 126 ASSERT(length <= digits_after_point - (-decimal_point));
michael@0 127 result_builder->AddSubstring(decimal_digits, length);
michael@0 128 int remaining_digits = digits_after_point - (-decimal_point) - length;
michael@0 129 result_builder->AddPadding('0', remaining_digits);
michael@0 130 }
michael@0 131 } else if (decimal_point >= length) {
michael@0 132 // "decimal_rep0000.00000" or "decimal_rep.0000"
michael@0 133 result_builder->AddSubstring(decimal_digits, length);
michael@0 134 result_builder->AddPadding('0', decimal_point - length);
michael@0 135 if (digits_after_point > 0) {
michael@0 136 result_builder->AddCharacter('.');
michael@0 137 result_builder->AddPadding('0', digits_after_point);
michael@0 138 }
michael@0 139 } else {
michael@0 140 // "decima.l_rep000"
michael@0 141 ASSERT(digits_after_point > 0);
michael@0 142 result_builder->AddSubstring(decimal_digits, decimal_point);
michael@0 143 result_builder->AddCharacter('.');
michael@0 144 ASSERT(length - decimal_point <= digits_after_point);
michael@0 145 result_builder->AddSubstring(&decimal_digits[decimal_point],
michael@0 146 length - decimal_point);
michael@0 147 int remaining_digits = digits_after_point - (length - decimal_point);
michael@0 148 result_builder->AddPadding('0', remaining_digits);
michael@0 149 }
michael@0 150 if (digits_after_point == 0) {
michael@0 151 if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
michael@0 152 result_builder->AddCharacter('.');
michael@0 153 }
michael@0 154 if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
michael@0 155 result_builder->AddCharacter('0');
michael@0 156 }
michael@0 157 }
michael@0 158 }
michael@0 159
michael@0 160
michael@0 161 bool DoubleToStringConverter::ToShortestIeeeNumber(
michael@0 162 double value,
michael@0 163 StringBuilder* result_builder,
michael@0 164 DoubleToStringConverter::DtoaMode mode) const {
michael@0 165 ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE);
michael@0 166 if (Double(value).IsSpecial()) {
michael@0 167 return HandleSpecialValues(value, result_builder);
michael@0 168 }
michael@0 169
michael@0 170 int decimal_point;
michael@0 171 bool sign;
michael@0 172 const int kDecimalRepCapacity = kBase10MaximalLength + 1;
michael@0 173 char decimal_rep[kDecimalRepCapacity];
michael@0 174 int decimal_rep_length;
michael@0 175
michael@0 176 DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
michael@0 177 &sign, &decimal_rep_length, &decimal_point);
michael@0 178
michael@0 179 bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
michael@0 180 if (sign && (value != 0.0 || !unique_zero)) {
michael@0 181 result_builder->AddCharacter('-');
michael@0 182 }
michael@0 183
michael@0 184 int exponent = decimal_point - 1;
michael@0 185 if ((decimal_in_shortest_low_ <= exponent) &&
michael@0 186 (exponent < decimal_in_shortest_high_)) {
michael@0 187 CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
michael@0 188 decimal_point,
michael@0 189 Max(0, decimal_rep_length - decimal_point),
michael@0 190 result_builder);
michael@0 191 } else {
michael@0 192 CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
michael@0 193 result_builder);
michael@0 194 }
michael@0 195 return true;
michael@0 196 }
michael@0 197
michael@0 198
michael@0 199 bool DoubleToStringConverter::ToFixed(double value,
michael@0 200 int requested_digits,
michael@0 201 StringBuilder* result_builder) const {
michael@0 202 ASSERT(kMaxFixedDigitsBeforePoint == 60);
michael@0 203 const double kFirstNonFixed = 1e60;
michael@0 204
michael@0 205 if (Double(value).IsSpecial()) {
michael@0 206 return HandleSpecialValues(value, result_builder);
michael@0 207 }
michael@0 208
michael@0 209 if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
michael@0 210 if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
michael@0 211
michael@0 212 // Find a sufficiently precise decimal representation of n.
michael@0 213 int decimal_point;
michael@0 214 bool sign;
michael@0 215 // Add space for the '\0' byte.
michael@0 216 const int kDecimalRepCapacity =
michael@0 217 kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
michael@0 218 char decimal_rep[kDecimalRepCapacity];
michael@0 219 int decimal_rep_length;
michael@0 220 DoubleToAscii(value, FIXED, requested_digits,
michael@0 221 decimal_rep, kDecimalRepCapacity,
michael@0 222 &sign, &decimal_rep_length, &decimal_point);
michael@0 223
michael@0 224 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
michael@0 225 if (sign && (value != 0.0 || !unique_zero)) {
michael@0 226 result_builder->AddCharacter('-');
michael@0 227 }
michael@0 228
michael@0 229 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
michael@0 230 requested_digits, result_builder);
michael@0 231 return true;
michael@0 232 }
michael@0 233
michael@0 234
michael@0 235 bool DoubleToStringConverter::ToExponential(
michael@0 236 double value,
michael@0 237 int requested_digits,
michael@0 238 StringBuilder* result_builder) const {
michael@0 239 if (Double(value).IsSpecial()) {
michael@0 240 return HandleSpecialValues(value, result_builder);
michael@0 241 }
michael@0 242
michael@0 243 if (requested_digits < -1) return false;
michael@0 244 if (requested_digits > kMaxExponentialDigits) return false;
michael@0 245
michael@0 246 int decimal_point;
michael@0 247 bool sign;
michael@0 248 // Add space for digit before the decimal point and the '\0' character.
michael@0 249 const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
michael@0 250 ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
michael@0 251 char decimal_rep[kDecimalRepCapacity];
michael@0 252 int decimal_rep_length;
michael@0 253
michael@0 254 if (requested_digits == -1) {
michael@0 255 DoubleToAscii(value, SHORTEST, 0,
michael@0 256 decimal_rep, kDecimalRepCapacity,
michael@0 257 &sign, &decimal_rep_length, &decimal_point);
michael@0 258 } else {
michael@0 259 DoubleToAscii(value, PRECISION, requested_digits + 1,
michael@0 260 decimal_rep, kDecimalRepCapacity,
michael@0 261 &sign, &decimal_rep_length, &decimal_point);
michael@0 262 ASSERT(decimal_rep_length <= requested_digits + 1);
michael@0 263
michael@0 264 for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
michael@0 265 decimal_rep[i] = '0';
michael@0 266 }
michael@0 267 decimal_rep_length = requested_digits + 1;
michael@0 268 }
michael@0 269
michael@0 270 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
michael@0 271 if (sign && (value != 0.0 || !unique_zero)) {
michael@0 272 result_builder->AddCharacter('-');
michael@0 273 }
michael@0 274
michael@0 275 int exponent = decimal_point - 1;
michael@0 276 CreateExponentialRepresentation(decimal_rep,
michael@0 277 decimal_rep_length,
michael@0 278 exponent,
michael@0 279 result_builder);
michael@0 280 return true;
michael@0 281 }
michael@0 282
michael@0 283
michael@0 284 bool DoubleToStringConverter::ToPrecision(double value,
michael@0 285 int precision,
michael@0 286 bool* used_exponential_notation,
michael@0 287 StringBuilder* result_builder) const {
michael@0 288 *used_exponential_notation = false;
michael@0 289 if (Double(value).IsSpecial()) {
michael@0 290 return HandleSpecialValues(value, result_builder);
michael@0 291 }
michael@0 292
michael@0 293 if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
michael@0 294 return false;
michael@0 295 }
michael@0 296
michael@0 297 // Find a sufficiently precise decimal representation of n.
michael@0 298 int decimal_point;
michael@0 299 bool sign;
michael@0 300 // Add one for the terminating null character.
michael@0 301 const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
michael@0 302 char decimal_rep[kDecimalRepCapacity];
michael@0 303 int decimal_rep_length;
michael@0 304
michael@0 305 DoubleToAscii(value, PRECISION, precision,
michael@0 306 decimal_rep, kDecimalRepCapacity,
michael@0 307 &sign, &decimal_rep_length, &decimal_point);
michael@0 308 ASSERT(decimal_rep_length <= precision);
michael@0 309
michael@0 310 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
michael@0 311 if (sign && (value != 0.0 || !unique_zero)) {
michael@0 312 result_builder->AddCharacter('-');
michael@0 313 }
michael@0 314
michael@0 315 // The exponent if we print the number as x.xxeyyy. That is with the
michael@0 316 // decimal point after the first digit.
michael@0 317 int exponent = decimal_point - 1;
michael@0 318
michael@0 319 int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
michael@0 320 if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
michael@0 321 (decimal_point - precision + extra_zero >
michael@0 322 max_trailing_padding_zeroes_in_precision_mode_)) {
michael@0 323 // Fill buffer to contain 'precision' digits.
michael@0 324 // Usually the buffer is already at the correct length, but 'DoubleToAscii'
michael@0 325 // is allowed to return less characters.
michael@0 326 for (int i = decimal_rep_length; i < precision; ++i) {
michael@0 327 decimal_rep[i] = '0';
michael@0 328 }
michael@0 329
michael@0 330 *used_exponential_notation = true;
michael@0 331 CreateExponentialRepresentation(decimal_rep,
michael@0 332 precision,
michael@0 333 exponent,
michael@0 334 result_builder);
michael@0 335 } else {
michael@0 336 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
michael@0 337 Max(0, precision - decimal_point),
michael@0 338 result_builder);
michael@0 339 }
michael@0 340 return true;
michael@0 341 }
michael@0 342
michael@0 343
michael@0 344 static BignumDtoaMode DtoaToBignumDtoaMode(
michael@0 345 DoubleToStringConverter::DtoaMode dtoa_mode) {
michael@0 346 switch (dtoa_mode) {
michael@0 347 case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST;
michael@0 348 case DoubleToStringConverter::SHORTEST_SINGLE:
michael@0 349 return BIGNUM_DTOA_SHORTEST_SINGLE;
michael@0 350 case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;
michael@0 351 case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
michael@0 352 default:
michael@0 353 UNREACHABLE();
michael@0 354 return BIGNUM_DTOA_SHORTEST; // To silence compiler.
michael@0 355 }
michael@0 356 }
michael@0 357
michael@0 358
michael@0 359 void DoubleToStringConverter::DoubleToAscii(double v,
michael@0 360 DtoaMode mode,
michael@0 361 int requested_digits,
michael@0 362 char* buffer,
michael@0 363 int buffer_length,
michael@0 364 bool* sign,
michael@0 365 int* length,
michael@0 366 int* point) {
michael@0 367 Vector<char> vector(buffer, buffer_length);
michael@0 368 ASSERT(!Double(v).IsSpecial());
michael@0 369 ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
michael@0 370
michael@0 371 if (Double(v).Sign() < 0) {
michael@0 372 *sign = true;
michael@0 373 v = -v;
michael@0 374 } else {
michael@0 375 *sign = false;
michael@0 376 }
michael@0 377
michael@0 378 if (mode == PRECISION && requested_digits == 0) {
michael@0 379 vector[0] = '\0';
michael@0 380 *length = 0;
michael@0 381 return;
michael@0 382 }
michael@0 383
michael@0 384 if (v == 0) {
michael@0 385 vector[0] = '0';
michael@0 386 vector[1] = '\0';
michael@0 387 *length = 1;
michael@0 388 *point = 1;
michael@0 389 return;
michael@0 390 }
michael@0 391
michael@0 392 bool fast_worked;
michael@0 393 switch (mode) {
michael@0 394 case SHORTEST:
michael@0 395 fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
michael@0 396 break;
michael@0 397 case SHORTEST_SINGLE:
michael@0 398 fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
michael@0 399 vector, length, point);
michael@0 400 break;
michael@0 401 case FIXED:
michael@0 402 fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
michael@0 403 break;
michael@0 404 case PRECISION:
michael@0 405 fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
michael@0 406 vector, length, point);
michael@0 407 break;
michael@0 408 default:
michael@0 409 UNREACHABLE();
michael@0 410 fast_worked = false;
michael@0 411 }
michael@0 412 if (fast_worked) return;
michael@0 413
michael@0 414 // If the fast dtoa didn't succeed use the slower bignum version.
michael@0 415 BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
michael@0 416 BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
michael@0 417 vector[*length] = '\0';
michael@0 418 }
michael@0 419
michael@0 420
michael@0 421 // Consumes the given substring from the iterator.
michael@0 422 // Returns false, if the substring does not match.
michael@0 423 static bool ConsumeSubString(const char** current,
michael@0 424 const char* end,
michael@0 425 const char* substring) {
michael@0 426 ASSERT(**current == *substring);
michael@0 427 for (substring++; *substring != '\0'; substring++) {
michael@0 428 ++*current;
michael@0 429 if (*current == end || **current != *substring) return false;
michael@0 430 }
michael@0 431 ++*current;
michael@0 432 return true;
michael@0 433 }
michael@0 434
michael@0 435
michael@0 436 // Maximum number of significant digits in decimal representation.
michael@0 437 // The longest possible double in decimal representation is
michael@0 438 // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
michael@0 439 // (768 digits). If we parse a number whose first digits are equal to a
michael@0 440 // mean of 2 adjacent doubles (that could have up to 769 digits) the result
michael@0 441 // must be rounded to the bigger one unless the tail consists of zeros, so
michael@0 442 // we don't need to preserve all the digits.
michael@0 443 const int kMaxSignificantDigits = 772;
michael@0 444
michael@0 445
michael@0 446 // Returns true if a nonspace found and false if the end has reached.
michael@0 447 static inline bool AdvanceToNonspace(const char** current, const char* end) {
michael@0 448 while (*current != end) {
michael@0 449 if (**current != ' ') return true;
michael@0 450 ++*current;
michael@0 451 }
michael@0 452 return false;
michael@0 453 }
michael@0 454
michael@0 455
michael@0 456 static bool isDigit(int x, int radix) {
michael@0 457 return (x >= '0' && x <= '9' && x < '0' + radix)
michael@0 458 || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
michael@0 459 || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
michael@0 460 }
michael@0 461
michael@0 462
michael@0 463 static double SignedZero(bool sign) {
michael@0 464 return sign ? -0.0 : 0.0;
michael@0 465 }
michael@0 466
michael@0 467
michael@0 468 // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
michael@0 469 template <int radix_log_2>
michael@0 470 static double RadixStringToIeee(const char* current,
michael@0 471 const char* end,
michael@0 472 bool sign,
michael@0 473 bool allow_trailing_junk,
michael@0 474 double junk_string_value,
michael@0 475 bool read_as_double,
michael@0 476 const char** trailing_pointer) {
michael@0 477 ASSERT(current != end);
michael@0 478
michael@0 479 const int kDoubleSize = Double::kSignificandSize;
michael@0 480 const int kSingleSize = Single::kSignificandSize;
michael@0 481 const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize;
michael@0 482
michael@0 483 // Skip leading 0s.
michael@0 484 while (*current == '0') {
michael@0 485 ++current;
michael@0 486 if (current == end) {
michael@0 487 *trailing_pointer = end;
michael@0 488 return SignedZero(sign);
michael@0 489 }
michael@0 490 }
michael@0 491
michael@0 492 int64_t number = 0;
michael@0 493 int exponent = 0;
michael@0 494 const int radix = (1 << radix_log_2);
michael@0 495
michael@0 496 do {
michael@0 497 int digit;
michael@0 498 if (*current >= '0' && *current <= '9' && *current < '0' + radix) {
michael@0 499 digit = static_cast<char>(*current) - '0';
michael@0 500 } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) {
michael@0 501 digit = static_cast<char>(*current) - 'a' + 10;
michael@0 502 } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) {
michael@0 503 digit = static_cast<char>(*current) - 'A' + 10;
michael@0 504 } else {
michael@0 505 if (allow_trailing_junk || !AdvanceToNonspace(&current, end)) {
michael@0 506 break;
michael@0 507 } else {
michael@0 508 return junk_string_value;
michael@0 509 }
michael@0 510 }
michael@0 511
michael@0 512 number = number * radix + digit;
michael@0 513 int overflow = static_cast<int>(number >> kSignificandSize);
michael@0 514 if (overflow != 0) {
michael@0 515 // Overflow occurred. Need to determine which direction to round the
michael@0 516 // result.
michael@0 517 int overflow_bits_count = 1;
michael@0 518 while (overflow > 1) {
michael@0 519 overflow_bits_count++;
michael@0 520 overflow >>= 1;
michael@0 521 }
michael@0 522
michael@0 523 int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
michael@0 524 int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
michael@0 525 number >>= overflow_bits_count;
michael@0 526 exponent = overflow_bits_count;
michael@0 527
michael@0 528 bool zero_tail = true;
michael@0 529 while (true) {
michael@0 530 ++current;
michael@0 531 if (current == end || !isDigit(*current, radix)) break;
michael@0 532 zero_tail = zero_tail && *current == '0';
michael@0 533 exponent += radix_log_2;
michael@0 534 }
michael@0 535
michael@0 536 if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
michael@0 537 return junk_string_value;
michael@0 538 }
michael@0 539
michael@0 540 int middle_value = (1 << (overflow_bits_count - 1));
michael@0 541 if (dropped_bits > middle_value) {
michael@0 542 number++; // Rounding up.
michael@0 543 } else if (dropped_bits == middle_value) {
michael@0 544 // Rounding to even to consistency with decimals: half-way case rounds
michael@0 545 // up if significant part is odd and down otherwise.
michael@0 546 if ((number & 1) != 0 || !zero_tail) {
michael@0 547 number++; // Rounding up.
michael@0 548 }
michael@0 549 }
michael@0 550
michael@0 551 // Rounding up may cause overflow.
michael@0 552 if ((number & ((int64_t)1 << kSignificandSize)) != 0) {
michael@0 553 exponent++;
michael@0 554 number >>= 1;
michael@0 555 }
michael@0 556 break;
michael@0 557 }
michael@0 558 ++current;
michael@0 559 } while (current != end);
michael@0 560
michael@0 561 ASSERT(number < ((int64_t)1 << kSignificandSize));
michael@0 562 ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
michael@0 563
michael@0 564 *trailing_pointer = current;
michael@0 565
michael@0 566 if (exponent == 0) {
michael@0 567 if (sign) {
michael@0 568 if (number == 0) return -0.0;
michael@0 569 number = -number;
michael@0 570 }
michael@0 571 return static_cast<double>(number);
michael@0 572 }
michael@0 573
michael@0 574 ASSERT(number != 0);
michael@0 575 return Double(DiyFp(number, exponent)).value();
michael@0 576 }
michael@0 577
michael@0 578
michael@0 579 double StringToDoubleConverter::StringToIeee(
michael@0 580 const char* input,
michael@0 581 int length,
michael@0 582 int* processed_characters_count,
michael@0 583 bool read_as_double) const {
michael@0 584 const char* current = input;
michael@0 585 const char* end = input + length;
michael@0 586
michael@0 587 *processed_characters_count = 0;
michael@0 588
michael@0 589 const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0;
michael@0 590 const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
michael@0 591 const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
michael@0 592 const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
michael@0 593
michael@0 594 // To make sure that iterator dereferencing is valid the following
michael@0 595 // convention is used:
michael@0 596 // 1. Each '++current' statement is followed by check for equality to 'end'.
michael@0 597 // 2. If AdvanceToNonspace returned false then current == end.
michael@0 598 // 3. If 'current' becomes equal to 'end' the function returns or goes to
michael@0 599 // 'parsing_done'.
michael@0 600 // 4. 'current' is not dereferenced after the 'parsing_done' label.
michael@0 601 // 5. Code before 'parsing_done' may rely on 'current != end'.
michael@0 602 if (current == end) return empty_string_value_;
michael@0 603
michael@0 604 if (allow_leading_spaces || allow_trailing_spaces) {
michael@0 605 if (!AdvanceToNonspace(&current, end)) {
michael@0 606 *processed_characters_count = current - input;
michael@0 607 return empty_string_value_;
michael@0 608 }
michael@0 609 if (!allow_leading_spaces && (input != current)) {
michael@0 610 // No leading spaces allowed, but AdvanceToNonspace moved forward.
michael@0 611 return junk_string_value_;
michael@0 612 }
michael@0 613 }
michael@0 614
michael@0 615 // The longest form of simplified number is: "-<significant digits>.1eXXX\0".
michael@0 616 const int kBufferSize = kMaxSignificantDigits + 10;
michael@0 617 char buffer[kBufferSize]; // NOLINT: size is known at compile time.
michael@0 618 int buffer_pos = 0;
michael@0 619
michael@0 620 // Exponent will be adjusted if insignificant digits of the integer part
michael@0 621 // or insignificant leading zeros of the fractional part are dropped.
michael@0 622 int exponent = 0;
michael@0 623 int significant_digits = 0;
michael@0 624 int insignificant_digits = 0;
michael@0 625 bool nonzero_digit_dropped = false;
michael@0 626
michael@0 627 bool sign = false;
michael@0 628
michael@0 629 if (*current == '+' || *current == '-') {
michael@0 630 sign = (*current == '-');
michael@0 631 ++current;
michael@0 632 const char* next_non_space = current;
michael@0 633 // Skip following spaces (if allowed).
michael@0 634 if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_;
michael@0 635 if (!allow_spaces_after_sign && (current != next_non_space)) {
michael@0 636 return junk_string_value_;
michael@0 637 }
michael@0 638 current = next_non_space;
michael@0 639 }
michael@0 640
michael@0 641 if (infinity_symbol_ != NULL) {
michael@0 642 if (*current == infinity_symbol_[0]) {
michael@0 643 if (!ConsumeSubString(&current, end, infinity_symbol_)) {
michael@0 644 return junk_string_value_;
michael@0 645 }
michael@0 646
michael@0 647 if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
michael@0 648 return junk_string_value_;
michael@0 649 }
michael@0 650 if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
michael@0 651 return junk_string_value_;
michael@0 652 }
michael@0 653
michael@0 654 ASSERT(buffer_pos == 0);
michael@0 655 *processed_characters_count = current - input;
michael@0 656 return sign ? -Double::Infinity() : Double::Infinity();
michael@0 657 }
michael@0 658 }
michael@0 659
michael@0 660 if (nan_symbol_ != NULL) {
michael@0 661 if (*current == nan_symbol_[0]) {
michael@0 662 if (!ConsumeSubString(&current, end, nan_symbol_)) {
michael@0 663 return junk_string_value_;
michael@0 664 }
michael@0 665
michael@0 666 if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
michael@0 667 return junk_string_value_;
michael@0 668 }
michael@0 669 if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
michael@0 670 return junk_string_value_;
michael@0 671 }
michael@0 672
michael@0 673 ASSERT(buffer_pos == 0);
michael@0 674 *processed_characters_count = current - input;
michael@0 675 return sign ? -Double::NaN() : Double::NaN();
michael@0 676 }
michael@0 677 }
michael@0 678
michael@0 679 bool leading_zero = false;
michael@0 680 if (*current == '0') {
michael@0 681 ++current;
michael@0 682 if (current == end) {
michael@0 683 *processed_characters_count = current - input;
michael@0 684 return SignedZero(sign);
michael@0 685 }
michael@0 686
michael@0 687 leading_zero = true;
michael@0 688
michael@0 689 // It could be hexadecimal value.
michael@0 690 if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
michael@0 691 ++current;
michael@0 692 if (current == end || !isDigit(*current, 16)) {
michael@0 693 return junk_string_value_; // "0x".
michael@0 694 }
michael@0 695
michael@0 696 const char* tail_pointer = NULL;
michael@0 697 double result = RadixStringToIeee<4>(current,
michael@0 698 end,
michael@0 699 sign,
michael@0 700 allow_trailing_junk,
michael@0 701 junk_string_value_,
michael@0 702 read_as_double,
michael@0 703 &tail_pointer);
michael@0 704 if (tail_pointer != NULL) {
michael@0 705 if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end);
michael@0 706 *processed_characters_count = tail_pointer - input;
michael@0 707 }
michael@0 708 return result;
michael@0 709 }
michael@0 710
michael@0 711 // Ignore leading zeros in the integer part.
michael@0 712 while (*current == '0') {
michael@0 713 ++current;
michael@0 714 if (current == end) {
michael@0 715 *processed_characters_count = current - input;
michael@0 716 return SignedZero(sign);
michael@0 717 }
michael@0 718 }
michael@0 719 }
michael@0 720
michael@0 721 bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0;
michael@0 722
michael@0 723 // Copy significant digits of the integer part (if any) to the buffer.
michael@0 724 while (*current >= '0' && *current <= '9') {
michael@0 725 if (significant_digits < kMaxSignificantDigits) {
michael@0 726 ASSERT(buffer_pos < kBufferSize);
michael@0 727 buffer[buffer_pos++] = static_cast<char>(*current);
michael@0 728 significant_digits++;
michael@0 729 // Will later check if it's an octal in the buffer.
michael@0 730 } else {
michael@0 731 insignificant_digits++; // Move the digit into the exponential part.
michael@0 732 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
michael@0 733 }
michael@0 734 octal = octal && *current < '8';
michael@0 735 ++current;
michael@0 736 if (current == end) goto parsing_done;
michael@0 737 }
michael@0 738
michael@0 739 if (significant_digits == 0) {
michael@0 740 octal = false;
michael@0 741 }
michael@0 742
michael@0 743 if (*current == '.') {
michael@0 744 if (octal && !allow_trailing_junk) return junk_string_value_;
michael@0 745 if (octal) goto parsing_done;
michael@0 746
michael@0 747 ++current;
michael@0 748 if (current == end) {
michael@0 749 if (significant_digits == 0 && !leading_zero) {
michael@0 750 return junk_string_value_;
michael@0 751 } else {
michael@0 752 goto parsing_done;
michael@0 753 }
michael@0 754 }
michael@0 755
michael@0 756 if (significant_digits == 0) {
michael@0 757 // octal = false;
michael@0 758 // Integer part consists of 0 or is absent. Significant digits start after
michael@0 759 // leading zeros (if any).
michael@0 760 while (*current == '0') {
michael@0 761 ++current;
michael@0 762 if (current == end) {
michael@0 763 *processed_characters_count = current - input;
michael@0 764 return SignedZero(sign);
michael@0 765 }
michael@0 766 exponent--; // Move this 0 into the exponent.
michael@0 767 }
michael@0 768 }
michael@0 769
michael@0 770 // There is a fractional part.
michael@0 771 // We don't emit a '.', but adjust the exponent instead.
michael@0 772 while (*current >= '0' && *current <= '9') {
michael@0 773 if (significant_digits < kMaxSignificantDigits) {
michael@0 774 ASSERT(buffer_pos < kBufferSize);
michael@0 775 buffer[buffer_pos++] = static_cast<char>(*current);
michael@0 776 significant_digits++;
michael@0 777 exponent--;
michael@0 778 } else {
michael@0 779 // Ignore insignificant digits in the fractional part.
michael@0 780 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
michael@0 781 }
michael@0 782 ++current;
michael@0 783 if (current == end) goto parsing_done;
michael@0 784 }
michael@0 785 }
michael@0 786
michael@0 787 if (!leading_zero && exponent == 0 && significant_digits == 0) {
michael@0 788 // If leading_zeros is true then the string contains zeros.
michael@0 789 // If exponent < 0 then string was [+-]\.0*...
michael@0 790 // If significant_digits != 0 the string is not equal to 0.
michael@0 791 // Otherwise there are no digits in the string.
michael@0 792 return junk_string_value_;
michael@0 793 }
michael@0 794
michael@0 795 // Parse exponential part.
michael@0 796 if (*current == 'e' || *current == 'E') {
michael@0 797 if (octal && !allow_trailing_junk) return junk_string_value_;
michael@0 798 if (octal) goto parsing_done;
michael@0 799 ++current;
michael@0 800 if (current == end) {
michael@0 801 if (allow_trailing_junk) {
michael@0 802 goto parsing_done;
michael@0 803 } else {
michael@0 804 return junk_string_value_;
michael@0 805 }
michael@0 806 }
michael@0 807 char sign = '+';
michael@0 808 if (*current == '+' || *current == '-') {
michael@0 809 sign = static_cast<char>(*current);
michael@0 810 ++current;
michael@0 811 if (current == end) {
michael@0 812 if (allow_trailing_junk) {
michael@0 813 goto parsing_done;
michael@0 814 } else {
michael@0 815 return junk_string_value_;
michael@0 816 }
michael@0 817 }
michael@0 818 }
michael@0 819
michael@0 820 if (current == end || *current < '0' || *current > '9') {
michael@0 821 if (allow_trailing_junk) {
michael@0 822 goto parsing_done;
michael@0 823 } else {
michael@0 824 return junk_string_value_;
michael@0 825 }
michael@0 826 }
michael@0 827
michael@0 828 const int max_exponent = INT_MAX / 2;
michael@0 829 ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
michael@0 830 int num = 0;
michael@0 831 do {
michael@0 832 // Check overflow.
michael@0 833 int digit = *current - '0';
michael@0 834 if (num >= max_exponent / 10
michael@0 835 && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
michael@0 836 num = max_exponent;
michael@0 837 } else {
michael@0 838 num = num * 10 + digit;
michael@0 839 }
michael@0 840 ++current;
michael@0 841 } while (current != end && *current >= '0' && *current <= '9');
michael@0 842
michael@0 843 exponent += (sign == '-' ? -num : num);
michael@0 844 }
michael@0 845
michael@0 846 if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
michael@0 847 return junk_string_value_;
michael@0 848 }
michael@0 849 if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
michael@0 850 return junk_string_value_;
michael@0 851 }
michael@0 852 if (allow_trailing_spaces) {
michael@0 853 AdvanceToNonspace(&current, end);
michael@0 854 }
michael@0 855
michael@0 856 parsing_done:
michael@0 857 exponent += insignificant_digits;
michael@0 858
michael@0 859 if (octal) {
michael@0 860 double result;
michael@0 861 const char* tail_pointer = NULL;
michael@0 862 result = RadixStringToIeee<3>(buffer,
michael@0 863 buffer + buffer_pos,
michael@0 864 sign,
michael@0 865 allow_trailing_junk,
michael@0 866 junk_string_value_,
michael@0 867 read_as_double,
michael@0 868 &tail_pointer);
michael@0 869 ASSERT(tail_pointer != NULL);
michael@0 870 *processed_characters_count = current - input;
michael@0 871 return result;
michael@0 872 }
michael@0 873
michael@0 874 if (nonzero_digit_dropped) {
michael@0 875 buffer[buffer_pos++] = '1';
michael@0 876 exponent--;
michael@0 877 }
michael@0 878
michael@0 879 ASSERT(buffer_pos < kBufferSize);
michael@0 880 buffer[buffer_pos] = '\0';
michael@0 881
michael@0 882 double converted;
michael@0 883 if (read_as_double) {
michael@0 884 converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
michael@0 885 } else {
michael@0 886 converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
michael@0 887 }
michael@0 888 *processed_characters_count = current - input;
michael@0 889 return sign? -converted: converted;
michael@0 890 }
michael@0 891
michael@0 892 } // namespace double_conversion

mercurial