double-conversion-double-to-string.cpp (16863B)
1 // © 2018 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 // 4 // From the double-conversion library. Original license: 5 // 6 // Copyright 2010 the V8 project authors. All rights reserved. 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are 9 // met: 10 // 11 // * Redistributions of source code must retain the above copyright 12 // notice, this list of conditions and the following disclaimer. 13 // * Redistributions in binary form must reproduce the above 14 // copyright notice, this list of conditions and the following 15 // disclaimer in the documentation and/or other materials provided 16 // with the distribution. 17 // * Neither the name of Google Inc. nor the names of its 18 // contributors may be used to endorse or promote products derived 19 // from this software without specific prior written permission. 20 // 21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33 // ICU PATCH: ifdef around UCONFIG_NO_FORMATTING 34 #include "unicode/utypes.h" 35 #if !UCONFIG_NO_FORMATTING 36 37 #include <algorithm> 38 #include <climits> 39 #include <cmath> 40 41 // ICU PATCH: Customize header file paths for ICU. 42 // The file fixed-dtoa.h is not needed. 43 44 #include "double-conversion-double-to-string.h" 45 46 #include "double-conversion-bignum-dtoa.h" 47 #include "double-conversion-fast-dtoa.h" 48 #include "double-conversion-ieee.h" 49 #include "double-conversion-utils.h" 50 51 // ICU PATCH: Wrap in ICU namespace 52 U_NAMESPACE_BEGIN 53 54 namespace double_conversion { 55 56 #if 0 // not needed for ICU 57 const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() { 58 int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN; 59 static DoubleToStringConverter converter(flags, 60 "Infinity", 61 "NaN", 62 'e', 63 -6, 21, 64 6, 0); 65 return converter; 66 } 67 68 69 bool DoubleToStringConverter::HandleSpecialValues( 70 double value, 71 StringBuilder* result_builder) const { 72 Double double_inspect(value); 73 if (double_inspect.IsInfinite()) { 74 if (infinity_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false; 75 if (value < 0) { 76 result_builder->AddCharacter('-'); 77 } 78 result_builder->AddString(infinity_symbol_); 79 return true; 80 } 81 if (double_inspect.IsNan()) { 82 if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false; 83 result_builder->AddString(nan_symbol_); 84 return true; 85 } 86 return false; 87 } 88 89 90 void DoubleToStringConverter::CreateExponentialRepresentation( 91 const char* decimal_digits, 92 int length, 93 int exponent, 94 StringBuilder* result_builder) const { 95 DOUBLE_CONVERSION_ASSERT(length != 0); 96 result_builder->AddCharacter(decimal_digits[0]); 97 if (length == 1) { 98 if ((flags_ & EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL) != 0) { 99 result_builder->AddCharacter('.'); 100 if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL) != 0) { 101 result_builder->AddCharacter('0'); 102 } 103 } 104 } else { 105 result_builder->AddCharacter('.'); 106 result_builder->AddSubstring(&decimal_digits[1], length-1); 107 } 108 result_builder->AddCharacter(exponent_character_); 109 if (exponent < 0) { 110 result_builder->AddCharacter('-'); 111 exponent = -exponent; 112 } else { 113 if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) { 114 result_builder->AddCharacter('+'); 115 } 116 } 117 DOUBLE_CONVERSION_ASSERT(exponent < 1e4); 118 // Changing this constant requires updating the comment of DoubleToStringConverter constructor 119 const int kMaxExponentLength = 5; 120 char buffer[kMaxExponentLength + 1]; 121 buffer[kMaxExponentLength] = '\0'; 122 int first_char_pos = kMaxExponentLength; 123 if (exponent == 0) { 124 buffer[--first_char_pos] = '0'; 125 } else { 126 while (exponent > 0) { 127 buffer[--first_char_pos] = '0' + (exponent % 10); 128 exponent /= 10; 129 } 130 } 131 // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength) 132 // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2 133 while(kMaxExponentLength - first_char_pos < std::min(min_exponent_width_, kMaxExponentLength)) { 134 buffer[--first_char_pos] = '0'; 135 } 136 result_builder->AddSubstring(&buffer[first_char_pos], 137 kMaxExponentLength - first_char_pos); 138 } 139 140 141 void DoubleToStringConverter::CreateDecimalRepresentation( 142 const char* decimal_digits, 143 int length, 144 int decimal_point, 145 int digits_after_point, 146 StringBuilder* result_builder) const { 147 // Create a representation that is padded with zeros if needed. 148 if (decimal_point <= 0) { 149 // "0.00000decimal_rep" or "0.000decimal_rep00". 150 result_builder->AddCharacter('0'); 151 if (digits_after_point > 0) { 152 result_builder->AddCharacter('.'); 153 result_builder->AddPadding('0', -decimal_point); 154 DOUBLE_CONVERSION_ASSERT(length <= digits_after_point - (-decimal_point)); 155 result_builder->AddSubstring(decimal_digits, length); 156 int remaining_digits = digits_after_point - (-decimal_point) - length; 157 result_builder->AddPadding('0', remaining_digits); 158 } 159 } else if (decimal_point >= length) { 160 // "decimal_rep0000.00000" or "decimal_rep.0000". 161 result_builder->AddSubstring(decimal_digits, length); 162 result_builder->AddPadding('0', decimal_point - length); 163 if (digits_after_point > 0) { 164 result_builder->AddCharacter('.'); 165 result_builder->AddPadding('0', digits_after_point); 166 } 167 } else { 168 // "decima.l_rep000". 169 DOUBLE_CONVERSION_ASSERT(digits_after_point > 0); 170 result_builder->AddSubstring(decimal_digits, decimal_point); 171 result_builder->AddCharacter('.'); 172 DOUBLE_CONVERSION_ASSERT(length - decimal_point <= digits_after_point); 173 result_builder->AddSubstring(&decimal_digits[decimal_point], 174 length - decimal_point); 175 int remaining_digits = digits_after_point - (length - decimal_point); 176 result_builder->AddPadding('0', remaining_digits); 177 } 178 if (digits_after_point == 0) { 179 if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) { 180 result_builder->AddCharacter('.'); 181 } 182 if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) { 183 result_builder->AddCharacter('0'); 184 } 185 } 186 } 187 188 189 bool DoubleToStringConverter::ToShortestIeeeNumber( 190 double value, 191 StringBuilder* result_builder, 192 DoubleToStringConverter::DtoaMode mode) const { 193 DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE); 194 if (Double(value).IsSpecial()) { 195 return HandleSpecialValues(value, result_builder); 196 } 197 198 int decimal_point; 199 bool sign; 200 const int kDecimalRepCapacity = kBase10MaximalLength + 1; 201 char decimal_rep[kDecimalRepCapacity]; 202 int decimal_rep_length; 203 204 DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity, 205 &sign, &decimal_rep_length, &decimal_point); 206 207 bool unique_zero = (flags_ & UNIQUE_ZERO) != 0; 208 if (sign && (value != 0.0 || !unique_zero)) { 209 result_builder->AddCharacter('-'); 210 } 211 212 int exponent = decimal_point - 1; 213 if ((decimal_in_shortest_low_ <= exponent) && 214 (exponent < decimal_in_shortest_high_)) { 215 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, 216 decimal_point, 217 (std::max)(0, decimal_rep_length - decimal_point), 218 result_builder); 219 } else { 220 CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, 221 result_builder); 222 } 223 return true; 224 } 225 226 227 bool DoubleToStringConverter::ToFixed(double value, 228 int requested_digits, 229 StringBuilder* result_builder) const { 230 DOUBLE_CONVERSION_ASSERT(kMaxFixedDigitsBeforePoint == 60); 231 const double kFirstNonFixed = 1e60; 232 233 if (Double(value).IsSpecial()) { 234 return HandleSpecialValues(value, result_builder); 235 } 236 237 if (requested_digits > kMaxFixedDigitsAfterPoint) return false; 238 if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false; 239 240 // Find a sufficiently precise decimal representation of n. 241 int decimal_point; 242 bool sign; 243 // Add space for the '\0' byte. 244 const int kDecimalRepCapacity = 245 kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1; 246 char decimal_rep[kDecimalRepCapacity]; 247 int decimal_rep_length; 248 DoubleToAscii(value, FIXED, requested_digits, 249 decimal_rep, kDecimalRepCapacity, 250 &sign, &decimal_rep_length, &decimal_point); 251 252 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); 253 if (sign && (value != 0.0 || !unique_zero)) { 254 result_builder->AddCharacter('-'); 255 } 256 257 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, 258 requested_digits, result_builder); 259 return true; 260 } 261 262 263 bool DoubleToStringConverter::ToExponential( 264 double value, 265 int requested_digits, 266 StringBuilder* result_builder) const { 267 if (Double(value).IsSpecial()) { 268 return HandleSpecialValues(value, result_builder); 269 } 270 271 if (requested_digits < -1) return false; 272 if (requested_digits > kMaxExponentialDigits) return false; 273 274 int decimal_point; 275 bool sign; 276 // Add space for digit before the decimal point and the '\0' character. 277 const int kDecimalRepCapacity = kMaxExponentialDigits + 2; 278 DOUBLE_CONVERSION_ASSERT(kDecimalRepCapacity > kBase10MaximalLength); 279 char decimal_rep[kDecimalRepCapacity]; 280 #ifndef NDEBUG 281 // Problem: there is an assert in StringBuilder::AddSubstring() that 282 // will pass this buffer to strlen(), and this buffer is not generally 283 // null-terminated. 284 memset(decimal_rep, 0, sizeof(decimal_rep)); 285 #endif 286 int decimal_rep_length; 287 288 if (requested_digits == -1) { 289 DoubleToAscii(value, SHORTEST, 0, 290 decimal_rep, kDecimalRepCapacity, 291 &sign, &decimal_rep_length, &decimal_point); 292 } else { 293 DoubleToAscii(value, PRECISION, requested_digits + 1, 294 decimal_rep, kDecimalRepCapacity, 295 &sign, &decimal_rep_length, &decimal_point); 296 DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= requested_digits + 1); 297 298 for (int i = decimal_rep_length; i < requested_digits + 1; ++i) { 299 decimal_rep[i] = '0'; 300 } 301 decimal_rep_length = requested_digits + 1; 302 } 303 304 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); 305 if (sign && (value != 0.0 || !unique_zero)) { 306 result_builder->AddCharacter('-'); 307 } 308 309 int exponent = decimal_point - 1; 310 CreateExponentialRepresentation(decimal_rep, 311 decimal_rep_length, 312 exponent, 313 result_builder); 314 return true; 315 } 316 317 318 bool DoubleToStringConverter::ToPrecision(double value, 319 int precision, 320 StringBuilder* result_builder) const { 321 if (Double(value).IsSpecial()) { 322 return HandleSpecialValues(value, result_builder); 323 } 324 325 if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) { 326 return false; 327 } 328 329 // Find a sufficiently precise decimal representation of n. 330 int decimal_point; 331 bool sign; 332 // Add one for the terminating null character. 333 const int kDecimalRepCapacity = kMaxPrecisionDigits + 1; 334 char decimal_rep[kDecimalRepCapacity]; 335 int decimal_rep_length; 336 337 DoubleToAscii(value, PRECISION, precision, 338 decimal_rep, kDecimalRepCapacity, 339 &sign, &decimal_rep_length, &decimal_point); 340 DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= precision); 341 342 bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); 343 if (sign && (value != 0.0 || !unique_zero)) { 344 result_builder->AddCharacter('-'); 345 } 346 347 // The exponent if we print the number as x.xxeyyy. That is with the 348 // decimal point after the first digit. 349 int exponent = decimal_point - 1; 350 351 int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0; 352 bool as_exponential = 353 (-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) || 354 (decimal_point - precision + extra_zero > 355 max_trailing_padding_zeroes_in_precision_mode_); 356 if ((flags_ & NO_TRAILING_ZERO) != 0) { 357 // Truncate trailing zeros that occur after the decimal point (if exponential, 358 // that is everything after the first digit). 359 int stop = as_exponential ? 1 : std::max(1, decimal_point); 360 while (decimal_rep_length > stop && decimal_rep[decimal_rep_length - 1] == '0') { 361 --decimal_rep_length; 362 } 363 // Clamp precision to avoid the code below re-adding the zeros. 364 precision = std::min(precision, decimal_rep_length); 365 } 366 if (as_exponential) { 367 // Fill buffer to contain 'precision' digits. 368 // Usually the buffer is already at the correct length, but 'DoubleToAscii' 369 // is allowed to return less characters. 370 for (int i = decimal_rep_length; i < precision; ++i) { 371 decimal_rep[i] = '0'; 372 } 373 374 CreateExponentialRepresentation(decimal_rep, 375 precision, 376 exponent, 377 result_builder); 378 } else { 379 CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, 380 (std::max)(0, precision - decimal_point), 381 result_builder); 382 } 383 return true; 384 } 385 #endif // not needed for ICU 386 387 388 static BignumDtoaMode DtoaToBignumDtoaMode( 389 DoubleToStringConverter::DtoaMode dtoa_mode) { 390 switch (dtoa_mode) { 391 case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST; 392 case DoubleToStringConverter::SHORTEST_SINGLE: 393 return BIGNUM_DTOA_SHORTEST_SINGLE; 394 case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED; 395 case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION; 396 default: 397 DOUBLE_CONVERSION_UNREACHABLE(); 398 } 399 } 400 401 402 void DoubleToStringConverter::DoubleToAscii(double v, 403 DtoaMode mode, 404 int requested_digits, 405 char* buffer, 406 int buffer_length, 407 bool* sign, 408 int* length, 409 int* point) { 410 Vector<char> vector(buffer, buffer_length); 411 DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial()); 412 DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0); 413 414 if (Double(v).Sign() < 0) { 415 *sign = true; 416 v = -v; 417 } else { 418 *sign = false; 419 } 420 421 if (mode == PRECISION && requested_digits == 0) { 422 vector[0] = '\0'; 423 *length = 0; 424 return; 425 } 426 427 if (v == 0) { 428 vector[0] = '0'; 429 vector[1] = '\0'; 430 *length = 1; 431 *point = 1; 432 return; 433 } 434 435 bool fast_worked; 436 switch (mode) { 437 case SHORTEST: 438 fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point); 439 break; 440 #if 0 // not needed for ICU 441 case SHORTEST_SINGLE: 442 fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0, 443 vector, length, point); 444 break; 445 case FIXED: 446 fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point); 447 break; 448 case PRECISION: 449 fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, 450 vector, length, point); 451 break; 452 #endif // not needed for ICU 453 default: 454 fast_worked = false; 455 DOUBLE_CONVERSION_UNREACHABLE(); 456 } 457 if (fast_worked) return; 458 459 // If the fast dtoa didn't succeed use the slower bignum version. 460 BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode); 461 BignumDtoa(v, bignum_mode, requested_digits, vector, length, point); 462 vector[*length] = '\0'; 463 } 464 465 } // namespace double_conversion 466 467 // ICU PATCH: Close ICU namespace 468 U_NAMESPACE_END 469 #endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING