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 <math.h> 30 #include <limits.h> 31 32 #include "conversions-inl.h" 33 #include "dtoa.h" 34 #include "strtod.h" 35 #include "utils.h" 36 37 namespace v8 { 38 namespace internal { 39 40 41 double StringToDouble(UnicodeCache* unicode_cache, 42 const char* str, int flags, double empty_string_val) { 43 const char* end = str + StrLength(str); 44 return InternalStringToDouble(unicode_cache, str, end, flags, 45 empty_string_val); 46 } 47 48 49 double StringToDouble(UnicodeCache* unicode_cache, 50 Vector<const char> str, 51 int flags, 52 double empty_string_val) { 53 const char* end = str.start() + str.length(); 54 return InternalStringToDouble(unicode_cache, str.start(), end, flags, 55 empty_string_val); 56 } 57 58 double StringToDouble(UnicodeCache* unicode_cache, 59 Vector<const uc16> str, 60 int flags, 61 double empty_string_val) { 62 const uc16* end = str.start() + str.length(); 63 return InternalStringToDouble(unicode_cache, str.start(), end, flags, 64 empty_string_val); 65 } 66 67 68 const char* DoubleToCString(double v, Vector<char> buffer) { 69 switch (fpclassify(v)) { 70 case FP_NAN: return "NaN"; 71 case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity"); 72 case FP_ZERO: return "0"; 73 default: { 74 SimpleStringBuilder builder(buffer.start(), buffer.length()); 75 int decimal_point; 76 int sign; 77 const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1; 78 char decimal_rep[kV8DtoaBufferCapacity]; 79 int length; 80 81 DoubleToAscii(v, DTOA_SHORTEST, 0, 82 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), 83 &sign, &length, &decimal_point); 84 85 if (sign) builder.AddCharacter('-'); 86 87 if (length <= decimal_point && decimal_point <= 21) { 88 // ECMA-262 section 9.8.1 step 6. 89 builder.AddString(decimal_rep); 90 builder.AddPadding('0', decimal_point - length); 91 92 } else if (0 < decimal_point && decimal_point <= 21) { 93 // ECMA-262 section 9.8.1 step 7. 94 builder.AddSubstring(decimal_rep, decimal_point); 95 builder.AddCharacter('.'); 96 builder.AddString(decimal_rep + decimal_point); 97 98 } else if (decimal_point <= 0 && decimal_point > -6) { 99 // ECMA-262 section 9.8.1 step 8. 100 builder.AddString("0."); 101 builder.AddPadding('0', -decimal_point); 102 builder.AddString(decimal_rep); 103 104 } else { 105 // ECMA-262 section 9.8.1 step 9 and 10 combined. 106 builder.AddCharacter(decimal_rep[0]); 107 if (length != 1) { 108 builder.AddCharacter('.'); 109 builder.AddString(decimal_rep + 1); 110 } 111 builder.AddCharacter('e'); 112 builder.AddCharacter((decimal_point >= 0) ? '+' : '-'); 113 int exponent = decimal_point - 1; 114 if (exponent < 0) exponent = -exponent; 115 builder.AddDecimalInteger(exponent); 116 } 117 return builder.Finalize(); 118 } 119 } 120 } 121 122 123 const char* IntToCString(int n, Vector<char> buffer) { 124 bool negative = false; 125 if (n < 0) { 126 // We must not negate the most negative int. 127 if (n == kMinInt) return DoubleToCString(n, buffer); 128 negative = true; 129 n = -n; 130 } 131 // Build the string backwards from the least significant digit. 132 int i = buffer.length(); 133 buffer[--i] = '\0'; 134 do { 135 buffer[--i] = '0' + (n % 10); 136 n /= 10; 137 } while (n); 138 if (negative) buffer[--i] = '-'; 139 return buffer.start() + i; 140 } 141 142 143 char* DoubleToFixedCString(double value, int f) { 144 const int kMaxDigitsBeforePoint = 21; 145 const double kFirstNonFixed = 1e21; 146 const int kMaxDigitsAfterPoint = 20; 147 ASSERT(f >= 0); 148 ASSERT(f <= kMaxDigitsAfterPoint); 149 150 bool negative = false; 151 double abs_value = value; 152 if (value < 0) { 153 abs_value = -value; 154 negative = true; 155 } 156 157 // If abs_value has more than kMaxDigitsBeforePoint digits before the point 158 // use the non-fixed conversion routine. 159 if (abs_value >= kFirstNonFixed) { 160 char arr[100]; 161 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 162 return StrDup(DoubleToCString(value, buffer)); 163 } 164 165 // Find a sufficiently precise decimal representation of n. 166 int decimal_point; 167 int sign; 168 // Add space for the '\0' byte. 169 const int kDecimalRepCapacity = 170 kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1; 171 char decimal_rep[kDecimalRepCapacity]; 172 int decimal_rep_length; 173 DoubleToAscii(value, DTOA_FIXED, f, 174 Vector<char>(decimal_rep, kDecimalRepCapacity), 175 &sign, &decimal_rep_length, &decimal_point); 176 177 // Create a representation that is padded with zeros if needed. 178 int zero_prefix_length = 0; 179 int zero_postfix_length = 0; 180 181 if (decimal_point <= 0) { 182 zero_prefix_length = -decimal_point + 1; 183 decimal_point = 1; 184 } 185 186 if (zero_prefix_length + decimal_rep_length < decimal_point + f) { 187 zero_postfix_length = decimal_point + f - decimal_rep_length - 188 zero_prefix_length; 189 } 190 191 unsigned rep_length = 192 zero_prefix_length + decimal_rep_length + zero_postfix_length; 193 SimpleStringBuilder rep_builder(rep_length + 1); 194 rep_builder.AddPadding('0', zero_prefix_length); 195 rep_builder.AddString(decimal_rep); 196 rep_builder.AddPadding('0', zero_postfix_length); 197 char* rep = rep_builder.Finalize(); 198 199 // Create the result string by appending a minus and putting in a 200 // decimal point if needed. 201 unsigned result_size = decimal_point + f + 2; 202 SimpleStringBuilder builder(result_size + 1); 203 if (negative) builder.AddCharacter('-'); 204 builder.AddSubstring(rep, decimal_point); 205 if (f > 0) { 206 builder.AddCharacter('.'); 207 builder.AddSubstring(rep + decimal_point, f); 208 } 209 DeleteArray(rep); 210 return builder.Finalize(); 211 } 212 213 214 static char* CreateExponentialRepresentation(char* decimal_rep, 215 int exponent, 216 bool negative, 217 int significant_digits) { 218 bool negative_exponent = false; 219 if (exponent < 0) { 220 negative_exponent = true; 221 exponent = -exponent; 222 } 223 224 // Leave room in the result for appending a minus, for a period, the 225 // letter 'e', a minus or a plus depending on the exponent, and a 226 // three digit exponent. 227 unsigned result_size = significant_digits + 7; 228 SimpleStringBuilder builder(result_size + 1); 229 230 if (negative) builder.AddCharacter('-'); 231 builder.AddCharacter(decimal_rep[0]); 232 if (significant_digits != 1) { 233 builder.AddCharacter('.'); 234 builder.AddString(decimal_rep + 1); 235 int rep_length = StrLength(decimal_rep); 236 builder.AddPadding('0', significant_digits - rep_length); 237 } 238 239 builder.AddCharacter('e'); 240 builder.AddCharacter(negative_exponent ? '-' : '+'); 241 builder.AddDecimalInteger(exponent); 242 return builder.Finalize(); 243 } 244 245 246 247 char* DoubleToExponentialCString(double value, int f) { 248 const int kMaxDigitsAfterPoint = 20; 249 // f might be -1 to signal that f was undefined in JavaScript. 250 ASSERT(f >= -1 && f <= kMaxDigitsAfterPoint); 251 252 bool negative = false; 253 if (value < 0) { 254 value = -value; 255 negative = true; 256 } 257 258 // Find a sufficiently precise decimal representation of n. 259 int decimal_point; 260 int sign; 261 // f corresponds to the digits after the point. There is always one digit 262 // before the point. The number of requested_digits equals hence f + 1. 263 // And we have to add one character for the null-terminator. 264 const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1; 265 // Make sure that the buffer is big enough, even if we fall back to the 266 // shortest representation (which happens when f equals -1). 267 ASSERT(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1); 268 char decimal_rep[kV8DtoaBufferCapacity]; 269 int decimal_rep_length; 270 271 if (f == -1) { 272 DoubleToAscii(value, DTOA_SHORTEST, 0, 273 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), 274 &sign, &decimal_rep_length, &decimal_point); 275 f = decimal_rep_length - 1; 276 } else { 277 DoubleToAscii(value, DTOA_PRECISION, f + 1, 278 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), 279 &sign, &decimal_rep_length, &decimal_point); 280 } 281 ASSERT(decimal_rep_length > 0); 282 ASSERT(decimal_rep_length <= f + 1); 283 284 int exponent = decimal_point - 1; 285 char* result = 286 CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1); 287 288 return result; 289 } 290 291 292 char* DoubleToPrecisionCString(double value, int p) { 293 const int kMinimalDigits = 1; 294 const int kMaximalDigits = 21; 295 ASSERT(p >= kMinimalDigits && p <= kMaximalDigits); 296 USE(kMinimalDigits); 297 298 bool negative = false; 299 if (value < 0) { 300 value = -value; 301 negative = true; 302 } 303 304 // Find a sufficiently precise decimal representation of n. 305 int decimal_point; 306 int sign; 307 // Add one for the terminating null character. 308 const int kV8DtoaBufferCapacity = kMaximalDigits + 1; 309 char decimal_rep[kV8DtoaBufferCapacity]; 310 int decimal_rep_length; 311 312 DoubleToAscii(value, DTOA_PRECISION, p, 313 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), 314 &sign, &decimal_rep_length, &decimal_point); 315 ASSERT(decimal_rep_length <= p); 316 317 int exponent = decimal_point - 1; 318 319 char* result = NULL; 320 321 if (exponent < -6 || exponent >= p) { 322 result = 323 CreateExponentialRepresentation(decimal_rep, exponent, negative, p); 324 } else { 325 // Use fixed notation. 326 // 327 // Leave room in the result for appending a minus, a period and in 328 // the case where decimal_point is not positive for a zero in 329 // front of the period. 330 unsigned result_size = (decimal_point <= 0) 331 ? -decimal_point + p + 3 332 : p + 2; 333 SimpleStringBuilder builder(result_size + 1); 334 if (negative) builder.AddCharacter('-'); 335 if (decimal_point <= 0) { 336 builder.AddString("0."); 337 builder.AddPadding('0', -decimal_point); 338 builder.AddString(decimal_rep); 339 builder.AddPadding('0', p - decimal_rep_length); 340 } else { 341 const int m = Min(decimal_rep_length, decimal_point); 342 builder.AddSubstring(decimal_rep, m); 343 builder.AddPadding('0', decimal_point - decimal_rep_length); 344 if (decimal_point < p) { 345 builder.AddCharacter('.'); 346 const int extra = negative ? 2 : 1; 347 if (decimal_rep_length > decimal_point) { 348 const int len = StrLength(decimal_rep + decimal_point); 349 const int n = Min(len, p - (builder.position() - extra)); 350 builder.AddSubstring(decimal_rep + decimal_point, n); 351 } 352 builder.AddPadding('0', extra + (p - builder.position())); 353 } 354 } 355 result = builder.Finalize(); 356 } 357 358 return result; 359 } 360 361 362 char* DoubleToRadixCString(double value, int radix) { 363 ASSERT(radix >= 2 && radix <= 36); 364 365 // Character array used for conversion. 366 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 367 368 // Buffer for the integer part of the result. 1024 chars is enough 369 // for max integer value in radix 2. We need room for a sign too. 370 static const int kBufferSize = 1100; 371 char integer_buffer[kBufferSize]; 372 integer_buffer[kBufferSize - 1] = '\0'; 373 374 // Buffer for the decimal part of the result. We only generate up 375 // to kBufferSize - 1 chars for the decimal part. 376 char decimal_buffer[kBufferSize]; 377 decimal_buffer[kBufferSize - 1] = '\0'; 378 379 // Make sure the value is positive. 380 bool is_negative = value < 0.0; 381 if (is_negative) value = -value; 382 383 // Get the integer part and the decimal part. 384 double integer_part = floor(value); 385 double decimal_part = value - integer_part; 386 387 // Convert the integer part starting from the back. Always generate 388 // at least one digit. 389 int integer_pos = kBufferSize - 2; 390 do { 391 integer_buffer[integer_pos--] = 392 chars[static_cast<int>(fmod(integer_part, radix))]; 393 integer_part /= radix; 394 } while (integer_part >= 1.0); 395 // Sanity check. 396 ASSERT(integer_pos > 0); 397 // Add sign if needed. 398 if (is_negative) integer_buffer[integer_pos--] = '-'; 399 400 // Convert the decimal part. Repeatedly multiply by the radix to 401 // generate the next char. Never generate more than kBufferSize - 1 402 // chars. 403 // 404 // TODO(1093998): We will often generate a full decimal_buffer of 405 // chars because hitting zero will often not happen. The right 406 // solution would be to continue until the string representation can 407 // be read back and yield the original value. To implement this 408 // efficiently, we probably have to modify dtoa. 409 int decimal_pos = 0; 410 while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) { 411 decimal_part *= radix; 412 decimal_buffer[decimal_pos++] = 413 chars[static_cast<int>(floor(decimal_part))]; 414 decimal_part -= floor(decimal_part); 415 } 416 decimal_buffer[decimal_pos] = '\0'; 417 418 // Compute the result size. 419 int integer_part_size = kBufferSize - 2 - integer_pos; 420 // Make room for zero termination. 421 unsigned result_size = integer_part_size + decimal_pos; 422 // If the number has a decimal part, leave room for the period. 423 if (decimal_pos > 0) result_size++; 424 // Allocate result and fill in the parts. 425 SimpleStringBuilder builder(result_size + 1); 426 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); 427 if (decimal_pos > 0) builder.AddCharacter('.'); 428 builder.AddSubstring(decimal_buffer, decimal_pos); 429 return builder.Finalize(); 430 } 431 432 } } // namespace v8::internal 433