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
37namespace v8 {
38namespace internal {
39
40
41double 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
49double 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
58double 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
68const 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
123const 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
143char* 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
214static 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
247char* 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
292char* 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
362char* 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