1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <stdarg.h> 29#include <limits.h> 30#include <cmath> 31 32#include "conversions-inl.h" 33#include "dtoa.h" 34#include "list-inl.h" 35#include "strtod.h" 36#include "utils.h" 37 38#ifndef _STLP_VENDOR_CSTD 39// STLPort doesn't import fpclassify into the std namespace. 40using std::fpclassify; 41#endif 42 43namespace v8 { 44namespace internal { 45 46 47double StringToDouble(UnicodeCache* unicode_cache, 48 const char* str, int flags, double empty_string_val) { 49 // We cast to const uint8_t* here to avoid instantiating the 50 // InternalStringToDouble() template for const char* as well. 51 const uint8_t* start = reinterpret_cast<const uint8_t*>(str); 52 const uint8_t* end = start + StrLength(str); 53 return InternalStringToDouble(unicode_cache, start, end, flags, 54 empty_string_val); 55} 56 57 58double StringToDouble(UnicodeCache* unicode_cache, 59 Vector<const char> str, 60 int flags, 61 double empty_string_val) { 62 // We cast to const uint8_t* here to avoid instantiating the 63 // InternalStringToDouble() template for const char* as well. 64 const uint8_t* start = reinterpret_cast<const uint8_t*>(str.start()); 65 const uint8_t* end = start + str.length(); 66 return InternalStringToDouble(unicode_cache, start, end, flags, 67 empty_string_val); 68} 69 70 71double StringToDouble(UnicodeCache* unicode_cache, 72 Vector<const uc16> str, 73 int flags, 74 double empty_string_val) { 75 const uc16* end = str.start() + str.length(); 76 return InternalStringToDouble(unicode_cache, str.start(), end, flags, 77 empty_string_val); 78} 79 80 81const char* DoubleToCString(double v, Vector<char> buffer) { 82 switch (fpclassify(v)) { 83 case FP_NAN: return "NaN"; 84 case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity"); 85 case FP_ZERO: return "0"; 86 default: { 87 SimpleStringBuilder builder(buffer.start(), buffer.length()); 88 int decimal_point; 89 int sign; 90 const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1; 91 char decimal_rep[kV8DtoaBufferCapacity]; 92 int length; 93 94 DoubleToAscii(v, DTOA_SHORTEST, 0, 95 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), 96 &sign, &length, &decimal_point); 97 98 if (sign) builder.AddCharacter('-'); 99 100 if (length <= decimal_point && decimal_point <= 21) { 101 // ECMA-262 section 9.8.1 step 6. 102 builder.AddString(decimal_rep); 103 builder.AddPadding('0', decimal_point - length); 104 105 } else if (0 < decimal_point && decimal_point <= 21) { 106 // ECMA-262 section 9.8.1 step 7. 107 builder.AddSubstring(decimal_rep, decimal_point); 108 builder.AddCharacter('.'); 109 builder.AddString(decimal_rep + decimal_point); 110 111 } else if (decimal_point <= 0 && decimal_point > -6) { 112 // ECMA-262 section 9.8.1 step 8. 113 builder.AddString("0."); 114 builder.AddPadding('0', -decimal_point); 115 builder.AddString(decimal_rep); 116 117 } else { 118 // ECMA-262 section 9.8.1 step 9 and 10 combined. 119 builder.AddCharacter(decimal_rep[0]); 120 if (length != 1) { 121 builder.AddCharacter('.'); 122 builder.AddString(decimal_rep + 1); 123 } 124 builder.AddCharacter('e'); 125 builder.AddCharacter((decimal_point >= 0) ? '+' : '-'); 126 int exponent = decimal_point - 1; 127 if (exponent < 0) exponent = -exponent; 128 builder.AddDecimalInteger(exponent); 129 } 130 return builder.Finalize(); 131 } 132 } 133} 134 135 136const char* IntToCString(int n, Vector<char> buffer) { 137 bool negative = false; 138 if (n < 0) { 139 // We must not negate the most negative int. 140 if (n == kMinInt) return DoubleToCString(n, buffer); 141 negative = true; 142 n = -n; 143 } 144 // Build the string backwards from the least significant digit. 145 int i = buffer.length(); 146 buffer[--i] = '\0'; 147 do { 148 buffer[--i] = '0' + (n % 10); 149 n /= 10; 150 } while (n); 151 if (negative) buffer[--i] = '-'; 152 return buffer.start() + i; 153} 154 155 156char* DoubleToFixedCString(double value, int f) { 157 const int kMaxDigitsBeforePoint = 21; 158 const double kFirstNonFixed = 1e21; 159 const int kMaxDigitsAfterPoint = 20; 160 ASSERT(f >= 0); 161 ASSERT(f <= kMaxDigitsAfterPoint); 162 163 bool negative = false; 164 double abs_value = value; 165 if (value < 0) { 166 abs_value = -value; 167 negative = true; 168 } 169 170 // If abs_value has more than kMaxDigitsBeforePoint digits before the point 171 // use the non-fixed conversion routine. 172 if (abs_value >= kFirstNonFixed) { 173 char arr[100]; 174 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 175 return StrDup(DoubleToCString(value, buffer)); 176 } 177 178 // Find a sufficiently precise decimal representation of n. 179 int decimal_point; 180 int sign; 181 // Add space for the '\0' byte. 182 const int kDecimalRepCapacity = 183 kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1; 184 char decimal_rep[kDecimalRepCapacity]; 185 int decimal_rep_length; 186 DoubleToAscii(value, DTOA_FIXED, f, 187 Vector<char>(decimal_rep, kDecimalRepCapacity), 188 &sign, &decimal_rep_length, &decimal_point); 189 190 // Create a representation that is padded with zeros if needed. 191 int zero_prefix_length = 0; 192 int zero_postfix_length = 0; 193 194 if (decimal_point <= 0) { 195 zero_prefix_length = -decimal_point + 1; 196 decimal_point = 1; 197 } 198 199 if (zero_prefix_length + decimal_rep_length < decimal_point + f) { 200 zero_postfix_length = decimal_point + f - decimal_rep_length - 201 zero_prefix_length; 202 } 203 204 unsigned rep_length = 205 zero_prefix_length + decimal_rep_length + zero_postfix_length; 206 SimpleStringBuilder rep_builder(rep_length + 1); 207 rep_builder.AddPadding('0', zero_prefix_length); 208 rep_builder.AddString(decimal_rep); 209 rep_builder.AddPadding('0', zero_postfix_length); 210 char* rep = rep_builder.Finalize(); 211 212 // Create the result string by appending a minus and putting in a 213 // decimal point if needed. 214 unsigned result_size = decimal_point + f + 2; 215 SimpleStringBuilder builder(result_size + 1); 216 if (negative) builder.AddCharacter('-'); 217 builder.AddSubstring(rep, decimal_point); 218 if (f > 0) { 219 builder.AddCharacter('.'); 220 builder.AddSubstring(rep + decimal_point, f); 221 } 222 DeleteArray(rep); 223 return builder.Finalize(); 224} 225 226 227static char* CreateExponentialRepresentation(char* decimal_rep, 228 int exponent, 229 bool negative, 230 int significant_digits) { 231 bool negative_exponent = false; 232 if (exponent < 0) { 233 negative_exponent = true; 234 exponent = -exponent; 235 } 236 237 // Leave room in the result for appending a minus, for a period, the 238 // letter 'e', a minus or a plus depending on the exponent, and a 239 // three digit exponent. 240 unsigned result_size = significant_digits + 7; 241 SimpleStringBuilder builder(result_size + 1); 242 243 if (negative) builder.AddCharacter('-'); 244 builder.AddCharacter(decimal_rep[0]); 245 if (significant_digits != 1) { 246 builder.AddCharacter('.'); 247 builder.AddString(decimal_rep + 1); 248 int rep_length = StrLength(decimal_rep); 249 builder.AddPadding('0', significant_digits - rep_length); 250 } 251 252 builder.AddCharacter('e'); 253 builder.AddCharacter(negative_exponent ? '-' : '+'); 254 builder.AddDecimalInteger(exponent); 255 return builder.Finalize(); 256} 257 258 259 260char* DoubleToExponentialCString(double value, int f) { 261 const int kMaxDigitsAfterPoint = 20; 262 // f might be -1 to signal that f was undefined in JavaScript. 263 ASSERT(f >= -1 && f <= kMaxDigitsAfterPoint); 264 265 bool negative = false; 266 if (value < 0) { 267 value = -value; 268 negative = true; 269 } 270 271 // Find a sufficiently precise decimal representation of n. 272 int decimal_point; 273 int sign; 274 // f corresponds to the digits after the point. There is always one digit 275 // before the point. The number of requested_digits equals hence f + 1. 276 // And we have to add one character for the null-terminator. 277 const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1; 278 // Make sure that the buffer is big enough, even if we fall back to the 279 // shortest representation (which happens when f equals -1). 280 ASSERT(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1); 281 char decimal_rep[kV8DtoaBufferCapacity]; 282 int decimal_rep_length; 283 284 if (f == -1) { 285 DoubleToAscii(value, DTOA_SHORTEST, 0, 286 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), 287 &sign, &decimal_rep_length, &decimal_point); 288 f = decimal_rep_length - 1; 289 } else { 290 DoubleToAscii(value, DTOA_PRECISION, f + 1, 291 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), 292 &sign, &decimal_rep_length, &decimal_point); 293 } 294 ASSERT(decimal_rep_length > 0); 295 ASSERT(decimal_rep_length <= f + 1); 296 297 int exponent = decimal_point - 1; 298 char* result = 299 CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1); 300 301 return result; 302} 303 304 305char* DoubleToPrecisionCString(double value, int p) { 306 const int kMinimalDigits = 1; 307 const int kMaximalDigits = 21; 308 ASSERT(p >= kMinimalDigits && p <= kMaximalDigits); 309 USE(kMinimalDigits); 310 311 bool negative = false; 312 if (value < 0) { 313 value = -value; 314 negative = true; 315 } 316 317 // Find a sufficiently precise decimal representation of n. 318 int decimal_point; 319 int sign; 320 // Add one for the terminating null character. 321 const int kV8DtoaBufferCapacity = kMaximalDigits + 1; 322 char decimal_rep[kV8DtoaBufferCapacity]; 323 int decimal_rep_length; 324 325 DoubleToAscii(value, DTOA_PRECISION, p, 326 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), 327 &sign, &decimal_rep_length, &decimal_point); 328 ASSERT(decimal_rep_length <= p); 329 330 int exponent = decimal_point - 1; 331 332 char* result = NULL; 333 334 if (exponent < -6 || exponent >= p) { 335 result = 336 CreateExponentialRepresentation(decimal_rep, exponent, negative, p); 337 } else { 338 // Use fixed notation. 339 // 340 // Leave room in the result for appending a minus, a period and in 341 // the case where decimal_point is not positive for a zero in 342 // front of the period. 343 unsigned result_size = (decimal_point <= 0) 344 ? -decimal_point + p + 3 345 : p + 2; 346 SimpleStringBuilder builder(result_size + 1); 347 if (negative) builder.AddCharacter('-'); 348 if (decimal_point <= 0) { 349 builder.AddString("0."); 350 builder.AddPadding('0', -decimal_point); 351 builder.AddString(decimal_rep); 352 builder.AddPadding('0', p - decimal_rep_length); 353 } else { 354 const int m = Min(decimal_rep_length, decimal_point); 355 builder.AddSubstring(decimal_rep, m); 356 builder.AddPadding('0', decimal_point - decimal_rep_length); 357 if (decimal_point < p) { 358 builder.AddCharacter('.'); 359 const int extra = negative ? 2 : 1; 360 if (decimal_rep_length > decimal_point) { 361 const int len = StrLength(decimal_rep + decimal_point); 362 const int n = Min(len, p - (builder.position() - extra)); 363 builder.AddSubstring(decimal_rep + decimal_point, n); 364 } 365 builder.AddPadding('0', extra + (p - builder.position())); 366 } 367 } 368 result = builder.Finalize(); 369 } 370 371 return result; 372} 373 374 375char* DoubleToRadixCString(double value, int radix) { 376 ASSERT(radix >= 2 && radix <= 36); 377 378 // Character array used for conversion. 379 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 380 381 // Buffer for the integer part of the result. 1024 chars is enough 382 // for max integer value in radix 2. We need room for a sign too. 383 static const int kBufferSize = 1100; 384 char integer_buffer[kBufferSize]; 385 integer_buffer[kBufferSize - 1] = '\0'; 386 387 // Buffer for the decimal part of the result. We only generate up 388 // to kBufferSize - 1 chars for the decimal part. 389 char decimal_buffer[kBufferSize]; 390 decimal_buffer[kBufferSize - 1] = '\0'; 391 392 // Make sure the value is positive. 393 bool is_negative = value < 0.0; 394 if (is_negative) value = -value; 395 396 // Get the integer part and the decimal part. 397 double integer_part = floor(value); 398 double decimal_part = value - integer_part; 399 400 // Convert the integer part starting from the back. Always generate 401 // at least one digit. 402 int integer_pos = kBufferSize - 2; 403 do { 404 double remainder = fmod(integer_part, radix); 405 integer_buffer[integer_pos--] = chars[static_cast<int>(remainder)]; 406 integer_part -= remainder; 407 integer_part /= radix; 408 } while (integer_part >= 1.0); 409 // Sanity check. 410 ASSERT(integer_pos > 0); 411 // Add sign if needed. 412 if (is_negative) integer_buffer[integer_pos--] = '-'; 413 414 // Convert the decimal part. Repeatedly multiply by the radix to 415 // generate the next char. Never generate more than kBufferSize - 1 416 // chars. 417 // 418 // TODO(1093998): We will often generate a full decimal_buffer of 419 // chars because hitting zero will often not happen. The right 420 // solution would be to continue until the string representation can 421 // be read back and yield the original value. To implement this 422 // efficiently, we probably have to modify dtoa. 423 int decimal_pos = 0; 424 while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) { 425 decimal_part *= radix; 426 decimal_buffer[decimal_pos++] = 427 chars[static_cast<int>(floor(decimal_part))]; 428 decimal_part -= floor(decimal_part); 429 } 430 decimal_buffer[decimal_pos] = '\0'; 431 432 // Compute the result size. 433 int integer_part_size = kBufferSize - 2 - integer_pos; 434 // Make room for zero termination. 435 unsigned result_size = integer_part_size + decimal_pos; 436 // If the number has a decimal part, leave room for the period. 437 if (decimal_pos > 0) result_size++; 438 // Allocate result and fill in the parts. 439 SimpleStringBuilder builder(result_size + 1); 440 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); 441 if (decimal_pos > 0) builder.AddCharacter('.'); 442 builder.AddSubstring(decimal_buffer, decimal_pos); 443 return builder.Finalize(); 444} 445 446} } // namespace v8::internal 447