Home | History | Annotate | Download | only in src
      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