• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
StringToDouble(UnicodeCache * unicode_cache,const char * str,int flags,double empty_string_val)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 
StringToDouble(UnicodeCache * unicode_cache,Vector<const char> str,int flags,double empty_string_val)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 
StringToDouble(UnicodeCache * unicode_cache,Vector<const uc16> str,int flags,double empty_string_val)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 
DoubleToCString(double v,Vector<char> buffer)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 
IntToCString(int n,Vector<char> buffer)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 
DoubleToFixedCString(double value,int f)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 
CreateExponentialRepresentation(char * decimal_rep,int exponent,bool negative,int significant_digits)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 
DoubleToExponentialCString(double value,int f)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 
DoubleToPrecisionCString(double value,int p)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 
DoubleToRadixCString(double value,int radix)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