Home | History | Annotate | Download | only in wtf
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "DecimalNumber.h"
     28 #include <math.h>
     29 #include "wtf/MathExtras.h"
     30 #include "wtf/text/WTFString.h"
     31 
     32 namespace WTF {
     33 
     34 unsigned DecimalNumber::bufferLengthForStringDecimal() const
     35 {
     36     unsigned length = 0;
     37     // if the exponent is negative the number decimal representation is of the form:
     38     // [<sign>]0.[<zeros>]<significand>
     39     if (m_exponent < 0) {
     40         if (m_sign)
     41             ++length;
     42         length += 2; // for "0."
     43         length += -m_exponent - 1;
     44         length += m_precision;
     45         return length;
     46     }
     47 
     48     unsigned digitsBeforeDecimalPoint = m_exponent + 1;
     49 
     50     // If the precision is <= than the number of digits to get up to the decimal
     51     // point, then there is no fractional part, number is of the form:
     52     // [<sign>]<significand>[<zeros>]
     53     if (m_precision <= digitsBeforeDecimalPoint) {
     54         if (m_sign)
     55             ++length;
     56         length += m_precision;
     57         length += digitsBeforeDecimalPoint - m_precision;
     58         return length;
     59     }
     60 
     61     // If we get here, number starts before the decimal point, and ends after it,
     62     // as such is of the form:
     63     // [<sign>]<significand-begin>.<significand-end>
     64     if (m_sign)
     65         ++length;
     66     length += digitsBeforeDecimalPoint;
     67     ++length; // for decimal point
     68     length += m_precision - digitsBeforeDecimalPoint;
     69 
     70     return length;
     71 }
     72 
     73 unsigned DecimalNumber::bufferLengthForStringExponential() const
     74 {
     75     unsigned length = 0;
     76     if (m_sign)
     77         ++length;
     78 
     79     // Add the significand
     80     ++length;
     81 
     82     if (m_precision > 1) {
     83         ++length; // for decimal point
     84         length += m_precision - 1;
     85     }
     86 
     87     // Add "e+" or "e-"
     88     length += 2;
     89 
     90     int exponent = (m_exponent >= 0) ? m_exponent : -m_exponent;
     91 
     92     // Add the exponent
     93     if (exponent >= 100)
     94         ++length;
     95     if (exponent >= 10)
     96         ++length;
     97     ++length;
     98 
     99     return length;
    100 }
    101 
    102 unsigned DecimalNumber::toStringDecimal(LChar* buffer, unsigned bufferLength) const
    103 {
    104     ASSERT_UNUSED(bufferLength, bufferLength >= bufferLengthForStringDecimal());
    105 
    106     // Should always be at least one digit to add to the string!
    107     ASSERT(m_precision);
    108     LChar* next = buffer;
    109 
    110     // if the exponent is negative the number decimal representation is of the form:
    111     // [<sign>]0.[<zeros>]<significand>
    112     if (m_exponent < 0) {
    113         unsigned zeros = -m_exponent - 1;
    114 
    115         if (m_sign)
    116             *next++ = '-';
    117         *next++ = '0';
    118         *next++ = '.';
    119         for (unsigned i = 0; i < zeros; ++i)
    120             *next++ = '0';
    121         for (unsigned i = 0; i < m_precision; ++i)
    122             *next++ = m_significand[i];
    123 
    124         return next - buffer;
    125     }
    126 
    127     unsigned digitsBeforeDecimalPoint = m_exponent + 1;
    128 
    129     // If the precision is <= than the number of digits to get up to the decimal
    130     // point, then there is no fractional part, number is of the form:
    131     // [<sign>]<significand>[<zeros>]
    132     if (m_precision <= digitsBeforeDecimalPoint) {
    133         if (m_sign)
    134             *next++ = '-';
    135         for (unsigned i = 0; i < m_precision; ++i)
    136             *next++ = m_significand[i];
    137         for (unsigned i = 0; i < (digitsBeforeDecimalPoint - m_precision); ++i)
    138             *next++ = '0';
    139 
    140         return next - buffer;
    141     }
    142 
    143     // If we get here, number starts before the decimal point, and ends after it,
    144     // as such is of the form:
    145     // [<sign>]<significand-begin>.<significand-end>
    146 
    147     if (m_sign)
    148         *next++ = '-';
    149     for (unsigned i = 0; i < digitsBeforeDecimalPoint; ++i)
    150         *next++ = m_significand[i];
    151     *next++ = '.';
    152     for (unsigned i = digitsBeforeDecimalPoint; i < m_precision; ++i)
    153         *next++ = m_significand[i];
    154 
    155     return next - buffer;
    156 }
    157 
    158 unsigned DecimalNumber::toStringExponential(LChar* buffer, unsigned bufferLength) const
    159 {
    160     ASSERT_UNUSED(bufferLength, bufferLength >= bufferLengthForStringExponential());
    161 
    162     // Should always be at least one digit to add to the string!
    163     ASSERT(m_precision);
    164     LChar* next = buffer;
    165 
    166     // Add the sign
    167     if (m_sign)
    168         *next++ = '-';
    169 
    170     // Add the significand
    171     *next++ = m_significand[0];
    172     if (m_precision > 1) {
    173         *next++ = '.';
    174         for (unsigned i = 1; i < m_precision; ++i)
    175             *next++ = m_significand[i];
    176     }
    177 
    178     // Add "e+" or "e-"
    179     *next++ = 'e';
    180     int exponent;
    181     if (m_exponent >= 0) {
    182         *next++ = '+';
    183         exponent = m_exponent;
    184     } else {
    185         *next++ = '-';
    186         exponent = -m_exponent;
    187     }
    188 
    189     // Add the exponent
    190     if (exponent >= 100)
    191         *next++ = '0' + exponent / 100;
    192     if (exponent >= 10)
    193         *next++ = '0' + (exponent % 100) / 10;
    194     *next++ = '0' + exponent % 10;
    195 
    196     return next - buffer;
    197 }
    198 
    199 } // namespace WTF
    200