double-conversion (empty) → 0.1.0.0
raw patch · 54 files changed
+13796/−0 lines, 54 filesdep +basedep +ghc-primdep +integersetup-changed
Dependencies added: base, ghc-prim, integer, integer-gmp, text
Files
- Data/Double/Conversion.hs +100/−0
- LICENSE +29/−0
- README.markdown +30/−0
- Setup.lhs +3/−0
- benchmarks/Benchmarks.hs +32/−0
- benchmarks/double-conversion-benchmarks.cabal +15/−0
- cbits/hs-double-conversion.cc +113/−0
- double-conversion.cabal +91/−0
- double-conversion/COPYING +26/−0
- double-conversion/LICENSE +26/−0
- double-conversion/Makefile +7/−0
- double-conversion/README +11/−0
- double-conversion/SConstruct +11/−0
- double-conversion/src/SConscript +12/−0
- double-conversion/src/bignum-dtoa.cc +653/−0
- double-conversion/src/bignum-dtoa.h +82/−0
- double-conversion/src/bignum.cc +764/−0
- double-conversion/src/bignum.h +141/−0
- double-conversion/src/cached-powers.cc +177/−0
- double-conversion/src/cached-powers.h +64/−0
- double-conversion/src/diy-fp.cc +57/−0
- double-conversion/src/diy-fp.h +118/−0
- double-conversion/src/double-conversion.cc +869/−0
- double-conversion/src/double-conversion.h +498/−0
- double-conversion/src/double.h +245/−0
- double-conversion/src/fast-dtoa.cc +735/−0
- double-conversion/src/fast-dtoa.h +84/−0
- double-conversion/src/fixed-dtoa.cc +402/−0
- double-conversion/src/fixed-dtoa.h +56/−0
- double-conversion/src/strtod.cc +441/−0
- double-conversion/src/strtod.h +41/−0
- double-conversion/src/utils.h +297/−0
- double-conversion/test/cctest/SConscript +16/−0
- double-conversion/test/cctest/cctest.cc +122/−0
- double-conversion/test/cctest/cctest.h +141/−0
- double-conversion/test/cctest/checks.h +314/−0
- double-conversion/test/cctest/gay-fixed.cc too large to diff
- double-conversion/test/cctest/gay-fixed.h +46/−0
- double-conversion/test/cctest/gay-precision.cc too large to diff
- double-conversion/test/cctest/gay-precision.h +46/−0
- double-conversion/test/cctest/gay-shortest.cc too large to diff
- double-conversion/test/cctest/gay-shortest.h +43/−0
- double-conversion/test/cctest/test-bignum-dtoa.cc +313/−0
- double-conversion/test/cctest/test-bignum.cc +1502/−0
- double-conversion/test/cctest/test-conversions.cc +3039/−0
- double-conversion/test/cctest/test-diy-fp.cc +65/−0
- double-conversion/test/cctest/test-double.cc +218/−0
- double-conversion/test/cctest/test-dtoa.cc +422/−0
- double-conversion/test/cctest/test-fast-dtoa.cc +266/−0
- double-conversion/test/cctest/test-fixed-dtoa.cc +511/−0
- double-conversion/test/cctest/test-strtod.cc +452/−0
- include/hs-double-conversion.h +24/−0
- tests/Properties.hs +11/−0
- tests/double-conversion-tests.cabal +15/−0
+ Data/Double/Conversion.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE ForeignFunctionInterface, MagicHash, Rank2Types,+ UnliftedFFITypes #-}++-- |+-- Module : Data.Double.Conversion+-- Copyright : (c) 2011 MailRank, Inc.+--+-- License : BSD-style+-- Maintainer : bos@mailrank.com+-- Stability : experimental+-- Portability : GHC+--+-- Fast, efficient support for converting between double precision+-- floating point values and text.++module Data.Double.Conversion+ (+ toExponential+ , toFixed+ , toPrecision+ , toShortest+ ) where++import Control.Monad (when)+import Control.Monad.ST (unsafeIOToST, runST)+import Data.Text.Internal (Text(Text))+import Foreign.C.Types (CDouble, CInt)+import GHC.Prim (MutableByteArray#)+import qualified Data.Text.Array as A++-- | Compute a representation in exponential format with the requested+-- number of digits after the decimal point. The last emitted digit is+-- rounded. If -1 digits are requested, then the shortest exponential+-- representation is computed.+toExponential :: Int -> Double -> Text+toExponential ndigits = convert "toExponential" len $ \val mba ->+ c_ToExponential val mba (fromIntegral ndigits)+ where len = c_ToExponentialLength+ {-# NOINLINE len #-}++-- | Compute a decimal representation with a fixed number of digits+-- after the decimal point. The last emitted digit is rounded.+toFixed :: Int -> Double -> Text+toFixed ndigits = convert "toFixed" len $ \val mba ->+ c_ToFixed val mba (fromIntegral ndigits)+ where len = c_ToFixedLength+ {-# NOINLINE len #-}++-- | Compute the shortest string of digits that correctly represent+-- the input number.+toShortest :: Double -> Text+toShortest = convert "toShortest" len c_ToShortest+ where len = c_ToShortestLength+ {-# NOINLINE len #-}++-- | Compute @precision@ leading digits of the given value either in+-- exponential or decimal format. The last computed digit is rounded.+toPrecision :: Int -> Double -> Text+toPrecision ndigits = convert "toPrecision" len $ \val mba ->+ c_ToPrecision val mba (fromIntegral ndigits)+ where len = c_ToPrecisionLength+ {-# NOINLINE len #-}++convert :: String -> CInt+ -> (forall s. CDouble -> MutableByteArray# s -> IO CInt)+ -> Double -> Text+convert func len act val = runST go+ where+ go = do+ buf <- A.new (fromIntegral len)+ size <- unsafeIOToST $ act (realToFrac val) (A.maBA buf)+ when (size == -1) .+ fail $ "Data.Double.Conversion." ++ func +++ ": conversion failed (invalid precision requested)"+ frozen <- A.unsafeFreeze buf+ return $ Text frozen 0 (fromIntegral size)++foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortestLength"+ c_ToShortestLength :: CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToShortest"+ c_ToShortest :: CDouble -> MutableByteArray# s -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixedLength"+ c_ToFixedLength :: CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToFixed"+ c_ToFixed :: CDouble -> MutableByteArray# s -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponentialLength"+ c_ToExponentialLength :: CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToExponential"+ c_ToExponential :: CDouble -> MutableByteArray# s -> CInt -> IO CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecisionLength"+ c_ToPrecisionLength :: CInt++foreign import ccall unsafe "hs-double-conversion.h _hs_ToPrecision"+ c_ToPrecision :: CDouble -> MutableByteArray# s -> CInt -> IO CInt
+ LICENSE view
@@ -0,0 +1,29 @@+See double-conversion/LICENSE for the license that applies to the C+++library.++Copyright (c) 2011 MailRank, Inc.+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.markdown view
@@ -0,0 +1,30 @@+# Welcome to double-conversion++double-conversion is a fast Haskell library for converting between+double precision floating point numbers and text strings. It is+implemented as a binding to the V8-derived C++ [double-conversion+library](http://code.google.com/p/double-conversion/).++# Join in!++We are happy to receive bug reports, fixes, documentation enhancements,+and other improvements.++Please report bugs via the+[github issue tracker](https://github.com/mailrank/double-conversion/issues).++Master [git repository](https://github.com/mailrank/double-conversion):++* `git clone git://github.com/mailrank/double-conversion.git`++There's also a [Mercurial mirror](https://bitbucket.org/bos/double-conversion):++* `hg clone https://bitbucket.org/bos/double-conversion`++(You can create and contribute changes using either git or Mercurial.)++Authors+-------++This library is written and maintained by Bryan O'Sullivan,+<bos@mailrank.com>.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ benchmarks/Benchmarks.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE ForeignFunctionInterface, OverloadedStrings #-}++import Criterion.Main+import Data.Double.Conversion+import Foreign.C.Types (CInt, CDouble)+import qualified Data.Text as T++showText :: Double -> T.Text+showText d = T.pack (show d)++main = defaultMain [+ bgroup "haskell" [+ bench "show" $ whnf showText pi+ , bench "toShortest" $ whnf toShortest pi+ , bench "toExponential" $ whnf (toExponential 3) pi+ , bench "toPrecision" $ whnf (toExponential 8) pi+ , bench "toFixed" $ whnf (toFixed 8) pi+ ]+ , bgroup "sprintf" [+ bench "exact" $ whnf sprintf_exact pi+ , bench "exponential" $ whnf (sprintf_exponential 3) pi+ , bench "fixed" $ whnf (sprintf_fixed 8) pi+ , bench "generic" $ whnf (sprintf_generic 6) pi+ , bench "generic_default" $ whnf sprintf_generic_default pi+ ]+ ]++foreign import ccall unsafe sprintf_exact :: CDouble -> ()+foreign import ccall unsafe sprintf_exponential :: CInt -> CDouble -> ()+foreign import ccall unsafe sprintf_fixed :: CInt -> CDouble -> ()+foreign import ccall unsafe sprintf_generic :: CInt -> CDouble -> ()+foreign import ccall unsafe sprintf_generic_default :: CDouble -> ()
+ benchmarks/double-conversion-benchmarks.cabal view
@@ -0,0 +1,15 @@+name: double-conversion-benchmarks+version: 0+cabal-version: >= 1.8+build-type: Simple++executable bm+ main-is: Benchmarks.hs++ c-sources: sprintf.c++ build-depends:+ base,+ criterion >= 0.5.0.10,+ double-conversion,+ text >= 0.11.0.8
+ cbits/hs-double-conversion.cc view
@@ -0,0 +1,113 @@+#include "double-conversion.h"+#include "hs-double-conversion.h"+#include <stdio.h>++using namespace double_conversion;++static const int kToShortestLength = 24;++extern "C"+int _hs_ToShortestLength(void)+{+ return kToShortestLength;+}++static const int kToFixedLength =+ 1 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint ++ 1 + DoubleToStringConverter::kMaxFixedDigitsAfterPoint;++extern "C"+int _hs_ToFixedLength(void)+{+ return kToFixedLength;+}++static const int kToExponentialLength =+ DoubleToStringConverter::kMaxExponentialDigits + 8;++extern "C"+int _hs_ToExponentialLength(void)+{+ return kToExponentialLength;+}++static const int kToPrecisionLength =+ DoubleToStringConverter::kMaxPrecisionDigits + 7;++extern "C"+int _hs_ToPrecisionLength(void)+{+ return kToPrecisionLength;+}++static int copy(uint16_t *buf, const StringBuilder& builder, const char *cbuf)+{+ const int pos = builder.position();+ for (int i = 0; i < pos; i++)+ buf[i] = cbuf[i];+ return pos;+}++static inline const DoubleToStringConverter& defaultConverter(void)+{+ const int flags = DoubleToStringConverter::UNIQUE_ZERO;+ static DoubleToStringConverter converter(flags,+ "Infinity",+ "NaN",+ 'e',+ -6, 21,+ 6, 0);+ return converter;+}++extern "C"+int _hs_ToShortest(double value, uint16_t *buf)+{+ char cbuf[kToShortestLength];+ StringBuilder builder(cbuf, kToShortestLength);+ bool ok = defaultConverter().ToShortest(value, &builder);++ if (!ok)+ return -1;++ return copy(buf, builder, cbuf);+}++extern "C"+int _hs_ToFixed(double value, uint16_t *buf, const int ndigits)+{+ char cbuf[kToFixedLength];+ StringBuilder builder(cbuf, kToFixedLength);+ bool ok = defaultConverter().ToFixed(value, ndigits, &builder);++ if (!ok)+ return -1;+ + return copy(buf, builder, cbuf);+}++extern "C"+int _hs_ToExponential(double value, uint16_t *buf, const int ndigits)+{+ char cbuf[kToExponentialLength];+ StringBuilder builder(cbuf, kToExponentialLength);+ bool ok = defaultConverter().ToExponential(value, ndigits, &builder);++ if (!ok)+ return -1;+ + return copy(buf, builder, cbuf);+}++extern "C"+int _hs_ToPrecision(double value, uint16_t *buf, const int precision)+{+ char cbuf[kToPrecisionLength];+ StringBuilder builder(cbuf, kToPrecisionLength);+ bool ok = defaultConverter().ToPrecision(value, precision, &builder);++ if (!ok)+ return -1;+ + return copy(buf, builder, cbuf);+}
+ double-conversion.cabal view
@@ -0,0 +1,91 @@+name: double-conversion+version: 0.1.0.0+license: BSD3+license-file: LICENSE+homepage: https://github.com/mailrank/double-conversion+bug-reports: https://github.com/mailrank/double-conversion/issues+category: Text+author: Bryan O'Sullivan <bos@mailrank.com>+maintainer: Bryan O'Sullivan <bos@mailrank.com>+stability: experimental+tested-with: GHC == 7.0.3+synopsis: Fast conversion between double precision floating point and text+cabal-version: >= 1.8+build-type: Simple+description:+ A library that performs fast conversion between double precision+ floating point and text, implemented as bindings to the C+++ double-conversion library written by Florian Loitsch at Google.++extra-source-files:+ README.markdown+ benchmarks/*.cabal+ benchmarks/*.hs+ double-conversion/COPYING+ double-conversion/LICENSE+ double-conversion/Makefile+ double-conversion/README+ double-conversion/SConstruct+ double-conversion/src/*.cc+ double-conversion/src/*.h+ double-conversion/src/SConscript+ double-conversion/test/cctest/*.cc+ double-conversion/test/cctest/*.h+ double-conversion/test/cctest/SConscript+ include/*.h+ tests/*.cabal+ tests/*.hs++flag developer+ description: operate in developer mode+ default: False++library+ c-sources:+ cbits/hs-double-conversion.cc+ double-conversion/src/bignum.cc+ double-conversion/src/bignum-dtoa.cc+ double-conversion/src/cached-powers.cc+ double-conversion/src/diy-fp.cc+ double-conversion/src/double-conversion.cc+ double-conversion/src/fast-dtoa.cc+ double-conversion/src/fixed-dtoa.cc+ double-conversion/src/strtod.cc++ extra-libraries: stdc++++ include-dirs:+ double-conversion/src+ include++ exposed-modules:+ Data.Double.Conversion++ build-depends:+ base == 4.*,+ ghc-prim,+ text >= 0.11.0.8++ if flag(developer)+ ghc-options: -Werror+ ghc-prof-options: -auto-all+ else+ cc-options: -DNDEBUG++ ghc-options: -Wall++ cpp-options: -DINTEGER_GMP++ if impl(ghc >= 6.11)+ build-depends: integer-gmp >= 0.2 && < 0.3++ if impl(ghc >= 6.9) && impl(ghc < 6.11)+ build-depends: integer >= 0.1 && < 0.2++source-repository head+ type: git+ location: https://github.com/mailrank/double-conversion++source-repository head+ type: mercurial+ location: https://bitbucket.org/bos/double-conversion
+ double-conversion/COPYING view
@@ -0,0 +1,26 @@+Copyright 2006-2011, the V8 project authors. All rights reserved.+Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.+ * Neither the name of Google Inc. nor the names of its+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ double-conversion/LICENSE view
@@ -0,0 +1,26 @@+Copyright 2006-2011, the V8 project authors. All rights reserved.+Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.+ * Neither the name of Google Inc. nor the names of its+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ double-conversion/Makefile view
@@ -0,0 +1,7 @@+all:+ scons debug=1++test:+ ./run_tests --list | tr -d '<' | xargs ./run_tests++.PHONY: test all
+ double-conversion/README view
@@ -0,0 +1,11 @@+http://code.google.com/p/double-conversion++This project (double-conversion) provides binary-decimal and decimal-binary+routines for IEEE doubles.++The library consists of efficient conversion routines that have been extracted+from the V8 JavaScript engine. The code has been refactored and improved so that+it can be used more easily in other projects.++There is extensive documentation in src/double-conversion.h. Other examples can+be found in test/cctest/test-conversions.cc.
+ double-conversion/SConstruct view
@@ -0,0 +1,11 @@+double_conversion_sources = ['src/' + x for x in SConscript('src/SConscript')]+double_conversion_test_sources = ['test/cctest/' + x for x in SConscript('test/cctest/SConscript')]+test = double_conversion_sources + double_conversion_test_sources+print(test)+env = Environment(CPPPATH='#/src')+debug = ARGUMENTS.get('debug', 0)+if int(debug):+ env.Append(CCFLAGS = '-g')+print double_conversion_sources+print double_conversion_test_sources+env.Program('run_tests', double_conversion_sources + double_conversion_test_sources)
+ double-conversion/src/SConscript view
@@ -0,0 +1,12 @@+# -*- coding: utf-8 -*-+double_conversion_sources = [+ 'bignum.cc',+ 'bignum-dtoa.cc',+ 'cached-powers.cc',+ 'diy-fp.cc',+ 'double-conversion.cc',+ 'fast-dtoa.cc',+ 'fixed-dtoa.cc',+ 'strtod.cc'+ ]+Return('double_conversion_sources')
+ double-conversion/src/bignum-dtoa.cc view
@@ -0,0 +1,653 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <math.h>++#include "bignum-dtoa.h"++#include "bignum.h"+#include "double.h"++namespace double_conversion {++static int NormalizedExponent(uint64_t significand, int exponent) {+ ASSERT(significand != 0);+ while ((significand & Double::kHiddenBit) == 0) {+ significand = significand << 1;+ exponent = exponent - 1;+ }+ return exponent;+}+++// Forward declarations:+// Returns an estimation of k such that 10^(k-1) <= v < 10^k.+static int EstimatePower(int exponent);+// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator+// and denominator.+static void InitialScaledStartValues(double v,+ int estimated_power,+ bool need_boundary_deltas,+ Bignum* numerator,+ Bignum* denominator,+ Bignum* delta_minus,+ Bignum* delta_plus);+// Multiplies numerator/denominator so that its values lies in the range 1-10.+// Returns decimal_point s.t.+// v = numerator'/denominator' * 10^(decimal_point-1)+// where numerator' and denominator' are the values of numerator and+// denominator after the call to this function.+static void FixupMultiply10(int estimated_power, bool is_even,+ int* decimal_point,+ Bignum* numerator, Bignum* denominator,+ Bignum* delta_minus, Bignum* delta_plus);+// Generates digits from the left to the right and stops when the generated+// digits yield the shortest decimal representation of v.+static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,+ Bignum* delta_minus, Bignum* delta_plus,+ bool is_even,+ Vector<char> buffer, int* length);+// Generates 'requested_digits' after the decimal point.+static void BignumToFixed(int requested_digits, int* decimal_point,+ Bignum* numerator, Bignum* denominator,+ Vector<char>(buffer), int* length);+// Generates 'count' digits of numerator/denominator.+// Once 'count' digits have been produced rounds the result depending on the+// remainder (remainders of exactly .5 round upwards). Might update the+// decimal_point when rounding up (for example for 0.9999).+static void GenerateCountedDigits(int count, int* decimal_point,+ Bignum* numerator, Bignum* denominator,+ Vector<char>(buffer), int* length);+++void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,+ Vector<char> buffer, int* length, int* decimal_point) {+ ASSERT(v > 0);+ ASSERT(!Double(v).IsSpecial());+ uint64_t significand = Double(v).Significand();+ bool is_even = (significand & 1) == 0;+ int exponent = Double(v).Exponent();+ int normalized_exponent = NormalizedExponent(significand, exponent);+ // estimated_power might be too low by 1.+ int estimated_power = EstimatePower(normalized_exponent);++ // Shortcut for Fixed.+ // The requested digits correspond to the digits after the point. If the+ // number is much too small, then there is no need in trying to get any+ // digits.+ if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {+ buffer[0] = '\0';+ *length = 0;+ // Set decimal-point to -requested_digits. This is what Gay does.+ // Note that it should not have any effect anyways since the string is+ // empty.+ *decimal_point = -requested_digits;+ return;+ }++ Bignum numerator;+ Bignum denominator;+ Bignum delta_minus;+ Bignum delta_plus;+ // Make sure the bignum can grow large enough. The smallest double equals+ // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.+ // The maximum double is 1.7976931348623157e308 which needs fewer than+ // 308*4 binary digits.+ ASSERT(Bignum::kMaxSignificantBits >= 324*4);+ bool need_boundary_deltas = (mode == BIGNUM_DTOA_SHORTEST);+ InitialScaledStartValues(v, estimated_power, need_boundary_deltas,+ &numerator, &denominator,+ &delta_minus, &delta_plus);+ // We now have v = (numerator / denominator) * 10^estimated_power.+ FixupMultiply10(estimated_power, is_even, decimal_point,+ &numerator, &denominator,+ &delta_minus, &delta_plus);+ // We now have v = (numerator / denominator) * 10^(decimal_point-1), and+ // 1 <= (numerator + delta_plus) / denominator < 10+ switch (mode) {+ case BIGNUM_DTOA_SHORTEST:+ GenerateShortestDigits(&numerator, &denominator,+ &delta_minus, &delta_plus,+ is_even, buffer, length);+ break;+ case BIGNUM_DTOA_FIXED:+ BignumToFixed(requested_digits, decimal_point,+ &numerator, &denominator,+ buffer, length);+ break;+ case BIGNUM_DTOA_PRECISION:+ GenerateCountedDigits(requested_digits, decimal_point,+ &numerator, &denominator,+ buffer, length);+ break;+ default:+ UNREACHABLE();+ }+ buffer[*length] = '\0';+}+++// The procedure starts generating digits from the left to the right and stops+// when the generated digits yield the shortest decimal representation of v. A+// decimal representation of v is a number lying closer to v than to any other+// double, so it converts to v when read.+//+// This is true if d, the decimal representation, is between m- and m+, the+// upper and lower boundaries. d must be strictly between them if !is_even.+// m- := (numerator - delta_minus) / denominator+// m+ := (numerator + delta_plus) / denominator+//+// Precondition: 0 <= (numerator+delta_plus) / denominator < 10.+// If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit+// will be produced. This should be the standard precondition.+static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,+ Bignum* delta_minus, Bignum* delta_plus,+ bool is_even,+ Vector<char> buffer, int* length) {+ // Small optimization: if delta_minus and delta_plus are the same just reuse+ // one of the two bignums.+ if (Bignum::Equal(*delta_minus, *delta_plus)) {+ delta_plus = delta_minus;+ }+ *length = 0;+ while (true) {+ uint16_t digit;+ digit = numerator->DivideModuloIntBignum(*denominator);+ ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.+ // digit = numerator / denominator (integer division).+ // numerator = numerator % denominator.+ buffer[(*length)++] = digit + '0';++ // Can we stop already?+ // If the remainder of the division is less than the distance to the lower+ // boundary we can stop. In this case we simply round down (discarding the+ // remainder).+ // Similarly we test if we can round up (using the upper boundary).+ bool in_delta_room_minus;+ bool in_delta_room_plus;+ if (is_even) {+ in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);+ } else {+ in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);+ }+ if (is_even) {+ in_delta_room_plus =+ Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;+ } else {+ in_delta_room_plus =+ Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;+ }+ if (!in_delta_room_minus && !in_delta_room_plus) {+ // Prepare for next iteration.+ numerator->Times10();+ delta_minus->Times10();+ // We optimized delta_plus to be equal to delta_minus (if they share the+ // same value). So don't multiply delta_plus if they point to the same+ // object.+ if (delta_minus != delta_plus) {+ delta_plus->Times10();+ }+ } else if (in_delta_room_minus && in_delta_room_plus) {+ // Let's see if 2*numerator < denominator.+ // If yes, then the next digit would be < 5 and we can round down.+ int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);+ if (compare < 0) {+ // Remaining digits are less than .5. -> Round down (== do nothing).+ } else if (compare > 0) {+ // Remaining digits are more than .5 of denominator. -> Round up.+ // Note that the last digit could not be a '9' as otherwise the whole+ // loop would have stopped earlier.+ // We still have an assert here in case the preconditions were not+ // satisfied.+ ASSERT(buffer[(*length) - 1] != '9');+ buffer[(*length) - 1]++;+ } else {+ // Halfway case.+ // TODO(floitsch): need a way to solve half-way cases.+ // For now let's round towards even (since this is what Gay seems to+ // do).++ if ((buffer[(*length) - 1] - '0') % 2 == 0) {+ // Round down => Do nothing.+ } else {+ ASSERT(buffer[(*length) - 1] != '9');+ buffer[(*length) - 1]++;+ }+ }+ return;+ } else if (in_delta_room_minus) {+ // Round down (== do nothing).+ return;+ } else { // in_delta_room_plus+ // Round up.+ // Note again that the last digit could not be '9' since this would have+ // stopped the loop earlier.+ // We still have an ASSERT here, in case the preconditions were not+ // satisfied.+ ASSERT(buffer[(*length) -1] != '9');+ buffer[(*length) - 1]++;+ return;+ }+ }+}+++// Let v = numerator / denominator < 10.+// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)+// from left to right. Once 'count' digits have been produced we decide wether+// to round up or down. Remainders of exactly .5 round upwards. Numbers such+// as 9.999999 propagate a carry all the way, and change the+// exponent (decimal_point), when rounding upwards.+static void GenerateCountedDigits(int count, int* decimal_point,+ Bignum* numerator, Bignum* denominator,+ Vector<char>(buffer), int* length) {+ ASSERT(count >= 0);+ for (int i = 0; i < count - 1; ++i) {+ uint16_t digit;+ digit = numerator->DivideModuloIntBignum(*denominator);+ ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.+ // digit = numerator / denominator (integer division).+ // numerator = numerator % denominator.+ buffer[i] = digit + '0';+ // Prepare for next iteration.+ numerator->Times10();+ }+ // Generate the last digit.+ uint16_t digit;+ digit = numerator->DivideModuloIntBignum(*denominator);+ if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {+ digit++;+ }+ buffer[count - 1] = digit + '0';+ // Correct bad digits (in case we had a sequence of '9's). Propagate the+ // carry until we hat a non-'9' or til we reach the first digit.+ for (int i = count - 1; i > 0; --i) {+ if (buffer[i] != '0' + 10) break;+ buffer[i] = '0';+ buffer[i - 1]++;+ }+ if (buffer[0] == '0' + 10) {+ // Propagate a carry past the top place.+ buffer[0] = '1';+ (*decimal_point)++;+ }+ *length = count;+}+++// Generates 'requested_digits' after the decimal point. It might omit+// trailing '0's. If the input number is too small then no digits at all are+// generated (ex.: 2 fixed digits for 0.00001).+//+// Input verifies: 1 <= (numerator + delta) / denominator < 10.+static void BignumToFixed(int requested_digits, int* decimal_point,+ Bignum* numerator, Bignum* denominator,+ Vector<char>(buffer), int* length) {+ // Note that we have to look at more than just the requested_digits, since+ // a number could be rounded up. Example: v=0.5 with requested_digits=0.+ // Even though the power of v equals 0 we can't just stop here.+ if (-(*decimal_point) > requested_digits) {+ // The number is definitively too small.+ // Ex: 0.001 with requested_digits == 1.+ // Set decimal-point to -requested_digits. This is what Gay does.+ // Note that it should not have any effect anyways since the string is+ // empty.+ *decimal_point = -requested_digits;+ *length = 0;+ return;+ } else if (-(*decimal_point) == requested_digits) {+ // We only need to verify if the number rounds down or up.+ // Ex: 0.04 and 0.06 with requested_digits == 1.+ ASSERT(*decimal_point == -requested_digits);+ // Initially the fraction lies in range (1, 10]. Multiply the denominator+ // by 10 so that we can compare more easily.+ denominator->Times10();+ if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {+ // If the fraction is >= 0.5 then we have to include the rounded+ // digit.+ buffer[0] = '1';+ *length = 1;+ (*decimal_point)++;+ } else {+ // Note that we caught most of similar cases earlier.+ *length = 0;+ }+ return;+ } else {+ // The requested digits correspond to the digits after the point.+ // The variable 'needed_digits' includes the digits before the point.+ int needed_digits = (*decimal_point) + requested_digits;+ GenerateCountedDigits(needed_digits, decimal_point,+ numerator, denominator,+ buffer, length);+ }+}+++// Returns an estimation of k such that 10^(k-1) <= v < 10^k where+// v = f * 2^exponent and 2^52 <= f < 2^53.+// v is hence a normalized double with the given exponent. The output is an+// approximation for the exponent of the decimal approimation .digits * 10^k.+//+// The result might undershoot by 1 in which case 10^k <= v < 10^k+1.+// Note: this property holds for v's upper boundary m+ too.+// 10^k <= m+ < 10^k+1.+// (see explanation below).+//+// Examples:+// EstimatePower(0) => 16+// EstimatePower(-52) => 0+//+// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.+static int EstimatePower(int exponent) {+ // This function estimates log10 of v where v = f*2^e (with e == exponent).+ // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).+ // Note that f is bounded by its container size. Let p = 53 (the double's+ // significand size). Then 2^(p-1) <= f < 2^p.+ //+ // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close+ // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).+ // The computed number undershoots by less than 0.631 (when we compute log3+ // and not log10).+ //+ // Optimization: since we only need an approximated result this computation+ // can be performed on 64 bit integers. On x86/x64 architecture the speedup is+ // not really measurable, though.+ //+ // Since we want to avoid overshooting we decrement by 1e10 so that+ // floating-point imprecisions don't affect us.+ //+ // Explanation for v's boundary m+: the computation takes advantage of+ // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement+ // (even for denormals where the delta can be much more important).++ const double k1Log10 = 0.30102999566398114; // 1/lg(10)++ // For doubles len(f) == 53 (don't forget the hidden bit).+ const int kSignificandSize = 53;+ double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);+ return static_cast<int>(estimate);+}+++// See comments for InitialScaledStartValues.+static void InitialScaledStartValuesPositiveExponent(+ double v, int estimated_power, bool need_boundary_deltas,+ Bignum* numerator, Bignum* denominator,+ Bignum* delta_minus, Bignum* delta_plus) {+ // A positive exponent implies a positive power.+ ASSERT(estimated_power >= 0);+ // Since the estimated_power is positive we simply multiply the denominator+ // by 10^estimated_power.++ // numerator = v.+ numerator->AssignUInt64(Double(v).Significand());+ numerator->ShiftLeft(Double(v).Exponent());+ // denominator = 10^estimated_power.+ denominator->AssignPowerUInt16(10, estimated_power);++ if (need_boundary_deltas) {+ // Introduce a common denominator so that the deltas to the boundaries are+ // integers.+ denominator->ShiftLeft(1);+ numerator->ShiftLeft(1);+ // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common+ // denominator (of 2) delta_plus equals 2^e.+ delta_plus->AssignUInt16(1);+ delta_plus->ShiftLeft(Double(v).Exponent());+ // Same for delta_minus (with adjustments below if f == 2^p-1).+ delta_minus->AssignUInt16(1);+ delta_minus->ShiftLeft(Double(v).Exponent());++ // If the significand (without the hidden bit) is 0, then the lower+ // boundary is closer than just half a ulp (unit in the last place).+ // There is only one exception: if the next lower number is a denormal then+ // the distance is 1 ulp. This cannot be the case for exponent >= 0 (but we+ // have to test it in the other function where exponent < 0).+ uint64_t v_bits = Double(v).AsUint64();+ if ((v_bits & Double::kSignificandMask) == 0) {+ // The lower boundary is closer at half the distance of "normal" numbers.+ // Increase the common denominator and adapt all but the delta_minus.+ denominator->ShiftLeft(1); // *2+ numerator->ShiftLeft(1); // *2+ delta_plus->ShiftLeft(1); // *2+ }+ }+}+++// See comments for InitialScaledStartValues+static void InitialScaledStartValuesNegativeExponentPositivePower(+ double v, int estimated_power, bool need_boundary_deltas,+ Bignum* numerator, Bignum* denominator,+ Bignum* delta_minus, Bignum* delta_plus) {+ uint64_t significand = Double(v).Significand();+ int exponent = Double(v).Exponent();+ // v = f * 2^e with e < 0, and with estimated_power >= 0.+ // This means that e is close to 0 (have a look at how estimated_power is+ // computed).++ // numerator = significand+ // since v = significand * 2^exponent this is equivalent to+ // numerator = v * / 2^-exponent+ numerator->AssignUInt64(significand);+ // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)+ denominator->AssignPowerUInt16(10, estimated_power);+ denominator->ShiftLeft(-exponent);++ if (need_boundary_deltas) {+ // Introduce a common denominator so that the deltas to the boundaries are+ // integers.+ denominator->ShiftLeft(1);+ numerator->ShiftLeft(1);+ // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common+ // denominator (of 2) delta_plus equals 2^e.+ // Given that the denominator already includes v's exponent the distance+ // to the boundaries is simply 1.+ delta_plus->AssignUInt16(1);+ // Same for delta_minus (with adjustments below if f == 2^p-1).+ delta_minus->AssignUInt16(1);++ // If the significand (without the hidden bit) is 0, then the lower+ // boundary is closer than just one ulp (unit in the last place).+ // There is only one exception: if the next lower number is a denormal+ // then the distance is 1 ulp. Since the exponent is close to zero+ // (otherwise estimated_power would have been negative) this cannot happen+ // here either.+ uint64_t v_bits = Double(v).AsUint64();+ if ((v_bits & Double::kSignificandMask) == 0) {+ // The lower boundary is closer at half the distance of "normal" numbers.+ // Increase the denominator and adapt all but the delta_minus.+ denominator->ShiftLeft(1); // *2+ numerator->ShiftLeft(1); // *2+ delta_plus->ShiftLeft(1); // *2+ }+ }+}+++// See comments for InitialScaledStartValues+static void InitialScaledStartValuesNegativeExponentNegativePower(+ double v, int estimated_power, bool need_boundary_deltas,+ Bignum* numerator, Bignum* denominator,+ Bignum* delta_minus, Bignum* delta_plus) {+ const uint64_t kMinimalNormalizedExponent =+ UINT64_2PART_C(0x00100000, 00000000);+ uint64_t significand = Double(v).Significand();+ int exponent = Double(v).Exponent();+ // Instead of multiplying the denominator with 10^estimated_power we+ // multiply all values (numerator and deltas) by 10^-estimated_power.++ // Use numerator as temporary container for power_ten.+ Bignum* power_ten = numerator;+ power_ten->AssignPowerUInt16(10, -estimated_power);++ if (need_boundary_deltas) {+ // Since power_ten == numerator we must make a copy of 10^estimated_power+ // before we complete the computation of the numerator.+ // delta_plus = delta_minus = 10^estimated_power+ delta_plus->AssignBignum(*power_ten);+ delta_minus->AssignBignum(*power_ten);+ }++ // numerator = significand * 2 * 10^-estimated_power+ // since v = significand * 2^exponent this is equivalent to+ // numerator = v * 10^-estimated_power * 2 * 2^-exponent.+ // Remember: numerator has been abused as power_ten. So no need to assign it+ // to itself.+ ASSERT(numerator == power_ten);+ numerator->MultiplyByUInt64(significand);++ // denominator = 2 * 2^-exponent with exponent < 0.+ denominator->AssignUInt16(1);+ denominator->ShiftLeft(-exponent);++ if (need_boundary_deltas) {+ // Introduce a common denominator so that the deltas to the boundaries are+ // integers.+ numerator->ShiftLeft(1);+ denominator->ShiftLeft(1);+ // With this shift the boundaries have their correct value, since+ // delta_plus = 10^-estimated_power, and+ // delta_minus = 10^-estimated_power.+ // These assignments have been done earlier.++ // The special case where the lower boundary is twice as close.+ // This time we have to look out for the exception too.+ uint64_t v_bits = Double(v).AsUint64();+ if ((v_bits & Double::kSignificandMask) == 0 &&+ // The only exception where a significand == 0 has its boundaries at+ // "normal" distances:+ (v_bits & Double::kExponentMask) != kMinimalNormalizedExponent) {+ numerator->ShiftLeft(1); // *2+ denominator->ShiftLeft(1); // *2+ delta_plus->ShiftLeft(1); // *2+ }+ }+}+++// Let v = significand * 2^exponent.+// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator+// and denominator. The functions GenerateShortestDigits and+// GenerateCountedDigits will then convert this ratio to its decimal+// representation d, with the required accuracy.+// Then d * 10^estimated_power is the representation of v.+// (Note: the fraction and the estimated_power might get adjusted before+// generating the decimal representation.)+//+// The initial start values consist of:+// - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.+// - a scaled (common) denominator.+// optionally (used by GenerateShortestDigits to decide if it has the shortest+// decimal converting back to v):+// - v - m-: the distance to the lower boundary.+// - m+ - v: the distance to the upper boundary.+//+// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.+//+// Let ep == estimated_power, then the returned values will satisfy:+// v / 10^ep = numerator / denominator.+// v's boundarys m- and m+:+// m- / 10^ep == v / 10^ep - delta_minus / denominator+// m+ / 10^ep == v / 10^ep + delta_plus / denominator+// Or in other words:+// m- == v - delta_minus * 10^ep / denominator;+// m+ == v + delta_plus * 10^ep / denominator;+//+// Since 10^(k-1) <= v < 10^k (with k == estimated_power)+// or 10^k <= v < 10^(k+1)+// we then have 0.1 <= numerator/denominator < 1+// or 1 <= numerator/denominator < 10+//+// It is then easy to kickstart the digit-generation routine.+//+// The boundary-deltas are only filled if need_boundary_deltas is set.+static void InitialScaledStartValues(double v,+ int estimated_power,+ bool need_boundary_deltas,+ Bignum* numerator,+ Bignum* denominator,+ Bignum* delta_minus,+ Bignum* delta_plus) {+ if (Double(v).Exponent() >= 0) {+ InitialScaledStartValuesPositiveExponent(+ v, estimated_power, need_boundary_deltas,+ numerator, denominator, delta_minus, delta_plus);+ } else if (estimated_power >= 0) {+ InitialScaledStartValuesNegativeExponentPositivePower(+ v, estimated_power, need_boundary_deltas,+ numerator, denominator, delta_minus, delta_plus);+ } else {+ InitialScaledStartValuesNegativeExponentNegativePower(+ v, estimated_power, need_boundary_deltas,+ numerator, denominator, delta_minus, delta_plus);+ }+}+++// This routine multiplies numerator/denominator so that its values lies in the+// range 1-10. That is after a call to this function we have:+// 1 <= (numerator + delta_plus) /denominator < 10.+// Let numerator the input before modification and numerator' the argument+// after modification, then the output-parameter decimal_point is such that+// numerator / denominator * 10^estimated_power ==+// numerator' / denominator' * 10^(decimal_point - 1)+// In some cases estimated_power was too low, and this is already the case. We+// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==+// estimated_power) but do not touch the numerator or denominator.+// Otherwise the routine multiplies the numerator and the deltas by 10.+static void FixupMultiply10(int estimated_power, bool is_even,+ int* decimal_point,+ Bignum* numerator, Bignum* denominator,+ Bignum* delta_minus, Bignum* delta_plus) {+ bool in_range;+ if (is_even) {+ // For IEEE doubles half-way cases (in decimal system numbers ending with 5)+ // are rounded to the closest floating-point number with even significand.+ in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;+ } else {+ in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;+ }+ if (in_range) {+ // Since numerator + delta_plus >= denominator we already have+ // 1 <= numerator/denominator < 10. Simply update the estimated_power.+ *decimal_point = estimated_power + 1;+ } else {+ *decimal_point = estimated_power;+ numerator->Times10();+ if (Bignum::Equal(*delta_minus, *delta_plus)) {+ delta_minus->Times10();+ delta_plus->AssignBignum(*delta_minus);+ } else {+ delta_minus->Times10();+ delta_plus->Times10();+ }+ }+}++} // namespace double_conversion
+ double-conversion/src/bignum-dtoa.h view
@@ -0,0 +1,82 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_BIGNUM_DTOA_H_+#define DOUBLE_CONVERSION_BIGNUM_DTOA_H_++#include "utils.h"++namespace double_conversion {++enum BignumDtoaMode {+ // Return the shortest correct representation.+ // For example the output of 0.299999999999999988897 is (the less accurate but+ // correct) 0.3.+ BIGNUM_DTOA_SHORTEST,+ // Return a fixed number of digits after the decimal point.+ // For instance fixed(0.1, 4) becomes 0.1000+ // If the input number is big, the output will be big.+ BIGNUM_DTOA_FIXED,+ // Return a fixed number of digits, no matter what the exponent is.+ BIGNUM_DTOA_PRECISION+};++// Converts the given double 'v' to ascii.+// The result should be interpreted as buffer * 10^(point-length).+// The buffer will be null-terminated.+//+// The input v must be > 0 and different from NaN, and Infinity.+//+// The output depends on the given mode:+// - SHORTEST: produce the least amount of digits for which the internal+// identity requirement is still satisfied. If the digits are printed+// (together with the correct exponent) then reading this number will give+// 'v' again. The buffer will choose the representation that is closest to+// 'v'. If there are two at the same distance, than the number is round up.+// In this mode the 'requested_digits' parameter is ignored.+// - FIXED: produces digits necessary to print a given number with+// 'requested_digits' digits after the decimal point. The produced digits+// might be too short in which case the caller has to fill the gaps with '0's.+// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.+// Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns+// buffer="2", point=0.+// Note: the length of the returned buffer has no meaning wrt the significance+// of its digits. That is, just because it contains '0's does not mean that+// any other digit would not satisfy the internal identity requirement.+// - PRECISION: produces 'requested_digits' where the first digit is not '0'.+// Even though the length of produced digits usually equals+// 'requested_digits', the function is allowed to return fewer digits, in+// which case the caller has to fill the missing digits with '0's.+// Halfway cases are again rounded up.+// 'BignumDtoa' expects the given buffer to be big enough to hold all digits+// and a terminating null-character.+void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,+ Vector<char> buffer, int* length, int* point);++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_BIGNUM_DTOA_H_
+ double-conversion/src/bignum.cc view
@@ -0,0 +1,764 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include "bignum.h"+#include "utils.h"++namespace double_conversion {++Bignum::Bignum()+ : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {+ for (int i = 0; i < kBigitCapacity; ++i) {+ bigits_[i] = 0;+ }+}+++template<typename S>+static int BitSize(S value) {+ return 8 * sizeof(value);+}++// Guaranteed to lie in one Bigit.+void Bignum::AssignUInt16(uint16_t value) {+ ASSERT(kBigitSize >= BitSize(value));+ Zero();+ if (value == 0) return;++ EnsureCapacity(1);+ bigits_[0] = value;+ used_digits_ = 1;+}+++void Bignum::AssignUInt64(uint64_t value) {+ const int kUInt64Size = 64;++ Zero();+ if (value == 0) return;++ int needed_bigits = kUInt64Size / kBigitSize + 1;+ EnsureCapacity(needed_bigits);+ for (int i = 0; i < needed_bigits; ++i) {+ bigits_[i] = value & kBigitMask;+ value = value >> kBigitSize;+ }+ used_digits_ = needed_bigits;+ Clamp();+}+++void Bignum::AssignBignum(const Bignum& other) {+ exponent_ = other.exponent_;+ for (int i = 0; i < other.used_digits_; ++i) {+ bigits_[i] = other.bigits_[i];+ }+ // Clear the excess digits (if there were any).+ for (int i = other.used_digits_; i < used_digits_; ++i) {+ bigits_[i] = 0;+ }+ used_digits_ = other.used_digits_;+}+++static uint64_t ReadUInt64(Vector<const char> buffer,+ int from,+ int digits_to_read) {+ uint64_t result = 0;+ for (int i = from; i < from + digits_to_read; ++i) {+ int digit = buffer[i] - '0';+ ASSERT(0 <= digit && digit <= 9);+ result = result * 10 + digit;+ }+ return result;+}+++void Bignum::AssignDecimalString(Vector<const char> value) {+ // 2^64 = 18446744073709551616 > 10^19+ const int kMaxUint64DecimalDigits = 19;+ Zero();+ int length = value.length();+ int pos = 0;+ // Let's just say that each digit needs 4 bits.+ while (length >= kMaxUint64DecimalDigits) {+ uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);+ pos += kMaxUint64DecimalDigits;+ length -= kMaxUint64DecimalDigits;+ MultiplyByPowerOfTen(kMaxUint64DecimalDigits);+ AddUInt64(digits);+ }+ uint64_t digits = ReadUInt64(value, pos, length);+ MultiplyByPowerOfTen(length);+ AddUInt64(digits);+ Clamp();+}+++static int HexCharValue(char c) {+ if ('0' <= c && c <= '9') return c - '0';+ if ('a' <= c && c <= 'f') return 10 + c - 'a';+ if ('A' <= c && c <= 'F') return 10 + c - 'A';+ UNREACHABLE();+ return 0; // To make compiler happy.+}+++void Bignum::AssignHexString(Vector<const char> value) {+ Zero();+ int length = value.length();++ int needed_bigits = length * 4 / kBigitSize + 1;+ EnsureCapacity(needed_bigits);+ int string_index = length - 1;+ for (int i = 0; i < needed_bigits - 1; ++i) {+ // These bigits are guaranteed to be "full".+ Chunk current_bigit = 0;+ for (int j = 0; j < kBigitSize / 4; j++) {+ current_bigit += HexCharValue(value[string_index--]) << (j * 4);+ }+ bigits_[i] = current_bigit;+ }+ used_digits_ = needed_bigits - 1;++ Chunk most_significant_bigit = 0; // Could be = 0;+ for (int j = 0; j <= string_index; ++j) {+ most_significant_bigit <<= 4;+ most_significant_bigit += HexCharValue(value[j]);+ }+ if (most_significant_bigit != 0) {+ bigits_[used_digits_] = most_significant_bigit;+ used_digits_++;+ }+ Clamp();+}+++void Bignum::AddUInt64(uint64_t operand) {+ if (operand == 0) return;+ Bignum other;+ other.AssignUInt64(operand);+ AddBignum(other);+}+++void Bignum::AddBignum(const Bignum& other) {+ ASSERT(IsClamped());+ ASSERT(other.IsClamped());++ // If this has a greater exponent than other append zero-bigits to this.+ // After this call exponent_ <= other.exponent_.+ Align(other);++ // There are two possibilities:+ // aaaaaaaaaaa 0000 (where the 0s represent a's exponent)+ // bbbbb 00000000+ // ----------------+ // ccccccccccc 0000+ // or+ // aaaaaaaaaa 0000+ // bbbbbbbbb 0000000+ // -----------------+ // cccccccccccc 0000+ // In both cases we might need a carry bigit.++ EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_);+ Chunk carry = 0;+ int bigit_pos = other.exponent_ - exponent_;+ ASSERT(bigit_pos >= 0);+ for (int i = 0; i < other.used_digits_; ++i) {+ Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry;+ bigits_[bigit_pos] = sum & kBigitMask;+ carry = sum >> kBigitSize;+ bigit_pos++;+ }++ while (carry != 0) {+ Chunk sum = bigits_[bigit_pos] + carry;+ bigits_[bigit_pos] = sum & kBigitMask;+ carry = sum >> kBigitSize;+ bigit_pos++;+ }+ used_digits_ = Max(bigit_pos, used_digits_);+ ASSERT(IsClamped());+}+++void Bignum::SubtractBignum(const Bignum& other) {+ ASSERT(IsClamped());+ ASSERT(other.IsClamped());+ // We require this to be bigger than other.+ ASSERT(LessEqual(other, *this));++ Align(other);++ int offset = other.exponent_ - exponent_;+ Chunk borrow = 0;+ int i;+ for (i = 0; i < other.used_digits_; ++i) {+ ASSERT((borrow == 0) || (borrow == 1));+ Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow;+ bigits_[i + offset] = difference & kBigitMask;+ borrow = difference >> (kChunkSize - 1);+ }+ while (borrow != 0) {+ Chunk difference = bigits_[i + offset] - borrow;+ bigits_[i + offset] = difference & kBigitMask;+ borrow = difference >> (kChunkSize - 1);+ ++i;+ }+ Clamp();+}+++void Bignum::ShiftLeft(int shift_amount) {+ if (used_digits_ == 0) return;+ exponent_ += shift_amount / kBigitSize;+ int local_shift = shift_amount % kBigitSize;+ EnsureCapacity(used_digits_ + 1);+ BigitsShiftLeft(local_shift);+}+++void Bignum::MultiplyByUInt32(uint32_t factor) {+ if (factor == 1) return;+ if (factor == 0) {+ Zero();+ return;+ }+ if (used_digits_ == 0) return;++ // The product of a bigit with the factor is of size kBigitSize + 32.+ // Assert that this number + 1 (for the carry) fits into double chunk.+ ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);+ DoubleChunk carry = 0;+ for (int i = 0; i < used_digits_; ++i) {+ DoubleChunk product = static_cast<DoubleChunk>(factor) * bigits_[i] + carry;+ bigits_[i] = static_cast<Chunk>(product & kBigitMask);+ carry = (product >> kBigitSize);+ }+ while (carry != 0) {+ EnsureCapacity(used_digits_ + 1);+ bigits_[used_digits_] = carry & kBigitMask;+ used_digits_++;+ carry >>= kBigitSize;+ }+}+++void Bignum::MultiplyByUInt64(uint64_t factor) {+ if (factor == 1) return;+ if (factor == 0) {+ Zero();+ return;+ }+ ASSERT(kBigitSize < 32);+ uint64_t carry = 0;+ uint64_t low = factor & 0xFFFFFFFF;+ uint64_t high = factor >> 32;+ for (int i = 0; i < used_digits_; ++i) {+ uint64_t product_low = low * bigits_[i];+ uint64_t product_high = high * bigits_[i];+ uint64_t tmp = (carry & kBigitMask) + product_low;+ bigits_[i] = tmp & kBigitMask;+ carry = (carry >> kBigitSize) + (tmp >> kBigitSize) ++ (product_high << (32 - kBigitSize));+ }+ while (carry != 0) {+ EnsureCapacity(used_digits_ + 1);+ bigits_[used_digits_] = carry & kBigitMask;+ used_digits_++;+ carry >>= kBigitSize;+ }+}+++void Bignum::MultiplyByPowerOfTen(int exponent) {+ const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d);+ const uint16_t kFive1 = 5;+ const uint16_t kFive2 = kFive1 * 5;+ const uint16_t kFive3 = kFive2 * 5;+ const uint16_t kFive4 = kFive3 * 5;+ const uint16_t kFive5 = kFive4 * 5;+ const uint16_t kFive6 = kFive5 * 5;+ const uint32_t kFive7 = kFive6 * 5;+ const uint32_t kFive8 = kFive7 * 5;+ const uint32_t kFive9 = kFive8 * 5;+ const uint32_t kFive10 = kFive9 * 5;+ const uint32_t kFive11 = kFive10 * 5;+ const uint32_t kFive12 = kFive11 * 5;+ const uint32_t kFive13 = kFive12 * 5;+ const uint32_t kFive1_to_12[] =+ { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,+ kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };++ ASSERT(exponent >= 0);+ if (exponent == 0) return;+ if (used_digits_ == 0) return;++ // We shift by exponent at the end just before returning.+ int remaining_exponent = exponent;+ while (remaining_exponent >= 27) {+ MultiplyByUInt64(kFive27);+ remaining_exponent -= 27;+ }+ while (remaining_exponent >= 13) {+ MultiplyByUInt32(kFive13);+ remaining_exponent -= 13;+ }+ if (remaining_exponent > 0) {+ MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);+ }+ ShiftLeft(exponent);+}+++void Bignum::Square() {+ ASSERT(IsClamped());+ int product_length = 2 * used_digits_;+ EnsureCapacity(product_length);++ // Comba multiplication: compute each column separately.+ // Example: r = a2a1a0 * b2b1b0.+ // r = 1 * a0b0 ++ // 10 * (a1b0 + a0b1) ++ // 100 * (a2b0 + a1b1 + a0b2) ++ // 1000 * (a2b1 + a1b2) ++ // 10000 * a2b2+ //+ // In the worst case we have to accumulate nb-digits products of digit*digit.+ //+ // Assert that the additional number of bits in a DoubleChunk are enough to+ // sum up used_digits of Bigit*Bigit.+ if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {+ UNIMPLEMENTED();+ }+ DoubleChunk accumulator = 0;+ // First shift the digits so we don't overwrite them.+ int copy_offset = used_digits_;+ for (int i = 0; i < used_digits_; ++i) {+ bigits_[copy_offset + i] = bigits_[i];+ }+ // We have two loops to avoid some 'if's in the loop.+ for (int i = 0; i < used_digits_; ++i) {+ // Process temporary digit i with power i.+ // The sum of the two indices must be equal to i.+ int bigit_index1 = i;+ int bigit_index2 = 0;+ // Sum all of the sub-products.+ while (bigit_index1 >= 0) {+ Chunk chunk1 = bigits_[copy_offset + bigit_index1];+ Chunk chunk2 = bigits_[copy_offset + bigit_index2];+ accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;+ bigit_index1--;+ bigit_index2++;+ }+ bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;+ accumulator >>= kBigitSize;+ }+ for (int i = used_digits_; i < product_length; ++i) {+ int bigit_index1 = used_digits_ - 1;+ int bigit_index2 = i - bigit_index1;+ // Invariant: sum of both indices is again equal to i.+ // Inner loop runs 0 times on last iteration, emptying accumulator.+ while (bigit_index2 < used_digits_) {+ Chunk chunk1 = bigits_[copy_offset + bigit_index1];+ Chunk chunk2 = bigits_[copy_offset + bigit_index2];+ accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;+ bigit_index1--;+ bigit_index2++;+ }+ // The overwritten bigits_[i] will never be read in further loop iterations,+ // because bigit_index1 and bigit_index2 are always greater+ // than i - used_digits_.+ bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;+ accumulator >>= kBigitSize;+ }+ // Since the result was guaranteed to lie inside the number the+ // accumulator must be 0 now.+ ASSERT(accumulator == 0);++ // Don't forget to update the used_digits and the exponent.+ used_digits_ = product_length;+ exponent_ *= 2;+ Clamp();+}+++void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {+ ASSERT(base != 0);+ ASSERT(power_exponent >= 0);+ if (power_exponent == 0) {+ AssignUInt16(1);+ return;+ }+ Zero();+ int shifts = 0;+ // We expect base to be in range 2-32, and most often to be 10.+ // It does not make much sense to implement different algorithms for counting+ // the bits.+ while ((base & 1) == 0) {+ base >>= 1;+ shifts++;+ }+ int bit_size = 0;+ int tmp_base = base;+ while (tmp_base != 0) {+ tmp_base >>= 1;+ bit_size++;+ }+ int final_size = bit_size * power_exponent;+ // 1 extra bigit for the shifting, and one for rounded final_size.+ EnsureCapacity(final_size / kBigitSize + 2);++ // Left to Right exponentiation.+ int mask = 1;+ while (power_exponent >= mask) mask <<= 1;++ // The mask is now pointing to the bit above the most significant 1-bit of+ // power_exponent.+ // Get rid of first 1-bit;+ mask >>= 2;+ uint64_t this_value = base;++ bool delayed_multipliciation = false;+ const uint64_t max_32bits = 0xFFFFFFFF;+ while (mask != 0 && this_value <= max_32bits) {+ this_value = this_value * this_value;+ // Verify that there is enough space in this_value to perform the+ // multiplication. The first bit_size bits must be 0.+ if ((power_exponent & mask) != 0) {+ uint64_t base_bits_mask =+ ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);+ bool high_bits_zero = (this_value & base_bits_mask) == 0;+ if (high_bits_zero) {+ this_value *= base;+ } else {+ delayed_multipliciation = true;+ }+ }+ mask >>= 1;+ }+ AssignUInt64(this_value);+ if (delayed_multipliciation) {+ MultiplyByUInt32(base);+ }++ // Now do the same thing as a bignum.+ while (mask != 0) {+ Square();+ if ((power_exponent & mask) != 0) {+ MultiplyByUInt32(base);+ }+ mask >>= 1;+ }++ // And finally add the saved shifts.+ ShiftLeft(shifts * power_exponent);+}+++// Precondition: this/other < 16bit.+uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {+ ASSERT(IsClamped());+ ASSERT(other.IsClamped());+ ASSERT(other.used_digits_ > 0);++ // Easy case: if we have less digits than the divisor than the result is 0.+ // Note: this handles the case where this == 0, too.+ if (BigitLength() < other.BigitLength()) {+ return 0;+ }++ Align(other);++ uint16_t result = 0;++ // Start by removing multiples of 'other' until both numbers have the same+ // number of digits.+ while (BigitLength() > other.BigitLength()) {+ // This naive approach is extremely inefficient if the this divided other+ // might be big. This function is implemented for doubleToString where+ // the result should be small (less than 10).+ ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));+ // Remove the multiples of the first digit.+ // Example this = 23 and other equals 9. -> Remove 2 multiples.+ result += bigits_[used_digits_ - 1];+ SubtractTimes(other, bigits_[used_digits_ - 1]);+ }++ ASSERT(BigitLength() == other.BigitLength());++ // Both bignums are at the same length now.+ // Since other has more than 0 digits we know that the access to+ // bigits_[used_digits_ - 1] is safe.+ Chunk this_bigit = bigits_[used_digits_ - 1];+ Chunk other_bigit = other.bigits_[other.used_digits_ - 1];++ if (other.used_digits_ == 1) {+ // Shortcut for easy (and common) case.+ int quotient = this_bigit / other_bigit;+ bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;+ result += quotient;+ Clamp();+ return result;+ }++ int division_estimate = this_bigit / (other_bigit + 1);+ result += division_estimate;+ SubtractTimes(other, division_estimate);++ if (other_bigit * (division_estimate + 1) > this_bigit) {+ // No need to even try to subtract. Even if other's remaining digits were 0+ // another subtraction would be too much.+ return result;+ }++ while (LessEqual(other, *this)) {+ SubtractBignum(other);+ result++;+ }+ return result;+}+++template<typename S>+static int SizeInHexChars(S number) {+ ASSERT(number > 0);+ int result = 0;+ while (number != 0) {+ number >>= 4;+ result++;+ }+ return result;+}+++static char HexCharOfValue(int value) {+ ASSERT(0 <= value && value <= 16);+ if (value < 10) return value + '0';+ return value - 10 + 'A';+}+++bool Bignum::ToHexString(char* buffer, int buffer_size) const {+ ASSERT(IsClamped());+ // Each bigit must be printable as separate hex-character.+ ASSERT(kBigitSize % 4 == 0);+ const int kHexCharsPerBigit = kBigitSize / 4;++ if (used_digits_ == 0) {+ if (buffer_size < 2) return false;+ buffer[0] = '0';+ buffer[1] = '\0';+ return true;+ }+ // We add 1 for the terminating '\0' character.+ int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit ++ SizeInHexChars(bigits_[used_digits_ - 1]) + 1;+ if (needed_chars > buffer_size) return false;+ int string_index = needed_chars - 1;+ buffer[string_index--] = '\0';+ for (int i = 0; i < exponent_; ++i) {+ for (int j = 0; j < kHexCharsPerBigit; ++j) {+ buffer[string_index--] = '0';+ }+ }+ for (int i = 0; i < used_digits_ - 1; ++i) {+ Chunk current_bigit = bigits_[i];+ for (int j = 0; j < kHexCharsPerBigit; ++j) {+ buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);+ current_bigit >>= 4;+ }+ }+ // And finally the last bigit.+ Chunk most_significant_bigit = bigits_[used_digits_ - 1];+ while (most_significant_bigit != 0) {+ buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);+ most_significant_bigit >>= 4;+ }+ return true;+}+++Bignum::Chunk Bignum::BigitAt(int index) const {+ if (index >= BigitLength()) return 0;+ if (index < exponent_) return 0;+ return bigits_[index - exponent_];+}+++int Bignum::Compare(const Bignum& a, const Bignum& b) {+ ASSERT(a.IsClamped());+ ASSERT(b.IsClamped());+ int bigit_length_a = a.BigitLength();+ int bigit_length_b = b.BigitLength();+ if (bigit_length_a < bigit_length_b) return -1;+ if (bigit_length_a > bigit_length_b) return +1;+ for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) {+ Chunk bigit_a = a.BigitAt(i);+ Chunk bigit_b = b.BigitAt(i);+ if (bigit_a < bigit_b) return -1;+ if (bigit_a > bigit_b) return +1;+ // Otherwise they are equal up to this digit. Try the next digit.+ }+ return 0;+}+++int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {+ ASSERT(a.IsClamped());+ ASSERT(b.IsClamped());+ ASSERT(c.IsClamped());+ if (a.BigitLength() < b.BigitLength()) {+ return PlusCompare(b, a, c);+ }+ if (a.BigitLength() + 1 < c.BigitLength()) return -1;+ if (a.BigitLength() > c.BigitLength()) return +1;+ // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than+ // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one+ // of 'a'.+ if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {+ return -1;+ }++ Chunk borrow = 0;+ // Starting at min_exponent all digits are == 0. So no need to compare them.+ int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_);+ for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {+ Chunk chunk_a = a.BigitAt(i);+ Chunk chunk_b = b.BigitAt(i);+ Chunk chunk_c = c.BigitAt(i);+ Chunk sum = chunk_a + chunk_b;+ if (sum > chunk_c + borrow) {+ return +1;+ } else {+ borrow = chunk_c + borrow - sum;+ if (borrow > 1) return -1;+ borrow <<= kBigitSize;+ }+ }+ if (borrow == 0) return 0;+ return -1;+}+++void Bignum::Clamp() {+ while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {+ used_digits_--;+ }+ if (used_digits_ == 0) {+ // Zero.+ exponent_ = 0;+ }+}+++bool Bignum::IsClamped() const {+ return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;+}+++void Bignum::Zero() {+ for (int i = 0; i < used_digits_; ++i) {+ bigits_[i] = 0;+ }+ used_digits_ = 0;+ exponent_ = 0;+}+++void Bignum::Align(const Bignum& other) {+ if (exponent_ > other.exponent_) {+ // If "X" represents a "hidden" digit (by the exponent) then we are in the+ // following case (a == this, b == other):+ // a: aaaaaaXXXX or a: aaaaaXXX+ // b: bbbbbbX b: bbbbbbbbXX+ // We replace some of the hidden digits (X) of a with 0 digits.+ // a: aaaaaa000X or a: aaaaa0XX+ int zero_digits = exponent_ - other.exponent_;+ EnsureCapacity(used_digits_ + zero_digits);+ for (int i = used_digits_ - 1; i >= 0; --i) {+ bigits_[i + zero_digits] = bigits_[i];+ }+ for (int i = 0; i < zero_digits; ++i) {+ bigits_[i] = 0;+ }+ used_digits_ += zero_digits;+ exponent_ -= zero_digits;+ ASSERT(used_digits_ >= 0);+ ASSERT(exponent_ >= 0);+ }+}+++void Bignum::BigitsShiftLeft(int shift_amount) {+ ASSERT(shift_amount < kBigitSize);+ ASSERT(shift_amount >= 0);+ Chunk carry = 0;+ for (int i = 0; i < used_digits_; ++i) {+ Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount);+ bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;+ carry = new_carry;+ }+ if (carry != 0) {+ bigits_[used_digits_] = carry;+ used_digits_++;+ }+}+++void Bignum::SubtractTimes(const Bignum& other, int factor) {+ ASSERT(exponent_ <= other.exponent_);+ if (factor < 3) {+ for (int i = 0; i < factor; ++i) {+ SubtractBignum(other);+ }+ return;+ }+ Chunk borrow = 0;+ int exponent_diff = other.exponent_ - exponent_;+ for (int i = 0; i < other.used_digits_; ++i) {+ DoubleChunk product = static_cast<DoubleChunk>(factor) * other.bigits_[i];+ DoubleChunk remove = borrow + product;+ Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask);+ bigits_[i + exponent_diff] = difference & kBigitMask;+ borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) ++ (remove >> kBigitSize));+ }+ for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {+ if (borrow == 0) return;+ Chunk difference = bigits_[i] - borrow;+ bigits_[i] = difference & kBigitMask;+ borrow = difference >> (kChunkSize - 1);+ ++i;+ }+ Clamp();+}+++} // namespace double_conversion
+ double-conversion/src/bignum.h view
@@ -0,0 +1,141 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_BIGNUM_H_+#define DOUBLE_CONVERSION_BIGNUM_H_++#include "utils.h"++namespace double_conversion {++class Bignum {+ public:+ // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.+ // This bignum can encode much bigger numbers, since it contains an+ // exponent.+ static const int kMaxSignificantBits = 3584;++ Bignum();+ void AssignUInt16(uint16_t value);+ void AssignUInt64(uint64_t value);+ void AssignBignum(const Bignum& other);++ void AssignDecimalString(Vector<const char> value);+ void AssignHexString(Vector<const char> value);++ void AssignPowerUInt16(uint16_t base, int exponent);++ void AddUInt16(uint16_t operand);+ void AddUInt64(uint64_t operand);+ void AddBignum(const Bignum& other);+ // Precondition: this >= other.+ void SubtractBignum(const Bignum& other);++ void Square();+ void ShiftLeft(int shift_amount);+ void MultiplyByUInt32(uint32_t factor);+ void MultiplyByUInt64(uint64_t factor);+ void MultiplyByPowerOfTen(int exponent);+ void Times10() { return MultiplyByUInt32(10); }+ // Pseudocode:+ // int result = this / other;+ // this = this % other;+ // In the worst case this function is in O(this/other).+ uint16_t DivideModuloIntBignum(const Bignum& other);++ bool ToHexString(char* buffer, int buffer_size) const;++ static int Compare(const Bignum& a, const Bignum& b);+ static bool Equal(const Bignum& a, const Bignum& b) {+ return Compare(a, b) == 0;+ }+ static bool LessEqual(const Bignum& a, const Bignum& b) {+ return Compare(a, b) <= 0;+ }+ static bool Less(const Bignum& a, const Bignum& b) {+ return Compare(a, b) < 0;+ }+ // Returns Compare(a + b, c);+ static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);+ // Returns a + b == c+ static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {+ return PlusCompare(a, b, c) == 0;+ }+ // Returns a + b <= c+ static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {+ return PlusCompare(a, b, c) <= 0;+ }+ // Returns a + b < c+ static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {+ return PlusCompare(a, b, c) < 0;+ }+ private:+ typedef uint32_t Chunk;+ typedef uint64_t DoubleChunk;++ static const int kChunkSize = sizeof(Chunk) * 8;+ static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;+ // With bigit size of 28 we loose some bits, but a double still fits easily+ // into two chunks, and more importantly we can use the Comba multiplication.+ static const int kBigitSize = 28;+ static const Chunk kBigitMask = (1 << kBigitSize) - 1;+ // Every instance allocates kBigitLength chunks on the stack. Bignums cannot+ // grow. There are no checks if the stack-allocated space is sufficient.+ static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;++ void EnsureCapacity(int size) {+ if (size > kBigitCapacity) {+ UNREACHABLE();+ }+ }+ void Align(const Bignum& other);+ void Clamp();+ bool IsClamped() const;+ void Zero();+ // Requires this to have enough capacity (no tests done).+ // Updates used_digits_ if necessary.+ // shift_amount must be < kBigitSize.+ void BigitsShiftLeft(int shift_amount);+ // BigitLength includes the "hidden" digits encoded in the exponent.+ int BigitLength() const { return used_digits_ + exponent_; }+ Chunk BigitAt(int index) const;+ void SubtractTimes(const Bignum& other, int factor);++ Chunk bigits_buffer_[kBigitCapacity];+ // A vector backed by bigits_buffer_. This way accesses to the array are+ // checked for out-of-bounds errors.+ Vector<Chunk> bigits_;+ int used_digits_;+ // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).+ int exponent_;++ DISALLOW_COPY_AND_ASSIGN(Bignum);+};++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_BIGNUM_H_
+ double-conversion/src/cached-powers.cc view
@@ -0,0 +1,177 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <stdarg.h>+#include <limits.h>+#include <math.h>++#include "utils.h"++#include "cached-powers.h"++namespace double_conversion {++struct CachedPower {+ uint64_t significand;+ int16_t binary_exponent;+ int16_t decimal_exponent;+};++static const CachedPower kCachedPowers[] = {+ {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348},+ {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340},+ {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332},+ {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324},+ {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316},+ {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308},+ {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300},+ {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292},+ {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284},+ {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276},+ {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268},+ {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260},+ {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252},+ {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244},+ {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236},+ {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228},+ {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220},+ {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212},+ {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204},+ {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196},+ {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188},+ {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180},+ {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172},+ {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164},+ {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156},+ {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148},+ {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140},+ {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132},+ {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124},+ {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116},+ {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108},+ {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100},+ {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92},+ {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84},+ {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76},+ {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68},+ {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60},+ {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52},+ {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44},+ {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36},+ {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28},+ {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20},+ {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12},+ {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4},+ {UINT64_2PART_C(0x9c400000, 00000000), -50, 4},+ {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12},+ {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20},+ {UINT64_2PART_C(0x813f3978, f8940984), 30, 28},+ {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36},+ {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44},+ {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52},+ {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60},+ {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68},+ {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76},+ {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84},+ {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92},+ {UINT64_2PART_C(0x924d692c, a61be758), 269, 100},+ {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108},+ {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116},+ {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124},+ {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132},+ {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140},+ {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148},+ {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156},+ {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164},+ {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172},+ {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180},+ {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188},+ {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196},+ {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204},+ {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212},+ {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220},+ {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228},+ {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236},+ {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244},+ {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252},+ {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260},+ {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268},+ {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276},+ {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284},+ {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292},+ {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300},+ {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308},+ {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316},+ {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324},+ {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332},+ {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340},+};++static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers);+static const int kCachedPowersOffset = -kCachedPowers[0].decimal_exponent;+static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)+const int PowersOfTenCache::kDecimalExponentDistance =+ kCachedPowers[1].decimal_exponent - kCachedPowers[0].decimal_exponent;+const int PowersOfTenCache::kMinDecimalExponent =+ kCachedPowers[0].decimal_exponent;+const int PowersOfTenCache::kMaxDecimalExponent =+ kCachedPowers[kCachedPowersLength - 1].decimal_exponent;++void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(+ int min_exponent,+ int max_exponent,+ DiyFp* power,+ int* decimal_exponent) {+ int kQ = DiyFp::kSignificandSize;+ double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);+ int foo = kCachedPowersOffset;+ int index =+ (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;+ ASSERT(0 <= index && index < kCachedPowersLength);+ CachedPower cached_power = kCachedPowers[index];+ ASSERT(min_exponent <= cached_power.binary_exponent);+ ASSERT(cached_power.binary_exponent <= max_exponent);+ *decimal_exponent = cached_power.decimal_exponent;+ *power = DiyFp(cached_power.significand, cached_power.binary_exponent);+}+++void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent,+ DiyFp* power,+ int* found_exponent) {+ ASSERT(kMinDecimalExponent <= requested_exponent);+ ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance);+ int index =+ (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance;+ CachedPower cached_power = kCachedPowers[index];+ *power = DiyFp(cached_power.significand, cached_power.binary_exponent);+ *found_exponent = cached_power.decimal_exponent;+ ASSERT(*found_exponent <= requested_exponent);+ ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance);+}++} // namespace double_conversion
+ double-conversion/src/cached-powers.h view
@@ -0,0 +1,64 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_CACHED_POWERS_H_+#define DOUBLE_CONVERSION_CACHED_POWERS_H_++#include "diy-fp.h"++namespace double_conversion {++class PowersOfTenCache {+ public:++ // Not all powers of ten are cached. The decimal exponent of two neighboring+ // cached numbers will differ by kDecimalExponentDistance.+ static const int kDecimalExponentDistance;++ static const int kMinDecimalExponent;+ static const int kMaxDecimalExponent;++ // Returns a cached power-of-ten with a binary exponent in the range+ // [min_exponent; max_exponent] (boundaries included).+ static void GetCachedPowerForBinaryExponentRange(int min_exponent,+ int max_exponent,+ DiyFp* power,+ int* decimal_exponent);++ // Returns a cached power of ten x ~= 10^k such that+ // k <= decimal_exponent < k + kCachedPowersDecimalDistance.+ // The given decimal_exponent must satisfy+ // kMinDecimalExponent <= requested_exponent, and+ // requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance.+ static void GetCachedPowerForDecimalExponent(int requested_exponent,+ DiyFp* power,+ int* found_exponent);+};++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_CACHED_POWERS_H_
+ double-conversion/src/diy-fp.cc view
@@ -0,0 +1,57 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+++#include "diy-fp.h"+#include "utils.h"++namespace double_conversion {++void DiyFp::Multiply(const DiyFp& other) {+ // Simply "emulates" a 128 bit multiplication.+ // However: the resulting number only contains 64 bits. The least+ // significant 64 bits are only used for rounding the most significant 64+ // bits.+ const uint64_t kM32 = 0xFFFFFFFFU;+ uint64_t a = f_ >> 32;+ uint64_t b = f_ & kM32;+ uint64_t c = other.f_ >> 32;+ uint64_t d = other.f_ & kM32;+ uint64_t ac = a * c;+ uint64_t bc = b * c;+ uint64_t ad = a * d;+ uint64_t bd = b * d;+ uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32);+ // By adding 1U << 31 to tmp we round the final result.+ // Halfway cases will be round up.+ tmp += 1U << 31;+ uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);+ e_ += other.e_ + 64;+ f_ = result_f;+}++} // namespace double_conversion
+ double-conversion/src/diy-fp.h view
@@ -0,0 +1,118 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_DIY_FP_H_+#define DOUBLE_CONVERSION_DIY_FP_H_++#include "utils.h"++namespace double_conversion {++// This "Do It Yourself Floating Point" class implements a floating-point number+// with a uint64 significand and an int exponent. Normalized DiyFp numbers will+// have the most significant bit of the significand set.+// Multiplication and Subtraction do not normalize their results.+// DiyFp are not designed to contain special doubles (NaN and Infinity).+class DiyFp {+ public:+ static const int kSignificandSize = 64;++ DiyFp() : f_(0), e_(0) {}+ DiyFp(uint64_t f, int e) : f_(f), e_(e) {}++ // this = this - other.+ // The exponents of both numbers must be the same and the significand of this+ // must be bigger than the significand of other.+ // The result will not be normalized.+ void Subtract(const DiyFp& other) {+ ASSERT(e_ == other.e_);+ ASSERT(f_ >= other.f_);+ f_ -= other.f_;+ }++ // Returns a - b.+ // The exponents of both numbers must be the same and this must be bigger+ // than other. The result will not be normalized.+ static DiyFp Minus(const DiyFp& a, const DiyFp& b) {+ DiyFp result = a;+ result.Subtract(b);+ return result;+ }+++ // this = this * other.+ void Multiply(const DiyFp& other);++ // returns a * b;+ static DiyFp Times(const DiyFp& a, const DiyFp& b) {+ DiyFp result = a;+ result.Multiply(b);+ return result;+ }++ void Normalize() {+ ASSERT(f_ != 0);+ uint64_t f = f_;+ int e = e_;++ // This method is mainly called for normalizing boundaries. In general+ // boundaries need to be shifted by 10 bits. We thus optimize for this case.+ const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000);+ while ((f & k10MSBits) == 0) {+ f <<= 10;+ e -= 10;+ }+ while ((f & kUint64MSB) == 0) {+ f <<= 1;+ e--;+ }+ f_ = f;+ e_ = e;+ }++ static DiyFp Normalize(const DiyFp& a) {+ DiyFp result = a;+ result.Normalize();+ return result;+ }++ uint64_t f() const { return f_; }+ int e() const { return e_; }++ void set_f(uint64_t new_value) { f_ = new_value; }+ void set_e(int new_value) { e_ = new_value; }++ private:+ static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000);++ uint64_t f_;+ int e_;+};++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_DIY_FP_H_
+ double-conversion/src/double-conversion.cc view
@@ -0,0 +1,869 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <limits.h>+#include <math.h>++#include "double-conversion.h"++#include "bignum-dtoa.h"+#include "double.h"+#include "fast-dtoa.h"+#include "fixed-dtoa.h"+#include "strtod.h"+#include "utils.h"++namespace double_conversion {++const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {+ int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;+ static DoubleToStringConverter converter(flags,+ "Infinity",+ "NaN",+ 'e',+ -6, 21,+ 6, 0);+ return converter;+}+++bool DoubleToStringConverter::HandleSpecialValues(+ double value,+ StringBuilder* result_builder) const {+ Double double_inspect(value);+ if (double_inspect.IsInfinite()) {+ if (infinity_symbol_ == NULL) return false;+ if (value < 0) {+ result_builder->AddCharacter('-');+ }+ result_builder->AddString(infinity_symbol_);+ return true;+ }+ if (double_inspect.IsNan()) {+ if (nan_symbol_ == NULL) return false;+ result_builder->AddString(nan_symbol_);+ return true;+ }+ return false;+}+++void DoubleToStringConverter::CreateExponentialRepresentation(+ const char* decimal_digits,+ int length,+ int exponent,+ StringBuilder* result_builder) const {+ ASSERT(length != 0);+ result_builder->AddCharacter(decimal_digits[0]);+ if (length != 1) {+ result_builder->AddCharacter('.');+ result_builder->AddSubstring(&decimal_digits[1], length-1);+ }+ result_builder->AddCharacter(exponent_character_);+ if (exponent < 0) {+ result_builder->AddCharacter('-');+ exponent = -exponent;+ } else {+ if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {+ result_builder->AddCharacter('+');+ }+ }+ if (exponent == 0) {+ result_builder->AddCharacter('0');+ return;+ }+ ASSERT(exponent < 1e4);+ const int kMaxExponentLength = 5;+ char buffer[kMaxExponentLength];+ int first_char_pos = kMaxExponentLength;+ while (exponent > 0) {+ buffer[--first_char_pos] = '0' + (exponent % 10);+ exponent /= 10;+ }+ result_builder->AddSubstring(&buffer[first_char_pos],+ kMaxExponentLength - first_char_pos);+}+++void DoubleToStringConverter::CreateDecimalRepresentation(+ const char* decimal_digits,+ int length,+ int decimal_point,+ int digits_after_point,+ StringBuilder* result_builder) const {+ // Create a representation that is padded with zeros if needed.+ if (decimal_point <= 0) {+ // "0.00000decimal_rep".+ result_builder->AddCharacter('0');+ if (digits_after_point > 0) {+ result_builder->AddCharacter('.');+ result_builder->AddPadding('0', -decimal_point);+ ASSERT(length <= digits_after_point - (-decimal_point));+ result_builder->AddSubstring(decimal_digits, length);+ int remaining_digits = digits_after_point - (-decimal_point) - length;+ result_builder->AddPadding('0', remaining_digits);+ }+ } else if (decimal_point >= length) {+ // "decimal_rep0000.00000" or "decimal_rep.0000"+ result_builder->AddSubstring(decimal_digits, length);+ result_builder->AddPadding('0', decimal_point - length);+ if (digits_after_point > 0) {+ result_builder->AddCharacter('.');+ result_builder->AddPadding('0', digits_after_point);+ }+ } else {+ // "decima.l_rep000"+ ASSERT(digits_after_point > 0);+ result_builder->AddSubstring(decimal_digits, decimal_point);+ result_builder->AddCharacter('.');+ ASSERT(length - decimal_point <= digits_after_point);+ result_builder->AddSubstring(&decimal_digits[decimal_point],+ length - decimal_point);+ int remaining_digits = digits_after_point - (length - decimal_point);+ result_builder->AddPadding('0', remaining_digits);+ }+ if (digits_after_point == 0) {+ if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {+ result_builder->AddCharacter('.');+ }+ if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {+ result_builder->AddCharacter('0');+ }+ }+}+++bool DoubleToStringConverter::ToShortest(double value,+ StringBuilder* result_builder) const {+ if (Double(value).IsSpecial()) {+ return HandleSpecialValues(value, result_builder);+ }++ int decimal_point;+ bool sign;+ const int kDecimalRepCapacity = kBase10MaximalLength + 1;+ char decimal_rep[kDecimalRepCapacity];+ int decimal_rep_length;++ DoubleToAscii(value, SHORTEST, 0, decimal_rep, kDecimalRepCapacity,+ &sign, &decimal_rep_length, &decimal_point);++ bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;+ if (sign && (value != 0.0 || !unique_zero)) {+ result_builder->AddCharacter('-');+ }++ int exponent = decimal_point - 1;+ if ((decimal_in_shortest_low_ <= exponent) &&+ (exponent < decimal_in_shortest_high_)) {+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length,+ decimal_point,+ Max(0, decimal_rep_length - decimal_point),+ result_builder);+ } else {+ CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,+ result_builder);+ }+ return true;+}+++bool DoubleToStringConverter::ToFixed(double value,+ int requested_digits,+ StringBuilder* result_builder) const {+ ASSERT(kMaxFixedDigitsBeforePoint == 60);+ const double kFirstNonFixed = 1e60;++ if (Double(value).IsSpecial()) {+ return HandleSpecialValues(value, result_builder);+ }++ if (requested_digits > kMaxFixedDigitsAfterPoint) return false;+ if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;++ // Find a sufficiently precise decimal representation of n.+ int decimal_point;+ bool sign;+ // Add space for the '\0' byte.+ const int kDecimalRepCapacity =+ kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;+ char decimal_rep[kDecimalRepCapacity];+ int decimal_rep_length;+ DoubleToAscii(value, FIXED, requested_digits,+ decimal_rep, kDecimalRepCapacity,+ &sign, &decimal_rep_length, &decimal_point);++ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);+ if (sign && (value != 0.0 || !unique_zero)) {+ result_builder->AddCharacter('-');+ }++ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,+ requested_digits, result_builder);+ return true;+}+++bool DoubleToStringConverter::ToExponential(+ double value,+ int requested_digits,+ StringBuilder* result_builder) const {+ if (Double(value).IsSpecial()) {+ return HandleSpecialValues(value, result_builder);+ }++ if (requested_digits < -1) return false;+ if (requested_digits > kMaxExponentialDigits) return false;++ int decimal_point;+ bool sign;+ // Add space for digit before the decimal point and the '\0' character.+ const int kDecimalRepCapacity = kMaxExponentialDigits + 2;+ ASSERT(kDecimalRepCapacity > kBase10MaximalLength);+ char decimal_rep[kDecimalRepCapacity];+ int decimal_rep_length;++ if (requested_digits == -1) {+ DoubleToAscii(value, SHORTEST, 0,+ decimal_rep, kDecimalRepCapacity,+ &sign, &decimal_rep_length, &decimal_point);+ } else {+ DoubleToAscii(value, PRECISION, requested_digits + 1,+ decimal_rep, kDecimalRepCapacity,+ &sign, &decimal_rep_length, &decimal_point);+ ASSERT(decimal_rep_length <= requested_digits + 1);++ for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {+ decimal_rep[i] = '0';+ }+ decimal_rep_length = requested_digits + 1;+ }++ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);+ if (sign && (value != 0.0 || !unique_zero)) {+ result_builder->AddCharacter('-');+ }++ int exponent = decimal_point - 1;+ CreateExponentialRepresentation(decimal_rep,+ decimal_rep_length,+ exponent,+ result_builder);+ return true;+}+++bool DoubleToStringConverter::ToPrecision(double value,+ int precision,+ StringBuilder* result_builder) const {+ if (Double(value).IsSpecial()) {+ return HandleSpecialValues(value, result_builder);+ }++ if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {+ return false;+ }++ // Find a sufficiently precise decimal representation of n.+ int decimal_point;+ bool sign;+ // Add one for the terminating null character.+ const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;+ char decimal_rep[kDecimalRepCapacity];+ int decimal_rep_length;++ DoubleToAscii(value, PRECISION, precision,+ decimal_rep, kDecimalRepCapacity,+ &sign, &decimal_rep_length, &decimal_point);+ ASSERT(decimal_rep_length <= precision);++ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);+ if (sign && (value != 0.0 || !unique_zero)) {+ result_builder->AddCharacter('-');+ }++ // The exponent if we print the number as x.xxeyyy. That is with the+ // decimal point after the first digit.+ int exponent = decimal_point - 1;++ int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;+ if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||+ (decimal_point - precision + extra_zero >+ max_trailing_padding_zeroes_in_precision_mode_)) {+ // Fill buffer to contain 'precision' digits.+ // Usually the buffer is already at the correct length, but 'DoubleToAscii'+ // is allowed to return less characters.+ for (int i = decimal_rep_length; i < precision; ++i) {+ decimal_rep[i] = '0';+ }++ CreateExponentialRepresentation(decimal_rep,+ precision,+ exponent,+ result_builder);+ } else {+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,+ Max(0, precision - decimal_point),+ result_builder);+ }+ return true;+}+++static BignumDtoaMode DtoaToBignumDtoaMode(+ DoubleToStringConverter::DtoaMode dtoa_mode) {+ switch (dtoa_mode) {+ case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST;+ case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;+ case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;+ default:+ UNREACHABLE();+ return BIGNUM_DTOA_SHORTEST; // To silence compiler.+ }+}+++void DoubleToStringConverter::DoubleToAscii(double v,+ DtoaMode mode,+ int requested_digits,+ char* buffer,+ int buffer_length,+ bool* sign,+ int* length,+ int* point) {+ Vector<char> vector(buffer, buffer_length);+ ASSERT(!Double(v).IsSpecial());+ ASSERT(mode == SHORTEST || requested_digits >= 0);++ if (Double(v).Sign() < 0) {+ *sign = true;+ v = -v;+ } else {+ *sign = false;+ }++ if (mode == PRECISION && requested_digits == 0) {+ vector[0] = '\0';+ *length = 0;+ return;+ }++ if (v == 0) {+ vector[0] = '0';+ vector[1] = '\0';+ *length = 1;+ *point = 1;+ return;+ }++ bool fast_worked;+ switch (mode) {+ case SHORTEST:+ fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);+ break;+ case FIXED:+ fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);+ break;+ case PRECISION:+ fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,+ vector, length, point);+ break;+ default:+ UNREACHABLE();+ fast_worked = false;+ }+ if (fast_worked) return;++ // If the fast dtoa didn't succeed use the slower bignum version.+ BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);+ BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);+ vector[*length] = '\0';+}+++// Consumes the given substring from the iterator.+// Returns false, if the substring does not match.+static bool ConsumeSubString(const char** current,+ const char* end,+ const char* substring) {+ ASSERT(**current == *substring);+ for (substring++; *substring != '\0'; substring++) {+ ++*current;+ if (*current == end || **current != *substring) return false;+ }+ ++*current;+ return true;+}+++// Maximum number of significant digits in decimal representation.+// The longest possible double in decimal representation is+// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074+// (768 digits). If we parse a number whose first digits are equal to a+// mean of 2 adjacent doubles (that could have up to 769 digits) the result+// must be rounded to the bigger one unless the tail consists of zeros, so+// we don't need to preserve all the digits.+const int kMaxSignificantDigits = 772;+++// Returns true if a nonspace found and false if the end has reached.+static inline bool AdvanceToNonspace(const char** current, const char* end) {+ while (*current != end) {+ if (**current != ' ') return true;+ ++*current;+ }+ return false;+}+++static bool isDigit(int x, int radix) {+ return (x >= '0' && x <= '9' && x < '0' + radix)+ || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)+ || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);+}+++static double SignedZero(bool sign) {+ return sign ? -0.0 : 0.0;+}+++// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.+template <int radix_log_2>+static double RadixStringToDouble(const char* current,+ const char* end,+ bool sign,+ bool allow_trailing_junk,+ double junk_string_value,+ const char** trailing_pointer) {+ ASSERT(current != end);++ // Skip leading 0s.+ while (*current == '0') {+ ++current;+ if (current == end) {+ *trailing_pointer = end;+ return SignedZero(sign);+ }+ }++ int64_t number = 0;+ int exponent = 0;+ const int radix = (1 << radix_log_2);++ do {+ int digit;+ if (*current >= '0' && *current <= '9' && *current < '0' + radix) {+ digit = static_cast<char>(*current) - '0';+ } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) {+ digit = static_cast<char>(*current) - 'a' + 10;+ } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) {+ digit = static_cast<char>(*current) - 'A' + 10;+ } else {+ if (allow_trailing_junk || !AdvanceToNonspace(¤t, end)) {+ break;+ } else {+ return junk_string_value;+ }+ }++ number = number * radix + digit;+ int overflow = static_cast<int>(number >> 53);+ if (overflow != 0) {+ // Overflow occurred. Need to determine which direction to round the+ // result.+ int overflow_bits_count = 1;+ while (overflow > 1) {+ overflow_bits_count++;+ overflow >>= 1;+ }++ int dropped_bits_mask = ((1 << overflow_bits_count) - 1);+ int dropped_bits = static_cast<int>(number) & dropped_bits_mask;+ number >>= overflow_bits_count;+ exponent = overflow_bits_count;++ bool zero_tail = true;+ while (true) {+ ++current;+ if (current == end || !isDigit(*current, radix)) break;+ zero_tail = zero_tail && *current == '0';+ exponent += radix_log_2;+ }++ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) {+ return junk_string_value;+ }++ int middle_value = (1 << (overflow_bits_count - 1));+ if (dropped_bits > middle_value) {+ number++; // Rounding up.+ } else if (dropped_bits == middle_value) {+ // Rounding to even to consistency with decimals: half-way case rounds+ // up if significant part is odd and down otherwise.+ if ((number & 1) != 0 || !zero_tail) {+ number++; // Rounding up.+ }+ }++ // Rounding up may cause overflow.+ if ((number & ((int64_t)1 << 53)) != 0) {+ exponent++;+ number >>= 1;+ }+ break;+ }+ ++current;+ } while (current != end);++ ASSERT(number < ((int64_t)1 << 53));+ ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);++ *trailing_pointer = current;++ if (exponent == 0) {+ if (sign) {+ if (number == 0) return -0.0;+ number = -number;+ }+ return static_cast<double>(number);+ }++ ASSERT(number != 0);+ return Double(DiyFp(number, exponent)).value();+}+++double StringToDoubleConverter::StringToDouble(+ const char* input,+ int length,+ int* processed_characters_count) {+ const char* current = input;+ const char* end = input + length;++ *processed_characters_count = 0;++ const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0;+ const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;+ const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;+ const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;++ // To make sure that iterator dereferencing is valid the following+ // convention is used:+ // 1. Each '++current' statement is followed by check for equality to 'end'.+ // 2. If AdvanceToNonspace returned false then current == end.+ // 3. If 'current' becomes equal to 'end' the function returns or goes to+ // 'parsing_done'.+ // 4. 'current' is not dereferenced after the 'parsing_done' label.+ // 5. Code before 'parsing_done' may rely on 'current != end'.+ if (current == end) return empty_string_value_;++ if (allow_leading_spaces || allow_trailing_spaces) {+ if (!AdvanceToNonspace(¤t, end)) {+ *processed_characters_count = current - input;+ return empty_string_value_;+ }+ if (!allow_leading_spaces && (input != current)) {+ // No leading spaces allowed, but AdvanceToNonspace moved forward.+ return junk_string_value_;+ }+ }++ // The longest form of simplified number is: "-<significant digits>.1eXXX\0".+ const int kBufferSize = kMaxSignificantDigits + 10;+ char buffer[kBufferSize]; // NOLINT: size is known at compile time.+ int buffer_pos = 0;++ // Exponent will be adjusted if insignificant digits of the integer part+ // or insignificant leading zeros of the fractional part are dropped.+ int exponent = 0;+ int significant_digits = 0;+ int insignificant_digits = 0;+ bool nonzero_digit_dropped = false;+ bool fractional_part = false;++ bool sign = false;++ if (*current == '+' || *current == '-') {+ sign = (*current == '-');+ ++current;+ const char* next_non_space = current;+ // Skip following spaces (if allowed).+ if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_;+ if (!allow_spaces_after_sign && (current != next_non_space)) {+ return junk_string_value_;+ }+ current = next_non_space;+ }++ if (infinity_symbol_ != NULL) {+ if (*current == infinity_symbol_[0]) {+ if (!ConsumeSubString(¤t, end, infinity_symbol_)) {+ return junk_string_value_;+ }++ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {+ return junk_string_value_;+ }+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) {+ return junk_string_value_;+ }++ ASSERT(buffer_pos == 0);+ *processed_characters_count = current - input;+ return sign ? -Double::Infinity() : Double::Infinity();+ }+ }++ if (nan_symbol_ != NULL) {+ if (*current == nan_symbol_[0]) {+ if (!ConsumeSubString(¤t, end, nan_symbol_)) {+ return junk_string_value_;+ }++ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {+ return junk_string_value_;+ }+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) {+ return junk_string_value_;+ }++ ASSERT(buffer_pos == 0);+ *processed_characters_count = current - input;+ return sign ? -Double::NaN() : Double::NaN();+ }+ }++ bool leading_zero = false;+ if (*current == '0') {+ ++current;+ if (current == end) {+ *processed_characters_count = current - input;+ return SignedZero(sign);+ }++ leading_zero = true;++ // It could be hexadecimal value.+ if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {+ ++current;+ if (current == end || !isDigit(*current, 16)) {+ return junk_string_value_; // "0x".+ }++ const char* tail_pointer = NULL;+ double result = RadixStringToDouble<4>(current,+ end,+ sign,+ allow_trailing_junk,+ junk_string_value_,+ &tail_pointer);+ if (tail_pointer != NULL) {+ if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end);+ *processed_characters_count = tail_pointer - input;+ }+ return result;+ }++ // Ignore leading zeros in the integer part.+ while (*current == '0') {+ ++current;+ if (current == end) {+ *processed_characters_count = current - input;+ return SignedZero(sign);+ }+ }+ }++ bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0;++ // Copy significant digits of the integer part (if any) to the buffer.+ while (*current >= '0' && *current <= '9') {+ if (significant_digits < kMaxSignificantDigits) {+ ASSERT(buffer_pos < kBufferSize);+ buffer[buffer_pos++] = static_cast<char>(*current);+ significant_digits++;+ // Will later check if it's an octal in the buffer.+ } else {+ insignificant_digits++; // Move the digit into the exponential part.+ nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';+ }+ octal = octal && *current < '8';+ ++current;+ if (current == end) goto parsing_done;+ }++ if (significant_digits == 0) {+ octal = false;+ }++ if (*current == '.') {+ if (octal && !allow_trailing_junk) return junk_string_value_;+ if (octal) goto parsing_done;++ ++current;+ if (current == end) {+ if (significant_digits == 0 && !leading_zero) {+ return junk_string_value_;+ } else {+ goto parsing_done;+ }+ }++ if (significant_digits == 0) {+ // octal = false;+ // Integer part consists of 0 or is absent. Significant digits start after+ // leading zeros (if any).+ while (*current == '0') {+ ++current;+ if (current == end) {+ *processed_characters_count = current - input;+ return SignedZero(sign);+ }+ exponent--; // Move this 0 into the exponent.+ }+ }++ // We don't emit a '.', but adjust the exponent instead.+ fractional_part = true;++ // There is a fractional part.+ while (*current >= '0' && *current <= '9') {+ if (significant_digits < kMaxSignificantDigits) {+ ASSERT(buffer_pos < kBufferSize);+ buffer[buffer_pos++] = static_cast<char>(*current);+ significant_digits++;+ exponent--;+ } else {+ // Ignore insignificant digits in the fractional part.+ nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';+ }+ ++current;+ if (current == end) goto parsing_done;+ }+ }++ if (!leading_zero && exponent == 0 && significant_digits == 0) {+ // If leading_zeros is true then the string contains zeros.+ // If exponent < 0 then string was [+-]\.0*...+ // If significant_digits != 0 the string is not equal to 0.+ // Otherwise there are no digits in the string.+ return junk_string_value_;+ }++ // Parse exponential part.+ if (*current == 'e' || *current == 'E') {+ if (octal && !allow_trailing_junk) return junk_string_value_;+ if (octal) goto parsing_done;+ ++current;+ if (current == end) {+ if (allow_trailing_junk) {+ goto parsing_done;+ } else {+ return junk_string_value_;+ }+ }+ char sign = '+';+ if (*current == '+' || *current == '-') {+ sign = static_cast<char>(*current);+ ++current;+ if (current == end) {+ if (allow_trailing_junk) {+ goto parsing_done;+ } else {+ return junk_string_value_;+ }+ }+ }++ if (current == end || *current < '0' || *current > '9') {+ if (allow_trailing_junk) {+ goto parsing_done;+ } else {+ return junk_string_value_;+ }+ }++ const int max_exponent = INT_MAX / 2;+ ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);+ int num = 0;+ do {+ // Check overflow.+ int digit = *current - '0';+ if (num >= max_exponent / 10+ && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {+ num = max_exponent;+ } else {+ num = num * 10 + digit;+ }+ ++current;+ } while (current != end && *current >= '0' && *current <= '9');++ exponent += (sign == '-' ? -num : num);+ }++ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {+ return junk_string_value_;+ }+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) {+ return junk_string_value_;+ }+ if (allow_trailing_spaces) {+ AdvanceToNonspace(¤t, end);+ }++ parsing_done:+ exponent += insignificant_digits;++ if (octal) {+ double result;+ const char* tail_pointer = NULL;+ result = RadixStringToDouble<3>(buffer,+ buffer + buffer_pos,+ sign,+ allow_trailing_junk,+ junk_string_value_,+ &tail_pointer);+ ASSERT(tail_pointer != NULL);+ *processed_characters_count = current - input;+ return result;+ }++ if (nonzero_digit_dropped) {+ buffer[buffer_pos++] = '1';+ exponent--;+ }++ ASSERT(buffer_pos < kBufferSize);+ buffer[buffer_pos] = '\0';++ double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);+ *processed_characters_count = current - input;+ return sign? -converted: converted;+}++} // namespace double_conversion
+ double-conversion/src/double-conversion.h view
@@ -0,0 +1,498 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_+#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_++#include "utils.h"++namespace double_conversion {++class DoubleToStringConverter {+ public:+ // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint+ // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the+ // function returns false.+ static const int kMaxFixedDigitsBeforePoint = 60;+ static const int kMaxFixedDigitsAfterPoint = 60;++ // When calling ToExponential with a requested_digits+ // parameter > kMaxExponentialDigits then the function returns false.+ static const int kMaxExponentialDigits = 120;++ // When calling ToPrecision with a requested_digits+ // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits+ // then the function returns false.+ static const int kMinPrecisionDigits = 1;+ static const int kMaxPrecisionDigits = 120;++ enum Flags {+ NO_FLAGS = 0,+ EMIT_POSITIVE_EXPONENT_SIGN = 1,+ EMIT_TRAILING_DECIMAL_POINT = 2,+ EMIT_TRAILING_ZERO_AFTER_POINT = 4,+ UNIQUE_ZERO = 8+ };++ // Flags should be a bit-or combination of the possible Flags-enum.+ // - NO_FLAGS: no special flags.+ // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent+ // form, emits a '+' for positive exponents. Example: 1.2e+2.+ // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is+ // converted into decimal format then a trailing decimal point is appended.+ // Example: 2345.0 is converted to "2345.".+ // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point+ // emits a trailing '0'-character. This flag requires the+ // EXMIT_TRAILING_DECIMAL_POINT flag.+ // Example: 2345.0 is converted to "2345.0".+ // - UNIQUE_ZERO: "-0.0" is converted to "0.0".+ //+ // Infinity symbol and nan_symbol provide the string representation for these+ // special values. If the string is NULL and the special value is encountered+ // then the conversion functions return false.+ //+ // The exponent_character is used in exponential representations. It is+ // usually 'e' or 'E'.+ //+ // When converting to the shortest representation the converter will+ // represent input numbers in decimal format if they are in the interval+ // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[+ // (lower boundary included, greater boundary excluded).+ // Example: with decimal_in_shortest_low = -6 and+ // decimal_in_shortest_high = 21:+ // ToShortest(0.000001) -> "0.000001"+ // ToShortest(0.0000001) -> "1e-7"+ // ToShortest(111111111111111111111.0) -> "111111111111111110000"+ // ToShortest(100000000000000000000.0) -> "100000000000000000000"+ // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"+ //+ // When converting to precision mode the converter may add+ // max_leading_padding_zeroes before returning the number in exponential+ // format.+ // Example with max_leading_padding_zeroes_in_precision_mode = 6.+ // ToPrecision(0.0000012345, 2) -> "0.0000012"+ // ToPrecision(0.00000012345, 2) -> "1.2e-7"+ // Similarily the converter may add up to+ // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid+ // returning an exponential representation. A zero added by the+ // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:+ // ToPrecision(230.0, 2) -> "230"+ // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.+ // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.+ DoubleToStringConverter(int flags,+ const char* infinity_symbol,+ const char* nan_symbol,+ char exponent_character,+ int decimal_in_shortest_low,+ int decimal_in_shortest_high,+ int max_leading_padding_zeroes_in_precision_mode,+ int max_trailing_padding_zeroes_in_precision_mode)+ : flags_(flags),+ infinity_symbol_(infinity_symbol),+ nan_symbol_(nan_symbol),+ exponent_character_(exponent_character),+ decimal_in_shortest_low_(decimal_in_shortest_low),+ decimal_in_shortest_high_(decimal_in_shortest_high),+ max_leading_padding_zeroes_in_precision_mode_(+ max_leading_padding_zeroes_in_precision_mode),+ max_trailing_padding_zeroes_in_precision_mode_(+ max_trailing_padding_zeroes_in_precision_mode) {+ // When 'trailing zero after the point' is set, then 'trailing point'+ // must be set too.+ ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) ||+ !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0));+ }++ // Returns a converter following the EcmaScript specification.+ static const DoubleToStringConverter& EcmaScriptConverter();++ // Computes the shortest string of digits that correctly represent the input+ // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high+ // (see constructor) it then either returns a decimal representation, or an+ // exponential representation.+ // Example with decimal_in_shortest_low = -6,+ // decimal_in_shortest_high = 21,+ // EMIT_POSITIVE_EXPONENT_SIGN activated, and+ // EMIT_TRAILING_DECIMAL_POINT deactived:+ // ToShortest(0.000001) -> "0.000001"+ // ToShortest(0.0000001) -> "1e-7"+ // ToShortest(111111111111111111111.0) -> "111111111111111110000"+ // ToShortest(100000000000000000000.0) -> "100000000000000000000"+ // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"+ //+ // Note: the conversion may round the output if the returned string+ // is accurate enough to uniquely identify the input-number.+ // For example the most precise representation of the double 9e59 equals+ // "899999999999999918767229449717619953810131273674690656206848", but+ // the converter will return the shorter (but still correct) "9e59".+ //+ // Returns true if the conversion succeeds. The conversion always succeeds+ // except when the input value is special and no infinity_symbol or+ // nan_symbol has been given to the constructor.+ bool ToShortest(double value, StringBuilder* result_builder) const;+++ // Computes a decimal representation with a fixed number of digits after the+ // decimal point. The last emitted digit is rounded.+ //+ // Examples:+ // ToFixed(3.12, 1) -> "3.1"+ // ToFixed(3.1415, 3) -> "3.142"+ // ToFixed(1234.56789, 4) -> "1234.5679"+ // ToFixed(1.23, 5) -> "1.23000"+ // ToFixed(0.1, 4) -> "0.1000"+ // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00"+ // ToFixed(0.1, 30) -> "0.100000000000000005551115123126"+ // ToFixed(0.1, 17) -> "0.10000000000000001"+ //+ // If requested_digits equals 0, then the tail of the result depends on+ // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT.+ // Examples, for requested_digits == 0,+ // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be+ // - false and false: then 123.45 -> 123+ // 0.678 -> 1+ // - true and false: then 123.45 -> 123.+ // 0.678 -> 1.+ // - true and true: then 123.45 -> 123.0+ // 0.678 -> 1.0+ //+ // Returns true if the conversion succeeds. The conversion always succeeds+ // except for the following cases:+ // - the input value is special and no infinity_symbol or nan_symbol has+ // been provided to the constructor,+ // - 'value' > 10^kMaxFixedDigitsBeforePoint, or+ // - 'requested_digits' > kMaxFixedDigitsAfterPoint.+ // The last two conditions imply that the result will never contain more than+ // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters+ // (one additional character for the sign, and one for the decimal point).+ bool ToFixed(double value,+ int requested_digits,+ StringBuilder* result_builder) const;++ // Computes a representation in exponential format with requested_digits+ // after the decimal point. The last emitted digit is rounded.+ // If requested_digits equals -1, then the shortest exponential representation+ // is computed.+ //+ // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and+ // exponent_character set to 'e'.+ // ToExponential(3.12, 1) -> "3.1e0"+ // ToExponential(5.0, 3) -> "5.000e0"+ // ToExponential(0.001, 2) -> "1.00e-3"+ // ToExponential(3.1415, -1) -> "3.1415e0"+ // ToExponential(3.1415, 4) -> "3.1415e0"+ // ToExponential(3.1415, 3) -> "3.142e0"+ // ToExponential(123456789000000, 3) -> "1.235e14"+ // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30"+ // ToExponential(1000000000000000019884624838656.0, 32) ->+ // "1.00000000000000001988462483865600e30"+ // ToExponential(1234, 0) -> "1e3"+ //+ // Returns true if the conversion succeeds. The conversion always succeeds+ // except for the following cases:+ // - the input value is special and no infinity_symbol or nan_symbol has+ // been provided to the constructor,+ // - 'requested_digits' > kMaxExponentialDigits.+ // The last condition implies that the result will never contain more than+ // kMaxExponentialDigits + 8 characters (the sign, the digit before the+ // decimal point, the decimal point, the exponent character, the+ // exponent's sign, and at most 3 exponent digits).+ bool ToExponential(double value,+ int requested_digits,+ StringBuilder* result_builder) const;++ // Computes 'precision' leading digits of the given 'value' and returns them+ // either in exponential or decimal format, depending on+ // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the+ // constructor).+ // The last computed digit is rounded.+ //+ // Example with max_leading_padding_zeroes_in_precision_mode = 6.+ // ToPrecision(0.0000012345, 2) -> "0.0000012"+ // ToPrecision(0.00000012345, 2) -> "1.2e-7"+ // Similarily the converter may add up to+ // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid+ // returning an exponential representation. A zero added by the+ // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:+ // ToPrecision(230.0, 2) -> "230"+ // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.+ // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no+ // EMIT_TRAILING_ZERO_AFTER_POINT:+ // ToPrecision(123450.0, 6) -> "123450"+ // ToPrecision(123450.0, 5) -> "123450"+ // ToPrecision(123450.0, 4) -> "123500"+ // ToPrecision(123450.0, 3) -> "123000"+ // ToPrecision(123450.0, 2) -> "1.2e5"+ //+ // Returns true if the conversion succeeds. The conversion always succeeds+ // except for the following cases:+ // - the input value is special and no infinity_symbol or nan_symbol has+ // been provided to the constructor,+ // - precision < kMinPericisionDigits+ // - precision > kMaxPrecisionDigits+ // The last condition implies that the result will never contain more than+ // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the+ // exponent character, the exponent's sign, and at most 3 exponent digits).+ bool ToPrecision(double value,+ int precision,+ StringBuilder* result_builder) const;++ enum DtoaMode {+ // Produce the shortest correct representation.+ // For example the output of 0.299999999999999988897 is (the less accurate+ // but correct) 0.3.+ SHORTEST,+ // Produce a fixed number of digits after the decimal point.+ // For instance fixed(0.1, 4) becomes 0.1000+ // If the input number is big, the output will be big.+ FIXED,+ // Fixed number of digits (independent of the decimal point).+ PRECISION+ };++ // The maximal number of digits that are needed to emit a double in base 10.+ // A higher precision can be achieved by using more digits, but the shortest+ // accurate representation of any double will never use more digits than+ // kBase10MaximalLength.+ // Note that DoubleToAscii null-terminates its input. So the given buffer+ // should be at least kBase10MaximalLength + 1 characters long.+ static const int kBase10MaximalLength = 17;++ // Converts the given double 'v' to ascii.+ // The result should be interpreted as buffer * 10^(point-length).+ //+ // The output depends on the given mode:+ // - SHORTEST: produce the least amount of digits for which the internal+ // identity requirement is still satisfied. If the digits are printed+ // (together with the correct exponent) then reading this number will give+ // 'v' again. The buffer will choose the representation that is closest to+ // 'v'. If there are two at the same distance, than the one farther away+ // from 0 is chosen (halfway cases - ending with 5 - are rounded up).+ // In this mode the 'requested_digits' parameter is ignored.+ // - FIXED: produces digits necessary to print a given number with+ // 'requested_digits' digits after the decimal point. The produced digits+ // might be too short in which case the caller has to fill the remainder+ // with '0's.+ // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.+ // Halfway cases are rounded towards +/-Infinity (away from 0). The call+ // toFixed(0.15, 2) thus returns buffer="2", point=0.+ // The returned buffer may contain digits that would be truncated from the+ // shortest representation of the input.+ // - PRECISION: produces 'requested_digits' where the first digit is not '0'.+ // Even though the length of produced digits usually equals+ // 'requested_digits', the function is allowed to return fewer digits, in+ // which case the caller has to fill the missing digits with '0's.+ // Halfway cases are again rounded away from 0.+ // DoubleToAscii expects the given buffer to be big enough to hold all+ // digits and a terminating null-character. In SHORTEST-mode it expects a+ // buffer of at least kBase10MaximalLength + 1. In all other modes the+ // requested_digits parameter (+ 1 for the null-character) limits the size of+ // the output. The given length is only used in debug mode to ensure the+ // buffer is big enough.+ static void DoubleToAscii(double v,+ DtoaMode mode,+ int requested_digits,+ char* buffer,+ int buffer_length,+ bool* sign,+ int* length,+ int* point);++ private:+ // If the value is a special value (NaN or Infinity) constructs the+ // corresponding string using the configured infinity/nan-symbol.+ // If either of them is NULL or the value is not special then the+ // function returns false.+ bool HandleSpecialValues(double value, StringBuilder* result_builder) const;+ // Constructs an exponential representation (i.e. 1.234e56).+ // The given exponent assumes a decimal point after the first decimal digit.+ void CreateExponentialRepresentation(const char* decimal_digits,+ int length,+ int exponent,+ StringBuilder* result_builder) const;+ // Creates a decimal representation (i.e 1234.5678).+ void CreateDecimalRepresentation(const char* decimal_digits,+ int length,+ int decimal_point,+ int digits_after_point,+ StringBuilder* result_builder) const;++ const int flags_;+ const char* const infinity_symbol_;+ const char* const nan_symbol_;+ const char exponent_character_;+ const int decimal_in_shortest_low_;+ const int decimal_in_shortest_high_;+ const int max_leading_padding_zeroes_in_precision_mode_;+ const int max_trailing_padding_zeroes_in_precision_mode_;++ DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);+};+++class StringToDoubleConverter {+ public:+ // Enumeration for allowing octals and ignoring junk when converting+ // strings to numbers.+ enum Flags {+ NO_FLAGS = 0,+ ALLOW_HEX = 1,+ ALLOW_OCTALS = 2,+ ALLOW_TRAILING_JUNK = 4,+ ALLOW_LEADING_SPACES = 8,+ ALLOW_TRAILING_SPACES = 16,+ ALLOW_SPACES_AFTER_SIGN = 32+ };++ // Flags should be a bit-or combination of the possible Flags-enum.+ // - NO_FLAGS: no special flags.+ // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.+ // Ex: StringToDouble("0x1234") -> 4660.0+ // In StringToDouble("0x1234.56") the characters ".56" are trailing+ // junk. The result of the call is hence dependent on+ // the ALLOW_TRAILING_JUNK flag and/or the junk value.+ // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK,+ // the string will not be parsed as "0" followed by junk.+ //+ // - ALLOW_OCTALS: recognizes the prefix "0" for octals:+ // If a sequence of octal digits starts with '0', then the number is+ // read as octal integer. Octal numbers may only be integers.+ // Ex: StringToDouble("01234") -> 668.0+ // StringToDouble("012349") -> 12349.0 // Not a sequence of octal+ // // digits.+ // In StringToDouble("01234.56") the characters ".56" are trailing+ // junk. The result of the call is hence dependent on+ // the ALLOW_TRAILING_JUNK flag and/or the junk value.+ // In StringToDouble("01234e56") the characters "e56" are trailing+ // junk, too.+ // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of+ // a double literal.+ // - ALLOW_LEADING_SPACES: skip over leading spaces.+ // - ALLOW_TRAILING_SPACES: ignore trailing spaces.+ // - ALLOW_SPACES_AFTER_SIGN: ignore spaces after the sign.+ // Ex: StringToDouble("- 123.2") -> -123.2.+ // StringToDouble("+ 123.2") -> 123.2+ //+ // empty_string_value is returned when an empty string is given as input.+ // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string+ // containing only spaces is converted to the 'empty_string_value', too.+ //+ // junk_string_value is returned when+ // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not+ // part of a double-literal) is found.+ // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a+ // double literal.+ //+ // infinity_symbol and nan_symbol are strings that are used to detect+ // inputs that represent infinity and NaN. They can be null, in which case+ // they are ignored.+ // The conversion routine first reads any possible signs. Then it compares the+ // following character of the input-string with the first character of+ // the infinity, and nan-symbol. If either matches, the function assumes, that+ // a match has been found, and expects the following input characters to match+ // the remaining characters of the special-value symbol.+ // This means that the following restrictions apply to special-value symbols:+ // - they must not start with signs ('+', or '-'),+ // - they must not have the same first character.+ // - they must not start with digits.+ //+ // Examples:+ // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,+ // empty_string_value = 0.0,+ // junk_string_value = NaN,+ // infinity_symbol = "infinity",+ // nan_symbol = "nan":+ // StringToDouble("0x1234") -> 4660.0.+ // StringToDouble("0x1234K") -> 4660.0.+ // StringToDouble("") -> 0.0 // empty_string_value.+ // StringToDouble(" ") -> NaN // junk_string_value.+ // StringToDouble(" 1") -> NaN // junk_string_value.+ // StringToDouble("0x") -> NaN // junk_string_value.+ // StringToDouble("-123.45") -> -123.45.+ // StringToDouble("--123.45") -> NaN // junk_string_value.+ // StringToDouble("123e45") -> 123e45.+ // StringToDouble("123E45") -> 123e45.+ // StringToDouble("123e+45") -> 123e45.+ // StringToDouble("123E-45") -> 123e-45.+ // StringToDouble("123e") -> 123.0 // trailing junk ignored.+ // StringToDouble("123e-") -> 123.0 // trailing junk ignored.+ // StringToDouble("+NaN") -> NaN // NaN string literal.+ // StringToDouble("-infinity") -> -inf. // infinity literal.+ // StringToDouble("Infinity") -> NaN // junk_string_value.+ //+ // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES,+ // empty_string_value = 0.0,+ // junk_string_value = NaN,+ // infinity_symbol = NULL,+ // nan_symbol = NULL:+ // StringToDouble("0x1234") -> NaN // junk_string_value.+ // StringToDouble("01234") -> 668.0.+ // StringToDouble("") -> 0.0 // empty_string_value.+ // StringToDouble(" ") -> 0.0 // empty_string_value.+ // StringToDouble(" 1") -> 1.0+ // StringToDouble("0x") -> NaN // junk_string_value.+ // StringToDouble("0123e45") -> NaN // junk_string_value.+ // StringToDouble("01239E45") -> 1239e45.+ // StringToDouble("-infinity") -> NaN // junk_string_value.+ // StringToDouble("NaN") -> NaN // junk_string_value.+ StringToDoubleConverter(int flags,+ double empty_string_value,+ double junk_string_value,+ const char* infinity_symbol,+ const char* nan_symbol)+ : flags_(flags),+ empty_string_value_(empty_string_value),+ junk_string_value_(junk_string_value),+ infinity_symbol_(infinity_symbol),+ nan_symbol_(nan_symbol) {+ }++ // Performs the conversion.+ // The output parameter 'processed_characters_count' is set to the number+ // of characters that have been processed to read the number.+ // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included+ // in the 'processed_characters_count'. Trailing junk is never included.+ double StringToDouble(const char* buffer,+ int length,+ int* processed_characters_count);++ private:+ const int flags_;+ const double empty_string_value_;+ const double junk_string_value_;+ const char* const infinity_symbol_;+ const char* const nan_symbol_;++ DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);+};++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
+ double-conversion/src/double.h view
@@ -0,0 +1,245 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_DOUBLE_H_+#define DOUBLE_CONVERSION_DOUBLE_H_++#include "diy-fp.h"++namespace double_conversion {++// We assume that doubles and uint64_t have the same endianness.+static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }+static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }++// Helper functions for doubles.+class Double {+ public:+ static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000);+ static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000);+ static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);+ static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000);+ static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit.+ static const int kSignificandSize = 53;++ Double() : d64_(0) {}+ explicit Double(double d) : d64_(double_to_uint64(d)) {}+ explicit Double(uint64_t d64) : d64_(d64) {}+ explicit Double(DiyFp diy_fp)+ : d64_(DiyFpToUint64(diy_fp)) {}++ // The value encoded by this Double must be greater or equal to +0.0.+ // It must not be special (infinity, or NaN).+ DiyFp AsDiyFp() const {+ ASSERT(Sign() > 0);+ ASSERT(!IsSpecial());+ return DiyFp(Significand(), Exponent());+ }++ // The value encoded by this Double must be strictly greater than 0.+ DiyFp AsNormalizedDiyFp() const {+ ASSERT(value() > 0.0);+ uint64_t f = Significand();+ int e = Exponent();++ // The current double could be a denormal.+ while ((f & kHiddenBit) == 0) {+ f <<= 1;+ e--;+ }+ // Do the final shifts in one go.+ f <<= DiyFp::kSignificandSize - kSignificandSize;+ e -= DiyFp::kSignificandSize - kSignificandSize;+ return DiyFp(f, e);+ }++ // Returns the double's bit as uint64.+ uint64_t AsUint64() const {+ return d64_;+ }++ // Returns the next greater double. Returns +infinity on input +infinity.+ double NextDouble() const {+ if (d64_ == kInfinity) return Double(kInfinity).value();+ if (Sign() < 0 && Significand() == 0) {+ // -0.0+ return 0.0;+ }+ if (Sign() < 0) {+ return Double(d64_ - 1).value();+ } else {+ return Double(d64_ + 1).value();+ }+ }++ int Exponent() const {+ if (IsDenormal()) return kDenormalExponent;++ uint64_t d64 = AsUint64();+ int biased_e =+ static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);+ return biased_e - kExponentBias;+ }++ uint64_t Significand() const {+ uint64_t d64 = AsUint64();+ uint64_t significand = d64 & kSignificandMask;+ if (!IsDenormal()) {+ return significand + kHiddenBit;+ } else {+ return significand;+ }+ }++ // Returns true if the double is a denormal.+ bool IsDenormal() const {+ uint64_t d64 = AsUint64();+ return (d64 & kExponentMask) == 0;+ }++ // We consider denormals not to be special.+ // Hence only Infinity and NaN are special.+ bool IsSpecial() const {+ uint64_t d64 = AsUint64();+ return (d64 & kExponentMask) == kExponentMask;+ }++ bool IsNan() const {+ uint64_t d64 = AsUint64();+ return ((d64 & kExponentMask) == kExponentMask) &&+ ((d64 & kSignificandMask) != 0);+ }++ bool IsInfinite() const {+ uint64_t d64 = AsUint64();+ return ((d64 & kExponentMask) == kExponentMask) &&+ ((d64 & kSignificandMask) == 0);+ }++ int Sign() const {+ uint64_t d64 = AsUint64();+ return (d64 & kSignMask) == 0? 1: -1;+ }++ // Precondition: the value encoded by this Double must be greater or equal+ // than +0.0.+ DiyFp UpperBoundary() const {+ ASSERT(Sign() > 0);+ return DiyFp(Significand() * 2 + 1, Exponent() - 1);+ }++ // Computes the two boundaries of this.+ // The bigger boundary (m_plus) is normalized. The lower boundary has the same+ // exponent as m_plus.+ // Precondition: the value encoded by this Double must be greater than 0.+ void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {+ ASSERT(value() > 0.0);+ DiyFp v = this->AsDiyFp();+ bool significand_is_zero = (v.f() == kHiddenBit);+ DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));+ DiyFp m_minus;+ if (significand_is_zero && v.e() != kDenormalExponent) {+ // The boundary is closer. Think of v = 1000e10 and v- = 9999e9.+ // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but+ // at a distance of 1e8.+ // The only exception is for the smallest normal: the largest denormal is+ // at the same distance as its successor.+ // Note: denormals have the same exponent as the smallest normals.+ m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);+ } else {+ m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);+ }+ m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));+ m_minus.set_e(m_plus.e());+ *out_m_plus = m_plus;+ *out_m_minus = m_minus;+ }++ double value() const { return uint64_to_double(d64_); }++ // Returns the significand size for a given order of magnitude.+ // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.+ // This function returns the number of significant binary digits v will have+ // once it's encoded into a double. In almost all cases this is equal to+ // kSignificandSize. The only exceptions are denormals. They start with+ // leading zeroes and their effective significand-size is hence smaller.+ static int SignificandSizeForOrderOfMagnitude(int order) {+ if (order >= (kDenormalExponent + kSignificandSize)) {+ return kSignificandSize;+ }+ if (order <= kDenormalExponent) return 0;+ return order - kDenormalExponent;+ }++ static double Infinity() {+ return Double(kInfinity).value();+ }++ static double NaN() {+ return Double(kNaN).value();+ }++ private:+ static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;+ static const int kDenormalExponent = -kExponentBias + 1;+ static const int kMaxExponent = 0x7FF - kExponentBias;+ static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000);+ static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000);++ const uint64_t d64_;++ static uint64_t DiyFpToUint64(DiyFp diy_fp) {+ uint64_t significand = diy_fp.f();+ int exponent = diy_fp.e();+ while (significand > kHiddenBit + kSignificandMask) {+ significand >>= 1;+ exponent++;+ }+ if (exponent >= kMaxExponent) {+ return kInfinity;+ }+ if (exponent < kDenormalExponent) {+ return 0;+ }+ while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {+ significand <<= 1;+ exponent--;+ }+ uint64_t biased_exponent;+ if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {+ biased_exponent = 0;+ } else {+ biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);+ }+ return (significand & kSignificandMask) |+ (biased_exponent << kPhysicalSignificandSize);+ }+};++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_DOUBLE_H_
+ double-conversion/src/fast-dtoa.cc view
@@ -0,0 +1,735 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include "fast-dtoa.h"++#include "cached-powers.h"+#include "diy-fp.h"+#include "double.h"++namespace double_conversion {++// The minimal and maximal target exponent define the range of w's binary+// exponent, where 'w' is the result of multiplying the input by a cached power+// of ten.+//+// A different range might be chosen on a different platform, to optimize digit+// generation, but a smaller range requires more powers of ten to be cached.+static const int kMinimalTargetExponent = -60;+static const int kMaximalTargetExponent = -32;+++// Adjusts the last digit of the generated number, and screens out generated+// solutions that may be inaccurate. A solution may be inaccurate if it is+// outside the safe interval, or if we cannot prove that it is closer to the+// input than a neighboring representation of the same length.+//+// Input: * buffer containing the digits of too_high / 10^kappa+// * the buffer's length+// * distance_too_high_w == (too_high - w).f() * unit+// * unsafe_interval == (too_high - too_low).f() * unit+// * rest = (too_high - buffer * 10^kappa).f() * unit+// * ten_kappa = 10^kappa * unit+// * unit = the common multiplier+// Output: returns true if the buffer is guaranteed to contain the closest+// representable number to the input.+// Modifies the generated digits in the buffer to approach (round towards) w.+static bool RoundWeed(Vector<char> buffer,+ int length,+ uint64_t distance_too_high_w,+ uint64_t unsafe_interval,+ uint64_t rest,+ uint64_t ten_kappa,+ uint64_t unit) {+ uint64_t small_distance = distance_too_high_w - unit;+ uint64_t big_distance = distance_too_high_w + unit;+ // Let w_low = too_high - big_distance, and+ // w_high = too_high - small_distance.+ // Note: w_low < w < w_high+ //+ // The real w (* unit) must lie somewhere inside the interval+ // ]w_low; w_high[ (often written as "(w_low; w_high)")++ // Basically the buffer currently contains a number in the unsafe interval+ // ]too_low; too_high[ with too_low < w < too_high+ //+ // too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -+ // ^v 1 unit ^ ^ ^ ^+ // boundary_high --------------------- . . . .+ // ^v 1 unit . . . .+ // - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . .+ // . . ^ . .+ // . big_distance . . .+ // . . . . rest+ // small_distance . . . .+ // v . . . .+ // w_high - - - - - - - - - - - - - - - - - - . . . .+ // ^v 1 unit . . . .+ // w ---------------------------------------- . . . .+ // ^v 1 unit v . . .+ // w_low - - - - - - - - - - - - - - - - - - - - - . . .+ // . . v+ // buffer --------------------------------------------------+-------+--------+ // . .+ // safe_interval .+ // v .+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .+ // ^v 1 unit .+ // boundary_low ------------------------- unsafe_interval+ // ^v 1 unit v+ // too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -+ //+ //+ // Note that the value of buffer could lie anywhere inside the range too_low+ // to too_high.+ //+ // boundary_low, boundary_high and w are approximations of the real boundaries+ // and v (the input number). They are guaranteed to be precise up to one unit.+ // In fact the error is guaranteed to be strictly less than one unit.+ //+ // Anything that lies outside the unsafe interval is guaranteed not to round+ // to v when read again.+ // Anything that lies inside the safe interval is guaranteed to round to v+ // when read again.+ // If the number inside the buffer lies inside the unsafe interval but not+ // inside the safe interval then we simply do not know and bail out (returning+ // false).+ //+ // Similarly we have to take into account the imprecision of 'w' when finding+ // the closest representation of 'w'. If we have two potential+ // representations, and one is closer to both w_low and w_high, then we know+ // it is closer to the actual value v.+ //+ // By generating the digits of too_high we got the largest (closest to+ // too_high) buffer that is still in the unsafe interval. In the case where+ // w_high < buffer < too_high we try to decrement the buffer.+ // This way the buffer approaches (rounds towards) w.+ // There are 3 conditions that stop the decrementation process:+ // 1) the buffer is already below w_high+ // 2) decrementing the buffer would make it leave the unsafe interval+ // 3) decrementing the buffer would yield a number below w_high and farther+ // away than the current number. In other words:+ // (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high+ // Instead of using the buffer directly we use its distance to too_high.+ // Conceptually rest ~= too_high - buffer+ // We need to do the following tests in this order to avoid over- and+ // underflows.+ ASSERT(rest <= unsafe_interval);+ while (rest < small_distance && // Negated condition 1+ unsafe_interval - rest >= ten_kappa && // Negated condition 2+ (rest + ten_kappa < small_distance || // buffer{-1} > w_high+ small_distance - rest >= rest + ten_kappa - small_distance)) {+ buffer[length - 1]--;+ rest += ten_kappa;+ }++ // We have approached w+ as much as possible. We now test if approaching w-+ // would require changing the buffer. If yes, then we have two possible+ // representations close to w, but we cannot decide which one is closer.+ if (rest < big_distance &&+ unsafe_interval - rest >= ten_kappa &&+ (rest + ten_kappa < big_distance ||+ big_distance - rest > rest + ten_kappa - big_distance)) {+ return false;+ }++ // Weeding test.+ // The safe interval is [too_low + 2 ulp; too_high - 2 ulp]+ // Since too_low = too_high - unsafe_interval this is equivalent to+ // [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]+ // Conceptually we have: rest ~= too_high - buffer+ return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit);+}+++// Rounds the buffer upwards if the result is closer to v by possibly adding+// 1 to the buffer. If the precision of the calculation is not sufficient to+// round correctly, return false.+// The rounding might shift the whole buffer in which case the kappa is+// adjusted. For example "99", kappa = 3 might become "10", kappa = 4.+//+// If 2*rest > ten_kappa then the buffer needs to be round up.+// rest can have an error of +/- 1 unit. This function accounts for the+// imprecision and returns false, if the rounding direction cannot be+// unambiguously determined.+//+// Precondition: rest < ten_kappa.+static bool RoundWeedCounted(Vector<char> buffer,+ int length,+ uint64_t rest,+ uint64_t ten_kappa,+ uint64_t unit,+ int* kappa) {+ ASSERT(rest < ten_kappa);+ // The following tests are done in a specific order to avoid overflows. They+ // will work correctly with any uint64 values of rest < ten_kappa and unit.+ //+ // If the unit is too big, then we don't know which way to round. For example+ // a unit of 50 means that the real number lies within rest +/- 50. If+ // 10^kappa == 40 then there is no way to tell which way to round.+ if (unit >= ten_kappa) return false;+ // Even if unit is just half the size of 10^kappa we are already completely+ // lost. (And after the previous test we know that the expression will not+ // over/underflow.)+ if (ten_kappa - unit <= unit) return false;+ // If 2 * (rest + unit) <= 10^kappa we can safely round down.+ if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) {+ return true;+ }+ // If 2 * (rest - unit) >= 10^kappa, then we can safely round up.+ if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) {+ // Increment the last digit recursively until we find a non '9' digit.+ buffer[length - 1]++;+ for (int i = length - 1; i > 0; --i) {+ if (buffer[i] != '0' + 10) break;+ buffer[i] = '0';+ buffer[i - 1]++;+ }+ // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the+ // exception of the first digit all digits are now '0'. Simply switch the+ // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and+ // the power (the kappa) is increased.+ if (buffer[0] == '0' + 10) {+ buffer[0] = '1';+ (*kappa) += 1;+ }+ return true;+ }+ return false;+}+++static const uint32_t kTen4 = 10000;+static const uint32_t kTen5 = 100000;+static const uint32_t kTen6 = 1000000;+static const uint32_t kTen7 = 10000000;+static const uint32_t kTen8 = 100000000;+static const uint32_t kTen9 = 1000000000;++// Returns the biggest power of ten that is less than or equal to the given+// number. We furthermore receive the maximum number of bits 'number' has.+// If number_bits == 0 then 0^-1 is returned+// The number of bits must be <= 32.+// Precondition: number < (1 << (number_bits + 1)).+static void BiggestPowerTen(uint32_t number,+ int number_bits,+ uint32_t* power,+ int* exponent) {+ ASSERT(number < (1 << (number_bits + 1)));++ switch (number_bits) {+ case 32:+ case 31:+ case 30:+ if (kTen9 <= number) {+ *power = kTen9;+ *exponent = 9;+ break;+ } // else fallthrough+ case 29:+ case 28:+ case 27:+ if (kTen8 <= number) {+ *power = kTen8;+ *exponent = 8;+ break;+ } // else fallthrough+ case 26:+ case 25:+ case 24:+ if (kTen7 <= number) {+ *power = kTen7;+ *exponent = 7;+ break;+ } // else fallthrough+ case 23:+ case 22:+ case 21:+ case 20:+ if (kTen6 <= number) {+ *power = kTen6;+ *exponent = 6;+ break;+ } // else fallthrough+ case 19:+ case 18:+ case 17:+ if (kTen5 <= number) {+ *power = kTen5;+ *exponent = 5;+ break;+ } // else fallthrough+ case 16:+ case 15:+ case 14:+ if (kTen4 <= number) {+ *power = kTen4;+ *exponent = 4;+ break;+ } // else fallthrough+ case 13:+ case 12:+ case 11:+ case 10:+ if (1000 <= number) {+ *power = 1000;+ *exponent = 3;+ break;+ } // else fallthrough+ case 9:+ case 8:+ case 7:+ if (100 <= number) {+ *power = 100;+ *exponent = 2;+ break;+ } // else fallthrough+ case 6:+ case 5:+ case 4:+ if (10 <= number) {+ *power = 10;+ *exponent = 1;+ break;+ } // else fallthrough+ case 3:+ case 2:+ case 1:+ if (1 <= number) {+ *power = 1;+ *exponent = 0;+ break;+ } // else fallthrough+ case 0:+ *power = 0;+ *exponent = -1;+ break;+ default:+ // Following assignments are here to silence compiler warnings.+ *power = 0;+ *exponent = 0;+ UNREACHABLE();+ }+}+++// Generates the digits of input number w.+// w is a floating-point number (DiyFp), consisting of a significand and an+// exponent. Its exponent is bounded by kMinimalTargetExponent and+// kMaximalTargetExponent.+// Hence -60 <= w.e() <= -32.+//+// Returns false if it fails, in which case the generated digits in the buffer+// should not be used.+// Preconditions:+// * low, w and high are correct up to 1 ulp (unit in the last place). That+// is, their error must be less than a unit of their last digits.+// * low.e() == w.e() == high.e()+// * low < w < high, and taking into account their error: low~ <= high~+// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent+// Postconditions: returns false if procedure fails.+// otherwise:+// * buffer is not null-terminated, but len contains the number of digits.+// * buffer contains the shortest possible decimal digit-sequence+// such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the+// correct values of low and high (without their error).+// * if more than one decimal representation gives the minimal number of+// decimal digits then the one closest to W (where W is the correct value+// of w) is chosen.+// Remark: this procedure takes into account the imprecision of its input+// numbers. If the precision is not enough to guarantee all the postconditions+// then false is returned. This usually happens rarely (~0.5%).+//+// Say, for the sake of example, that+// w.e() == -48, and w.f() == 0x1234567890abcdef+// w's value can be computed by w.f() * 2^w.e()+// We can obtain w's integral digits by simply shifting w.f() by -w.e().+// -> w's integral part is 0x1234+// w's fractional part is therefore 0x567890abcdef.+// Printing w's integral part is easy (simply print 0x1234 in decimal).+// In order to print its fraction we repeatedly multiply the fraction by 10 and+// get each digit. Example the first digit after the point would be computed by+// (0x567890abcdef * 10) >> 48. -> 3+// The whole thing becomes slightly more complicated because we want to stop+// once we have enough digits. That is, once the digits inside the buffer+// represent 'w' we can stop. Everything inside the interval low - high+// represents w. However we have to pay attention to low, high and w's+// imprecision.+static bool DigitGen(DiyFp low,+ DiyFp w,+ DiyFp high,+ Vector<char> buffer,+ int* length,+ int* kappa) {+ ASSERT(low.e() == w.e() && w.e() == high.e());+ ASSERT(low.f() + 1 <= high.f() - 1);+ ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);+ // low, w and high are imprecise, but by less than one ulp (unit in the last+ // place).+ // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that+ // the new numbers are outside of the interval we want the final+ // representation to lie in.+ // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield+ // numbers that are certain to lie in the interval. We will use this fact+ // later on.+ // We will now start by generating the digits within the uncertain+ // interval. Later we will weed out representations that lie outside the safe+ // interval and thus _might_ lie outside the correct interval.+ uint64_t unit = 1;+ DiyFp too_low = DiyFp(low.f() - unit, low.e());+ DiyFp too_high = DiyFp(high.f() + unit, high.e());+ // too_low and too_high are guaranteed to lie outside the interval we want the+ // generated number in.+ DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low);+ // We now cut the input number into two parts: the integral digits and the+ // fractionals. We will not write any decimal separator though, but adapt+ // kappa instead.+ // Reminder: we are currently computing the digits (stored inside the buffer)+ // such that: too_low < buffer * 10^kappa < too_high+ // We use too_high for the digit_generation and stop as soon as possible.+ // If we stop early we effectively round down.+ DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());+ // Division by one is a shift.+ uint32_t integrals = static_cast<uint32_t>(too_high.f() >> -one.e());+ // Modulo by one is an and.+ uint64_t fractionals = too_high.f() & (one.f() - 1);+ uint32_t divisor;+ int divisor_exponent;+ BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),+ &divisor, &divisor_exponent);+ *kappa = divisor_exponent + 1;+ *length = 0;+ // Loop invariant: buffer = too_high / 10^kappa (integer division)+ // The invariant holds for the first iteration: kappa has been initialized+ // with the divisor exponent + 1. And the divisor is the biggest power of ten+ // that is smaller than integrals.+ while (*kappa > 0) {+ int digit = integrals / divisor;+ buffer[*length] = '0' + digit;+ (*length)++;+ integrals %= divisor;+ (*kappa)--;+ // Note that kappa now equals the exponent of the divisor and that the+ // invariant thus holds again.+ uint64_t rest =+ (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;+ // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())+ // Reminder: unsafe_interval.e() == one.e()+ if (rest < unsafe_interval.f()) {+ // Rounding down (by not emitting the remaining digits) yields a number+ // that lies within the unsafe interval.+ return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(),+ unsafe_interval.f(), rest,+ static_cast<uint64_t>(divisor) << -one.e(), unit);+ }+ divisor /= 10;+ }++ // The integrals have been generated. We are at the point of the decimal+ // separator. In the following loop we simply multiply the remaining digits by+ // 10 and divide by one. We just need to pay attention to multiply associated+ // data (like the interval or 'unit'), too.+ // Note that the multiplication by 10 does not overflow, because w.e >= -60+ // and thus one.e >= -60.+ ASSERT(one.e() >= -60);+ ASSERT(fractionals < one.f());+ ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());+ while (true) {+ fractionals *= 10;+ unit *= 10;+ unsafe_interval.set_f(unsafe_interval.f() * 10);+ // Integer division by one.+ int digit = static_cast<int>(fractionals >> -one.e());+ buffer[*length] = '0' + digit;+ (*length)++;+ fractionals &= one.f() - 1; // Modulo by one.+ (*kappa)--;+ if (fractionals < unsafe_interval.f()) {+ return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit,+ unsafe_interval.f(), fractionals, one.f(), unit);+ }+ }+}++++// Generates (at most) requested_digits digits of input number w.+// w is a floating-point number (DiyFp), consisting of a significand and an+// exponent. Its exponent is bounded by kMinimalTargetExponent and+// kMaximalTargetExponent.+// Hence -60 <= w.e() <= -32.+//+// Returns false if it fails, in which case the generated digits in the buffer+// should not be used.+// Preconditions:+// * w is correct up to 1 ulp (unit in the last place). That+// is, its error must be strictly less than a unit of its last digit.+// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent+//+// Postconditions: returns false if procedure fails.+// otherwise:+// * buffer is not null-terminated, but length contains the number of+// digits.+// * the representation in buffer is the most precise representation of+// requested_digits digits.+// * buffer contains at most requested_digits digits of w. If there are less+// than requested_digits digits then some trailing '0's have been removed.+// * kappa is such that+// w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.+//+// Remark: This procedure takes into account the imprecision of its input+// numbers. If the precision is not enough to guarantee all the postconditions+// then false is returned. This usually happens rarely, but the failure-rate+// increases with higher requested_digits.+static bool DigitGenCounted(DiyFp w,+ int requested_digits,+ Vector<char> buffer,+ int* length,+ int* kappa) {+ ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);+ ASSERT(kMinimalTargetExponent >= -60);+ ASSERT(kMaximalTargetExponent <= -32);+ // w is assumed to have an error less than 1 unit. Whenever w is scaled we+ // also scale its error.+ uint64_t w_error = 1;+ // We cut the input number into two parts: the integral digits and the+ // fractional digits. We don't emit any decimal separator, but adapt kappa+ // instead. Example: instead of writing "1.2" we put "12" into the buffer and+ // increase kappa by 1.+ DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());+ // Division by one is a shift.+ uint32_t integrals = static_cast<uint32_t>(w.f() >> -one.e());+ // Modulo by one is an and.+ uint64_t fractionals = w.f() & (one.f() - 1);+ uint32_t divisor;+ int divisor_exponent;+ BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),+ &divisor, &divisor_exponent);+ *kappa = divisor_exponent + 1;+ *length = 0;++ // Loop invariant: buffer = w / 10^kappa (integer division)+ // The invariant holds for the first iteration: kappa has been initialized+ // with the divisor exponent + 1. And the divisor is the biggest power of ten+ // that is smaller than 'integrals'.+ while (*kappa > 0) {+ int digit = integrals / divisor;+ buffer[*length] = '0' + digit;+ (*length)++;+ requested_digits--;+ integrals %= divisor;+ (*kappa)--;+ // Note that kappa now equals the exponent of the divisor and that the+ // invariant thus holds again.+ if (requested_digits == 0) break;+ divisor /= 10;+ }++ if (requested_digits == 0) {+ uint64_t rest =+ (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;+ return RoundWeedCounted(buffer, *length, rest,+ static_cast<uint64_t>(divisor) << -one.e(), w_error,+ kappa);+ }++ // The integrals have been generated. We are at the point of the decimal+ // separator. In the following loop we simply multiply the remaining digits by+ // 10 and divide by one. We just need to pay attention to multiply associated+ // data (the 'unit'), too.+ // Note that the multiplication by 10 does not overflow, because w.e >= -60+ // and thus one.e >= -60.+ ASSERT(one.e() >= -60);+ ASSERT(fractionals < one.f());+ ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());+ while (requested_digits > 0 && fractionals > w_error) {+ fractionals *= 10;+ w_error *= 10;+ // Integer division by one.+ int digit = static_cast<int>(fractionals >> -one.e());+ buffer[*length] = '0' + digit;+ (*length)++;+ requested_digits--;+ fractionals &= one.f() - 1; // Modulo by one.+ (*kappa)--;+ }+ if (requested_digits != 0) return false;+ return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error,+ kappa);+}+++// Provides a decimal representation of v.+// Returns true if it succeeds, otherwise the result cannot be trusted.+// There will be *length digits inside the buffer (not null-terminated).+// If the function returns true then+// v == (double) (buffer * 10^decimal_exponent).+// The digits in the buffer are the shortest representation possible: no+// 0.09999999999999999 instead of 0.1. The shorter representation will even be+// chosen even if the longer one would be closer to v.+// The last digit will be closest to the actual v. That is, even if several+// digits might correctly yield 'v' when read again, the closest will be+// computed.+static bool Grisu3(double v,+ Vector<char> buffer,+ int* length,+ int* decimal_exponent) {+ DiyFp w = Double(v).AsNormalizedDiyFp();+ // boundary_minus and boundary_plus are the boundaries between v and its+ // closest floating-point neighbors. Any number strictly between+ // boundary_minus and boundary_plus will round to v when convert to a double.+ // Grisu3 will never output representations that lie exactly on a boundary.+ DiyFp boundary_minus, boundary_plus;+ Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);+ ASSERT(boundary_plus.e() == w.e());+ DiyFp ten_mk; // Cached power of ten: 10^-k+ int mk; // -k+ int ten_mk_minimal_binary_exponent =+ kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);+ int ten_mk_maximal_binary_exponent =+ kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);+ PowersOfTenCache::GetCachedPowerForBinaryExponentRange(+ ten_mk_minimal_binary_exponent,+ ten_mk_maximal_binary_exponent,+ &ten_mk, &mk);+ ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() ++ DiyFp::kSignificandSize) &&+ (kMaximalTargetExponent >= w.e() + ten_mk.e() ++ DiyFp::kSignificandSize));+ // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a+ // 64 bit significand and ten_mk is thus only precise up to 64 bits.++ // The DiyFp::Times procedure rounds its result, and ten_mk is approximated+ // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now+ // off by a small amount.+ // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.+ // In other words: let f = scaled_w.f() and e = scaled_w.e(), then+ // (f-1) * 2^e < w*10^k < (f+1) * 2^e+ DiyFp scaled_w = DiyFp::Times(w, ten_mk);+ ASSERT(scaled_w.e() ==+ boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize);+ // In theory it would be possible to avoid some recomputations by computing+ // the difference between w and boundary_minus/plus (a power of 2) and to+ // compute scaled_boundary_minus/plus by subtracting/adding from+ // scaled_w. However the code becomes much less readable and the speed+ // enhancements are not terriffic.+ DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk);+ DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk);++ // DigitGen will generate the digits of scaled_w. Therefore we have+ // v == (double) (scaled_w * 10^-mk).+ // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an+ // integer than it will be updated. For instance if scaled_w == 1.23 then+ // the buffer will be filled with "123" und the decimal_exponent will be+ // decreased by 2.+ int kappa;+ bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,+ buffer, length, &kappa);+ *decimal_exponent = -mk + kappa;+ return result;+}+++// The "counted" version of grisu3 (see above) only generates requested_digits+// number of digits. This version does not generate the shortest representation,+// and with enough requested digits 0.1 will at some point print as 0.9999999...+// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and+// therefore the rounding strategy for halfway cases is irrelevant.+static bool Grisu3Counted(double v,+ int requested_digits,+ Vector<char> buffer,+ int* length,+ int* decimal_exponent) {+ DiyFp w = Double(v).AsNormalizedDiyFp();+ DiyFp ten_mk; // Cached power of ten: 10^-k+ int mk; // -k+ int ten_mk_minimal_binary_exponent =+ kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);+ int ten_mk_maximal_binary_exponent =+ kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);+ PowersOfTenCache::GetCachedPowerForBinaryExponentRange(+ ten_mk_minimal_binary_exponent,+ ten_mk_maximal_binary_exponent,+ &ten_mk, &mk);+ ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() ++ DiyFp::kSignificandSize) &&+ (kMaximalTargetExponent >= w.e() + ten_mk.e() ++ DiyFp::kSignificandSize));+ // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a+ // 64 bit significand and ten_mk is thus only precise up to 64 bits.++ // The DiyFp::Times procedure rounds its result, and ten_mk is approximated+ // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now+ // off by a small amount.+ // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.+ // In other words: let f = scaled_w.f() and e = scaled_w.e(), then+ // (f-1) * 2^e < w*10^k < (f+1) * 2^e+ DiyFp scaled_w = DiyFp::Times(w, ten_mk);++ // We now have (double) (scaled_w * 10^-mk).+ // DigitGen will generate the first requested_digits digits of scaled_w and+ // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It+ // will not always be exactly the same since DigitGenCounted only produces a+ // limited number of digits.)+ int kappa;+ bool result = DigitGenCounted(scaled_w, requested_digits,+ buffer, length, &kappa);+ *decimal_exponent = -mk + kappa;+ return result;+}+++bool FastDtoa(double v,+ FastDtoaMode mode,+ int requested_digits,+ Vector<char> buffer,+ int* length,+ int* decimal_point) {+ ASSERT(v > 0);+ ASSERT(!Double(v).IsSpecial());++ bool result = false;+ int decimal_exponent = 0;+ switch (mode) {+ case FAST_DTOA_SHORTEST:+ result = Grisu3(v, buffer, length, &decimal_exponent);+ break;+ case FAST_DTOA_PRECISION:+ result = Grisu3Counted(v, requested_digits,+ buffer, length, &decimal_exponent);+ break;+ default:+ UNREACHABLE();+ }+ if (result) {+ *decimal_point = *length + decimal_exponent;+ buffer[*length] = '\0';+ }+ return result;+}++} // namespace double_conversion
+ double-conversion/src/fast-dtoa.h view
@@ -0,0 +1,84 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_FAST_DTOA_H_+#define DOUBLE_CONVERSION_FAST_DTOA_H_++#include "utils.h"++namespace double_conversion {++enum FastDtoaMode {+ // Computes the shortest representation of the given input. The returned+ // result will be the most accurate number of this length. Longer+ // representations might be more accurate.+ FAST_DTOA_SHORTEST,+ // Computes a representation where the precision (number of digits) is+ // given as input. The precision is independent of the decimal point.+ FAST_DTOA_PRECISION+};++// FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not+// include the terminating '\0' character.+static const int kFastDtoaMaximalLength = 17;++// Provides a decimal representation of v.+// The result should be interpreted as buffer * 10^(point - length).+//+// Precondition:+// * v must be a strictly positive finite double.+//+// Returns true if it succeeds, otherwise the result can not be trusted.+// There will be *length digits inside the buffer followed by a null terminator.+// If the function returns true and mode equals+// - FAST_DTOA_SHORTEST, then+// the parameter requested_digits is ignored.+// The result satisfies+// v == (double) (buffer * 10^(point - length)).+// The digits in the buffer are the shortest representation possible. E.g.+// if 0.099999999999 and 0.1 represent the same double then "1" is returned+// with point = 0.+// The last digit will be closest to the actual v. That is, even if several+// digits might correctly yield 'v' when read again, the buffer will contain+// the one closest to v.+// - FAST_DTOA_PRECISION, then+// the buffer contains requested_digits digits.+// the difference v - (buffer * 10^(point-length)) is closest to zero for+// all possible representations of requested_digits digits.+// If there are two values that are equally close, then FastDtoa returns+// false.+// For both modes the buffer must be large enough to hold the result.+bool FastDtoa(double d,+ FastDtoaMode mode,+ int requested_digits,+ Vector<char> buffer,+ int* length,+ int* decimal_point);++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_FAST_DTOA_H_
+ double-conversion/src/fixed-dtoa.cc view
@@ -0,0 +1,402 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <math.h>++#include "fixed-dtoa.h"+#include "double.h"++namespace double_conversion {++// Represents a 128bit type. This class should be replaced by a native type on+// platforms that support 128bit integers.+class UInt128 {+ public:+ UInt128() : high_bits_(0), low_bits_(0) { }+ UInt128(uint64_t high, uint64_t low) : high_bits_(high), low_bits_(low) { }++ void Multiply(uint32_t multiplicand) {+ uint64_t accumulator;++ accumulator = (low_bits_ & kMask32) * multiplicand;+ uint32_t part = static_cast<uint32_t>(accumulator & kMask32);+ accumulator >>= 32;+ accumulator = accumulator + (low_bits_ >> 32) * multiplicand;+ low_bits_ = (accumulator << 32) + part;+ accumulator >>= 32;+ accumulator = accumulator + (high_bits_ & kMask32) * multiplicand;+ part = static_cast<uint32_t>(accumulator & kMask32);+ accumulator >>= 32;+ accumulator = accumulator + (high_bits_ >> 32) * multiplicand;+ high_bits_ = (accumulator << 32) + part;+ ASSERT((accumulator >> 32) == 0);+ }++ void Shift(int shift_amount) {+ ASSERT(-64 <= shift_amount && shift_amount <= 64);+ if (shift_amount == 0) {+ return;+ } else if (shift_amount == -64) {+ high_bits_ = low_bits_;+ low_bits_ = 0;+ } else if (shift_amount == 64) {+ low_bits_ = high_bits_;+ high_bits_ = 0;+ } else if (shift_amount <= 0) {+ high_bits_ <<= -shift_amount;+ high_bits_ += low_bits_ >> (64 + shift_amount);+ low_bits_ <<= -shift_amount;+ } else {+ low_bits_ >>= shift_amount;+ low_bits_ += high_bits_ << (64 - shift_amount);+ high_bits_ >>= shift_amount;+ }+ }++ // Modifies *this to *this MOD (2^power).+ // Returns *this DIV (2^power).+ int DivModPowerOf2(int power) {+ if (power >= 64) {+ int result = static_cast<int>(high_bits_ >> (power - 64));+ high_bits_ -= static_cast<uint64_t>(result) << (power - 64);+ return result;+ } else {+ uint64_t part_low = low_bits_ >> power;+ uint64_t part_high = high_bits_ << (64 - power);+ int result = static_cast<int>(part_low + part_high);+ high_bits_ = 0;+ low_bits_ -= part_low << power;+ return result;+ }+ }++ bool IsZero() const {+ return high_bits_ == 0 && low_bits_ == 0;+ }++ int BitAt(int position) {+ if (position >= 64) {+ return static_cast<int>(high_bits_ >> (position - 64)) & 1;+ } else {+ return static_cast<int>(low_bits_ >> position) & 1;+ }+ }++ private:+ static const uint64_t kMask32 = 0xFFFFFFFF;+ // Value == (high_bits_ << 64) + low_bits_+ uint64_t high_bits_;+ uint64_t low_bits_;+};+++static const int kDoubleSignificandSize = 53; // Includes the hidden bit.+++static void FillDigits32FixedLength(uint32_t number, int requested_length,+ Vector<char> buffer, int* length) {+ for (int i = requested_length - 1; i >= 0; --i) {+ buffer[(*length) + i] = '0' + number % 10;+ number /= 10;+ }+ *length += requested_length;+}+++static void FillDigits32(uint32_t number, Vector<char> buffer, int* length) {+ int number_length = 0;+ // We fill the digits in reverse order and exchange them afterwards.+ while (number != 0) {+ int digit = number % 10;+ number /= 10;+ buffer[(*length) + number_length] = '0' + digit;+ number_length++;+ }+ // Exchange the digits.+ int i = *length;+ int j = *length + number_length - 1;+ while (i < j) {+ char tmp = buffer[i];+ buffer[i] = buffer[j];+ buffer[j] = tmp;+ i++;+ j--;+ }+ *length += number_length;+}+++static void FillDigits64FixedLength(uint64_t number, int requested_length,+ Vector<char> buffer, int* length) {+ const uint32_t kTen7 = 10000000;+ // For efficiency cut the number into 3 uint32_t parts, and print those.+ uint32_t part2 = static_cast<uint32_t>(number % kTen7);+ number /= kTen7;+ uint32_t part1 = static_cast<uint32_t>(number % kTen7);+ uint32_t part0 = static_cast<uint32_t>(number / kTen7);++ FillDigits32FixedLength(part0, 3, buffer, length);+ FillDigits32FixedLength(part1, 7, buffer, length);+ FillDigits32FixedLength(part2, 7, buffer, length);+}+++static void FillDigits64(uint64_t number, Vector<char> buffer, int* length) {+ const uint32_t kTen7 = 10000000;+ // For efficiency cut the number into 3 uint32_t parts, and print those.+ uint32_t part2 = static_cast<uint32_t>(number % kTen7);+ number /= kTen7;+ uint32_t part1 = static_cast<uint32_t>(number % kTen7);+ uint32_t part0 = static_cast<uint32_t>(number / kTen7);++ if (part0 != 0) {+ FillDigits32(part0, buffer, length);+ FillDigits32FixedLength(part1, 7, buffer, length);+ FillDigits32FixedLength(part2, 7, buffer, length);+ } else if (part1 != 0) {+ FillDigits32(part1, buffer, length);+ FillDigits32FixedLength(part2, 7, buffer, length);+ } else {+ FillDigits32(part2, buffer, length);+ }+}+++static void RoundUp(Vector<char> buffer, int* length, int* decimal_point) {+ // An empty buffer represents 0.+ if (*length == 0) {+ buffer[0] = '1';+ *decimal_point = 1;+ *length = 1;+ return;+ }+ // Round the last digit until we either have a digit that was not '9' or until+ // we reached the first digit.+ buffer[(*length) - 1]++;+ for (int i = (*length) - 1; i > 0; --i) {+ if (buffer[i] != '0' + 10) {+ return;+ }+ buffer[i] = '0';+ buffer[i - 1]++;+ }+ // If the first digit is now '0' + 10, we would need to set it to '0' and add+ // a '1' in front. However we reach the first digit only if all following+ // digits had been '9' before rounding up. Now all trailing digits are '0' and+ // we simply switch the first digit to '1' and update the decimal-point+ // (indicating that the point is now one digit to the right).+ if (buffer[0] == '0' + 10) {+ buffer[0] = '1';+ (*decimal_point)++;+ }+}+++// The given fractionals number represents a fixed-point number with binary+// point at bit (-exponent).+// Preconditions:+// -128 <= exponent <= 0.+// 0 <= fractionals * 2^exponent < 1+// The buffer holds the result.+// The function will round its result. During the rounding-process digits not+// generated by this function might be updated, and the decimal-point variable+// might be updated. If this function generates the digits 99 and the buffer+// already contained "199" (thus yielding a buffer of "19999") then a+// rounding-up will change the contents of the buffer to "20000".+static void FillFractionals(uint64_t fractionals, int exponent,+ int fractional_count, Vector<char> buffer,+ int* length, int* decimal_point) {+ ASSERT(-128 <= exponent && exponent <= 0);+ // 'fractionals' is a fixed-point number, with binary point at bit+ // (-exponent). Inside the function the non-converted remainder of fractionals+ // is a fixed-point number, with binary point at bit 'point'.+ if (-exponent <= 64) {+ // One 64 bit number is sufficient.+ ASSERT(fractionals >> 56 == 0);+ int point = -exponent;+ for (int i = 0; i < fractional_count; ++i) {+ if (fractionals == 0) break;+ // Instead of multiplying by 10 we multiply by 5 and adjust the point+ // location. This way the fractionals variable will not overflow.+ // Invariant at the beginning of the loop: fractionals < 2^point.+ // Initially we have: point <= 64 and fractionals < 2^56+ // After each iteration the point is decremented by one.+ // Note that 5^3 = 125 < 128 = 2^7.+ // Therefore three iterations of this loop will not overflow fractionals+ // (even without the subtraction at the end of the loop body). At this+ // time point will satisfy point <= 61 and therefore fractionals < 2^point+ // and any further multiplication of fractionals by 5 will not overflow.+ fractionals *= 5;+ point--;+ int digit = static_cast<int>(fractionals >> point);+ buffer[*length] = '0' + digit;+ (*length)++;+ fractionals -= static_cast<uint64_t>(digit) << point;+ }+ // If the first bit after the point is set we have to round up.+ if (((fractionals >> (point - 1)) & 1) == 1) {+ RoundUp(buffer, length, decimal_point);+ }+ } else { // We need 128 bits.+ ASSERT(64 < -exponent && -exponent <= 128);+ UInt128 fractionals128 = UInt128(fractionals, 0);+ fractionals128.Shift(-exponent - 64);+ int point = 128;+ for (int i = 0; i < fractional_count; ++i) {+ if (fractionals128.IsZero()) break;+ // As before: instead of multiplying by 10 we multiply by 5 and adjust the+ // point location.+ // This multiplication will not overflow for the same reasons as before.+ fractionals128.Multiply(5);+ point--;+ int digit = fractionals128.DivModPowerOf2(point);+ buffer[*length] = '0' + digit;+ (*length)++;+ }+ if (fractionals128.BitAt(point - 1) == 1) {+ RoundUp(buffer, length, decimal_point);+ }+ }+}+++// Removes leading and trailing zeros.+// If leading zeros are removed then the decimal point position is adjusted.+static void TrimZeros(Vector<char> buffer, int* length, int* decimal_point) {+ while (*length > 0 && buffer[(*length) - 1] == '0') {+ (*length)--;+ }+ int first_non_zero = 0;+ while (first_non_zero < *length && buffer[first_non_zero] == '0') {+ first_non_zero++;+ }+ if (first_non_zero != 0) {+ for (int i = first_non_zero; i < *length; ++i) {+ buffer[i - first_non_zero] = buffer[i];+ }+ *length -= first_non_zero;+ *decimal_point -= first_non_zero;+ }+}+++bool FastFixedDtoa(double v,+ int fractional_count,+ Vector<char> buffer,+ int* length,+ int* decimal_point) {+ const uint32_t kMaxUInt32 = 0xFFFFFFFF;+ uint64_t significand = Double(v).Significand();+ int exponent = Double(v).Exponent();+ // v = significand * 2^exponent (with significand a 53bit integer).+ // If the exponent is larger than 20 (i.e. we may have a 73bit number) then we+ // don't know how to compute the representation. 2^73 ~= 9.5*10^21.+ // If necessary this limit could probably be increased, but we don't need+ // more.+ if (exponent > 20) return false;+ if (fractional_count > 20) return false;+ *length = 0;+ // At most kDoubleSignificandSize bits of the significand are non-zero.+ // Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero+ // bits: 0..11*..0xxx..53*..xx+ if (exponent + kDoubleSignificandSize > 64) {+ // The exponent must be > 11.+ //+ // We know that v = significand * 2^exponent.+ // And the exponent > 11.+ // We simplify the task by dividing v by 10^17.+ // The quotient delivers the first digits, and the remainder fits into a 64+ // bit number.+ // Dividing by 10^17 is equivalent to dividing by 5^17*2^17.+ const uint64_t kFive17 = UINT64_2PART_C(0xB1, A2BC2EC5); // 5^17+ uint64_t divisor = kFive17;+ int divisor_power = 17;+ uint64_t dividend = significand;+ uint32_t quotient;+ uint64_t remainder;+ // Let v = f * 2^e with f == significand and e == exponent.+ // Then need q (quotient) and r (remainder) as follows:+ // v = q * 10^17 + r+ // f * 2^e = q * 10^17 + r+ // f * 2^e = q * 5^17 * 2^17 + r+ // If e > 17 then+ // f * 2^(e-17) = q * 5^17 + r/2^17+ // else+ // f = q * 5^17 * 2^(17-e) + r/2^e+ if (exponent > divisor_power) {+ // We only allow exponents of up to 20 and therefore (17 - e) <= 3+ dividend <<= exponent - divisor_power;+ quotient = static_cast<uint32_t>(dividend / divisor);+ remainder = (dividend % divisor) << divisor_power;+ } else {+ divisor <<= divisor_power - exponent;+ quotient = static_cast<uint32_t>(dividend / divisor);+ remainder = (dividend % divisor) << exponent;+ }+ FillDigits32(quotient, buffer, length);+ FillDigits64FixedLength(remainder, divisor_power, buffer, length);+ *decimal_point = *length;+ } else if (exponent >= 0) {+ // 0 <= exponent <= 11+ significand <<= exponent;+ FillDigits64(significand, buffer, length);+ *decimal_point = *length;+ } else if (exponent > -kDoubleSignificandSize) {+ // We have to cut the number.+ uint64_t integrals = significand >> -exponent;+ uint64_t fractionals = significand - (integrals << -exponent);+ if (integrals > kMaxUInt32) {+ FillDigits64(integrals, buffer, length);+ } else {+ FillDigits32(static_cast<uint32_t>(integrals), buffer, length);+ }+ *decimal_point = *length;+ FillFractionals(fractionals, exponent, fractional_count,+ buffer, length, decimal_point);+ } else if (exponent < -128) {+ // This configuration (with at most 20 digits) means that all digits must be+ // 0.+ ASSERT(fractional_count <= 20);+ buffer[0] = '\0';+ *length = 0;+ *decimal_point = -fractional_count;+ } else {+ *decimal_point = 0;+ FillFractionals(significand, exponent, fractional_count,+ buffer, length, decimal_point);+ }+ TrimZeros(buffer, length, decimal_point);+ buffer[*length] = '\0';+ if ((*length) == 0) {+ // The string is empty and the decimal_point thus has no importance. Mimick+ // Gay's dtoa and and set it to -fractional_count.+ *decimal_point = -fractional_count;+ }+ return true;+}++} // namespace double_conversion
+ double-conversion/src/fixed-dtoa.h view
@@ -0,0 +1,56 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_FIXED_DTOA_H_+#define DOUBLE_CONVERSION_FIXED_DTOA_H_++#include "utils.h"++namespace double_conversion {++// Produces digits necessary to print a given number with+// 'fractional_count' digits after the decimal point.+// The buffer must be big enough to hold the result plus one terminating null+// character.+//+// The produced digits might be too short in which case the caller has to fill+// the gaps with '0's.+// Example: FastFixedDtoa(0.001, 5, ...) is allowed to return buffer = "1", and+// decimal_point = -2.+// Halfway cases are rounded towards +/-Infinity (away from 0). The call+// FastFixedDtoa(0.15, 2, ...) thus returns buffer = "2", decimal_point = 0.+// The returned buffer may contain digits that would be truncated from the+// shortest representation of the input.+//+// This method only works for some parameters. If it can't handle the input it+// returns false. The output is null-terminated when the function succeeds.+bool FastFixedDtoa(double v, int fractional_count,+ Vector<char> buffer, int* length, int* decimal_point);++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_FIXED_DTOA_H_
+ double-conversion/src/strtod.cc view
@@ -0,0 +1,441 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <stdarg.h>+#include <limits.h>++#include "strtod.h"+#include "bignum.h"+#include "cached-powers.h"+#include "double.h"++namespace double_conversion {++// 2^53 = 9007199254740992.+// Any integer with at most 15 decimal digits will hence fit into a double+// (which has a 53bit significand) without loss of precision.+static const int kMaxExactDoubleIntegerDecimalDigits = 15;+// 2^64 = 18446744073709551616 > 10^19+static const int kMaxUint64DecimalDigits = 19;++// Max double: 1.7976931348623157 x 10^308+// Min non-zero double: 4.9406564584124654 x 10^-324+// Any x >= 10^309 is interpreted as +infinity.+// Any x <= 10^-324 is interpreted as 0.+// Note that 2.5e-324 (despite being smaller than the min double) will be read+// as non-zero (equal to the min non-zero double).+static const int kMaxDecimalPower = 309;+static const int kMinDecimalPower = -324;++// 2^64 = 18446744073709551616+static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF);+++static const double exact_powers_of_ten[] = {+ 1.0, // 10^0+ 10.0,+ 100.0,+ 1000.0,+ 10000.0,+ 100000.0,+ 1000000.0,+ 10000000.0,+ 100000000.0,+ 1000000000.0,+ 10000000000.0, // 10^10+ 100000000000.0,+ 1000000000000.0,+ 10000000000000.0,+ 100000000000000.0,+ 1000000000000000.0,+ 10000000000000000.0,+ 100000000000000000.0,+ 1000000000000000000.0,+ 10000000000000000000.0,+ 100000000000000000000.0, // 10^20+ 1000000000000000000000.0,+ // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22+ 10000000000000000000000.0+};+static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);++// Maximum number of significant digits in the decimal representation.+// In fact the value is 772 (see conversions.cc), but to give us some margin+// we round up to 780.+static const int kMaxSignificantDecimalDigits = 780;++static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {+ for (int i = 0; i < buffer.length(); i++) {+ if (buffer[i] != '0') {+ return buffer.SubVector(i, buffer.length());+ }+ }+ return Vector<const char>(buffer.start(), 0);+}+++static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {+ for (int i = buffer.length() - 1; i >= 0; --i) {+ if (buffer[i] != '0') {+ return buffer.SubVector(0, i + 1);+ }+ }+ return Vector<const char>(buffer.start(), 0);+}+++static void TrimToMaxSignificantDigits(Vector<const char> buffer,+ int exponent,+ char* significant_buffer,+ int* significant_exponent) {+ for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {+ significant_buffer[i] = buffer[i];+ }+ // The input buffer has been trimmed. Therefore the last digit must be+ // different from '0'.+ ASSERT(buffer[buffer.length() - 1] != '0');+ // Set the last digit to be non-zero. This is sufficient to guarantee+ // correct rounding.+ significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';+ *significant_exponent =+ exponent + (buffer.length() - kMaxSignificantDecimalDigits);+}++// Reads digits from the buffer and converts them to a uint64.+// Reads in as many digits as fit into a uint64.+// When the string starts with "1844674407370955161" no further digit is read.+// Since 2^64 = 18446744073709551616 it would still be possible read another+// digit if it was less or equal than 6, but this would complicate the code.+static uint64_t ReadUint64(Vector<const char> buffer,+ int* number_of_read_digits) {+ uint64_t result = 0;+ int i = 0;+ while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) {+ int digit = buffer[i++] - '0';+ ASSERT(0 <= digit && digit <= 9);+ result = 10 * result + digit;+ }+ *number_of_read_digits = i;+ return result;+}+++// Reads a DiyFp from the buffer.+// The returned DiyFp is not necessarily normalized.+// If remaining_decimals is zero then the returned DiyFp is accurate.+// Otherwise it has been rounded and has error of at most 1/2 ulp.+static void ReadDiyFp(Vector<const char> buffer,+ DiyFp* result,+ int* remaining_decimals) {+ int read_digits;+ uint64_t significand = ReadUint64(buffer, &read_digits);+ if (buffer.length() == read_digits) {+ *result = DiyFp(significand, 0);+ *remaining_decimals = 0;+ } else {+ // Round the significand.+ if (buffer[read_digits] >= '5') {+ significand++;+ }+ // Compute the binary exponent.+ int exponent = 0;+ *result = DiyFp(significand, exponent);+ *remaining_decimals = buffer.length() - read_digits;+ }+}+++static bool DoubleStrtod(Vector<const char> trimmed,+ int exponent,+ double* result) {+#if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)+ // On x86 the floating-point stack can be 64 or 80 bits wide. If it is+ // 80 bits wide (as is the case on Linux) then double-rounding occurs and the+ // result is not accurate.+ // We know that Windows32 uses 64 bits and is therefore accurate.+ // Note that the ARM simulator is compiled for 32bits. It therefore exhibits+ // the same problem.+ return false;+#endif+ if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {+ int read_digits;+ // The trimmed input fits into a double.+ // If the 10^exponent (resp. 10^-exponent) fits into a double too then we+ // can compute the result-double simply by multiplying (resp. dividing) the+ // two numbers.+ // This is possible because IEEE guarantees that floating-point operations+ // return the best possible approximation.+ if (exponent < 0 && -exponent < kExactPowersOfTenSize) {+ // 10^-exponent fits into a double.+ *result = static_cast<double>(ReadUint64(trimmed, &read_digits));+ ASSERT(read_digits == trimmed.length());+ *result /= exact_powers_of_ten[-exponent];+ return true;+ }+ if (0 <= exponent && exponent < kExactPowersOfTenSize) {+ // 10^exponent fits into a double.+ *result = static_cast<double>(ReadUint64(trimmed, &read_digits));+ ASSERT(read_digits == trimmed.length());+ *result *= exact_powers_of_ten[exponent];+ return true;+ }+ int remaining_digits =+ kMaxExactDoubleIntegerDecimalDigits - trimmed.length();+ if ((0 <= exponent) &&+ (exponent - remaining_digits < kExactPowersOfTenSize)) {+ // The trimmed string was short and we can multiply it with+ // 10^remaining_digits. As a result the remaining exponent now fits+ // into a double too.+ *result = static_cast<double>(ReadUint64(trimmed, &read_digits));+ ASSERT(read_digits == trimmed.length());+ *result *= exact_powers_of_ten[remaining_digits];+ *result *= exact_powers_of_ten[exponent - remaining_digits];+ return true;+ }+ }+ return false;+}+++// Returns 10^exponent as an exact DiyFp.+// The given exponent must be in the range [1; kDecimalExponentDistance[.+static DiyFp AdjustmentPowerOfTen(int exponent) {+ ASSERT(0 < exponent);+ ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance);+ // Simply hardcode the remaining powers for the given decimal exponent+ // distance.+ ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8);+ switch (exponent) {+ case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60);+ case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57);+ case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54);+ case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50);+ case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47);+ case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44);+ case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40);+ default:+ UNREACHABLE();+ return DiyFp(0, 0);+ }+}+++// If the function returns true then the result is the correct double.+// Otherwise it is either the correct double or the double that is just below+// the correct double.+static bool DiyFpStrtod(Vector<const char> buffer,+ int exponent,+ double* result) {+ DiyFp input;+ int remaining_decimals;+ ReadDiyFp(buffer, &input, &remaining_decimals);+ // Since we may have dropped some digits the input is not accurate.+ // If remaining_decimals is different than 0 than the error is at most+ // .5 ulp (unit in the last place).+ // We don't want to deal with fractions and therefore keep a common+ // denominator.+ const int kDenominatorLog = 3;+ const int kDenominator = 1 << kDenominatorLog;+ // Move the remaining decimals into the exponent.+ exponent += remaining_decimals;+ int error = (remaining_decimals == 0 ? 0 : kDenominator / 2);++ int old_e = input.e();+ input.Normalize();+ error <<= old_e - input.e();++ ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent);+ if (exponent < PowersOfTenCache::kMinDecimalExponent) {+ *result = 0.0;+ return true;+ }+ DiyFp cached_power;+ int cached_decimal_exponent;+ PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent,+ &cached_power,+ &cached_decimal_exponent);++ if (cached_decimal_exponent != exponent) {+ int adjustment_exponent = exponent - cached_decimal_exponent;+ DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent);+ input.Multiply(adjustment_power);+ if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) {+ // The product of input with the adjustment power fits into a 64 bit+ // integer.+ ASSERT(DiyFp::kSignificandSize == 64);+ } else {+ // The adjustment power is exact. There is hence only an error of 0.5.+ error += kDenominator / 2;+ }+ }++ input.Multiply(cached_power);+ // The error introduced by a multiplication of a*b equals+ // error_a + error_b + error_a*error_b/2^64 + 0.5+ // Substituting a with 'input' and b with 'cached_power' we have+ // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp),+ // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64+ int error_b = kDenominator / 2;+ int error_ab = (error == 0 ? 0 : 1); // We round up to 1.+ int fixed_error = kDenominator / 2;+ error += error_b + error_ab + fixed_error;++ old_e = input.e();+ input.Normalize();+ error <<= old_e - input.e();++ // See if the double's significand changes if we add/subtract the error.+ int order_of_magnitude = DiyFp::kSignificandSize + input.e();+ int effective_significand_size =+ Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude);+ int precision_digits_count =+ DiyFp::kSignificandSize - effective_significand_size;+ if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) {+ // This can only happen for very small denormals. In this case the+ // half-way multiplied by the denominator exceeds the range of an uint64.+ // Simply shift everything to the right.+ int shift_amount = (precision_digits_count + kDenominatorLog) -+ DiyFp::kSignificandSize + 1;+ input.set_f(input.f() >> shift_amount);+ input.set_e(input.e() + shift_amount);+ // We add 1 for the lost precision of error, and kDenominator for+ // the lost precision of input.f().+ error = (error >> shift_amount) + 1 + kDenominator;+ precision_digits_count -= shift_amount;+ }+ // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too.+ ASSERT(DiyFp::kSignificandSize == 64);+ ASSERT(precision_digits_count < 64);+ uint64_t one64 = 1;+ uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1;+ uint64_t precision_bits = input.f() & precision_bits_mask;+ uint64_t half_way = one64 << (precision_digits_count - 1);+ precision_bits *= kDenominator;+ half_way *= kDenominator;+ DiyFp rounded_input(input.f() >> precision_digits_count,+ input.e() + precision_digits_count);+ if (precision_bits >= half_way + error) {+ rounded_input.set_f(rounded_input.f() + 1);+ }+ // If the last_bits are too close to the half-way case than we are too+ // inaccurate and round down. In this case we return false so that we can+ // fall back to a more precise algorithm.++ *result = Double(rounded_input).value();+ if (half_way - error < precision_bits && precision_bits < half_way + error) {+ // Too imprecise. The caller will have to fall back to a slower version.+ // However the returned number is guaranteed to be either the correct+ // double, or the next-lower double.+ return false;+ } else {+ return true;+ }+}+++// Returns the correct double for the buffer*10^exponent.+// The variable guess should be a close guess that is either the correct double+// or its lower neighbor (the nearest double less than the correct one).+// Preconditions:+// buffer.length() + exponent <= kMaxDecimalPower + 1+// buffer.length() + exponent > kMinDecimalPower+// buffer.length() <= kMaxDecimalSignificantDigits+static double BignumStrtod(Vector<const char> buffer,+ int exponent,+ double guess) {+ if (guess == Double::Infinity()) {+ return guess;+ }++ DiyFp upper_boundary = Double(guess).UpperBoundary();++ ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);+ ASSERT(buffer.length() + exponent > kMinDecimalPower);+ ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);+ // Make sure that the Bignum will be able to hold all our numbers.+ // Our Bignum implementation has a separate field for exponents. Shifts will+ // consume at most one bigit (< 64 bits).+ // ln(10) == 3.3219...+ ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);+ Bignum input;+ Bignum boundary;+ input.AssignDecimalString(buffer);+ boundary.AssignUInt64(upper_boundary.f());+ if (exponent >= 0) {+ input.MultiplyByPowerOfTen(exponent);+ } else {+ boundary.MultiplyByPowerOfTen(-exponent);+ }+ if (upper_boundary.e() > 0) {+ boundary.ShiftLeft(upper_boundary.e());+ } else {+ input.ShiftLeft(-upper_boundary.e());+ }+ int comparison = Bignum::Compare(input, boundary);+ if (comparison < 0) {+ return guess;+ } else if (comparison > 0) {+ return Double(guess).NextDouble();+ } else if ((Double(guess).Significand() & 1) == 0) {+ // Round towards even.+ return guess;+ } else {+ return Double(guess).NextDouble();+ }+}+++double Strtod(Vector<const char> buffer, int exponent) {+ Vector<const char> left_trimmed = TrimLeadingZeros(buffer);+ Vector<const char> trimmed = TrimTrailingZeros(left_trimmed);+ exponent += left_trimmed.length() - trimmed.length();+ if (trimmed.length() == 0) return 0.0;+ if (trimmed.length() > kMaxSignificantDecimalDigits) {+ char significant_buffer[kMaxSignificantDecimalDigits];+ int significant_exponent;+ TrimToMaxSignificantDigits(trimmed, exponent,+ significant_buffer, &significant_exponent);+ return Strtod(Vector<const char>(significant_buffer,+ kMaxSignificantDecimalDigits),+ significant_exponent);+ }+ if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {+ return Double::Infinity();+ }+ if (exponent + trimmed.length() <= kMinDecimalPower) {+ return 0.0;+ }++ double guess;+ if (DoubleStrtod(trimmed, exponent, &guess) ||+ DiyFpStrtod(trimmed, exponent, &guess)) {+ return guess;+ }+ return BignumStrtod(trimmed, exponent, guess);+}++} // namespace double_conversion
+ double-conversion/src/strtod.h view
@@ -0,0 +1,41 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_STRTOD_H_+#define DOUBLE_CONVERSION_STRTOD_H_++#include "utils.h"++namespace double_conversion {++// The buffer must only contain digits in the range [0-9]. It must not+// contain a dot or a sign. It must not start with '0', and must not be empty.+double Strtod(Vector<const char> buffer, int exponent);++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_STRTOD_H_
+ double-conversion/src/utils.h view
@@ -0,0 +1,297 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef DOUBLE_CONVERSION_UTILS_H_+#define DOUBLE_CONVERSION_UTILS_H_++#include <stdlib.h>+#include <string.h>++#include <assert.h>+#define ASSERT(condition) (assert(condition))+#define UNIMPLEMENTED() (abort())+#define UNREACHABLE() (abort())++// Double operations detection based on target architecture.+// Linux uses a 80bit wide floating point stack on x86. This induces double+// rounding, which in turn leads to wrong results.+// An easy way to test if the floating-point operations are correct is to+// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then+// the result is equal to 89255e-22.+// The best way to test this, is to create a division-function and to compare+// the output of the division with the expected result. (Inlining must be+// disabled.)+// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)+#if defined(_M_X64) || defined(__x86_64__) || \+ defined(__ARMEL__) || \+ defined(_MIPS_ARCH_MIPS32R2)+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1+#elif defined(_M_IX86) || defined(__i386__)+#if defined(_WIN32)+// Windows uses a 64bit wide floating point stack.+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1+#else+#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS+#endif // _WIN32+#else+#error Target architecture was not detected as supported by Double-Conversion.+#endif+++#if defined(_WIN32) && !defined(__MINGW32__)++typedef signed char int8_t;+typedef unsigned char uint8_t;+typedef short int16_t; // NOLINT+typedef unsigned short uint16_t; // NOLINT+typedef int int32_t;+typedef unsigned int uint32_t;+typedef __int64 int64_t;+typedef unsigned __int64 uint64_t;+// intptr_t and friends are defined in crtdefs.h through stdio.h.++#else++#include <stdint.h>++#endif++// The following macro works on both 32 and 64-bit platforms.+// Usage: instead of writing 0x1234567890123456+// write UINT64_2PART_C(0x12345678,90123456);+#define UINT64_2PART_C(a, b) (((static_cast<uint64_t>(a) << 32) + 0x##b##u))+++// The expression ARRAY_SIZE(a) is a compile-time constant of type+// size_t which represents the number of elements of the given+// array. You should only use ARRAY_SIZE on statically allocated+// arrays.+#define ARRAY_SIZE(a) \+ ((sizeof(a) / sizeof(*(a))) / \+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))++// A macro to disallow the evil copy constructor and operator= functions+// This should be used in the private: declarations for a class+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \+ TypeName(const TypeName&); \+ void operator=(const TypeName&)++// A macro to disallow all the implicit constructors, namely the+// default constructor, copy constructor and operator= functions.+//+// This should be used in the private: declarations for a class+// that wants to prevent anyone from instantiating it. This is+// especially useful for classes containing only static methods.+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \+ TypeName(); \+ DISALLOW_COPY_AND_ASSIGN(TypeName)++namespace double_conversion {++static const int kCharSize = sizeof(char);++// Returns the maximum of the two parameters.+template <typename T>+static T Max(T a, T b) {+ return a < b ? b : a;+}+++// Returns the minimum of the two parameters.+template <typename T>+static T Min(T a, T b) {+ return a < b ? a : b;+}+++inline int StrLength(const char* string) {+ size_t length = strlen(string);+ ASSERT(length == static_cast<size_t>(static_cast<int>(length)));+ return static_cast<int>(length);+}++// This is a simplified version of V8's Vector class.+template <typename T>+class Vector {+ public:+ Vector() : start_(NULL), length_(0) {}+ Vector(T* data, int length) : start_(data), length_(length) {+ ASSERT(length == 0 || (length > 0 && data != NULL));+ }++ // Returns a vector using the same backing storage as this one,+ // spanning from and including 'from', to but not including 'to'.+ Vector<T> SubVector(int from, int to) {+ ASSERT(to <= length_);+ ASSERT(from < to);+ ASSERT(0 <= from);+ return Vector<T>(start() + from, to - from);+ }++ // Returns the length of the vector.+ int length() const { return length_; }++ // Returns whether or not the vector is empty.+ bool is_empty() const { return length_ == 0; }++ // Returns the pointer to the start of the data in the vector.+ T* start() const { return start_; }++ // Access individual vector elements - checks bounds in debug mode.+ T& operator[](int index) const {+ ASSERT(0 <= index && index < length_);+ return start_[index];+ }++ T& first() { return start_[0]; }++ T& last() { return start_[length_ - 1]; }++ private:+ T* start_;+ int length_;+};+++// Helper class for building result strings in a character buffer. The+// purpose of the class is to use safe operations that checks the+// buffer bounds on all operations in debug mode.+class StringBuilder {+ public:+ StringBuilder(char* buffer, int size)+ : buffer_(buffer, size), position_(0) { }++ ~StringBuilder() { if (!is_finalized()) Finalize(); }++ int size() const { return buffer_.length(); }++ // Get the current position in the builder.+ int position() const {+ ASSERT(!is_finalized());+ return position_;+ }++ // Reset the position.+ void Reset() { position_ = 0; }++ // Add a single character to the builder. It is not allowed to add+ // 0-characters; use the Finalize() method to terminate the string+ // instead.+ void AddCharacter(char c) {+ ASSERT(c != '\0');+ ASSERT(!is_finalized() && position_ < buffer_.length());+ buffer_[position_++] = c;+ }++ // Add an entire string to the builder. Uses strlen() internally to+ // compute the length of the input string.+ void AddString(const char* s) {+ AddSubstring(s, StrLength(s));+ }++ // Add the first 'n' characters of the given string 's' to the+ // builder. The input string must have enough characters.+ void AddSubstring(const char* s, int n) {+ ASSERT(!is_finalized() && position_ + n < buffer_.length());+ ASSERT(static_cast<size_t>(n) <= strlen(s));+ memcpy(&buffer_[position_], s, n * kCharSize);+ position_ += n;+ }+++ // Add character padding to the builder. If count is non-positive,+ // nothing is added to the builder.+ void AddPadding(char c, int count) {+ for (int i = 0; i < count; i++) {+ AddCharacter(c);+ }+ }++ // Finalize the string by 0-terminating it and returning the buffer.+ char* Finalize() {+ ASSERT(!is_finalized() && position_ < buffer_.length());+ buffer_[position_] = '\0';+ // Make sure nobody managed to add a 0-character to the+ // buffer while building the string.+ ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));+ position_ = -1;+ ASSERT(is_finalized());+ return buffer_.start();+ }++ private:+ Vector<char> buffer_;+ int position_;++ bool is_finalized() const { return position_ < 0; }++ DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);+};++// The type-based aliasing rule allows the compiler to assume that pointers of+// different types (for some definition of different) never alias each other.+// Thus the following code does not work:+//+// float f = foo();+// int fbits = *(int*)(&f);+//+// The compiler 'knows' that the int pointer can't refer to f since the types+// don't match, so the compiler may cache f in a register, leaving random data+// in fbits. Using C++ style casts makes no difference, however a pointer to+// char data is assumed to alias any other pointer. This is the 'memcpy+// exception'.+//+// Bit_cast uses the memcpy exception to move the bits from a variable of one+// type of a variable of another type. Of course the end result is likely to+// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005)+// will completely optimize BitCast away.+//+// There is an additional use for BitCast.+// Recent gccs will warn when they see casts that may result in breakage due to+// the type-based aliasing rule. If you have checked that there is no breakage+// you can use BitCast to cast one pointer type to another. This confuses gcc+// enough that it can no longer see that you have cast one pointer type to+// another thus avoiding the warning.+template <class Dest, class Source>+inline Dest BitCast(const Source& source) {+ // Compile time assertion: sizeof(Dest) == sizeof(Source)+ // A compile error here means your Dest and Source have different sizes.+ typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];++ Dest dest;+ memcpy(&dest, &source, sizeof(dest));+ return dest;+}++template <class Dest, class Source>+inline Dest BitCast(Source* source) {+ return BitCast<Dest>(reinterpret_cast<uintptr_t>(source));+}++} // namespace double_conversion++#endif // DOUBLE_CONVERSION_UTILS_H_
+ double-conversion/test/cctest/SConscript view
@@ -0,0 +1,16 @@+double_conversion_test_sources = [+ 'cctest.cc',+ 'gay-fixed.cc',+ 'gay-precision.cc',+ 'gay-shortest.cc',+ 'test-bignum.cc',+ 'test-bignum-dtoa.cc',+ 'test-conversions.cc',+ 'test-diy-fp.cc',+ 'test-double.cc',+ 'test-dtoa.cc',+ 'test-fast-dtoa.cc',+ 'test-fixed-dtoa.cc',+ 'test-strtod.cc',+ ]+Return('double_conversion_test_sources')
+ double-conversion/test/cctest/cctest.cc view
@@ -0,0 +1,122 @@+// Copyright 2008 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include "cctest.h"+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+++CcTest* CcTest::last_ = NULL;+++CcTest::CcTest(TestFunction* callback, const char* file, const char* name,+ const char* dependency, bool enabled)+ : callback_(callback), name_(name), dependency_(dependency), prev_(last_) {+ // Find the base name of this test (const_cast required on Windows).+ char *basename = strrchr(const_cast<char *>(file), '/');+ if (!basename) {+ basename = strrchr(const_cast<char *>(file), '\\');+ }+ if (!basename) {+ basename = strdup(file);+ } else {+ basename = strdup(basename + 1);+ }+ // Drop the extension, if there is one.+ char *extension = strrchr(basename, '.');+ if (extension) *extension = 0;+ // Install this test in the list of tests+ file_ = basename;+ enabled_ = enabled;+ prev_ = last_;+ last_ = this;+}+++static void PrintTestList(CcTest* current) {+ if (current == NULL) return;+ PrintTestList(current->prev());+ if (current->dependency() != NULL) {+ printf("%s/%s<%s\n",+ current->file(), current->name(), current->dependency());+ } else {+ printf("%s/%s<\n", current->file(), current->name());+ }+}+++int main(int argc, char* argv[]) {+ int tests_run = 0;+ bool print_run_count = true;+ for (int i = 1; i < argc; i++) {+ char* arg = argv[i];+ if (strcmp(arg, "--list") == 0) {+ PrintTestList(CcTest::last());+ print_run_count = false;++ } else {+ char* arg_copy = strdup(arg);+ char* testname = strchr(arg_copy, '/');+ if (testname) {+ // Split the string in two by nulling the slash and then run+ // exact matches.+ *testname = 0;+ char* file = arg_copy;+ char* name = testname + 1;+ CcTest* test = CcTest::last();+ while (test != NULL) {+ if (test->enabled()+ && strcmp(test->file(), file) == 0+ && strcmp(test->name(), name) == 0) {+ test->Run();+ tests_run++;+ }+ test = test->prev();+ }++ } else {+ // Run all tests with the specified file or test name.+ char* file_or_name = arg_copy;+ CcTest* test = CcTest::last();+ while (test != NULL) {+ if (test->enabled()+ && (strcmp(test->file(), file_or_name) == 0+ || strcmp(test->name(), file_or_name) == 0)) {+ test->Run();+ tests_run++;+ }+ test = test->prev();+ }+ }+ delete[] arg_copy;+ }+ }+ if (print_run_count && tests_run != 1)+ printf("Ran %i tests.\n", tests_run);+ return 0;+}
+ double-conversion/test/cctest/cctest.h view
@@ -0,0 +1,141 @@+// Copyright 2008 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef CCTEST_H_+#define CCTEST_H_++#include <stdio.h>+#include <string.h>++#include "utils.h"++#ifndef TEST+#define TEST(Name) \+ static void Test##Name(); \+ CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true); \+ static void Test##Name()+#endif++#ifndef DEPENDENT_TEST+#define DEPENDENT_TEST(Name, Dep) \+ static void Test##Name(); \+ CcTest register_test_##Name(Test##Name, __FILE__, #Name, #Dep, true); \+ static void Test##Name()+#endif++#ifndef DISABLED_TEST+#define DISABLED_TEST(Name) \+ static void Test##Name(); \+ CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, false); \+ static void Test##Name()+#endif++#define CHECK(condition) CheckHelper(__FILE__, __LINE__, #condition, condition)+#define CHECK_GE(a, b) CHECK((a) >= (b))++static inline void CheckHelper(const char* file,+ int line,+ const char* source,+ bool condition) {+ if (!condition) {+ printf("%s:%d:\n CHECK(%s) failed\n", file, line, source);+ abort();+ }+}++#define CHECK_EQ(a, b) CheckEqualsHelper(__FILE__, __LINE__, #a, a, #b, b)++static inline void CheckEqualsHelper(const char* file, int line,+ const char* expected_source,+ const char* expected,+ const char* value_source,+ const char* value) {+ if ((expected == NULL && value != NULL) ||+ (expected != NULL && value == NULL) ||+ (expected != NULL && value != NULL && strcmp(expected, value) != 0)) {+ printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n"+ "# Expected: %s\n"+ "# Found: %s\n",+ file, line, expected_source, value_source, expected, value);+ abort();+ }+}++static inline void CheckEqualsHelper(const char* file, int line,+ const char* expected_source,+ int expected,+ const char* value_source,+ int value) {+ if (expected != value) {+ printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n"+ "# Expected: %d\n"+ "# Found: %d\n",+ file, line, expected_source, value_source, expected, value);+ abort();+ }+}++static inline void CheckEqualsHelper(const char* file, int line,+ const char* expected_source,+ double expected,+ const char* value_source,+ double value) {+ // If expected and value are NaNs then expected != value.+ if (expected != value && (expected == expected || value == value)) {+ printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n"+ "# Expected: %.30e\n"+ "# Found: %.30e\n",+ file, line, expected_source, value_source, expected, value);+ abort();+ }+}+++class CcTest {+ public:+ typedef void (TestFunction)();+ CcTest(TestFunction* callback, const char* file, const char* name,+ const char* dependency, bool enabled);+ void Run() { callback_(); }+ static int test_count();+ static CcTest* last() { return last_; }+ CcTest* prev() { return prev_; }+ const char* file() { return file_; }+ const char* name() { return name_; }+ const char* dependency() { return dependency_; }+ bool enabled() { return enabled_; }+ private:+ TestFunction* callback_;+ const char* file_;+ const char* name_;+ const char* dependency_;+ bool enabled_;+ static CcTest* last_;+ CcTest* prev_;+};++#endif // ifndef CCTEST_H_
+ double-conversion/test/cctest/checks.h view
@@ -0,0 +1,314 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef V8_CHECKS_H_+#define V8_CHECKS_H_++#include <string.h>++#include "flags.h"++extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);+void API_Fatal(const char* location, const char* format, ...);++// The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during+// development, but they should not be relied on in the final product.+#ifdef DEBUG+#define FATAL(msg) \+ V8_Fatal(__FILE__, __LINE__, "%s", (msg))+#define UNIMPLEMENTED() \+ V8_Fatal(__FILE__, __LINE__, "unimplemented code")+#define UNREACHABLE() \+ V8_Fatal(__FILE__, __LINE__, "unreachable code")+#else+#define FATAL(msg) \+ V8_Fatal("", 0, "%s", (msg))+#define UNIMPLEMENTED() \+ V8_Fatal("", 0, "unimplemented code")+#define UNREACHABLE() ((void) 0)+#endif+++// Used by the CHECK macro -- should not be called directly.+static inline void CheckHelper(const char* file,+ int line,+ const char* source,+ bool condition) {+ if (!condition)+ V8_Fatal(file, line, "CHECK(%s) failed", source);+}+++// The CHECK macro checks that the given condition is true; if not, it+// prints a message to stderr and aborts.+#define CHECK(condition) CheckHelper(__FILE__, __LINE__, #condition, condition)+++// Helper function used by the CHECK_EQ function when given int+// arguments. Should not be called directly.+static inline void CheckEqualsHelper(const char* file, int line,+ const char* expected_source, int expected,+ const char* value_source, int value) {+ if (expected != value) {+ V8_Fatal(file, line,+ "CHECK_EQ(%s, %s) failed\n# Expected: %i\n# Found: %i",+ expected_source, value_source, expected, value);+ }+}+++// Helper function used by the CHECK_EQ function when given int64_t+// arguments. Should not be called directly.+static inline void CheckEqualsHelper(const char* file, int line,+ const char* expected_source,+ int64_t expected,+ const char* value_source,+ int64_t value) {+ if (expected != value) {+ // Print int64_t values in hex, as two int32s,+ // to avoid platform-dependencies.+ V8_Fatal(file, line,+ "CHECK_EQ(%s, %s) failed\n#"+ " Expected: 0x%08x%08x\n# Found: 0x%08x%08x",+ expected_source, value_source,+ static_cast<uint32_t>(expected >> 32),+ static_cast<uint32_t>(expected),+ static_cast<uint32_t>(value >> 32),+ static_cast<uint32_t>(value));+ }+}+++// Helper function used by the CHECK_NE function when given int+// arguments. Should not be called directly.+static inline void CheckNonEqualsHelper(const char* file,+ int line,+ const char* unexpected_source,+ int unexpected,+ const char* value_source,+ int value) {+ if (unexpected == value) {+ V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",+ unexpected_source, value_source, value);+ }+}+++// Helper function used by the CHECK function when given string+// arguments. Should not be called directly.+static inline void CheckEqualsHelper(const char* file,+ int line,+ const char* expected_source,+ const char* expected,+ const char* value_source,+ const char* value) {+ if ((expected == NULL && value != NULL) ||+ (expected != NULL && value == NULL) ||+ (expected != NULL && value != NULL && strcmp(expected, value) != 0)) {+ V8_Fatal(file, line,+ "CHECK_EQ(%s, %s) failed\n# Expected: %s\n# Found: %s",+ expected_source, value_source, expected, value);+ }+}+++static inline void CheckNonEqualsHelper(const char* file,+ int line,+ const char* expected_source,+ const char* expected,+ const char* value_source,+ const char* value) {+ if (expected == value ||+ (expected != NULL && value != NULL && strcmp(expected, value) == 0)) {+ V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %s",+ expected_source, value_source, value);+ }+}+++// Helper function used by the CHECK function when given pointer+// arguments. Should not be called directly.+static inline void CheckEqualsHelper(const char* file,+ int line,+ const char* expected_source,+ const void* expected,+ const char* value_source,+ const void* value) {+ if (expected != value) {+ V8_Fatal(file, line,+ "CHECK_EQ(%s, %s) failed\n# Expected: %p\n# Found: %p",+ expected_source, value_source,+ expected, value);+ }+}+++static inline void CheckNonEqualsHelper(const char* file,+ int line,+ const char* expected_source,+ const void* expected,+ const char* value_source,+ const void* value) {+ if (expected == value) {+ V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",+ expected_source, value_source, value);+ }+}+++// Helper function used by the CHECK function when given floating+// point arguments. Should not be called directly.+static inline void CheckEqualsHelper(const char* file,+ int line,+ const char* expected_source,+ double expected,+ const char* value_source,+ double value) {+ // Force values to 64 bit memory to truncate 80 bit precision on IA32.+ volatile double* exp = new double[1];+ *exp = expected;+ volatile double* val = new double[1];+ *val = value;+ if (*exp != *val) {+ V8_Fatal(file, line,+ "CHECK_EQ(%s, %s) failed\n# Expected: %f\n# Found: %f",+ expected_source, value_source, *exp, *val);+ }+ delete[] exp;+ delete[] val;+}+++static inline void CheckNonEqualsHelper(const char* file,+ int line,+ const char* expected_source,+ double expected,+ const char* value_source,+ double value) {+ // Force values to 64 bit memory to truncate 80 bit precision on IA32.+ volatile double* exp = new double[1];+ *exp = expected;+ volatile double* val = new double[1];+ *val = value;+ if (*exp == *val) {+ V8_Fatal(file, line,+ "CHECK_NE(%s, %s) failed\n# Value: %f",+ expected_source, value_source, *val);+ }+ delete[] exp;+ delete[] val;+}+++namespace v8 {+ class Value;+ template <class T> class Handle;+}+++void CheckNonEqualsHelper(const char* file,+ int line,+ const char* unexpected_source,+ v8::Handle<v8::Value> unexpected,+ const char* value_source,+ v8::Handle<v8::Value> value);+++void CheckEqualsHelper(const char* file,+ int line,+ const char* expected_source,+ v8::Handle<v8::Value> expected,+ const char* value_source,+ v8::Handle<v8::Value> value);+++#define CHECK_EQ(expected, value) CheckEqualsHelper(__FILE__, __LINE__, \+ #expected, expected, #value, value)+++#define CHECK_NE(unexpected, value) CheckNonEqualsHelper(__FILE__, __LINE__, \+ #unexpected, unexpected, #value, value)+++#define CHECK_GT(a, b) CHECK((a) > (b))+#define CHECK_GE(a, b) CHECK((a) >= (b))+++// This is inspired by the static assertion facility in boost. This+// is pretty magical. If it causes you trouble on a platform you may+// find a fix in the boost code.+template <bool> class StaticAssertion;+template <> class StaticAssertion<true> { };+// This macro joins two tokens. If one of the tokens is a macro the+// helper call causes it to be resolved before joining.+#define SEMI_STATIC_JOIN(a, b) SEMI_STATIC_JOIN_HELPER(a, b)+#define SEMI_STATIC_JOIN_HELPER(a, b) a##b+// Causes an error during compilation of the condition is not+// statically known to be true. It is formulated as a typedef so that+// it can be used wherever a typedef can be used. Beware that this+// actually causes each use to introduce a new defined type with a+// name depending on the source line.+template <int> class StaticAssertionHelper { };+#define STATIC_CHECK(test) \+ typedef \+ StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>(test)>)> \+ SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)+++// The ASSERT macro is equivalent to CHECK except that it only+// generates code in debug builds.+#ifdef DEBUG+#define ASSERT_RESULT(expr) CHECK(expr)+#define ASSERT(condition) CHECK(condition)+#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2)+#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2)+#define ASSERT_GE(v1, v2) CHECK_GE(v1, v2)+#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)+#else+#define ASSERT_RESULT(expr) (expr)+#define ASSERT(condition) ((void) 0)+#define ASSERT_EQ(v1, v2) ((void) 0)+#define ASSERT_NE(v1, v2) ((void) 0)+#define ASSERT_GE(v1, v2) ((void) 0)+#define SLOW_ASSERT(condition) ((void) 0)+#endif+// Static asserts has no impact on runtime performance, so they can be+// safely enabled in release mode. Moreover, the ((void) 0) expression+// obeys different syntax rules than typedef's, e.g. it can't appear+// inside class declaration, this leads to inconsistency between debug+// and release compilation modes behaviour.+#define STATIC_ASSERT(test) STATIC_CHECK(test)+++#define ASSERT_TAG_ALIGNED(address) \+ ASSERT((reinterpret_cast<intptr_t>(address) & kHeapObjectTagMask) == 0)++#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)++#define ASSERT_NOT_NULL(p) ASSERT_NE(NULL, p)++#endif // V8_CHECKS_H_
+ double-conversion/test/cctest/gay-fixed.cc view
file too large to diff
+ double-conversion/test/cctest/gay-fixed.h view
@@ -0,0 +1,46 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef GAY_FIXED_H_+#define GAY_FIXED_H_++namespace double_conversion {++struct PrecomputedFixed {+ double v;+ int number_digits;+ const char* representation;+ int decimal_point;+};++// Returns precomputed values of dtoa. The strings have been generated using+// Gay's dtoa in mode "fixed".+Vector<const PrecomputedFixed> PrecomputedFixedRepresentations();++} // namespace double_conversion++#endif // GAY_FIXED_H_
+ double-conversion/test/cctest/gay-precision.cc view
file too large to diff
+ double-conversion/test/cctest/gay-precision.h view
@@ -0,0 +1,46 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef GAY_PRECISION_H_+#define GAY_PRECISION_H_++namespace double_conversion {++struct PrecomputedPrecision {+ double v;+ int number_digits;+ const char* representation;+ int decimal_point;+};++// Returns precomputed values of dtoa. The strings have been generated using+// Gay's dtoa in mode "precision".+Vector<const PrecomputedPrecision> PrecomputedPrecisionRepresentations();++} // namespace double_conversion++#endif // GAY_PRECISION_H_
+ double-conversion/test/cctest/gay-shortest.cc view
file too large to diff
+ double-conversion/test/cctest/gay-shortest.h view
@@ -0,0 +1,43 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#ifndef GAY_SHORTEST_H_+#define GAY_SHORTEST_H_++namespace double_conversion {++struct PrecomputedShortest {+ double v;+ const char* representation;+ int decimal_point;+};++Vector<const PrecomputedShortest> PrecomputedShortestRepresentations();++} // namespace double_conversion++#endif // GAY_SHORTEST_H_
+ double-conversion/test/cctest/test-bignum-dtoa.cc view
@@ -0,0 +1,313 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <stdlib.h>++#include "bignum-dtoa.h"++#include "cctest.h"+#include "double.h"+#include "gay-fixed.h"+#include "gay-precision.h"+#include "gay-shortest.h"+#include "utils.h"++using namespace double_conversion;+++// Removes trailing '0' digits.+// Can return the empty string if all digits are 0.+static void TrimRepresentation(Vector<char> representation) {+ int len = strlen(representation.start());+ int i;+ for (i = len - 1; i >= 0; --i) {+ if (representation[i] != '0') break;+ }+ representation[i + 1] = '\0';+}+++static const int kBufferSize = 100;+++TEST(BignumDtoaVariousDoubles) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ int length;+ int point;++ BignumDtoa(1.0, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ BignumDtoa(1.0, BIGNUM_DTOA_FIXED, 3, buffer, &length, &point);+ CHECK_GE(3, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ BignumDtoa(1.0, BIGNUM_DTOA_PRECISION, 3, buffer, &length, &point);+ CHECK_GE(3, length);+ TrimRepresentation(buffer);+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ BignumDtoa(1.5, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ("15", buffer.start());+ CHECK_EQ(1, point);++ BignumDtoa(1.5, BIGNUM_DTOA_FIXED, 10, buffer, &length, &point);+ CHECK_GE(10, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("15", buffer.start());+ CHECK_EQ(1, point);++ BignumDtoa(1.5, BIGNUM_DTOA_PRECISION, 10, buffer, &length, &point);+ CHECK_GE(10, length);+ TrimRepresentation(buffer);+ CHECK_EQ("15", buffer.start());+ CHECK_EQ(1, point);++ double min_double = 5e-324;+ BignumDtoa(min_double, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ("5", buffer.start());+ CHECK_EQ(-323, point);++ BignumDtoa(min_double, BIGNUM_DTOA_FIXED, 5, buffer, &length, &point);+ CHECK_GE(5, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("", buffer.start());++ BignumDtoa(min_double, BIGNUM_DTOA_PRECISION, 5, buffer, &length, &point);+ CHECK_GE(5, length);+ TrimRepresentation(buffer);+ CHECK_EQ("49407", buffer.start());+ CHECK_EQ(-323, point);++ double max_double = 1.7976931348623157e308;+ BignumDtoa(max_double, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ("17976931348623157", buffer.start());+ CHECK_EQ(309, point);++ BignumDtoa(max_double, BIGNUM_DTOA_PRECISION, 7, buffer, &length, &point);+ CHECK_GE(7, length);+ TrimRepresentation(buffer);+ CHECK_EQ("1797693", buffer.start());+ CHECK_EQ(309, point);++ BignumDtoa(4294967272.0, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ("4294967272", buffer.start());+ CHECK_EQ(10, point);++ BignumDtoa(4294967272.0, BIGNUM_DTOA_FIXED, 5, buffer, &length, &point);+ CHECK_EQ("429496727200000", buffer.start());+ CHECK_EQ(10, point);+++ BignumDtoa(4294967272.0, BIGNUM_DTOA_PRECISION, 14, buffer, &length, &point);+ CHECK_GE(14, length);+ TrimRepresentation(buffer);+ CHECK_EQ("4294967272", buffer.start());+ CHECK_EQ(10, point);++ BignumDtoa(4.1855804968213567e298, BIGNUM_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK_EQ("4185580496821357", buffer.start());+ CHECK_EQ(299, point);++ BignumDtoa(4.1855804968213567e298, BIGNUM_DTOA_PRECISION, 20,+ buffer, &length, &point);+ CHECK_GE(20, length);+ TrimRepresentation(buffer);+ CHECK_EQ("41855804968213567225", buffer.start());+ CHECK_EQ(299, point);++ BignumDtoa(5.5626846462680035e-309, BIGNUM_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK_EQ("5562684646268003", buffer.start());+ CHECK_EQ(-308, point);++ BignumDtoa(5.5626846462680035e-309, BIGNUM_DTOA_PRECISION, 1,+ buffer, &length, &point);+ CHECK_GE(1, length);+ TrimRepresentation(buffer);+ CHECK_EQ("6", buffer.start());+ CHECK_EQ(-308, point);++ BignumDtoa(2147483648.0, BIGNUM_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK_EQ("2147483648", buffer.start());+ CHECK_EQ(10, point);+++ BignumDtoa(2147483648.0, BIGNUM_DTOA_FIXED, 2,+ buffer, &length, &point);+ CHECK_GE(2, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("2147483648", buffer.start());+ CHECK_EQ(10, point);++ BignumDtoa(2147483648.0, BIGNUM_DTOA_PRECISION, 5,+ buffer, &length, &point);+ CHECK_GE(5, length);+ TrimRepresentation(buffer);+ CHECK_EQ("21475", buffer.start());+ CHECK_EQ(10, point);++ BignumDtoa(3.5844466002796428e+298, BIGNUM_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK_EQ("35844466002796428", buffer.start());+ CHECK_EQ(299, point);++ BignumDtoa(3.5844466002796428e+298, BIGNUM_DTOA_PRECISION, 10,+ buffer, &length, &point);+ CHECK_GE(10, length);+ TrimRepresentation(buffer);+ CHECK_EQ("35844466", buffer.start());+ CHECK_EQ(299, point);++ uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000);+ double v = Double(smallest_normal64).value();+ BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ("22250738585072014", buffer.start());+ CHECK_EQ(-307, point);++ BignumDtoa(v, BIGNUM_DTOA_PRECISION, 20, buffer, &length, &point);+ CHECK_GE(20, length);+ TrimRepresentation(buffer);+ CHECK_EQ("22250738585072013831", buffer.start());+ CHECK_EQ(-307, point);++ uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);+ v = Double(largest_denormal64).value();+ BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ("2225073858507201", buffer.start());+ CHECK_EQ(-307, point);++ BignumDtoa(v, BIGNUM_DTOA_PRECISION, 20, buffer, &length, &point);+ CHECK_GE(20, length);+ TrimRepresentation(buffer);+ CHECK_EQ("2225073858507200889", buffer.start());+ CHECK_EQ(-307, point);++ BignumDtoa(4128420500802942e-24, BIGNUM_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK_EQ("4128420500802942", buffer.start());+ CHECK_EQ(-8, point);++ v = 3.9292015898194142585311918e-10;+ BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ("39292015898194143", buffer.start());++ v = 4194304.0;+ BignumDtoa(v, BIGNUM_DTOA_FIXED, 5, buffer, &length, &point);+ CHECK_GE(5, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("4194304", buffer.start());++ v = 3.3161339052167390562200598e-237;+ BignumDtoa(v, BIGNUM_DTOA_PRECISION, 19, buffer, &length, &point);+ CHECK_GE(19, length);+ TrimRepresentation(buffer);+ CHECK_EQ("3316133905216739056", buffer.start());+ CHECK_EQ(-236, point);++ v = 7.9885183916008099497815232e+191;+ BignumDtoa(v, BIGNUM_DTOA_PRECISION, 4, buffer, &length, &point);+ CHECK_GE(4, length);+ TrimRepresentation(buffer);+ CHECK_EQ("7989", buffer.start());+ CHECK_EQ(192, point);++ v = 1.0000000000000012800000000e+17;+ BignumDtoa(v, BIGNUM_DTOA_FIXED, 1, buffer, &length, &point);+ CHECK_GE(1, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("100000000000000128", buffer.start());+ CHECK_EQ(18, point);+}+++TEST(BignumDtoaGayShortest) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ int length;+ int point;++ Vector<const PrecomputedShortest> precomputed =+ PrecomputedShortestRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedShortest current_test = precomputed[i];+ double v = current_test.v;+ BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK_EQ(current_test.decimal_point, point);+ CHECK_EQ(current_test.representation, buffer.start());+ }+}+++TEST(BignumDtoaGayFixed) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ int length;+ int point;++ Vector<const PrecomputedFixed> precomputed =+ PrecomputedFixedRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedFixed current_test = precomputed[i];+ double v = current_test.v;+ int number_digits = current_test.number_digits;+ BignumDtoa(v, BIGNUM_DTOA_FIXED, number_digits, buffer, &length, &point);+ CHECK_EQ(current_test.decimal_point, point);+ CHECK_GE(number_digits, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ(current_test.representation, buffer.start());+ }+}+++TEST(BignumDtoaGayPrecision) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ int length;+ int point;++ Vector<const PrecomputedPrecision> precomputed =+ PrecomputedPrecisionRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedPrecision current_test = precomputed[i];+ double v = current_test.v;+ int number_digits = current_test.number_digits;+ BignumDtoa(v, BIGNUM_DTOA_PRECISION, number_digits,+ buffer, &length, &point);+ CHECK_EQ(current_test.decimal_point, point);+ CHECK_GE(number_digits, length);+ TrimRepresentation(buffer);+ CHECK_EQ(current_test.representation, buffer.start());+ }+}
+ double-conversion/test/cctest/test-bignum.cc view
@@ -0,0 +1,1502 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <stdlib.h>+#include <string.h>+++#include "bignum.h"+#include "cctest.h"+#include "utils.h"++using namespace double_conversion;+++static const int kBufferSize = 1024;++static void AssignHexString(Bignum* bignum, const char* str) {+ bignum->AssignHexString(Vector<const char>(str, strlen(str)));+}+++static void AssignDecimalString(Bignum* bignum, const char* str) {+ bignum->AssignDecimalString(Vector<const char>(str, strlen(str)));+}+++TEST(Assign) {+ char buffer[kBufferSize];+ Bignum bignum;+ Bignum bignum2;+ bignum.AssignUInt16(0);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("0", buffer);+ bignum.AssignUInt16(0xA);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A", buffer);+ bignum.AssignUInt16(0x20);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("20", buffer);+++ bignum.AssignUInt64(0);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("0", buffer);+ bignum.AssignUInt64(0xA);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A", buffer);+ bignum.AssignUInt64(0x20);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("20", buffer);+ bignum.AssignUInt64(0x100);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100", buffer);++ // The first real test, since this will not fit into one bigit.+ bignum.AssignUInt64(0x12345678);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("12345678", buffer);++ uint64_t big = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF);+ bignum.AssignUInt64(big);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFFFFF", buffer);++ big = UINT64_2PART_C(0x12345678, 9ABCDEF0);+ bignum.AssignUInt64(big);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("123456789ABCDEF0", buffer);++ bignum2.AssignBignum(bignum);+ CHECK(bignum2.ToHexString(buffer, kBufferSize));+ CHECK_EQ("123456789ABCDEF0", buffer);++ AssignDecimalString(&bignum, "0");+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("0", buffer);++ AssignDecimalString(&bignum, "1");+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ AssignDecimalString(&bignum, "1234567890");+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("499602D2", buffer);++ AssignHexString(&bignum, "0");+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("0", buffer);++ AssignHexString(&bignum, "123456789ABCDEF0");+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("123456789ABCDEF0", buffer);+}+++TEST(ShiftLeft) {+ char buffer[kBufferSize];+ Bignum bignum;+ AssignHexString(&bignum, "0");+ bignum.ShiftLeft(100);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("0", buffer);++ AssignHexString(&bignum, "1");+ bignum.ShiftLeft(1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2", buffer);++ AssignHexString(&bignum, "1");+ bignum.ShiftLeft(4);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10", buffer);++ AssignHexString(&bignum, "1");+ bignum.ShiftLeft(32);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100000000", buffer);++ AssignHexString(&bignum, "1");+ bignum.ShiftLeft(64);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000", buffer);++ AssignHexString(&bignum, "123456789ABCDEF");+ bignum.ShiftLeft(64);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("123456789ABCDEF0000000000000000", buffer);+ bignum.ShiftLeft(1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2468ACF13579BDE0000000000000000", buffer);+}+++TEST(AddUInt64) {+ char buffer[kBufferSize];+ Bignum bignum;+ AssignHexString(&bignum, "0");+ bignum.AddUInt64(0xA);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A", buffer);++ AssignHexString(&bignum, "1");+ bignum.AddUInt64(0xA);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("B", buffer);++ AssignHexString(&bignum, "1");+ bignum.AddUInt64(0x100);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("101", buffer);++ AssignHexString(&bignum, "1");+ bignum.AddUInt64(0xFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000", buffer);++ AssignHexString(&bignum, "FFFFFFF");+ bignum.AddUInt64(0x1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000", buffer);++ AssignHexString(&bignum, "10000000000000000000000000000000000000000000");+ bignum.AddUInt64(0xFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1000000000000000000000000000000000000000FFFF", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");+ bignum.AddUInt64(0x1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100000000000000000000000000000000000000000000", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ bignum.AddUInt64(1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000000000001", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ bignum.AddUInt64(0xFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1000000000000000000000FFFF", buffer);++ AssignHexString(&bignum, "0");+ bignum.AddUInt64(UINT64_2PART_C(0xA, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A00000000", buffer);++ AssignHexString(&bignum, "1");+ bignum.AddUInt64(UINT64_2PART_C(0xA, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A00000001", buffer);++ AssignHexString(&bignum, "1");+ bignum.AddUInt64(UINT64_2PART_C(0x100, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000001", buffer);++ AssignHexString(&bignum, "1");+ bignum.AddUInt64(UINT64_2PART_C(0xFFFF, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFF00000001", buffer);++ AssignHexString(&bignum, "FFFFFFF");+ bignum.AddUInt64(UINT64_2PART_C(0x1, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10FFFFFFF", buffer);++ AssignHexString(&bignum, "10000000000000000000000000000000000000000000");+ bignum.AddUInt64(UINT64_2PART_C(0xFFFF, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000000000000000000FFFF00000000", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");+ bignum.AddUInt64(UINT64_2PART_C(0x1, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1000000000000000000000000000000000000FFFFFFFF", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ bignum.AddUInt64(UINT64_2PART_C(0x1, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000100000000", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ bignum.AddUInt64(UINT64_2PART_C(0xFFFF, 00000000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000FFFF00000000", buffer);+}+++TEST(AddBignum) {+ char buffer[kBufferSize];+ Bignum bignum;+ Bignum other;++ AssignHexString(&other, "1");+ AssignHexString(&bignum, "0");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ AssignHexString(&bignum, "1");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2", buffer);++ AssignHexString(&bignum, "FFFFFFF");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFF");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100000000000000", buffer);++ AssignHexString(&bignum, "10000000000000000000000000000000000000000000");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000000000000000000000000000001", buffer);++ AssignHexString(&other, "1000000000000");++ AssignHexString(&bignum, "1");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1000000000001", buffer);++ AssignHexString(&bignum, "FFFFFFF");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100000FFFFFFF", buffer);++ AssignHexString(&bignum, "10000000000000000000000000000000000000000000");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000000000000000001000000000000", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1000000000000000000000000000000FFFFFFFFFFFF", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000001000000000000", buffer);++ other.ShiftLeft(64);+ // other == "10000000000000000000000000000"++ bignum.AssignUInt16(0x1);+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000000000000001", buffer);++ AssignHexString(&bignum, "FFFFFFF");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1000000000000000000000FFFFFFF", buffer);++ AssignHexString(&bignum, "10000000000000000000000000000000000000000000");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000010000000000000000000000000000", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ bignum.AddBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10010000000000000000000000000", buffer);+}+++TEST(SubtractBignum) {+ char buffer[kBufferSize];+ Bignum bignum;+ Bignum other;++ AssignHexString(&bignum, "1");+ AssignHexString(&other, "0");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ AssignHexString(&bignum, "2");+ AssignHexString(&other, "0");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2", buffer);++ AssignHexString(&bignum, "10000000");+ AssignHexString(&other, "1");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFF", buffer);++ AssignHexString(&bignum, "100000000000000");+ AssignHexString(&other, "1");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFFF", buffer);++ AssignHexString(&bignum, "10000000000000000000000000000000000000000001");+ AssignHexString(&other, "1");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000000000000000000000000000000", buffer);++ AssignHexString(&bignum, "1000000000001");+ AssignHexString(&other, "1000000000000");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ AssignHexString(&bignum, "100000FFFFFFF");+ AssignHexString(&other, "1000000000000");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFF", buffer);++ AssignHexString(&bignum, "10000000000000000000000000000001000000000000");+ AssignHexString(&other, "1000000000000");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000000000000000000000000000000", buffer);++ AssignHexString(&bignum, "1000000000000000000000000000000FFFFFFFFFFFF");+ AssignHexString(&other, "1000000000000");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ // "10 0000 0000 0000 0000 0000 0000"+ AssignHexString(&other, "1000000000000");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFF000000000000", buffer);++ AssignHexString(&other, "1000000000000");+ other.ShiftLeft(48);+ // other == "1000000000000000000000000"++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ // bignum == "10000000000000000000000000"+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("F000000000000000000000000", buffer);++ other.AssignUInt16(0x1);+ other.ShiftLeft(35);+ // other == "800000000"+ AssignHexString(&bignum, "FFFFFFF");+ bignum.ShiftLeft(60);+ // bignum = FFFFFFF000000000000000+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFEFFFFFF800000000", buffer);++ AssignHexString(&bignum, "10000000000000000000000000000000000000000000");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000000", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");+ bignum.SubtractBignum(other);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFF", buffer);+}+++TEST(MultiplyUInt32) {+ char buffer[kBufferSize];+ Bignum bignum;++ AssignHexString(&bignum, "0");+ bignum.MultiplyByUInt32(0x25);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("0", buffer);++ AssignHexString(&bignum, "2");+ bignum.MultiplyByUInt32(0x5);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A", buffer);++ AssignHexString(&bignum, "10000000");+ bignum.MultiplyByUInt32(0x9);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("90000000", buffer);++ AssignHexString(&bignum, "100000000000000");+ bignum.MultiplyByUInt32(0xFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFF00000000000000", buffer);++ AssignHexString(&bignum, "100000000000000");+ bignum.MultiplyByUInt32(0xFFFFFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFF00000000000000", buffer);++ AssignHexString(&bignum, "1234567ABCD");+ bignum.MultiplyByUInt32(0xFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("12333335552433", buffer);++ AssignHexString(&bignum, "1234567ABCD");+ bignum.MultiplyByUInt32(0xFFFFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("12345679998A985433", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");+ bignum.MultiplyByUInt32(0x2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1FFFFFFFFFFFFFFFE", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");+ bignum.MultiplyByUInt32(0x4);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("3FFFFFFFFFFFFFFFC", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");+ bignum.MultiplyByUInt32(0xF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("EFFFFFFFFFFFFFFF1", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");+ bignum.MultiplyByUInt32(0xFFFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFEFFFFFFFFFF000001", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ // "10 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt32(2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("20000000000000000000000000", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ // "10 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt32(0xF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("F0000000000000000000000000", buffer);++ bignum.AssignUInt16(0xFFFF);+ bignum.ShiftLeft(100);+ // "FFFF0 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt32(0xFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFE00010000000000000000000000000", buffer);++ bignum.AssignUInt16(0xFFFF);+ bignum.ShiftLeft(100);+ // "FFFF0 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt32(0xFFFFFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);++ bignum.AssignUInt16(0xFFFF);+ bignum.ShiftLeft(100);+ // "FFFF0 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt32(0xFFFFFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);++ AssignDecimalString(&bignum, "15611230384529777");+ bignum.MultiplyByUInt32(10000000);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("210EDD6D4CDD2580EE80", buffer);+}+++TEST(MultiplyUInt64) {+ char buffer[kBufferSize];+ Bignum bignum;++ AssignHexString(&bignum, "0");+ bignum.MultiplyByUInt64(0x25);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("0", buffer);++ AssignHexString(&bignum, "2");+ bignum.MultiplyByUInt64(0x5);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A", buffer);++ AssignHexString(&bignum, "10000000");+ bignum.MultiplyByUInt64(0x9);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("90000000", buffer);++ AssignHexString(&bignum, "100000000000000");+ bignum.MultiplyByUInt64(0xFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFF00000000000000", buffer);++ AssignHexString(&bignum, "100000000000000");+ bignum.MultiplyByUInt64(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFFFFF00000000000000", buffer);++ AssignHexString(&bignum, "1234567ABCD");+ bignum.MultiplyByUInt64(0xFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("12333335552433", buffer);++ AssignHexString(&bignum, "1234567ABCD");+ bignum.MultiplyByUInt64(UINT64_2PART_C(0xFF, FFFFFFFF));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1234567ABCBDCBA985433", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");+ bignum.MultiplyByUInt64(0x2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1FFFFFFFFFFFFFFFE", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");+ bignum.MultiplyByUInt64(0x4);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("3FFFFFFFFFFFFFFFC", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");+ bignum.MultiplyByUInt64(0xF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("EFFFFFFFFFFFFFFF1", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");+ bignum.MultiplyByUInt64(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFFFFE0000000000000001", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ // "10 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt64(2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("20000000000000000000000000", buffer);++ bignum.AssignUInt16(0x1);+ bignum.ShiftLeft(100);+ // "10 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt64(0xF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("F0000000000000000000000000", buffer);++ bignum.AssignUInt16(0xFFFF);+ bignum.ShiftLeft(100);+ // "FFFF0 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt64(0xFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFE00010000000000000000000000000", buffer);++ bignum.AssignUInt16(0xFFFF);+ bignum.ShiftLeft(100);+ // "FFFF0 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt64(0xFFFFFFFF);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);++ bignum.AssignUInt16(0xFFFF);+ bignum.ShiftLeft(100);+ // "FFFF0 0000 0000 0000 0000 0000 0000"+ bignum.MultiplyByUInt64(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFEFFFFFFFFFFFF00010000000000000000000000000", buffer);++ AssignDecimalString(&bignum, "15611230384529777");+ bignum.MultiplyByUInt64(UINT64_2PART_C(0x8ac72304, 89e80000));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1E10EE4B11D15A7F3DE7F3C7680000", buffer);+}+++TEST(MultiplyPowerOfTen) {+ char buffer[kBufferSize];+ Bignum bignum;++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("3034", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1E208", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(3);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("12D450", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(4);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("BC4B20", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(5);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("75AEF40", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(6);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("498D5880", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(7);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2DF857500", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(8);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1CBB369200", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(9);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("11F5021B400", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(10);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("B3921510800", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(11);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("703B4D2A5000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(12);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("4625103A72000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(13);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2BD72A24874000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(14);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1B667A56D488000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(15);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("11200C7644D50000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(16);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("AB407C9EB0520000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(17);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("6B084DE32E3340000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(18);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("42E530ADFCE0080000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(19);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("29CF3E6CBE0C0500000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(20);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1A218703F6C783200000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(21);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1054F4627A3CB1F400000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(22);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A3518BD8C65EF38800000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(23);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("6612F7677BFB5835000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(24);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("3FCBDAA0AD7D17212000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(25);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("27DF68A46C6E2E74B4000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(26);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("18EBA166C3C4DD08F08000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(27);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("F9344E03A5B0A259650000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(28);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("9BC0B0C2478E6577DF20000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(29);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("61586E796CB8FF6AEB740000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(30);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("3CD7450BE3F39FA2D32880000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(31);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("26068B276E7843C5C3F9500000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(50);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("149D1B4CFED03B23AB5F4E1196EF45C08000000000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(100);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("5827249F27165024FBC47DFCA9359BF316332D1B91ACEECF471FBAB06D9B2"+ "0000000000000000000000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(200);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("64C1F5C06C3816AFBF8DAFD5A3D756365BB0FD020E6F084E759C1F7C99E4F"+ "55B9ACC667CEC477EB958C2AEEB3C6C19BA35A1AD30B35C51EB72040920000"+ "0000000000000000000000000000000000000000000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(500);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("96741A625EB5D7C91039FEB5C5ACD6D9831EDA5B083D800E6019442C8C8223"+ "3EAFB3501FE2058062221E15121334928880827DEE1EC337A8B26489F3A40A"+ "CB440A2423734472D10BFCE886F41B3AF9F9503013D86D088929CA86EEB4D8"+ "B9C831D0BD53327B994A0326227CFD0ECBF2EB48B02387AAE2D4CCCDF1F1A1"+ "B8CC4F1FA2C56AD40D0E4DAA9C28CDBF0A549098EA13200000000000000000"+ "00000000000000000000000000000000000000000000000000000000000000"+ "0000000000000000000000000000000000000000000000", buffer);++ AssignDecimalString(&bignum, "1234");+ bignum.MultiplyByPowerOfTen(1000);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1258040F99B1CD1CC9819C676D413EA50E4A6A8F114BB0C65418C62D399B81"+ "6361466CA8E095193E1EE97173553597C96673AF67FAFE27A66E7EF2E5EF2E"+ "E3F5F5070CC17FE83BA53D40A66A666A02F9E00B0E11328D2224B8694C7372"+ "F3D536A0AD1985911BD361496F268E8B23112500EAF9B88A9BC67B2AB04D38"+ "7FEFACD00F5AF4F764F9ABC3ABCDE54612DE38CD90CB6647CA389EA0E86B16"+ "BF7A1F34086E05ADBE00BD1673BE00FAC4B34AF1091E8AD50BA675E0381440"+ "EA8E9D93E75D816BAB37C9844B1441C38FC65CF30ABB71B36433AF26DD97BD"+ "ABBA96C03B4919B8F3515B92826B85462833380DC193D79F69D20DD6038C99"+ "6114EF6C446F0BA28CC772ACBA58B81C04F8FFDE7B18C4E5A3ABC51E637FDF"+ "6E37FDFF04C940919390F4FF92000000000000000000000000000000000000"+ "00000000000000000000000000000000000000000000000000000000000000"+ "00000000000000000000000000000000000000000000000000000000000000"+ "00000000000000000000000000000000000000000000000000000000000000"+ "0000000000000000000000000000", buffer);++ Bignum bignum2;+ AssignHexString(&bignum2, "3DA774C07FB5DF54284D09C675A492165B830D5DAAEB2A7501"+ "DA17CF9DFA1CA2282269F92A25A97314296B717E3DCBB9FE17"+ "41A842FE2913F540F40796F2381155763502C58B15AF7A7F88"+ "6F744C9164FF409A28F7FA0C41F89ED79C1BE9F322C8578B97"+ "841F1CBAA17D901BE1230E3C00E1C643AF32638B5674E01FEA"+ "96FC90864E621B856A9E1CE56E6EB545B9C2F8F0CC10DDA88D"+ "CC6D282605F8DB67044F2DFD3695E7BA63877AE16701536AE6"+ "567C794D0BFE338DFBB42D92D4215AF3BB22BF0A8B283FDDC2"+ "C667A10958EA6D2");+ CHECK(bignum2.ToHexString(buffer, kBufferSize));+ CHECK_EQ("3DA774C07FB5DF54284D09C675A492165B830D5DAAEB2A7501"+ "DA17CF9DFA1CA2282269F92A25A97314296B717E3DCBB9FE17"+ "41A842FE2913F540F40796F2381155763502C58B15AF7A7F88"+ "6F744C9164FF409A28F7FA0C41F89ED79C1BE9F322C8578B97"+ "841F1CBAA17D901BE1230E3C00E1C643AF32638B5674E01FEA"+ "96FC90864E621B856A9E1CE56E6EB545B9C2F8F0CC10DDA88D"+ "CC6D282605F8DB67044F2DFD3695E7BA63877AE16701536AE6"+ "567C794D0BFE338DFBB42D92D4215AF3BB22BF0A8B283FDDC2"+ "C667A10958EA6D2", buffer);++ bignum.AssignBignum(bignum2);+ bignum.MultiplyByPowerOfTen(1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2688A8F84FD1AB949930261C0986DB4DF931E85A8AD2FA8921284EE1C2BC51"+ "E55915823BBA5789E7EC99E326EEE69F543ECE890929DED9AC79489884BE57"+ "630AD569E121BB76ED8DAC8FB545A8AFDADF1F8860599AFC47A93B6346C191"+ "7237F5BD36B73EB29371F4A4EE7A116CB5E8E5808D1BEA4D7F7E3716090C13"+ "F29E5DDA53F0FD513362A2D20F6505314B9419DB967F8A8A89589FC43917C3"+ "BB892062B17CBE421DB0D47E34ACCCE060D422CFF60DCBD0277EE038BD509C"+ "7BC494D8D854F5B76696F927EA99BC00C4A5D7928434", buffer);++ bignum.AssignBignum(bignum2);+ bignum.MultiplyByPowerOfTen(2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1815699B31E30B3CDFBE17D185F44910BBBF313896C3DC95B4B9314D19B5B32"+ "F57AD71655476B630F3E02DF855502394A74115A5BA2B480BCBCD5F52F6F69D"+ "E6C5622CB5152A54788BD9D14B896DE8CB73B53C3800DDACC9C51E0C38FAE76"+ "2F9964232872F9C2738E7150C4AE3F1B18F70583172706FAEE26DC5A78C77A2"+ "FAA874769E52C01DA5C3499F233ECF3C90293E0FB69695D763DAA3AEDA5535B"+ "43DAEEDF6E9528E84CEE0EC000C3C8495C1F9C89F6218AF4C23765261CD5ADD"+ "0787351992A01E5BB8F2A015807AE7A6BB92A08", buffer);++ bignum.AssignBignum(bignum2);+ bignum.MultiplyByPowerOfTen(5);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("5E13A4863ADEE3E5C9FE8D0A73423D695D62D8450CED15A8C9F368952C6DC3"+ "F0EE7D82F3D1EFB7AF38A3B3920D410AFCAD563C8F5F39116E141A3C5C14B3"+ "58CD73077EA35AAD59F6E24AD98F10D5555ABBFBF33AC361EAF429FD5FBE94"+ "17DA9EF2F2956011F9F93646AA38048A681D984ED88127073443247CCC167C"+ "B354A32206EF5A733E73CF82D795A1AD598493211A6D613C39515E0E0F6304"+ "DCD9C810F3518C7F6A7CB6C81E99E02FCC65E8FDB7B7AE97306CC16A8631CE"+ "0A2AEF6568276BE4C176964A73C153FDE018E34CB4C2F40", buffer);++ bignum.AssignBignum(bignum2);+ bignum.MultiplyByPowerOfTen(10);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("8F8CB8EB51945A7E815809F6121EF2F4E61EF3405CD9432CAD2709749EEAFD"+ "1B81E843F14A3667A7BDCCC9E0BB795F63CDFDB62844AC7438976C885A0116"+ "29607DA54F9C023CC366570B7637ED0F855D931752038A614922D0923E382C"+ "B8E5F6C975672DB76E0DE471937BB9EDB11E28874F1C122D5E1EF38CECE9D0"+ "0723056BCBD4F964192B76830634B1D322B7EB0062F3267E84F5C824343A77"+ "4B7DCEE6DD464F01EBDC8C671BB18BB4EF4300A42474A6C77243F2A12B03BF"+ "0443C38A1C0D2701EDB393135AE0DEC94211F9D4EB51F990800", buffer);++ bignum.AssignBignum(bignum2);+ bignum.MultiplyByPowerOfTen(50);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("107A8BE345E24407372FC1DE442CBA696BC23C4FFD5B4BDFD9E5C39559815"+ "86628CF8472D2D589F2FC2BAD6E0816EC72CBF85CCA663D8A1EC6C51076D8"+ "2D247E6C26811B7EC4D4300FB1F91028DCB7B2C4E7A60C151161AA7E65E79"+ "B40917B12B2B5FBE7745984D4E8EFA31F9AE6062427B068B144A9CB155873"+ "E7C0C9F0115E5AC72DC5A73C4796DB970BF9205AB8C77A6996EB1B417F9D1"+ "6232431E6313C392203601B9C22CC10DDA88DCC6D282605F8DB67044F2DFD"+ "3695E7BA63877AE16701536AE6567C794D0BFE338DFBB42D924CF964BD2C0"+ "F586E03A2FCD35A408000000000000", buffer);++ bignum.AssignBignum(bignum2);+ bignum.MultiplyByPowerOfTen(100);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("46784A90ACD0ED3E7759CC585FB32D36EB6034A6F78D92604E3BAA5ED3D8B"+ "6E60E854439BE448897FB4B7EA5A3D873AA0FCB3CFFD80D0530880E45F511"+ "722A50CE7E058B5A6F5464DB7500E34984EE3202A9441F44FA1554C0CEA96"+ "B438A36F25E7C9D56D71AE2CD313EC37534DA299AC0854FC48591A7CF3171"+ "31265AA4AE62DE32344CE7BEEEF894AE686A2DAAFE5D6D9A10971FFD9C064"+ "5079B209E1048F58B5192D41D84336AC4C8C489EEF00939CFC9D55C122036"+ "01B9C22CC10DDA88DCC6D282605F8DB67044F2DFD3695E7BA3F67B96D3A32"+ "E11FB5561B68744C4035B0800DC166D49D98E3FD1D5BB2000000000000000"+ "0000000000", buffer);++ bignum.AssignBignum(bignum2);+ bignum.MultiplyByPowerOfTen(200);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("508BD351221DF139D72D88CDC0416845A53EE2D0E6B98352509A9AC312F8C"+ "6CB1A144889416201E0B6CE66EA3EBE259B5FD79ECFC1FD77963CE516CC7E"+ "2FE73D4B5B710C19F6BCB092C7A2FD76286543B8DBD2C596DFF2C896720BA"+ "DFF7BC9C366ACEA3A880AEC287C5E6207DF2739B5326FC19D773BD830B109"+ "ED36C7086544BF8FDB9D4B73719C2B5BC2F571A5937EC46876CD428281F6B"+ "F287E1E07F25C1B1D46BC37324FF657A8B2E0071DB83B86123CA34004F406"+ "001082D7945E90C6E8C9A9FEC2B44BE0DDA46E9F52B152E4D1336D2FCFBC9"+ "96E30CA0082256737365158FE36482AA7EB9DAF2AB128F10E7551A3CD5BE6"+ "0A922F3A7D5EED38B634A7EC95BCF7021BA6820A292000000000000000000"+ "00000000000000000000000000000000", buffer);++ bignum.AssignBignum(bignum2);+ bignum.MultiplyByPowerOfTen(500);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("7845F900E475B5086885BAAAE67C8E85185ACFE4633727F82A4B06B5582AC"+ "BE933C53357DA0C98C20C5AC900C4D76A97247DF52B79F48F9E35840FB715"+ "D392CE303E22622B0CF82D9471B398457DD3196F639CEE8BBD2C146873841"+ "F0699E6C41F04FC7A54B48CEB995BEB6F50FE81DE9D87A8D7F849CC523553"+ "7B7BBBC1C7CAAFF6E9650BE03B308C6D31012AEF9580F70D3EE2083ADE126"+ "8940FA7D6308E239775DFD2F8C97FF7EBD525DAFA6512216F7047A62A93DC"+ "38A0165BDC67E250DCC96A0181DE935A70B38704DC71819F02FC5261FF7E1"+ "E5F11907678B0A3E519FF4C10A867B0C26CE02BE6960BA8621A87303C101C"+ "3F88798BB9F7739655946F8B5744E6B1EAF10B0C5621330F0079209033C69"+ "20DE2E2C8D324F0624463735D482BF291926C22A910F5B80FA25170B6B57D"+ "8D5928C7BCA3FE87461275F69BD5A1B83181DAAF43E05FC3C72C4E93111B6"+ "6205EBF49B28FEDFB7E7526CBDA658A332000000000000000000000000000"+ "0000000000000000000000000000000000000000000000000000000000000"+ "0000000000000000000000000000000000000", buffer);+}+++TEST(DivideModuloIntBignum) {+ char buffer[kBufferSize];+ Bignum bignum;+ Bignum other;+ Bignum third;++ bignum.AssignUInt16(10);+ other.AssignUInt16(2);+ CHECK_EQ(5, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("0", buffer);++ bignum.AssignUInt16(10);+ bignum.ShiftLeft(500);+ other.AssignUInt16(2);+ other.ShiftLeft(500);+ CHECK_EQ(5, bignum.DivideModuloIntBignum(other));+ CHECK_EQ("0", buffer);++ bignum.AssignUInt16(11);+ other.AssignUInt16(2);+ CHECK_EQ(5, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignUInt16(10);+ bignum.ShiftLeft(500);+ other.AssignUInt16(1);+ bignum.AddBignum(other);+ other.AssignUInt16(2);+ other.ShiftLeft(500);+ CHECK_EQ(5, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignUInt16(10);+ bignum.ShiftLeft(500);+ other.AssignBignum(bignum);+ bignum.MultiplyByUInt32(0x1234);+ third.AssignUInt16(0xFFF);+ bignum.AddBignum(third);+ CHECK_EQ(0x1234, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFF", buffer);++ bignum.AssignUInt16(10);+ AssignHexString(&other, "1234567890");+ CHECK_EQ(0, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A", buffer);++ AssignHexString(&bignum, "12345678");+ AssignHexString(&other, "3789012");+ CHECK_EQ(5, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("D9861E", buffer);++ AssignHexString(&bignum, "70000001");+ AssignHexString(&other, "1FFFFFFF");+ CHECK_EQ(3, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000004", buffer);++ AssignHexString(&bignum, "28000000");+ AssignHexString(&other, "12A05F20");+ CHECK_EQ(2, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2BF41C0", buffer);++ bignum.AssignUInt16(10);+ bignum.ShiftLeft(500);+ other.AssignBignum(bignum);+ bignum.MultiplyByUInt32(0x1234);+ third.AssignUInt16(0xFFF);+ other.SubtractBignum(third);+ CHECK_EQ(0x1234, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1232DCC", buffer);+ CHECK_EQ(0, bignum.DivideModuloIntBignum(other));+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1232DCC", buffer);+}+++TEST(Compare) {+ Bignum bignum1;+ Bignum bignum2;+ bignum1.AssignUInt16(1);+ bignum2.AssignUInt16(1);+ CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));+ CHECK(Bignum::Equal(bignum1, bignum2));+ CHECK(Bignum::LessEqual(bignum1, bignum2));+ CHECK(!Bignum::Less(bignum1, bignum2));++ bignum1.AssignUInt16(0);+ bignum2.AssignUInt16(1);+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));+ CHECK(!Bignum::Equal(bignum1, bignum2));+ CHECK(!Bignum::Equal(bignum2, bignum1));+ CHECK(Bignum::LessEqual(bignum1, bignum2));+ CHECK(!Bignum::LessEqual(bignum2, bignum1));+ CHECK(Bignum::Less(bignum1, bignum2));+ CHECK(!Bignum::Less(bignum2, bignum1));++ AssignHexString(&bignum1, "1234567890ABCDEF12345");+ AssignHexString(&bignum2, "1234567890ABCDEF12345");+ CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));++ AssignHexString(&bignum1, "1234567890ABCDEF12345");+ AssignHexString(&bignum2, "1234567890ABCDEF12346");+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));++ AssignHexString(&bignum1, "1234567890ABCDEF12345");+ bignum1.ShiftLeft(500);+ AssignHexString(&bignum2, "1234567890ABCDEF12345");+ bignum2.ShiftLeft(500);+ CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));++ AssignHexString(&bignum1, "1234567890ABCDEF12345");+ bignum1.ShiftLeft(500);+ AssignHexString(&bignum2, "1234567890ABCDEF12346");+ bignum2.ShiftLeft(500);+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));++ bignum1.AssignUInt16(1);+ bignum1.ShiftLeft(64);+ AssignHexString(&bignum2, "10000000000000000");+ CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(0, Bignum::Compare(bignum2, bignum1));++ bignum1.AssignUInt16(1);+ bignum1.ShiftLeft(64);+ AssignHexString(&bignum2, "10000000000000001");+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));++ bignum1.AssignUInt16(1);+ bignum1.ShiftLeft(96);+ AssignHexString(&bignum2, "10000000000000001");+ bignum2.ShiftLeft(32);+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));++ AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");+ bignum2.AssignUInt16(1);+ bignum2.ShiftLeft(64);+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));++ AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");+ bignum1.ShiftLeft(32);+ bignum2.AssignUInt16(1);+ bignum2.ShiftLeft(96);+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));++ AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");+ bignum1.ShiftLeft(32);+ bignum2.AssignUInt16(1);+ bignum2.ShiftLeft(95);+ CHECK_EQ(+1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(-1, Bignum::Compare(bignum2, bignum1));++ AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");+ bignum1.ShiftLeft(32);+ bignum2.AssignUInt16(1);+ bignum2.ShiftLeft(100);+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));++ AssignHexString(&bignum1, "100000000000000");+ bignum2.AssignUInt16(1);+ bignum2.ShiftLeft(14*4);+ CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(0, Bignum::Compare(bignum2, bignum1));++ AssignHexString(&bignum1, "100000000000001");+ bignum2.AssignUInt16(1);+ bignum2.ShiftLeft(14*4);+ CHECK_EQ(+1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(-1, Bignum::Compare(bignum2, bignum1));++ AssignHexString(&bignum1, "200000000000000");+ bignum2.AssignUInt16(3);+ bignum2.ShiftLeft(14*4);+ CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));+ CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));+}+++TEST(PlusCompare) {+ Bignum a;+ Bignum b;+ Bignum c;+ a.AssignUInt16(1);+ b.AssignUInt16(0);+ c.AssignUInt16(1);+ CHECK_EQ(0, Bignum::PlusCompare(a, b, c));+ CHECK(Bignum::PlusEqual(a, b, c));+ CHECK(Bignum::PlusLessEqual(a, b, c));+ CHECK(!Bignum::PlusLess(a, b, c));++ a.AssignUInt16(0);+ b.AssignUInt16(0);+ c.AssignUInt16(1);+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));+ CHECK_EQ(+1, Bignum::PlusCompare(c, b, a));+ CHECK(!Bignum::PlusEqual(a, b, c));+ CHECK(!Bignum::PlusEqual(c, b, a));+ CHECK(Bignum::PlusLessEqual(a, b, c));+ CHECK(!Bignum::PlusLessEqual(c, b, a));+ CHECK(Bignum::PlusLess(a, b, c));+ CHECK(!Bignum::PlusLess(c, b, a));++ AssignHexString(&a, "1234567890ABCDEF12345");+ b.AssignUInt16(1);+ AssignHexString(&c, "1234567890ABCDEF12345");+ CHECK_EQ(+1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890ABCDEF12344");+ b.AssignUInt16(1);+ AssignHexString(&c, "1234567890ABCDEF12345");+ CHECK_EQ(0, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4);+ AssignHexString(&b, "ABCDEF12345");+ AssignHexString(&c, "1234567890ABCDEF12345");+ CHECK_EQ(0, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4);+ AssignHexString(&b, "ABCDEF12344");+ AssignHexString(&c, "1234567890ABCDEF12345");+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4);+ AssignHexString(&b, "ABCDEF12346");+ AssignHexString(&c, "1234567890ABCDEF12345");+ CHECK_EQ(1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567891");+ a.ShiftLeft(11*4);+ AssignHexString(&b, "ABCDEF12345");+ AssignHexString(&c, "1234567890ABCDEF12345");+ CHECK_EQ(1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567889");+ a.ShiftLeft(11*4);+ AssignHexString(&b, "ABCDEF12345");+ AssignHexString(&c, "1234567890ABCDEF12345");+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF12345");+ c.ShiftLeft(32);+ CHECK_EQ(0, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12344");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF12345");+ c.ShiftLeft(32);+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12346");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF12345");+ c.ShiftLeft(32);+ CHECK_EQ(1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567891");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF12345");+ c.ShiftLeft(32);+ CHECK_EQ(1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567889");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF12345");+ c.ShiftLeft(32);+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF1234500000000");+ CHECK_EQ(0, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12344");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF1234500000000");+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12346");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF1234500000000");+ CHECK_EQ(1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567891");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF1234500000000");+ CHECK_EQ(1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567889");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ b.ShiftLeft(32);+ AssignHexString(&c, "1234567890ABCDEF1234500000000");+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ AssignHexString(&c, "123456789000000000ABCDEF12345");+ CHECK_EQ(0, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12346");+ AssignHexString(&c, "123456789000000000ABCDEF12345");+ CHECK_EQ(1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12344");+ AssignHexString(&c, "123456789000000000ABCDEF12345");+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ b.ShiftLeft(16);+ AssignHexString(&c, "12345678900000ABCDEF123450000");+ CHECK_EQ(0, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12344");+ b.ShiftLeft(16);+ AssignHexString(&c, "12345678900000ABCDEF123450000");+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12345");+ b.ShiftLeft(16);+ AssignHexString(&c, "12345678900000ABCDEF123450001");+ CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));++ AssignHexString(&a, "1234567890");+ a.ShiftLeft(11*4 + 32);+ AssignHexString(&b, "ABCDEF12346");+ b.ShiftLeft(16);+ AssignHexString(&c, "12345678900000ABCDEF123450000");+ CHECK_EQ(+1, Bignum::PlusCompare(a, b, c));+}+++TEST(Square) {+ Bignum bignum;+ char buffer[kBufferSize];++ bignum.AssignUInt16(1);+ bignum.Square();+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignUInt16(2);+ bignum.Square();+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("4", buffer);++ bignum.AssignUInt16(10);+ bignum.Square();+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("64", buffer);++ AssignHexString(&bignum, "FFFFFFF");+ bignum.Square();+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFE0000001", buffer);++ AssignHexString(&bignum, "FFFFFFFFFFFFFF");+ bignum.Square();+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FFFFFFFFFFFFFE00000000000001", buffer);+}+++TEST(AssignPowerUInt16) {+ Bignum bignum;+ char buffer[kBufferSize];++ bignum.AssignPowerUInt16(1, 0);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignPowerUInt16(1, 1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignPowerUInt16(1, 2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignPowerUInt16(2, 0);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignPowerUInt16(2, 1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2", buffer);++ bignum.AssignPowerUInt16(2, 2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("4", buffer);++ bignum.AssignPowerUInt16(16, 1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10", buffer);++ bignum.AssignPowerUInt16(16, 2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100", buffer);++ bignum.AssignPowerUInt16(16, 5);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100000", buffer);++ bignum.AssignPowerUInt16(16, 8);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("100000000", buffer);++ bignum.AssignPowerUInt16(16, 16);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000", buffer);++ bignum.AssignPowerUInt16(16, 30);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1000000000000000000000000000000", buffer);++ bignum.AssignPowerUInt16(10, 0);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignPowerUInt16(10, 1);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("A", buffer);++ bignum.AssignPowerUInt16(10, 2);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("64", buffer);++ bignum.AssignPowerUInt16(10, 5);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("186A0", buffer);++ bignum.AssignPowerUInt16(10, 8);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("5F5E100", buffer);++ bignum.AssignPowerUInt16(10, 16);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("2386F26FC10000", buffer);++ bignum.AssignPowerUInt16(10, 30);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("C9F2C9CD04674EDEA40000000", buffer);++ bignum.AssignPowerUInt16(10, 31);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("7E37BE2022C0914B2680000000", buffer);++ bignum.AssignPowerUInt16(2, 0);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignPowerUInt16(2, 100);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("10000000000000000000000000", buffer);++ bignum.AssignPowerUInt16(17, 0);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1", buffer);++ bignum.AssignPowerUInt16(17, 99);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("1942BB9853FAD924A3D4DD92B89B940E0207BEF05DB9C26BC1B757"+ "80BE0C5A2C2990E02A681224F34ED68558CE4C6E33760931",+ buffer);++ bignum.AssignPowerUInt16(0xFFFF, 99);+ CHECK(bignum.ToHexString(buffer, kBufferSize));+ CHECK_EQ("FF9D12F09B886C54E77E7439C7D2DED2D34F669654C0C2B6B8C288250"+ "5A2211D0E3DC9A61831349EAE674B11D56E3049D7BD79DAAD6C9FA2BA"+ "528E3A794299F2EE9146A324DAFE3E88967A0358233B543E233E575B9"+ "DD4E3AA7942146426C328FF55BFD5C45E0901B1629260AF9AE2F310C5"+ "50959FAF305C30116D537D80CF6EBDBC15C5694062AF1AC3D956D0A41"+ "B7E1B79FF11E21D83387A1CE1F5882B31E4B5D8DE415BDBE6854466DF"+ "343362267A7E8833119D31D02E18DB5B0E8F6A64B0ED0D0062FFFF",+ buffer);+}
+ double-conversion/test/cctest/test-conversions.cc view
@@ -0,0 +1,3039 @@+// Copyright 2010 the V8 project authors. All rights reserved.++#include <string.h>++#include "cctest.h"+#include "double.h"+#include "double-conversion.h"+#include "utils.h"++// DoubleToString is already tested in test-dtoa.cc.++using namespace double_conversion;+++TEST(DoubleToShortest) {+ const int kBufferSize = 128;+ char buffer[kBufferSize];+ StringBuilder builder(buffer, kBufferSize);+ int flags = DoubleToStringConverter::UNIQUE_ZERO |+ DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;+ DoubleToStringConverter dc(flags, NULL, NULL, 'e', -6, 21, 0, 0);++ CHECK(dc.ToShortest(0.0, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(12345.0, &builder));+ CHECK_EQ("12345", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(12345e23, &builder));+ CHECK_EQ("1.2345e+27", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(1e21, &builder));+ CHECK_EQ("1e+21", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(1e20, &builder));+ CHECK_EQ("100000000000000000000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(111111111111111111111.0, &builder));+ CHECK_EQ("111111111111111110000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(1111111111111111111111.0, &builder));+ CHECK_EQ("1.1111111111111111e+21", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(11111111111111111111111.0, &builder));+ CHECK_EQ("1.1111111111111111e+22", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.00001, &builder));+ CHECK_EQ("-0.00001", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.000001, &builder));+ CHECK_EQ("-0.000001", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.0000001, &builder));+ CHECK_EQ("-1e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.0, &builder));+ CHECK_EQ("0", builder.Finalize());++ flags = DoubleToStringConverter::NO_FLAGS;+ DoubleToStringConverter dc2(flags, NULL, NULL, 'e', -1, 1, 0, 0);+ builder.Reset();+ CHECK(dc2.ToShortest(0.1, &builder));+ CHECK_EQ("0.1", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToShortest(0.01, &builder));+ CHECK_EQ("1e-2", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToShortest(1.0, &builder));+ CHECK_EQ("1", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToShortest(10.0, &builder));+ CHECK_EQ("1e1", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToShortest(-0.0, &builder));+ CHECK_EQ("-0", builder.Finalize());++ flags = DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |+ DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT;+ DoubleToStringConverter dc3(flags, NULL, NULL, 'E', -5, 5, 0, 0);++ builder.Reset();+ CHECK(dc3.ToShortest(0.1, &builder));+ CHECK_EQ("0.1", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToShortest(1.0, &builder));+ CHECK_EQ("1.0", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToShortest(10000.0, &builder));+ CHECK_EQ("10000.0", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToShortest(100000.0, &builder));+ CHECK_EQ("1E5", builder.Finalize());++ // Test the examples in the comments of ToShortest.+ flags = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;+ DoubleToStringConverter dc4(flags, NULL, NULL, 'e', -6, 21, 0, 0);++ builder.Reset();+ CHECK(dc4.ToShortest(0.000001, &builder));+ CHECK_EQ("0.000001", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToShortest(0.0000001, &builder));+ CHECK_EQ("1e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToShortest(111111111111111111111.0, &builder));+ CHECK_EQ("111111111111111110000", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToShortest(100000000000000000000.0, &builder));+ CHECK_EQ("100000000000000000000", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToShortest(1111111111111111111111.0, &builder));+ CHECK_EQ("1.1111111111111111e+21", builder.Finalize());++ // Test special value handling.+ DoubleToStringConverter dc5(flags, NULL, NULL, 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(!dc5.ToShortest(Double::Infinity(), &builder));++ builder.Reset();+ CHECK(!dc5.ToShortest(-Double::Infinity(), &builder));++ builder.Reset();+ CHECK(!dc5.ToShortest(Double::NaN(), &builder));++ builder.Reset();+ CHECK(!dc5.ToShortest(-Double::NaN(), &builder));++ DoubleToStringConverter dc6(flags, "Infinity", "NaN", 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(dc6.ToShortest(Double::Infinity(), &builder));+ CHECK_EQ("Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc6.ToShortest(-Double::Infinity(), &builder));+ CHECK_EQ("-Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc6.ToShortest(Double::NaN(), &builder));+ CHECK_EQ("NaN", builder.Finalize());++ builder.Reset();+ CHECK(dc6.ToShortest(-Double::NaN(), &builder));+ CHECK_EQ("NaN", builder.Finalize());+}+++TEST(DoubleToFixed) {+ const int kBufferSize = 128;+ char buffer[kBufferSize];+ StringBuilder builder(buffer, kBufferSize);+ int flags = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |+ DoubleToStringConverter::UNIQUE_ZERO;+ DoubleToStringConverter dc(flags, "Infinity", "NaN", 'e',+ 0, 0, 0, 0); // Padding zeroes.++ CHECK(dc.ToFixed(0.0, 0, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.0, 0, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.0, 1, &builder));+ CHECK_EQ("0.0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.0, 1, &builder));+ CHECK_EQ("0.0", builder.Finalize());++ ASSERT(DoubleToStringConverter::kMaxFixedDigitsBeforePoint == 60);+ ASSERT(DoubleToStringConverter::kMaxFixedDigitsAfterPoint == 60);+ builder.Reset();+ CHECK(dc.ToFixed(+ 0.0, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder));+ CHECK_EQ("0.000000000000000000000000000000000000000000000000000000000000",+ builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(+ 9e59, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder));+ CHECK_EQ("899999999999999918767229449717619953810131273674690656206848."+ "000000000000000000000000000000000000000000000000000000000000",+ builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(+ -9e59, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder));+ CHECK_EQ("-899999999999999918767229449717619953810131273674690656206848."+ "000000000000000000000000000000000000000000000000000000000000",+ builder.Finalize());++ builder.Reset();+ CHECK(!dc.ToFixed(+ 1e60, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder));+ CHECK_EQ(0, builder.position());++ builder.Reset();+ CHECK(!dc.ToFixed(+ 9e59, DoubleToStringConverter::kMaxFixedDigitsAfterPoint + 1, &builder));+ CHECK_EQ(0, builder.position());++ builder.Reset();+ CHECK(dc.ToFixed(3.0, 0, &builder));+ CHECK_EQ("3", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(3.23, 1, &builder));+ CHECK_EQ("3.2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(3.23, 3, &builder));+ CHECK_EQ("3.230", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.0323, 2, &builder));+ CHECK_EQ("0.03", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.0373, 2, &builder));+ CHECK_EQ("0.04", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.0000373, 2, &builder));+ CHECK_EQ("0.00", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(1.5, 0, &builder));+ CHECK_EQ("2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(2.5, 0, &builder));+ CHECK_EQ("3", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(3.5, 0, &builder));+ CHECK_EQ("4", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.15, 1, &builder));+ CHECK_EQ("0.1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.25, 1, &builder));+ CHECK_EQ("0.3", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.35, 1, &builder));+ CHECK_EQ("0.3", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.45, 1, &builder));+ CHECK_EQ("0.5", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.55, 1, &builder));+ CHECK_EQ("0.6", builder.Finalize());++ // Test positive/negative zeroes.+ int flags2 = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;+ DoubleToStringConverter dc2(flags2, "Infinity", "NaN", 'e',+ 0, 0, 0, 0); // Padding zeroes.+ builder.Reset();+ CHECK(dc2.ToFixed(0.0, 1, &builder));+ CHECK_EQ("0.0", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToFixed(-0.0, 1, &builder));+ CHECK_EQ("-0.0", builder.Finalize());++ // Verify the trailing dot is emitted.+ int flags3 = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |+ DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT;+ DoubleToStringConverter dc3(flags3, "Infinity", "NaN", 'e',+ 0, 0, 0, 0); // Padding zeroes.+ builder.Reset();+ CHECK(dc3.ToFixed(0.0, 0, &builder));+ CHECK_EQ("0.", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToFixed(-0.0, 0, &builder));+ CHECK_EQ("-0.", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToFixed(1.0, 0, &builder));+ CHECK_EQ("1.", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToFixed(-1.0, 0, &builder));+ CHECK_EQ("-1.", builder.Finalize());++ // Verify no trailing zero is emitted, even if the configuration is set.+ // The given parameter takes precedence.+ int flags4 = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |+ DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |+ DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT;+ DoubleToStringConverter dc4(flags4, "Infinity", "NaN", 'e',+ 0, 0, 0, 0); // Padding zeroes.+ builder.Reset();+ CHECK(dc4.ToFixed(0.0, 0, &builder));+ CHECK_EQ("0.0", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToFixed(-0.0, 0, &builder));+ CHECK_EQ("-0.0", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToFixed(1.0, 0, &builder));+ CHECK_EQ("1.0", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToFixed(-1.0, 0, &builder));+ CHECK_EQ("-1.0", builder.Finalize());++ // Test the examples in the comments of ToFixed.+ flags = DoubleToStringConverter::NO_FLAGS;+ DoubleToStringConverter dc5(flags, NULL, NULL, 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(dc5.ToFixed(3.12, 1, &builder));+ CHECK_EQ("3.1", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(3.1415, 3, &builder));+ CHECK_EQ("3.142", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(1234.56789, 4, &builder));+ CHECK_EQ("1234.5679", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(1.23, 5, &builder));+ CHECK_EQ("1.23000", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(0.1, 4, &builder));+ CHECK_EQ("0.1000", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(1e30, 2, &builder));+ CHECK_EQ("1000000000000000019884624838656.00", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(0.1, 30, &builder));+ CHECK_EQ("0.100000000000000005551115123126", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(0.1, 17, &builder));+ CHECK_EQ("0.10000000000000001", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(123.45, 0, &builder));+ CHECK_EQ("123", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToFixed(0.678, 0, &builder));+ CHECK_EQ("1", builder.Finalize());++ flags = DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT;+ DoubleToStringConverter dc6(flags, NULL, NULL, 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(dc6.ToFixed(123.45, 0, &builder));+ CHECK_EQ("123.", builder.Finalize());++ builder.Reset();+ CHECK(dc6.ToFixed(0.678, 0, &builder));+ CHECK_EQ("1.", builder.Finalize());++ flags = DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |+ DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT;+ DoubleToStringConverter dc7(flags, NULL, NULL, 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(dc7.ToFixed(123.45, 0, &builder));+ CHECK_EQ("123.0", builder.Finalize());++ builder.Reset();+ CHECK(dc7.ToFixed(0.678, 0, &builder));+ CHECK_EQ("1.0", builder.Finalize());++ // Test special value handling.+ DoubleToStringConverter dc8(flags, NULL, NULL, 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(!dc8.ToFixed(Double::Infinity(), 1, &builder));++ builder.Reset();+ CHECK(!dc8.ToFixed(-Double::Infinity(), 1, &builder));++ builder.Reset();+ CHECK(!dc8.ToFixed(Double::NaN(), 1, &builder));++ builder.Reset();+ CHECK(!dc8.ToFixed(-Double::NaN(), 1, &builder));++ DoubleToStringConverter dc9(flags, "Infinity", "NaN", 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(dc9.ToFixed(Double::Infinity(), 1, &builder));+ CHECK_EQ("Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc9.ToFixed(-Double::Infinity(), 1, &builder));+ CHECK_EQ("-Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc9.ToFixed(Double::NaN(), 1, &builder));+ CHECK_EQ("NaN", builder.Finalize());++ builder.Reset();+ CHECK(dc9.ToFixed(-Double::NaN(), 1, &builder));+ CHECK_EQ("NaN", builder.Finalize());+}+++TEST(DoubleToExponential) {+ const int kBufferSize = 256;+ char buffer[kBufferSize];+ int flags = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |+ DoubleToStringConverter::UNIQUE_ZERO;+ StringBuilder builder(buffer, kBufferSize);+ DoubleToStringConverter dc(flags, "Infinity", "NaN", 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(dc.ToExponential(0.0, 5, &builder));+ CHECK_EQ("0.00000e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.0, 0, &builder));+ CHECK_EQ("0e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.0, 1, &builder));+ CHECK_EQ("0.0e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.123456, 5, &builder));+ CHECK_EQ("1.23456e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(1.2, 1, &builder));+ CHECK_EQ("1.2e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.0, 1, &builder));+ CHECK_EQ("0.0e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.0, 2, &builder));+ CHECK_EQ("0.00e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.0, 2, &builder));+ CHECK_EQ("0.00e+0", builder.Finalize());++ ASSERT(DoubleToStringConverter::kMaxExponentialDigits == 120);+ builder.Reset();+ CHECK(dc.ToExponential(+ 0.0, DoubleToStringConverter::kMaxExponentialDigits, &builder));+ CHECK_EQ("0.00000000000000000000000000000000000000000000000000000000000"+ "0000000000000000000000000000000000000000000000000000000000000e+0",+ builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(+ 9e59, DoubleToStringConverter::kMaxExponentialDigits, &builder));+ CHECK_EQ("8.99999999999999918767229449717619953810131273674690656206848"+ "0000000000000000000000000000000000000000000000000000000000000e+59",+ builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(+ -9e59, DoubleToStringConverter::kMaxExponentialDigits, &builder));+ CHECK_EQ("-8.99999999999999918767229449717619953810131273674690656206848"+ "0000000000000000000000000000000000000000000000000000000000000e+59",+ builder.Finalize());++ const double max_double = 1.7976931348623157e308;+ builder.Reset();+ CHECK(dc.ToExponential(+ max_double, DoubleToStringConverter::kMaxExponentialDigits, &builder));+ CHECK_EQ("1.79769313486231570814527423731704356798070567525844996598917"+ "4768031572607800285387605895586327668781715404589535143824642e+308",+ builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.000001, 2, &builder));+ CHECK_EQ("1.00e-6", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.0000001, 2, &builder));+ CHECK_EQ("1.00e-7", builder.Finalize());++ // Test the examples in the comments of ToExponential.+ flags = DoubleToStringConverter::NO_FLAGS;+ DoubleToStringConverter dc2(flags, "Infinity", "NaN", 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(dc2.ToExponential(3.12, 1, &builder));+ CHECK_EQ("3.1e0", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(5.0, 3, &builder));+ CHECK_EQ("5.000e0", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(0.001, 2, &builder));+ CHECK_EQ("1.00e-3", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(3.1415, -1, &builder));+ CHECK_EQ("3.1415e0", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(3.1415, 4, &builder));+ CHECK_EQ("3.1415e0", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(3.1415, 3, &builder));+ CHECK_EQ("3.142e0", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(123456789000000, 3, &builder));+ CHECK_EQ("1.235e14", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(1000000000000000019884624838656.0, -1, &builder));+ CHECK_EQ("1e30", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(1000000000000000019884624838656.0, 32, &builder));+ CHECK_EQ("1.00000000000000001988462483865600e30", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToExponential(1234, 0, &builder));+ CHECK_EQ("1e3", builder.Finalize());++ // Test special value handling.+ DoubleToStringConverter dc3(flags, NULL, NULL, 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(!dc3.ToExponential(Double::Infinity(), 1, &builder));++ builder.Reset();+ CHECK(!dc3.ToExponential(-Double::Infinity(), 1, &builder));++ builder.Reset();+ CHECK(!dc3.ToExponential(Double::NaN(), 1, &builder));++ builder.Reset();+ CHECK(!dc3.ToExponential(-Double::NaN(), 1, &builder));++ DoubleToStringConverter dc4(flags, "Infinity", "NaN", 'e', 0, 0, 0, 0);++ builder.Reset();+ CHECK(dc4.ToExponential(Double::Infinity(), 1, &builder));+ CHECK_EQ("Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToExponential(-Double::Infinity(), 1, &builder));+ CHECK_EQ("-Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToExponential(Double::NaN(), 1, &builder));+ CHECK_EQ("NaN", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToExponential(-Double::NaN(), 1, &builder));+ CHECK_EQ("NaN", builder.Finalize());+}+++TEST(DoubleToPrecision) {+ const int kBufferSize = 256;+ char buffer[kBufferSize];+ int flags = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |+ DoubleToStringConverter::UNIQUE_ZERO;+ StringBuilder builder(buffer, kBufferSize);+ DoubleToStringConverter dc(flags, "Infinity", "NaN", 'e',+ 0, 0, // Padding zeroes for shortest mode.+ 6, 0); // Padding zeroes for precision mode.++ ASSERT(DoubleToStringConverter::kMinPrecisionDigits == 1);+ CHECK(dc.ToPrecision(0.0, 1, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-0.0, 1, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(0.0, 2, &builder));+ CHECK_EQ("0.0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-0.0, 2, &builder));+ CHECK_EQ("0.0", builder.Finalize());++ ASSERT(DoubleToStringConverter::kMaxPrecisionDigits == 120);+ builder.Reset();+ CHECK(dc.ToPrecision(+ 0.0, DoubleToStringConverter::kMaxPrecisionDigits, &builder));+ CHECK_EQ("0.00000000000000000000000000000000000000000000000000000000000"+ "000000000000000000000000000000000000000000000000000000000000",+ builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(+ 9e59, DoubleToStringConverter::kMaxPrecisionDigits, &builder));+ CHECK_EQ("899999999999999918767229449717619953810131273674690656206848."+ "000000000000000000000000000000000000000000000000000000000000",+ builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(+ -9e59, DoubleToStringConverter::kMaxPrecisionDigits, &builder));+ CHECK_EQ("-899999999999999918767229449717619953810131273674690656206848."+ "000000000000000000000000000000000000000000000000000000000000",+ builder.Finalize());++ const double max_double = 1.7976931348623157e308;+ builder.Reset();+ CHECK(dc.ToPrecision(+ max_double, DoubleToStringConverter::kMaxPrecisionDigits, &builder));+ CHECK_EQ("1.79769313486231570814527423731704356798070567525844996598917"+ "476803157260780028538760589558632766878171540458953514382464e+308",+ builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(0.000001, 2, &builder));+ CHECK_EQ("0.0000010", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(0.0000001, 2, &builder));+ CHECK_EQ("1.0e-7", builder.Finalize());++ flags = DoubleToStringConverter::NO_FLAGS;+ DoubleToStringConverter dc2(flags, NULL, NULL, 'e', 0, 0, 0, 1);+ builder.Reset();+ CHECK(dc2.ToPrecision(230.0, 2, &builder));+ CHECK_EQ("230", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToPrecision(23.0, 2, &builder));+ CHECK_EQ("23", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToPrecision(2.30, 2, &builder));+ CHECK_EQ("2.3", builder.Finalize());++ builder.Reset();+ CHECK(dc2.ToPrecision(2300.0, 2, &builder));+ CHECK_EQ("2.3e3", builder.Finalize());++ flags = DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT;+ DoubleToStringConverter dc3(flags, NULL, NULL, 'e', 0, 0, 0, 1);+ builder.Reset();+ CHECK(dc3.ToPrecision(230.0, 2, &builder));+ CHECK_EQ("230.", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToPrecision(23.0, 2, &builder));+ CHECK_EQ("23.", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToPrecision(2.30, 2, &builder));+ CHECK_EQ("2.3", builder.Finalize());++ builder.Reset();+ CHECK(dc3.ToPrecision(2300.0, 2, &builder));+ CHECK_EQ("2.3e3", builder.Finalize());++ flags = DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |+ DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT;+ DoubleToStringConverter dc4(flags, NULL, NULL, 'e', 0, 0, 0, 1);+ builder.Reset();+ CHECK(dc4.ToPrecision(230.0, 2, &builder));+ CHECK_EQ("2.3e2", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToPrecision(23.0, 2, &builder));+ CHECK_EQ("23.0", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToPrecision(2.30, 2, &builder));+ CHECK_EQ("2.3", builder.Finalize());++ builder.Reset();+ CHECK(dc4.ToPrecision(2300.0, 2, &builder));+ CHECK_EQ("2.3e3", builder.Finalize());++ // Test the examples in the comments of ToPrecision.+ flags = DoubleToStringConverter::NO_FLAGS;+ DoubleToStringConverter dc5(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1);+ flags = DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT;+ DoubleToStringConverter dc6(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1);+ flags = DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |+ DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT;+ DoubleToStringConverter dc7(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1);++ builder.Reset();+ CHECK(dc5.ToPrecision(0.0000012345, 2, &builder));+ CHECK_EQ("0.0000012", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToPrecision(0.00000012345, 2, &builder));+ CHECK_EQ("1.2e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc5.ToPrecision(230.0, 2, &builder));+ CHECK_EQ("230", builder.Finalize());++ builder.Reset();+ CHECK(dc6.ToPrecision(230.0, 2, &builder));+ CHECK_EQ("230.", builder.Finalize());++ builder.Reset();+ CHECK(dc7.ToPrecision(230.0, 2, &builder));+ CHECK_EQ("2.3e2", builder.Finalize());++ flags = DoubleToStringConverter::NO_FLAGS;+ DoubleToStringConverter dc8(flags, NULL, NULL, 'e', 0, 0, 6, 3);++ builder.Reset();+ CHECK(dc8.ToPrecision(123450.0, 6, &builder));+ CHECK_EQ("123450", builder.Finalize());++ builder.Reset();+ CHECK(dc8.ToPrecision(123450.0, 5, &builder));+ CHECK_EQ("123450", builder.Finalize());++ builder.Reset();+ CHECK(dc8.ToPrecision(123450.0, 4, &builder));+ CHECK_EQ("123500", builder.Finalize());++ builder.Reset();+ CHECK(dc8.ToPrecision(123450.0, 3, &builder));+ CHECK_EQ("123000", builder.Finalize());++ builder.Reset();+ CHECK(dc8.ToPrecision(123450.0, 2, &builder));+ CHECK_EQ("1.2e5", builder.Finalize());++ // Test special value handling.+ builder.Reset();+ CHECK(!dc8.ToPrecision(Double::Infinity(), 1, &builder));++ builder.Reset();+ CHECK(!dc8.ToPrecision(-Double::Infinity(), 1, &builder));++ builder.Reset();+ CHECK(!dc8.ToPrecision(Double::NaN(), 1, &builder));++ builder.Reset();+ CHECK(!dc8.ToPrecision(-Double::NaN(), 1, &builder));++ builder.Reset();+ CHECK(dc7.ToPrecision(Double::Infinity(), 1, &builder));+ CHECK_EQ("Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc7.ToPrecision(-Double::Infinity(), 1, &builder));+ CHECK_EQ("-Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc7.ToPrecision(Double::NaN(), 1, &builder));+ CHECK_EQ("NaN", builder.Finalize());++ builder.Reset();+ CHECK(dc7.ToPrecision(-Double::NaN(), 1, &builder));+ CHECK_EQ("NaN", builder.Finalize());+}+++TEST(DoubleToStringJavaScript) {+ const int kBufferSize = 128;+ char buffer[kBufferSize];+ StringBuilder builder(buffer, kBufferSize);+ const DoubleToStringConverter& dc =+ DoubleToStringConverter::EcmaScriptConverter();++ builder.Reset();+ CHECK(dc.ToShortest(Double::NaN(), &builder));+ CHECK_EQ("NaN", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(Double::Infinity(), &builder));+ CHECK_EQ("Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-Double::Infinity(), &builder));+ CHECK_EQ("-Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.0, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(9.0, &builder));+ CHECK_EQ("9", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(90.0, &builder));+ CHECK_EQ("90", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(90.12, &builder));+ CHECK_EQ("90.12", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.1, &builder));+ CHECK_EQ("0.1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.01, &builder));+ CHECK_EQ("0.01", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.0123, &builder));+ CHECK_EQ("0.0123", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(111111111111111111111.0, &builder));+ CHECK_EQ("111111111111111110000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(100000000000000000000.0, &builder));+ CHECK_EQ("100000000000000000000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(1111111111111111111111.0, &builder));+ CHECK_EQ("1.1111111111111111e+21", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(11111111111111111111111.0, &builder));+ CHECK_EQ("1.1111111111111111e+22", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.00001, &builder));+ CHECK_EQ("0.00001", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.000001, &builder));+ CHECK_EQ("0.000001", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.0000001, &builder));+ CHECK_EQ("1e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.00000012, &builder));+ CHECK_EQ("1.2e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.000000123, &builder));+ CHECK_EQ("1.23e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.00000001, &builder));+ CHECK_EQ("1e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.000000012, &builder));+ CHECK_EQ("1.2e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.000000012, &builder));+ CHECK_EQ("1.2e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(0.0000000123, &builder));+ CHECK_EQ("1.23e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.0, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-9.0, &builder));+ CHECK_EQ("-9", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-90.0, &builder));+ CHECK_EQ("-90", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-90.12, &builder));+ CHECK_EQ("-90.12", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.1, &builder));+ CHECK_EQ("-0.1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.01, &builder));+ CHECK_EQ("-0.01", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.0123, &builder));+ CHECK_EQ("-0.0123", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-111111111111111111111.0, &builder));+ CHECK_EQ("-111111111111111110000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-1111111111111111111111.0, &builder));+ CHECK_EQ("-1.1111111111111111e+21", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-11111111111111111111111.0, &builder));+ CHECK_EQ("-1.1111111111111111e+22", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.00001, &builder));+ CHECK_EQ("-0.00001", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.000001, &builder));+ CHECK_EQ("-0.000001", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.0000001, &builder));+ CHECK_EQ("-1e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.00000012, &builder));+ CHECK_EQ("-1.2e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.000000123, &builder));+ CHECK_EQ("-1.23e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.00000001, &builder));+ CHECK_EQ("-1e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.000000012, &builder));+ CHECK_EQ("-1.2e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.000000012, &builder));+ CHECK_EQ("-1.2e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToShortest(-0.0000000123, &builder));+ CHECK_EQ("-1.23e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(Double::NaN(), 2, &builder));+ CHECK_EQ("NaN", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(Double::Infinity(), 2, &builder));+ CHECK_EQ("Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-Double::Infinity(), 2, &builder));+ CHECK_EQ("-Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.1, 1, &builder));+ CHECK_EQ("-0.1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.1, 2, &builder));+ CHECK_EQ("-0.10", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.1, 3, &builder));+ CHECK_EQ("-0.100", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.01, 2, &builder));+ CHECK_EQ("-0.01", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.01, 3, &builder));+ CHECK_EQ("-0.010", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.01, 4, &builder));+ CHECK_EQ("-0.0100", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.001, 2, &builder));+ CHECK_EQ("-0.00", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.001, 3, &builder));+ CHECK_EQ("-0.001", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.001, 4, &builder));+ CHECK_EQ("-0.0010", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-1.0, 4, &builder));+ CHECK_EQ("-1.0000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-1.0, 1, &builder));+ CHECK_EQ("-1.0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-1.0, 0, &builder));+ CHECK_EQ("-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-12.0, 0, &builder));+ CHECK_EQ("-12", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-1.1, 0, &builder));+ CHECK_EQ("-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-12.1, 0, &builder));+ CHECK_EQ("-12", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-1.12, 0, &builder));+ CHECK_EQ("-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-12.12, 0, &builder));+ CHECK_EQ("-12", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.0000006, 7, &builder));+ CHECK_EQ("-0.0000006", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.00000006, 8, &builder));+ CHECK_EQ("-0.00000006", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.00000006, 9, &builder));+ CHECK_EQ("-0.000000060", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.00000006, 10, &builder));+ CHECK_EQ("-0.0000000600", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0, 0, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0, 1, &builder));+ CHECK_EQ("0.0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0, 2, &builder));+ CHECK_EQ("0.00", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(1000, 0, &builder));+ CHECK_EQ("1000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.00001, 0, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.00001, 5, &builder));+ CHECK_EQ("0.00001", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.0000000000000000001, 20, &builder));+ CHECK_EQ("0.00000000000000000010", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.00001, 17, &builder));+ CHECK_EQ("0.00001000000000000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(1000000000000000128.0, 0, &builder));+ CHECK_EQ("1000000000000000128", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(1000000000000000128.0, 1, &builder));+ CHECK_EQ("1000000000000000128.0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(1000000000000000128.0, 2, &builder));+ CHECK_EQ("1000000000000000128.00", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(1000000000000000128.0, 20, &builder));+ CHECK_EQ("1000000000000000128.00000000000000000000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.0, 0, &builder));+ CHECK_EQ("0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-42.0, 3, &builder));+ CHECK_EQ("-42.000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-1000000000000000128.0, 0, &builder));+ CHECK_EQ("-1000000000000000128", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.0000000000000000001, 20, &builder));+ CHECK_EQ("-0.00000000000000000010", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.123123123123123, 20, &builder));+ CHECK_EQ("0.12312312312312299889", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(0.5, 0, &builder));+ CHECK_EQ("1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(-0.5, 0, &builder));+ CHECK_EQ("-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(1.25, 1, &builder));+ CHECK_EQ("1.3", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(234.20405, 4, &builder));+ CHECK_EQ("234.2040", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToFixed(234.2040506, 4, &builder));+ CHECK_EQ("234.2041", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(1.0, -1, &builder));+ CHECK_EQ("1e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(11.0, -1, &builder));+ CHECK_EQ("1.1e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(112.0, -1, &builder));+ CHECK_EQ("1.12e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(1.0, 0, &builder));+ CHECK_EQ("1e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(11.0, 0, &builder));+ CHECK_EQ("1e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(112.0, 0, &builder));+ CHECK_EQ("1e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(1.0, 1, &builder));+ CHECK_EQ("1.0e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(11.0, 1, &builder));+ CHECK_EQ("1.1e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(112.0, 1, &builder));+ CHECK_EQ("1.1e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(1.0, 2, &builder));+ CHECK_EQ("1.00e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(11.0, 2, &builder));+ CHECK_EQ("1.10e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(112.0, 2, &builder));+ CHECK_EQ("1.12e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(1.0, 3, &builder));+ CHECK_EQ("1.000e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(11.0, 3, &builder));+ CHECK_EQ("1.100e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(112.0, 3, &builder));+ CHECK_EQ("1.120e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.1, -1, &builder));+ CHECK_EQ("1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.11, -1, &builder));+ CHECK_EQ("1.1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.112, -1, &builder));+ CHECK_EQ("1.12e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.1, 0, &builder));+ CHECK_EQ("1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.11, 0, &builder));+ CHECK_EQ("1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.112, 0, &builder));+ CHECK_EQ("1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.1, 1, &builder));+ CHECK_EQ("1.0e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.11, 1, &builder));+ CHECK_EQ("1.1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.112, 1, &builder));+ CHECK_EQ("1.1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.1, 2, &builder));+ CHECK_EQ("1.00e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.11, 2, &builder));+ CHECK_EQ("1.10e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.112, 2, &builder));+ CHECK_EQ("1.12e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.1, 3, &builder));+ CHECK_EQ("1.000e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.11, 3, &builder));+ CHECK_EQ("1.100e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.112, 3, &builder));+ CHECK_EQ("1.120e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-1.0, -1, &builder));+ CHECK_EQ("-1e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-11.0, -1, &builder));+ CHECK_EQ("-1.1e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-112.0, -1, &builder));+ CHECK_EQ("-1.12e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-1.0, 0, &builder));+ CHECK_EQ("-1e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-11.0, 0, &builder));+ CHECK_EQ("-1e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-112.0, 0, &builder));+ CHECK_EQ("-1e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-1.0, 1, &builder));+ CHECK_EQ("-1.0e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-11.0, 1, &builder));+ CHECK_EQ("-1.1e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-112.0, 1, &builder));+ CHECK_EQ("-1.1e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-1.0, 2, &builder));+ CHECK_EQ("-1.00e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-11.0, 2, &builder));+ CHECK_EQ("-1.10e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-112.0, 2, &builder));+ CHECK_EQ("-1.12e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-1.0, 3, &builder));+ CHECK_EQ("-1.000e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-11.0, 3, &builder));+ CHECK_EQ("-1.100e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-112.0, 3, &builder));+ CHECK_EQ("-1.120e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.1, -1, &builder));+ CHECK_EQ("-1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.11, -1, &builder));+ CHECK_EQ("-1.1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.112, -1, &builder));+ CHECK_EQ("-1.12e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.1, 0, &builder));+ CHECK_EQ("-1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.11, 0, &builder));+ CHECK_EQ("-1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.112, 0, &builder));+ CHECK_EQ("-1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.1, 1, &builder));+ CHECK_EQ("-1.0e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.11, 1, &builder));+ CHECK_EQ("-1.1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.112, 1, &builder));+ CHECK_EQ("-1.1e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.1, 2, &builder));+ CHECK_EQ("-1.00e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.11, 2, &builder));+ CHECK_EQ("-1.10e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.112, 2, &builder));+ CHECK_EQ("-1.12e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.1, 3, &builder));+ CHECK_EQ("-1.000e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.11, 3, &builder));+ CHECK_EQ("-1.100e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.112, 3, &builder));+ CHECK_EQ("-1.120e-1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(Double::NaN(), 2, &builder));+ CHECK_EQ("NaN", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(Double::Infinity(), 2, &builder));+ CHECK_EQ("Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-Double::Infinity(), 2, &builder));+ CHECK_EQ("-Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(1.0, 0, &builder));+ CHECK_EQ("1e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.0, -1, &builder));+ CHECK_EQ("0e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.0, 2, &builder));+ CHECK_EQ("0.00e+0", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(11.2356, 0, &builder));+ CHECK_EQ("1e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(11.2356, 4, &builder));+ CHECK_EQ("1.1236e+1", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.000112356, 4, &builder));+ CHECK_EQ("1.1236e-4", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.000112356, 4, &builder));+ CHECK_EQ("-1.1236e-4", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(0.000112356, -1, &builder));+ CHECK_EQ("1.12356e-4", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToExponential(-0.000112356, -1, &builder));+ CHECK_EQ("-1.12356e-4", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(Double::NaN(), 1, &builder));+ CHECK_EQ("NaN", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(Double::Infinity(), 2, &builder));+ CHECK_EQ("Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-Double::Infinity(), 2, &builder));+ CHECK_EQ("-Infinity", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(0.000555, 15, &builder));+ CHECK_EQ("0.000555000000000000", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(0.000000555, 15, &builder));+ CHECK_EQ("5.55000000000000e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-0.000000555, 15, &builder));+ CHECK_EQ("-5.55000000000000e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(123456789.0, 1, &builder));+ CHECK_EQ("1e+8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(123456789.0, 9, &builder));+ CHECK_EQ("123456789", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(123456789.0, 8, &builder));+ CHECK_EQ("1.2345679e+8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(123456789.0, 7, &builder));+ CHECK_EQ("1.234568e+8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-123456789.0, 7, &builder));+ CHECK_EQ("-1.234568e+8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.0000000012345, 2, &builder));+ CHECK_EQ("-1.2e-9", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.000000012345, 2, &builder));+ CHECK_EQ("-1.2e-8", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.00000012345, 2, &builder));+ CHECK_EQ("-1.2e-7", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.0000012345, 2, &builder));+ CHECK_EQ("-0.0000012", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.000012345, 2, &builder));+ CHECK_EQ("-0.000012", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.00012345, 2, &builder));+ CHECK_EQ("-0.00012", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.0012345, 2, &builder));+ CHECK_EQ("-0.0012", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.012345, 2, &builder));+ CHECK_EQ("-0.012", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-.12345, 2, &builder));+ CHECK_EQ("-0.12", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-1.2345, 2, &builder));+ CHECK_EQ("-1.2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-12.345, 2, &builder));+ CHECK_EQ("-12", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-123.45, 2, &builder));+ CHECK_EQ("-1.2e+2", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-1234.5, 2, &builder));+ CHECK_EQ("-1.2e+3", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-12345.0, 2, &builder));+ CHECK_EQ("-1.2e+4", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-12345.67, 4, &builder));+ CHECK_EQ("-1.235e+4", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(-12344.67, 4, &builder));+ CHECK_EQ("-1.234e+4", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(1.25, 2, &builder));+ CHECK_EQ("1.3", builder.Finalize());++ builder.Reset();+ CHECK(dc.ToPrecision(1.35, 2, &builder));+ CHECK_EQ("1.4", builder.Finalize());+}+++static double StrToD(const char* str, int flags, double empty_string_value,+ int* processed_characters_count, bool* processed_all) {+ StringToDoubleConverter converter(flags, empty_string_value, Double::NaN(),+ NULL, NULL);+ double result = converter.StringToDouble(str, strlen(str),+ processed_characters_count);+ *processed_all = ((strlen(str) == *processed_characters_count));+ return result;+}+++TEST(StringToDoubleVarious) {+ int flags;+ int processed;+ bool all_used;++ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |+ StringToDoubleConverter::ALLOW_TRAILING_SPACES;++ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(42.0, StrToD("42", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(42.0, StrToD(" + 42 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-42.0, StrToD(" - 42 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("x", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" x", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("42x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" + 42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" - 42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);+++ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |+ StringToDoubleConverter::ALLOW_TRAILING_SPACES |+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;++ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(42.0, StrToD("42", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(42.0, StrToD(" + 42 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-42.0, StrToD(" - 42 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("x", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" x", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(42.0, StrToD("42x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(2, processed);++ CHECK_EQ(42.0, StrToD("42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(42.0, StrToD(" + 42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(6, processed);++ CHECK_EQ(-42.0, StrToD(" - 42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(6, processed);+++ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;++ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(42.0, StrToD("42", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(42.0, StrToD(" + 42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(5, processed);++ CHECK_EQ(-42.0, StrToD(" - 42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(5, processed);++ CHECK_EQ(Double::NaN(), StrToD("x", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" x", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(42.0, StrToD("42x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(2, processed);++ CHECK_EQ(42.0, StrToD("42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(2, processed);++ CHECK_EQ(42.0, StrToD(" + 42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(5, processed);++ CHECK_EQ(-42.0, StrToD(" - 42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(5, processed);++ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;++ CHECK_EQ(42.0, StrToD(" +42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(4, processed);++ CHECK_EQ(-42.0, StrToD(" -42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(4, processed);++ CHECK_EQ(Double::NaN(), StrToD(" + 42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" - 42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);+++ flags = StringToDoubleConverter::NO_FLAGS;++ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(42.0, StrToD("42", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" + 42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" - 42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("x", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" x", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("42x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" + 42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" - 42 x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);+++ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES;++ CHECK_EQ(0.0, StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(42.0, StrToD(" 42", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("42 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);+++ flags = StringToDoubleConverter::ALLOW_TRAILING_SPACES;++ CHECK_EQ(0.0, StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(42.0, StrToD("42 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" 42", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);+}+++TEST(StringToDoubleEmptyString) {+ int flags;+ int processed;+ bool all_used;++ flags = StringToDoubleConverter::NO_FLAGS;+ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(0, processed);++ flags = StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN;+ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(0, processed);++ flags = StringToDoubleConverter::ALLOW_LEADING_SPACES;+ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ flags = StringToDoubleConverter::ALLOW_TRAILING_SPACES;+ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK;+ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD("", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);+}+++TEST(StringToDoubleHexString) {+ int flags;+ int processed;+ bool all_used;++ flags = StringToDoubleConverter::ALLOW_HEX |+ StringToDoubleConverter::ALLOW_LEADING_SPACES |+ StringToDoubleConverter::ALLOW_TRAILING_SPACES |+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN;++ CHECK_EQ(18.0, StrToD("0x12", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("0x0", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0x123456789),+ StrToD("0x123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(18.0, StrToD(" 0x12 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" 0x0 ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0x123456789),+ StrToD(" 0x123456789 ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xabcdef", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xABCDEF", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD(" 0xabcdef ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD(" 0xABCDEF ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("0x", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x ", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x 3", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("0x3g", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("0x3.23", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("x3", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("0x3 foo", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x3 foo", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+ 0x3 foo", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("-", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(-5.0, StrToD("-0x5", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-5.0, StrToD(" - 0x5 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(5.0, StrToD(" + 0x5 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("- -0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("- +0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+ +0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ flags = StringToDoubleConverter::ALLOW_HEX;++ CHECK_EQ(18.0, StrToD("0x12", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("0x0", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0x123456789),+ StrToD("0x123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" 0x12 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x0 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x123456789 ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xabcdef", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xABCDEF", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0xabcdef ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0xABCDEF ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("0x", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x ", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x 3", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("0x3g", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("0x3.23", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("x3", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+ 0x3 foo", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("-", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(-5.0, StrToD("-0x5", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" - 0x5 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" + 0x5 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("- -0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("- +0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+ +0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK |+ StringToDoubleConverter::ALLOW_HEX;++ CHECK_EQ(18.0, StrToD("0x12", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("0x0", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0x123456789),+ StrToD("0x123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" 0x12 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x0 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(18.0, StrToD("0x12 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(4, processed);++ CHECK_EQ(0.0, StrToD("0x0 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0x123456789 ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xabcdef", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xABCDEF", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0xabcdef ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0xABCDEF ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xabcdef ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(8, processed);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xABCDEF ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(8, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0xabcdef", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0xABCDEF", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("0x", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x ", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x 3", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(3.0, StrToD("0x3g", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(3.0, StrToD("0x3.234", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x3g", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0x3.234", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("x3", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+ 0x3 foo", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("-", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(-5.0, StrToD("-0x5", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" - 0x5 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" + 0x5 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("- -0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("- +0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("+ +0x5", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK |+ StringToDoubleConverter::ALLOW_LEADING_SPACES |+ StringToDoubleConverter::ALLOW_TRAILING_SPACES |+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |+ StringToDoubleConverter::ALLOW_HEX;++ CHECK_EQ(18.0, StrToD("0x12", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("0x0", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0x123456789),+ StrToD("0x123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(18.0, StrToD(" 0x12 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" 0x0 ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0x123456789),+ StrToD(" 0x123456789 ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xabcdef", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD("0xABCDEF", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD(" 0xabcdef ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabcdef),+ StrToD(" 0xABCDEF ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0xabc),+ StrToD(" 0xabc def ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(7, processed);++ CHECK_EQ(static_cast<double>(0xabc),+ StrToD(" 0xABC DEF ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(7, processed);++ CHECK_EQ(static_cast<double>(0x12),+ StrToD(" 0x12 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" 0x0 ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(static_cast<double>(0x123456789),+ StrToD(" 0x123456789 ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("0x", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x ", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 0x 3", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ((double)0x3, StrToD("0x3g", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ((double)0x3, StrToD("0x3.234", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(Double::NaN(), StrToD("x3", flags, 0.0,+ &processed, &all_used));+ CHECK_EQ(0, processed);+}+++TEST(StringToDoubleOctalString) {+ int flags;+ int processed;+ bool all_used;++ flags = StringToDoubleConverter::ALLOW_OCTALS |+ StringToDoubleConverter::ALLOW_LEADING_SPACES |+ StringToDoubleConverter::ALLOW_TRAILING_SPACES |+ StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN;++ CHECK_EQ(10.0, StrToD("012", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("00", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD("012", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123456789.0,+ StrToD("0123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("+01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD("-01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD(" 012", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" 00", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD(" 012", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123456789.0,+ StrToD(" 0123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD(" 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD(" + 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD(" - 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD(" 012 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" 00 ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD(" 012 ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123456789.0,+ StrToD(" 0123456789 ", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD(" 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD(" + 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD(" - 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD("012 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("00 ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD("012 ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123456789.0,+ StrToD("0123456789 ", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("+01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD("-01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(),+ StrToD("01234567e0", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);+++ flags = StringToDoubleConverter::ALLOW_OCTALS;+ CHECK_EQ(10.0, StrToD("012", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("00", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD("012", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123456789.0,+ StrToD("0123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("+01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD("-01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" 012", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 00", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" + 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" - 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 00 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0123456789 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" + 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" - 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("012 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("00 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("012 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD("0123456789 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD("01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(342391.0,+ StrToD("+01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD("-01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(),+ StrToD("01234567e0", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);+++ flags = StringToDoubleConverter::ALLOW_OCTALS |+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;+ CHECK_EQ(10.0, StrToD("012", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("00", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD("012", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123456789.0,+ StrToD("0123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("+01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD("-01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" 012", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 00", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" + 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" - 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 00 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0123456789 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" + 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" - 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(10.0, StrToD("012 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(0.0, StrToD("00 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(2, processed);++ CHECK_EQ(123456789.0,+ StrToD("0123456789 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(10, processed);++ CHECK_EQ(342391.0,+ StrToD("01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(8, processed);++ CHECK_EQ(342391.0,+ StrToD("+01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD("-01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD("012foo ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(0.0, StrToD("00foo ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(2, processed);++ CHECK_EQ(123456789.0,+ StrToD("0123456789foo ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(10, processed);++ CHECK_EQ(342391.0,+ StrToD("01234567foo ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(8, processed);++ CHECK_EQ(342391.0,+ StrToD("+01234567foo", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(9, processed);++ CHECK_EQ(-342391.0,+ StrToD("-01234567foo", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(9, processed);++ CHECK_EQ(10.0, StrToD("012 foo ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(0.0, StrToD("00 foo ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(2, processed);++ CHECK_EQ(123456789.0,+ StrToD("0123456789 foo ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(10, processed);++ CHECK_EQ(342391.0,+ StrToD("01234567 foo ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(8, processed);++ CHECK_EQ(342391.0,+ StrToD("+01234567 foo", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(9, processed);++ CHECK_EQ(-342391.0,+ StrToD("-01234567 foo", flags, Double::NaN(), &processed,+ &all_used));+ CHECK_EQ(9, processed);++ CHECK_EQ(342391.0,+ StrToD("01234567e0", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(8, processed);++ CHECK_EQ(342391.0,+ StrToD("01234567e", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(8, processed);++ flags = StringToDoubleConverter::ALLOW_OCTALS |+ StringToDoubleConverter::ALLOW_TRAILING_SPACES |+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;+ CHECK_EQ(10.0, StrToD("012", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("00", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD("012", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123456789.0,+ StrToD("0123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("+01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD("-01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" 012", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 00", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0123456789", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" + 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" - 01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012 ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 00 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD(" 012 ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 0123456789 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" + 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(),+ StrToD(" - 01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(10.0, StrToD("012 ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("00 ", flags, 1.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123456789.0,+ StrToD("0123456789 ", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("01234567 ", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(342391.0,+ StrToD("+01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(-342391.0,+ StrToD("-01234567", flags, Double::NaN(), &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(10.0, StrToD("012foo ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(0.0, StrToD("00foo ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(2, processed);++ CHECK_EQ(123456789.0,+ StrToD("0123456789foo ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(10, processed);++ CHECK_EQ(342391.0,+ StrToD("01234567foo ", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(8, processed);++ CHECK_EQ(342391.0,+ StrToD("+01234567foo", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(9, processed);++ CHECK_EQ(-342391.0,+ StrToD("-01234567foo", flags, Double::NaN(), &processed, &all_used));+ CHECK_EQ(9, processed);++ CHECK_EQ(10.0, StrToD("012 foo ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(4, processed);++ CHECK_EQ(0.0, StrToD("00 foo ", flags, 1.0, &processed, &all_used));+ CHECK_EQ(3, processed);++ CHECK_EQ(123456789.0,+ StrToD("0123456789 foo ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(11, processed);++ CHECK_EQ(342391.0,+ StrToD("01234567 foo ", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(9, processed);++ CHECK_EQ(342391.0,+ StrToD("+01234567 foo", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(10, processed);++ CHECK_EQ(-342391.0,+ StrToD("-01234567 foo", flags, Double::NaN(),+ &processed, &all_used));+ CHECK_EQ(10, processed);+}+++TEST(StringToDoubleSpecialValues) {+ int processed;+ int flags = StringToDoubleConverter::NO_FLAGS;++ {+ // Use 1.0 as junk_string_value.+ StringToDoubleConverter converter(flags, 0.0, 1.0, "infinity", "NaN");++ CHECK_EQ(Double::NaN(), converter.StringToDouble("+NaN", 4, &processed));+ CHECK_EQ(4, processed);++ CHECK_EQ(-Double::Infinity(),+ converter.StringToDouble("-infinity", 9, &processed));+ CHECK_EQ(9, processed);++ CHECK_EQ(1.0, converter.StringToDouble("Infinity", 8, &processed));+ CHECK_EQ(0, processed);++ CHECK_EQ(1.0, converter.StringToDouble("++NaN", 5, &processed));+ CHECK_EQ(0, processed);+ }++ {+ // Use 1.0 as junk_string_value.+ StringToDoubleConverter converter(flags, 0.0, 1.0, "+infinity", "1NaN");++ // The '+' is consumed before trying to match the infinity string.+ CHECK_EQ(1.0, converter.StringToDouble("+infinity", 9, &processed));+ CHECK_EQ(0, processed);++ // The match for "1NaN" triggers, and doesn't let the 1234.0 complete.+ CHECK_EQ(1.0, converter.StringToDouble("1234.0", 6, &processed));+ CHECK_EQ(0, processed);+ }+}+++TEST(StringToDoubleCommentExamples) {+ // Make sure the examples in the comments are correct.+ int flags;+ int processed;+ bool all_used;++ flags = StringToDoubleConverter::ALLOW_HEX;++ CHECK_EQ(4660.0, StrToD("0x1234", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(),+ StrToD("0x1234.56", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ flags |= StringToDoubleConverter::ALLOW_TRAILING_JUNK;+ CHECK_EQ(4660.0,+ StrToD("0x1234.56", flags, 0.0, &processed, &all_used));+ CHECK_EQ(6, processed);++ flags = StringToDoubleConverter::ALLOW_OCTALS;+ CHECK_EQ(668.0, StrToD("01234", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(12349.0, StrToD("012349", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(),+ StrToD("01234.56", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 0);++ flags |= StringToDoubleConverter::ALLOW_TRAILING_JUNK;+ CHECK_EQ(668.0,+ StrToD("01234.56", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 5);++ flags = StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN;+ CHECK_EQ(-123.2, StrToD("- 123.2", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ flags = StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN;+ CHECK_EQ(123.2, StrToD("+ 123.2", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ flags = StringToDoubleConverter::ALLOW_HEX |+ StringToDoubleConverter::ALLOW_TRAILING_JUNK;++ CHECK_EQ(4660.0, StrToD("0x1234", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(4660.0, StrToD("0x1234K", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 6);++ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 0);++ CHECK_EQ(Double::NaN(), StrToD(" 1", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 0);++ CHECK_EQ(Double::NaN(), StrToD("0x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 0);++ CHECK_EQ(-123.45, StrToD("-123.45", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(),+ StrToD("--123.45", flags, 0.0, &processed, &all_used));+ CHECK_EQ(processed, 0);++ CHECK_EQ(123e45, StrToD("123e45", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123e45, StrToD("123E45", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123e45, StrToD("123e+45", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123e-45, StrToD("123e-45", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123.0, StrToD("123e", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(123.0, StrToD("123e-", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ {+ StringToDoubleConverter converter(flags, 0.0, 1.0, "infinity", "NaN");+ CHECK_EQ(Double::NaN(), converter.StringToDouble("+NaN", 4, &processed));+ CHECK_EQ(4, processed);++ CHECK_EQ(-Double::Infinity(),+ converter.StringToDouble("-infinity", 9, &processed));+ CHECK_EQ(9, processed);++ CHECK_EQ(1.0, converter.StringToDouble("Infinity", 9, &processed));+ CHECK_EQ(0, processed);+ }++ flags = StringToDoubleConverter::ALLOW_OCTALS |+ StringToDoubleConverter::ALLOW_LEADING_SPACES;++ CHECK_EQ(Double::NaN(), StrToD("0x1234", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(668.0, StrToD("01234", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD("", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(0.0, StrToD(" ", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(1.0, StrToD(" 1", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(), StrToD("0x", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("0123e45", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(1239e45, StrToD("01239e45", flags, 0.0, &processed, &all_used));+ CHECK(all_used);++ CHECK_EQ(Double::NaN(),+ StrToD("-infinity", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);++ CHECK_EQ(Double::NaN(), StrToD("NaN", flags, 0.0, &processed, &all_used));+ CHECK_EQ(0, processed);+}
+ double-conversion/test/cctest/test-diy-fp.cc view
@@ -0,0 +1,65 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.++#include <stdlib.h>++#include "cctest.h"+#include "diy-fp.h"+#include "utils.h"+++using namespace double_conversion;+++TEST(Subtract) {+ DiyFp diy_fp1 = DiyFp(3, 0);+ DiyFp diy_fp2 = DiyFp(1, 0);+ DiyFp diff = DiyFp::Minus(diy_fp1, diy_fp2);++ CHECK(2 == diff.f()); // NOLINT+ CHECK_EQ(0, diff.e());+ diy_fp1.Subtract(diy_fp2);+ CHECK(2 == diy_fp1.f()); // NOLINT+ CHECK_EQ(0, diy_fp1.e());+}+++TEST(Multiply) {+ DiyFp diy_fp1 = DiyFp(3, 0);+ DiyFp diy_fp2 = DiyFp(2, 0);+ DiyFp product = DiyFp::Times(diy_fp1, diy_fp2);++ CHECK(0 == product.f()); // NOLINT+ CHECK_EQ(64, product.e());+ diy_fp1.Multiply(diy_fp2);+ CHECK(0 == diy_fp1.f()); // NOLINT+ CHECK_EQ(64, diy_fp1.e());++ diy_fp1 = DiyFp(UINT64_2PART_C(0x80000000, 00000000), 11);+ diy_fp2 = DiyFp(2, 13);+ product = DiyFp::Times(diy_fp1, diy_fp2);+ CHECK(1 == product.f()); // NOLINT+ CHECK_EQ(11 + 13 + 64, product.e());++ // Test rounding.+ diy_fp1 = DiyFp(UINT64_2PART_C(0x80000000, 00000001), 11);+ diy_fp2 = DiyFp(1, 13);+ product = DiyFp::Times(diy_fp1, diy_fp2);+ CHECK(1 == product.f()); // NOLINT+ CHECK_EQ(11 + 13 + 64, product.e());++ diy_fp1 = DiyFp(UINT64_2PART_C(0x7fffffff, ffffffff), 11);+ diy_fp2 = DiyFp(1, 13);+ product = DiyFp::Times(diy_fp1, diy_fp2);+ CHECK(0 == product.f()); // NOLINT+ CHECK_EQ(11 + 13 + 64, product.e());++ // Halfway cases are allowed to round either way. So don't check for it.++ // Big numbers.+ diy_fp1 = DiyFp(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF), 11);+ diy_fp2 = DiyFp(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF), 13);+ // 128bit result: 0xfffffffffffffffe0000000000000001+ product = DiyFp::Times(diy_fp1, diy_fp2);+ CHECK(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFe) == product.f());+ CHECK_EQ(11 + 13 + 64, product.e());+}
+ double-conversion/test/cctest/test-double.cc view
@@ -0,0 +1,218 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.++#include <stdlib.h>++#include "cctest.h"+#include "diy-fp.h"+#include "double.h"+#include "utils.h"+++using namespace double_conversion;+++TEST(Uint64Conversions) {+ // Start by checking the byte-order.+ uint64_t ordered = UINT64_2PART_C(0x01234567, 89ABCDEF);+ CHECK_EQ(3512700564088504e-318, Double(ordered).value());++ uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001);+ CHECK_EQ(5e-324, Double(min_double64).value());++ uint64_t max_double64 = UINT64_2PART_C(0x7fefffff, ffffffff);+ CHECK_EQ(1.7976931348623157e308, Double(max_double64).value());+}++TEST(AsDiyFp) {+ uint64_t ordered = UINT64_2PART_C(0x01234567, 89ABCDEF);+ DiyFp diy_fp = Double(ordered).AsDiyFp();+ CHECK_EQ(0x12 - 0x3FF - 52, diy_fp.e());+ // The 52 mantissa bits, plus the implicit 1 in bit 52 as a UINT64.+ CHECK(UINT64_2PART_C(0x00134567, 89ABCDEF) == diy_fp.f()); // NOLINT++ uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001);+ diy_fp = Double(min_double64).AsDiyFp();+ CHECK_EQ(-0x3FF - 52 + 1, diy_fp.e());+ // This is a denormal; so no hidden bit.+ CHECK(1 == diy_fp.f()); // NOLINT++ uint64_t max_double64 = UINT64_2PART_C(0x7fefffff, ffffffff);+ diy_fp = Double(max_double64).AsDiyFp();+ CHECK_EQ(0x7FE - 0x3FF - 52, diy_fp.e());+ CHECK(UINT64_2PART_C(0x001fffff, ffffffff) == diy_fp.f()); // NOLINT+}+++TEST(AsNormalizedDiyFp) {+ uint64_t ordered = UINT64_2PART_C(0x01234567, 89ABCDEF);+ DiyFp diy_fp = Double(ordered).AsNormalizedDiyFp();+ CHECK_EQ(0x12 - 0x3FF - 52 - 11, diy_fp.e());+ CHECK((UINT64_2PART_C(0x00134567, 89ABCDEF) << 11) ==+ diy_fp.f()); // NOLINT++ uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001);+ diy_fp = Double(min_double64).AsNormalizedDiyFp();+ CHECK_EQ(-0x3FF - 52 + 1 - 63, diy_fp.e());+ // This is a denormal; so no hidden bit.+ CHECK(UINT64_2PART_C(0x80000000, 00000000) == diy_fp.f()); // NOLINT++ uint64_t max_double64 = UINT64_2PART_C(0x7fefffff, ffffffff);+ diy_fp = Double(max_double64).AsNormalizedDiyFp();+ CHECK_EQ(0x7FE - 0x3FF - 52 - 11, diy_fp.e());+ CHECK((UINT64_2PART_C(0x001fffff, ffffffff) << 11) ==+ diy_fp.f()); // NOLINT+}+++TEST(IsDenormal) {+ uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001);+ CHECK(Double(min_double64).IsDenormal());+ uint64_t bits = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);+ CHECK(Double(bits).IsDenormal());+ bits = UINT64_2PART_C(0x00100000, 00000000);+ CHECK(!Double(bits).IsDenormal());+}+++TEST(IsSpecial) {+ CHECK(Double(Double::Infinity()).IsSpecial());+ CHECK(Double(-Double::Infinity()).IsSpecial());+ CHECK(Double(Double::NaN()).IsSpecial());+ uint64_t bits = UINT64_2PART_C(0xFFF12345, 00000000);+ CHECK(Double(bits).IsSpecial());+ // Denormals are not special:+ CHECK(!Double(5e-324).IsSpecial());+ CHECK(!Double(-5e-324).IsSpecial());+ // And some random numbers:+ CHECK(!Double(0.0).IsSpecial());+ CHECK(!Double(-0.0).IsSpecial());+ CHECK(!Double(1.0).IsSpecial());+ CHECK(!Double(-1.0).IsSpecial());+ CHECK(!Double(1000000.0).IsSpecial());+ CHECK(!Double(-1000000.0).IsSpecial());+ CHECK(!Double(1e23).IsSpecial());+ CHECK(!Double(-1e23).IsSpecial());+ CHECK(!Double(1.7976931348623157e308).IsSpecial());+ CHECK(!Double(-1.7976931348623157e308).IsSpecial());+}+++TEST(IsInfinite) {+ CHECK(Double(Double::Infinity()).IsInfinite());+ CHECK(Double(-Double::Infinity()).IsInfinite());+ CHECK(!Double(Double::NaN()).IsInfinite());+ CHECK(!Double(0.0).IsInfinite());+ CHECK(!Double(-0.0).IsInfinite());+ CHECK(!Double(1.0).IsInfinite());+ CHECK(!Double(-1.0).IsInfinite());+ uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001);+ CHECK(!Double(min_double64).IsInfinite());+}+++TEST(IsNan) {+ CHECK(Double(Double::NaN()).IsNan());+ uint64_t other_nan = UINT64_2PART_C(0xFFFFFFFF, 00000001);+ CHECK(Double(other_nan).IsNan());+ CHECK(!Double(Double::Infinity()).IsNan());+ CHECK(!Double(-Double::Infinity()).IsNan());+ CHECK(!Double(0.0).IsNan());+ CHECK(!Double(-0.0).IsNan());+ CHECK(!Double(1.0).IsNan());+ CHECK(!Double(-1.0).IsNan());+ uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001);+ CHECK(!Double(min_double64).IsNan());+}+++TEST(Sign) {+ CHECK_EQ(1, Double(1.0).Sign());+ CHECK_EQ(1, Double(Double::Infinity()).Sign());+ CHECK_EQ(-1, Double(-Double::Infinity()).Sign());+ CHECK_EQ(1, Double(0.0).Sign());+ CHECK_EQ(-1, Double(-0.0).Sign());+ uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001);+ CHECK_EQ(1, Double(min_double64).Sign());+}+++TEST(NormalizedBoundaries) {+ DiyFp boundary_plus;+ DiyFp boundary_minus;+ DiyFp diy_fp = Double(1.5).AsNormalizedDiyFp();+ Double(1.5).NormalizedBoundaries(&boundary_minus, &boundary_plus);+ CHECK_EQ(diy_fp.e(), boundary_minus.e());+ CHECK_EQ(diy_fp.e(), boundary_plus.e());+ // 1.5 does not have a significand of the form 2^p (for some p).+ // Therefore its boundaries are at the same distance.+ CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f());+ CHECK((1 << 10) == diy_fp.f() - boundary_minus.f()); // NOLINT++ diy_fp = Double(1.0).AsNormalizedDiyFp();+ Double(1.0).NormalizedBoundaries(&boundary_minus, &boundary_plus);+ CHECK_EQ(diy_fp.e(), boundary_minus.e());+ CHECK_EQ(diy_fp.e(), boundary_plus.e());+ // 1.0 does have a significand of the form 2^p (for some p).+ // Therefore its lower boundary is twice as close as the upper boundary.+ CHECK(boundary_plus.f() - diy_fp.f() > diy_fp.f() - boundary_minus.f());+ CHECK((1 << 9) == diy_fp.f() - boundary_minus.f()); // NOLINT+ CHECK((1 << 10) == boundary_plus.f() - diy_fp.f()); // NOLINT++ uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001);+ diy_fp = Double(min_double64).AsNormalizedDiyFp();+ Double(min_double64).NormalizedBoundaries(&boundary_minus, &boundary_plus);+ CHECK_EQ(diy_fp.e(), boundary_minus.e());+ CHECK_EQ(diy_fp.e(), boundary_plus.e());+ // min-value does not have a significand of the form 2^p (for some p).+ // Therefore its boundaries are at the same distance.+ CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f());+ // Denormals have their boundaries much closer.+ CHECK((static_cast<uint64_t>(1) << 62) ==+ diy_fp.f() - boundary_minus.f()); // NOLINT++ uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000);+ diy_fp = Double(smallest_normal64).AsNormalizedDiyFp();+ Double(smallest_normal64).NormalizedBoundaries(&boundary_minus,+ &boundary_plus);+ CHECK_EQ(diy_fp.e(), boundary_minus.e());+ CHECK_EQ(diy_fp.e(), boundary_plus.e());+ // Even though the significand is of the form 2^p (for some p), its boundaries+ // are at the same distance. (This is the only exception).+ CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f());+ CHECK((1 << 10) == diy_fp.f() - boundary_minus.f()); // NOLINT++ uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);+ diy_fp = Double(largest_denormal64).AsNormalizedDiyFp();+ Double(largest_denormal64).NormalizedBoundaries(&boundary_minus,+ &boundary_plus);+ CHECK_EQ(diy_fp.e(), boundary_minus.e());+ CHECK_EQ(diy_fp.e(), boundary_plus.e());+ CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f());+ CHECK((1 << 11) == diy_fp.f() - boundary_minus.f()); // NOLINT++ uint64_t max_double64 = UINT64_2PART_C(0x7fefffff, ffffffff);+ diy_fp = Double(max_double64).AsNormalizedDiyFp();+ Double(max_double64).NormalizedBoundaries(&boundary_minus, &boundary_plus);+ CHECK_EQ(diy_fp.e(), boundary_minus.e());+ CHECK_EQ(diy_fp.e(), boundary_plus.e());+ // max-value does not have a significand of the form 2^p (for some p).+ // Therefore its boundaries are at the same distance.+ CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f());+ CHECK((1 << 10) == diy_fp.f() - boundary_minus.f()); // NOLINT+}+++TEST(NextDouble) {+ CHECK_EQ(4e-324, Double(0.0).NextDouble());+ CHECK_EQ(0.0, Double(-0.0).NextDouble());+ CHECK_EQ(-0.0, Double(-4e-324).NextDouble());+ Double d0(-4e-324);+ Double d1(d0.NextDouble());+ Double d2(d1.NextDouble());+ CHECK_EQ(-0.0, d1.value());+ CHECK_EQ(0.0, d2.value());+ CHECK_EQ(4e-324, d2.NextDouble());+ CHECK_EQ(-1.7976931348623157e308, Double(-Double::Infinity()).NextDouble());+ CHECK_EQ(Double::Infinity(),+ Double(UINT64_2PART_C(0x7fefffff, ffffffff)).NextDouble());+}
+ double-conversion/test/cctest/test-dtoa.cc view
@@ -0,0 +1,422 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <stdlib.h>++#include "double-conversion.h"++#include "cctest.h"+#include "double.h"+#include "gay-fixed.h"+#include "gay-precision.h"+#include "gay-shortest.h"+++using namespace double_conversion;+++enum DtoaMode {+ SHORTEST,+ FIXED,+ PRECISION+};++static void DoubleToAscii(double v, DtoaMode test_mode, int requested_digits,+ Vector<char> buffer, bool* sign, int* length,+ int* point) {+ DoubleToStringConverter::DtoaMode mode = DoubleToStringConverter::SHORTEST;+ switch (test_mode) {+ case SHORTEST: mode = DoubleToStringConverter::SHORTEST; break;+ case FIXED: mode = DoubleToStringConverter::FIXED; break;+ case PRECISION: mode = DoubleToStringConverter::PRECISION; break;+ }+ DoubleToStringConverter::DoubleToAscii(v, mode, requested_digits,+ buffer.start(), buffer.length(),+ sign, length, point);+}++// Removes trailing '0' digits.+static void TrimRepresentation(Vector<char> representation) {+ int len = strlen(representation.start());+ int i;+ for (i = len - 1; i >= 0; --i) {+ if (representation[i] != '0') break;+ }+ representation[i + 1] = '\0';+}+++static const int kBufferSize = 100;+++TEST(DtoaVariousDoubles) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ int length;+ int point;+ bool sign;++ DoubleToAscii(0.0, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("0", buffer.start());+ CHECK_EQ(1, point);++ DoubleToAscii(0.0, FIXED, 2, buffer, &sign, &length, &point);+ CHECK_EQ(1, length);+ CHECK_EQ("0", buffer.start());+ CHECK_EQ(1, point);++ DoubleToAscii(0.0, PRECISION, 3, buffer, &sign, &length, &point);+ CHECK_EQ(1, length);+ CHECK_EQ("0", buffer.start());+ CHECK_EQ(1, point);++ DoubleToAscii(1.0, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ DoubleToAscii(1.0, FIXED, 3, buffer, &sign, &length, &point);+ CHECK_GE(3, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ DoubleToAscii(1.0, PRECISION, 3, buffer, &sign, &length, &point);+ CHECK_GE(3, length);+ TrimRepresentation(buffer);+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ DoubleToAscii(1.5, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("15", buffer.start());+ CHECK_EQ(1, point);++ DoubleToAscii(1.5, FIXED, 10, buffer, &sign, &length, &point);+ CHECK_GE(10, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("15", buffer.start());+ CHECK_EQ(1, point);++ DoubleToAscii(1.5, PRECISION, 10, buffer, &sign, &length, &point);+ CHECK_GE(10, length);+ TrimRepresentation(buffer);+ CHECK_EQ("15", buffer.start());+ CHECK_EQ(1, point);++ double min_double = 5e-324;+ DoubleToAscii(min_double, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("5", buffer.start());+ CHECK_EQ(-323, point);++ DoubleToAscii(min_double, FIXED, 5, buffer, &sign, &length, &point);+ CHECK_GE(5, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("", buffer.start());+ CHECK_GE(-5, point);++ DoubleToAscii(min_double, PRECISION, 5, buffer, &sign, &length, &point);+ CHECK_GE(5, length);+ TrimRepresentation(buffer);+ CHECK_EQ("49407", buffer.start());+ CHECK_EQ(-323, point);++ double max_double = 1.7976931348623157e308;+ DoubleToAscii(max_double, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("17976931348623157", buffer.start());+ CHECK_EQ(309, point);++ DoubleToAscii(max_double, PRECISION, 7, buffer, &sign, &length, &point);+ CHECK_GE(7, length);+ TrimRepresentation(buffer);+ CHECK_EQ("1797693", buffer.start());+ CHECK_EQ(309, point);++ DoubleToAscii(4294967272.0, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("4294967272", buffer.start());+ CHECK_EQ(10, point);++ DoubleToAscii(4294967272.0, FIXED, 5, buffer, &sign, &length, &point);+ CHECK_GE(5, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("4294967272", buffer.start());+ CHECK_EQ(10, point);+++ DoubleToAscii(4294967272.0, PRECISION, 14,+ buffer, &sign, &length, &point);+ CHECK_GE(14, length);+ TrimRepresentation(buffer);+ CHECK_EQ("4294967272", buffer.start());+ CHECK_EQ(10, point);++ DoubleToAscii(4.1855804968213567e298, SHORTEST, 0,+ buffer, &sign, &length, &point);+ CHECK_EQ("4185580496821357", buffer.start());+ CHECK_EQ(299, point);++ DoubleToAscii(4.1855804968213567e298, PRECISION, 20,+ buffer, &sign, &length, &point);+ CHECK_GE(20, length);+ TrimRepresentation(buffer);+ CHECK_EQ("41855804968213567225", buffer.start());+ CHECK_EQ(299, point);++ DoubleToAscii(5.5626846462680035e-309, SHORTEST, 0,+ buffer, &sign, &length, &point);+ CHECK_EQ("5562684646268003", buffer.start());+ CHECK_EQ(-308, point);++ DoubleToAscii(5.5626846462680035e-309, PRECISION, 1,+ buffer, &sign, &length, &point);+ CHECK_GE(1, length);+ TrimRepresentation(buffer);+ CHECK_EQ("6", buffer.start());+ CHECK_EQ(-308, point);++ DoubleToAscii(-2147483648.0, SHORTEST, 0,+ buffer, &sign, &length, &point);+ CHECK_EQ(1, sign);+ CHECK_EQ("2147483648", buffer.start());+ CHECK_EQ(10, point);+++ DoubleToAscii(-2147483648.0, FIXED, 2, buffer, &sign, &length, &point);+ CHECK_GE(2, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ(1, sign);+ CHECK_EQ("2147483648", buffer.start());+ CHECK_EQ(10, point);++ DoubleToAscii(-2147483648.0, PRECISION, 5,+ buffer, &sign, &length, &point);+ CHECK_GE(5, length);+ TrimRepresentation(buffer);+ CHECK_EQ(1, sign);+ CHECK_EQ("21475", buffer.start());+ CHECK_EQ(10, point);++ DoubleToAscii(-3.5844466002796428e+298, SHORTEST, 0,+ buffer, &sign, &length, &point);+ CHECK_EQ(1, sign);+ CHECK_EQ("35844466002796428", buffer.start());+ CHECK_EQ(299, point);++ DoubleToAscii(-3.5844466002796428e+298, PRECISION, 10,+ buffer, &sign, &length, &point);+ CHECK_EQ(1, sign);+ CHECK_GE(10, length);+ TrimRepresentation(buffer);+ CHECK_EQ("35844466", buffer.start());+ CHECK_EQ(299, point);++ uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000);+ double v = Double(smallest_normal64).value();+ DoubleToAscii(v, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("22250738585072014", buffer.start());+ CHECK_EQ(-307, point);++ DoubleToAscii(v, PRECISION, 20, buffer, &sign, &length, &point);+ CHECK_GE(20, length);+ TrimRepresentation(buffer);+ CHECK_EQ("22250738585072013831", buffer.start());+ CHECK_EQ(-307, point);++ uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);+ v = Double(largest_denormal64).value();+ DoubleToAscii(v, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("2225073858507201", buffer.start());+ CHECK_EQ(-307, point);++ DoubleToAscii(v, PRECISION, 20, buffer, &sign, &length, &point);+ CHECK_GE(20, length);+ TrimRepresentation(buffer);+ CHECK_EQ("2225073858507200889", buffer.start());+ CHECK_EQ(-307, point);++ DoubleToAscii(4128420500802942e-24, SHORTEST, 0,+ buffer, &sign, &length, &point);+ CHECK_EQ(0, sign);+ CHECK_EQ("4128420500802942", buffer.start());+ CHECK_EQ(-8, point);++ v = -3.9292015898194142585311918e-10;+ DoubleToAscii(v, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK_EQ("39292015898194143", buffer.start());++ v = 4194304.0;+ DoubleToAscii(v, FIXED, 5, buffer, &sign, &length, &point);+ CHECK_GE(5, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ("4194304", buffer.start());++ v = 3.3161339052167390562200598e-237;+ DoubleToAscii(v, PRECISION, 19, buffer, &sign, &length, &point);+ CHECK_GE(19, length);+ TrimRepresentation(buffer);+ CHECK_EQ("3316133905216739056", buffer.start());+ CHECK_EQ(-236, point);+}+++TEST(DtoaSign) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ bool sign;+ int length;+ int point;++ DoubleToAscii(0.0, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK(!sign);++ DoubleToAscii(-0.0, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK(sign);++ DoubleToAscii(1.0, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK(!sign);++ DoubleToAscii(-1.0, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK(sign);++ DoubleToAscii(0.0, PRECISION, 1, buffer, &sign, &length, &point);+ CHECK(!sign);++ DoubleToAscii(-0.0, PRECISION, 1, buffer, &sign, &length, &point);+ CHECK(sign);++ DoubleToAscii(1.0, PRECISION, 1, buffer, &sign, &length, &point);+ CHECK(!sign);++ DoubleToAscii(-1.0, PRECISION, 1, buffer, &sign, &length, &point);+ CHECK(sign);++ DoubleToAscii(0.0, FIXED, 1, buffer, &sign, &length, &point);+ CHECK(!sign);++ DoubleToAscii(-0.0, FIXED, 1, buffer, &sign, &length, &point);+ CHECK(sign);++ DoubleToAscii(1.0, FIXED, 1, buffer, &sign, &length, &point);+ CHECK(!sign);++ DoubleToAscii(-1.0, FIXED, 1, buffer, &sign, &length, &point);+ CHECK(sign);+}+++TEST(DtoaCorners) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ bool sign;+ int length;+ int point;++ DoubleToAscii(0.0, PRECISION, 0, buffer, &sign, &length, &point);+ CHECK_EQ(0, length);+ CHECK_EQ("", buffer.start());+ CHECK(!sign);++ DoubleToAscii(1.0, PRECISION, 0, buffer, &sign, &length, &point);+ CHECK_EQ(0, length);+ CHECK_EQ("", buffer.start());+ CHECK(!sign);++ DoubleToAscii(0.0, FIXED, 0, buffer, &sign, &length, &point);+ CHECK_EQ(1, length);+ CHECK_EQ("0", buffer.start());+ CHECK(!sign);++ DoubleToAscii(1.0, FIXED, 0, buffer, &sign, &length, &point);+ CHECK_EQ(1, length);+ CHECK_EQ("1", buffer.start());+ CHECK(!sign);+}+++TEST(DtoaGayShortest) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ bool sign;+ int length;+ int point;++ Vector<const PrecomputedShortest> precomputed =+ PrecomputedShortestRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedShortest current_test = precomputed[i];+ double v = current_test.v;+ DoubleToAscii(v, SHORTEST, 0, buffer, &sign, &length, &point);+ CHECK(!sign); // All precomputed numbers are positive.+ CHECK_EQ(current_test.decimal_point, point);+ CHECK_EQ(current_test.representation, buffer.start());+ }+}+++TEST(DtoaGayFixed) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ bool sign;+ int length;+ int point;++ Vector<const PrecomputedFixed> precomputed =+ PrecomputedFixedRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedFixed current_test = precomputed[i];+ double v = current_test.v;+ int number_digits = current_test.number_digits;+ DoubleToAscii(v, FIXED, number_digits, buffer, &sign, &length, &point);+ CHECK(!sign); // All precomputed numbers are positive.+ CHECK_EQ(current_test.decimal_point, point);+ CHECK_GE(number_digits, length - point);+ TrimRepresentation(buffer);+ CHECK_EQ(current_test.representation, buffer.start());+ }+}+++TEST(DtoaGayPrecision) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ bool sign;+ int length;+ int point;++ Vector<const PrecomputedPrecision> precomputed =+ PrecomputedPrecisionRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedPrecision current_test = precomputed[i];+ double v = current_test.v;+ int number_digits = current_test.number_digits;+ DoubleToAscii(v, PRECISION, number_digits,+ buffer, &sign, &length, &point);+ CHECK(!sign); // All precomputed numbers are positive.+ CHECK_EQ(current_test.decimal_point, point);+ CHECK_GE(number_digits, length);+ TrimRepresentation(buffer);+ CHECK_EQ(current_test.representation, buffer.start());+ }+}
+ double-conversion/test/cctest/test-fast-dtoa.cc view
@@ -0,0 +1,266 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.++#include <stdlib.h>++#include "cctest.h"+#include "diy-fp.h"+#include "double.h"+#include "fast-dtoa.h"+#include "gay-precision.h"+#include "gay-shortest.h"+#include "utils.h"++using namespace double_conversion;++static const int kBufferSize = 100;+++// Removes trailing '0' digits.+static void TrimRepresentation(Vector<char> representation) {+ int len = strlen(representation.start());+ int i;+ for (i = len - 1; i >= 0; --i) {+ if (representation[i] != '0') break;+ }+ representation[i + 1] = '\0';+}+++TEST(FastDtoaShortestVariousDoubles) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ int length;+ int point;+ int status;++ double min_double = 5e-324;+ status = FastDtoa(min_double, FAST_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("5", buffer.start());+ CHECK_EQ(-323, point);++ double max_double = 1.7976931348623157e308;+ status = FastDtoa(max_double, FAST_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("17976931348623157", buffer.start());+ CHECK_EQ(309, point);++ status = FastDtoa(4294967272.0, FAST_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("4294967272", buffer.start());+ CHECK_EQ(10, point);++ status = FastDtoa(4.1855804968213567e298, FAST_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("4185580496821357", buffer.start());+ CHECK_EQ(299, point);++ status = FastDtoa(5.5626846462680035e-309, FAST_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("5562684646268003", buffer.start());+ CHECK_EQ(-308, point);++ status = FastDtoa(2147483648.0, FAST_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("2147483648", buffer.start());+ CHECK_EQ(10, point);++ status = FastDtoa(3.5844466002796428e+298, FAST_DTOA_SHORTEST, 0,+ buffer, &length, &point);+ if (status) { // Not all FastDtoa variants manage to compute this number.+ CHECK_EQ("35844466002796428", buffer.start());+ CHECK_EQ(299, point);+ }++ uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000);+ double v = Double(smallest_normal64).value();+ status = FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, &length, &point);+ if (status) {+ CHECK_EQ("22250738585072014", buffer.start());+ CHECK_EQ(-307, point);+ }++ uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);+ v = Double(largest_denormal64).value();+ status = FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, &length, &point);+ if (status) {+ CHECK_EQ("2225073858507201", buffer.start());+ CHECK_EQ(-307, point);+ }+}+++TEST(FastDtoaPrecisionVariousDoubles) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ int length;+ int point;+ int status;++ status = FastDtoa(1.0, FAST_DTOA_PRECISION, 3, buffer, &length, &point);+ CHECK(status);+ CHECK(3 >= length);+ TrimRepresentation(buffer);+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ status = FastDtoa(1.5, FAST_DTOA_PRECISION, 10, buffer, &length, &point);+ if (status) {+ CHECK(10 >= length);+ TrimRepresentation(buffer);+ CHECK_EQ("15", buffer.start());+ CHECK_EQ(1, point);+ }++ double min_double = 5e-324;+ status = FastDtoa(min_double, FAST_DTOA_PRECISION, 5,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("49407", buffer.start());+ CHECK_EQ(-323, point);++ double max_double = 1.7976931348623157e308;+ status = FastDtoa(max_double, FAST_DTOA_PRECISION, 7,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("1797693", buffer.start());+ CHECK_EQ(309, point);++ status = FastDtoa(4294967272.0, FAST_DTOA_PRECISION, 14,+ buffer, &length, &point);+ if (status) {+ CHECK(14 >= length);+ TrimRepresentation(buffer);+ CHECK_EQ("4294967272", buffer.start());+ CHECK_EQ(10, point);+ }++ status = FastDtoa(4.1855804968213567e298, FAST_DTOA_PRECISION, 17,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("41855804968213567", buffer.start());+ CHECK_EQ(299, point);++ status = FastDtoa(5.5626846462680035e-309, FAST_DTOA_PRECISION, 1,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("6", buffer.start());+ CHECK_EQ(-308, point);++ status = FastDtoa(2147483648.0, FAST_DTOA_PRECISION, 5,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("21475", buffer.start());+ CHECK_EQ(10, point);++ status = FastDtoa(3.5844466002796428e+298, FAST_DTOA_PRECISION, 10,+ buffer, &length, &point);+ CHECK(status);+ CHECK(10 >= length);+ TrimRepresentation(buffer);+ CHECK_EQ("35844466", buffer.start());+ CHECK_EQ(299, point);++ uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000);+ double v = Double(smallest_normal64).value();+ status = FastDtoa(v, FAST_DTOA_PRECISION, 17, buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("22250738585072014", buffer.start());+ CHECK_EQ(-307, point);++ uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);+ v = Double(largest_denormal64).value();+ status = FastDtoa(v, FAST_DTOA_PRECISION, 17, buffer, &length, &point);+ CHECK(status);+ CHECK(20 >= length);+ TrimRepresentation(buffer);+ CHECK_EQ("22250738585072009", buffer.start());+ CHECK_EQ(-307, point);++ v = 3.3161339052167390562200598e-237;+ status = FastDtoa(v, FAST_DTOA_PRECISION, 18, buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("331613390521673906", buffer.start());+ CHECK_EQ(-236, point);++ v = 7.9885183916008099497815232e+191;+ status = FastDtoa(v, FAST_DTOA_PRECISION, 4, buffer, &length, &point);+ CHECK(status);+ CHECK_EQ("7989", buffer.start());+ CHECK_EQ(192, point);+}+++TEST(FastDtoaGayShortest) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ bool status;+ int length;+ int point;+ int succeeded = 0;+ int total = 0;+ bool needed_max_length = false;++ Vector<const PrecomputedShortest> precomputed =+ PrecomputedShortestRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedShortest current_test = precomputed[i];+ total++;+ double v = current_test.v;+ status = FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, &length, &point);+ CHECK(kFastDtoaMaximalLength >= length);+ if (!status) continue;+ if (length == kFastDtoaMaximalLength) needed_max_length = true;+ succeeded++;+ CHECK_EQ(current_test.decimal_point, point);+ CHECK_EQ(current_test.representation, buffer.start());+ }+ CHECK(succeeded*1.0/total > 0.99);+ CHECK(needed_max_length);+}+++TEST(FastDtoaGayPrecision) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ bool status;+ int length;+ int point;+ int succeeded = 0;+ int total = 0;+ // Count separately for entries with less than 15 requested digits.+ int succeeded_15 = 0;+ int total_15 = 0;++ Vector<const PrecomputedPrecision> precomputed =+ PrecomputedPrecisionRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedPrecision current_test = precomputed[i];+ double v = current_test.v;+ int number_digits = current_test.number_digits;+ total++;+ if (number_digits <= 15) total_15++;+ status = FastDtoa(v, FAST_DTOA_PRECISION, number_digits,+ buffer, &length, &point);+ CHECK(number_digits >= length);+ if (!status) continue;+ succeeded++;+ if (number_digits <= 15) succeeded_15++;+ TrimRepresentation(buffer);+ CHECK_EQ(current_test.decimal_point, point);+ CHECK_EQ(current_test.representation, buffer.start());+ }+ // The precomputed numbers contain many entries with many requested+ // digits. These have a high failure rate and we therefore expect a lower+ // success rate than for the shortest representation.+ CHECK(succeeded*1.0/total > 0.85);+ // However with less than 15 digits almost the algorithm should almost always+ // succeed.+ CHECK(succeeded_15*1.0/total_15 > 0.9999);+}
+ double-conversion/test/cctest/test-fixed-dtoa.cc view
@@ -0,0 +1,511 @@+// Copyright 2010 the V8 project authors. All rights reserved.+// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are+// met:+//+// * Redistributions of source code must retain the above copyright+// notice, this list of conditions and the following disclaimer.+// * Redistributions in binary form must reproduce the above+// copyright notice, this list of conditions and the following+// disclaimer in the documentation and/or other materials provided+// with the distribution.+// * Neither the name of Google Inc. nor the names of its+// contributors may be used to endorse or promote products derived+// from this software without specific prior written permission.+//+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++#include <stdlib.h>+++#include "cctest.h"+#include "double.h"+#include "fixed-dtoa.h"+#include "gay-fixed.h"+#include "utils.h"++using namespace double_conversion;++static const int kBufferSize = 500;++TEST(FastFixedVariousDoubles) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ int length;+ int point;++ CHECK(FastFixedDtoa(1.0, 1, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(1.0, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(1.0, 0, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0xFFFFFFFF, 5, buffer, &length, &point));+ CHECK_EQ("4294967295", buffer.start());+ CHECK_EQ(10, point);++ CHECK(FastFixedDtoa(4294967296.0, 5, buffer, &length, &point));+ CHECK_EQ("4294967296", buffer.start());+ CHECK_EQ(10, point);++ CHECK(FastFixedDtoa(1e21, 5, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ // CHECK_EQ(22, point);+ CHECK_EQ(22, point);++ CHECK(FastFixedDtoa(999999999999999868928.00, 2, buffer, &length, &point));+ CHECK_EQ("999999999999999868928", buffer.start());+ CHECK_EQ(21, point);++ CHECK(FastFixedDtoa(6.9999999999999989514240000e+21, 5, buffer,+ &length, &point));+ CHECK_EQ("6999999999999998951424", buffer.start());+ CHECK_EQ(22, point);++ CHECK(FastFixedDtoa(1.5, 5, buffer, &length, &point));+ CHECK_EQ("15", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(1.55, 5, buffer, &length, &point));+ CHECK_EQ("155", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(1.55, 1, buffer, &length, &point));+ CHECK_EQ("16", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(1.00000001, 15, buffer, &length, &point));+ CHECK_EQ("100000001", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.1, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(0, point);++ CHECK(FastFixedDtoa(0.01, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-1, point);++ CHECK(FastFixedDtoa(0.001, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-2, point);++ CHECK(FastFixedDtoa(0.0001, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-3, point);++ CHECK(FastFixedDtoa(0.00001, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-4, point);++ CHECK(FastFixedDtoa(0.000001, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-5, point);++ CHECK(FastFixedDtoa(0.0000001, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-6, point);++ CHECK(FastFixedDtoa(0.00000001, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-7, point);++ CHECK(FastFixedDtoa(0.000000001, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-8, point);++ CHECK(FastFixedDtoa(0.0000000001, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-9, point);++ CHECK(FastFixedDtoa(0.00000000001, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-10, point);++ CHECK(FastFixedDtoa(0.000000000001, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-11, point);++ CHECK(FastFixedDtoa(0.0000000000001, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-12, point);++ CHECK(FastFixedDtoa(0.00000000000001, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-13, point);++ CHECK(FastFixedDtoa(0.000000000000001, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-14, point);++ CHECK(FastFixedDtoa(0.0000000000000001, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-15, point);++ CHECK(FastFixedDtoa(0.00000000000000001, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-16, point);++ CHECK(FastFixedDtoa(0.000000000000000001, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-17, point);++ CHECK(FastFixedDtoa(0.0000000000000000001, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-18, point);++ CHECK(FastFixedDtoa(0.00000000000000000001, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-19, point);++ CHECK(FastFixedDtoa(0.10000000004, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(0, point);++ CHECK(FastFixedDtoa(0.01000000004, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-1, point);++ CHECK(FastFixedDtoa(0.00100000004, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-2, point);++ CHECK(FastFixedDtoa(0.00010000004, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-3, point);++ CHECK(FastFixedDtoa(0.00001000004, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-4, point);++ CHECK(FastFixedDtoa(0.00000100004, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-5, point);++ CHECK(FastFixedDtoa(0.00000010004, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-6, point);++ CHECK(FastFixedDtoa(0.00000001004, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-7, point);++ CHECK(FastFixedDtoa(0.00000000104, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-8, point);++ CHECK(FastFixedDtoa(0.0000000001000004, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-9, point);++ CHECK(FastFixedDtoa(0.0000000000100004, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-10, point);++ CHECK(FastFixedDtoa(0.0000000000010004, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-11, point);++ CHECK(FastFixedDtoa(0.0000000000001004, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-12, point);++ CHECK(FastFixedDtoa(0.0000000000000104, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-13, point);++ CHECK(FastFixedDtoa(0.000000000000001000004, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-14, point);++ CHECK(FastFixedDtoa(0.000000000000000100004, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-15, point);++ CHECK(FastFixedDtoa(0.000000000000000010004, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-16, point);++ CHECK(FastFixedDtoa(0.000000000000000001004, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-17, point);++ CHECK(FastFixedDtoa(0.000000000000000000104, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-18, point);++ CHECK(FastFixedDtoa(0.000000000000000000014, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-19, point);++ CHECK(FastFixedDtoa(0.10000000006, 10, buffer, &length, &point));+ CHECK_EQ("1000000001", buffer.start());+ CHECK_EQ(0, point);++ CHECK(FastFixedDtoa(0.01000000006, 10, buffer, &length, &point));+ CHECK_EQ("100000001", buffer.start());+ CHECK_EQ(-1, point);++ CHECK(FastFixedDtoa(0.00100000006, 10, buffer, &length, &point));+ CHECK_EQ("10000001", buffer.start());+ CHECK_EQ(-2, point);++ CHECK(FastFixedDtoa(0.00010000006, 10, buffer, &length, &point));+ CHECK_EQ("1000001", buffer.start());+ CHECK_EQ(-3, point);++ CHECK(FastFixedDtoa(0.00001000006, 10, buffer, &length, &point));+ CHECK_EQ("100001", buffer.start());+ CHECK_EQ(-4, point);++ CHECK(FastFixedDtoa(0.00000100006, 10, buffer, &length, &point));+ CHECK_EQ("10001", buffer.start());+ CHECK_EQ(-5, point);++ CHECK(FastFixedDtoa(0.00000010006, 10, buffer, &length, &point));+ CHECK_EQ("1001", buffer.start());+ CHECK_EQ(-6, point);++ CHECK(FastFixedDtoa(0.00000001006, 10, buffer, &length, &point));+ CHECK_EQ("101", buffer.start());+ CHECK_EQ(-7, point);++ CHECK(FastFixedDtoa(0.00000000106, 10, buffer, &length, &point));+ CHECK_EQ("11", buffer.start());+ CHECK_EQ(-8, point);++ CHECK(FastFixedDtoa(0.0000000001000006, 15, buffer, &length, &point));+ CHECK_EQ("100001", buffer.start());+ CHECK_EQ(-9, point);++ CHECK(FastFixedDtoa(0.0000000000100006, 15, buffer, &length, &point));+ CHECK_EQ("10001", buffer.start());+ CHECK_EQ(-10, point);++ CHECK(FastFixedDtoa(0.0000000000010006, 15, buffer, &length, &point));+ CHECK_EQ("1001", buffer.start());+ CHECK_EQ(-11, point);++ CHECK(FastFixedDtoa(0.0000000000001006, 15, buffer, &length, &point));+ CHECK_EQ("101", buffer.start());+ CHECK_EQ(-12, point);++ CHECK(FastFixedDtoa(0.0000000000000106, 15, buffer, &length, &point));+ CHECK_EQ("11", buffer.start());+ CHECK_EQ(-13, point);++ CHECK(FastFixedDtoa(0.000000000000001000006, 20, buffer, &length, &point));+ CHECK_EQ("100001", buffer.start());+ CHECK_EQ(-14, point);++ CHECK(FastFixedDtoa(0.000000000000000100006, 20, buffer, &length, &point));+ CHECK_EQ("10001", buffer.start());+ CHECK_EQ(-15, point);++ CHECK(FastFixedDtoa(0.000000000000000010006, 20, buffer, &length, &point));+ CHECK_EQ("1001", buffer.start());+ CHECK_EQ(-16, point);++ CHECK(FastFixedDtoa(0.000000000000000001006, 20, buffer, &length, &point));+ CHECK_EQ("101", buffer.start());+ CHECK_EQ(-17, point);++ CHECK(FastFixedDtoa(0.000000000000000000106, 20, buffer, &length, &point));+ CHECK_EQ("11", buffer.start());+ CHECK_EQ(-18, point);++ CHECK(FastFixedDtoa(0.000000000000000000016, 20, buffer, &length, &point));+ CHECK_EQ("2", buffer.start());+ CHECK_EQ(-19, point);++ CHECK(FastFixedDtoa(0.6, 0, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.96, 1, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.996, 2, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.9996, 3, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.99996, 4, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.999996, 5, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.9999996, 6, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.99999996, 7, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.999999996, 8, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.9999999996, 9, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.99999999996, 10, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.999999999996, 11, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.9999999999996, 12, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.99999999999996, 13, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.999999999999996, 14, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.9999999999999996, 15, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(0.00999999999999996, 16, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-1, point);++ CHECK(FastFixedDtoa(0.000999999999999996, 17, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-2, point);++ CHECK(FastFixedDtoa(0.0000999999999999996, 18, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-3, point);++ CHECK(FastFixedDtoa(0.00000999999999999996, 19, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-4, point);++ CHECK(FastFixedDtoa(0.000000999999999999996, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-5, point);++ CHECK(FastFixedDtoa(323423.234234, 10, buffer, &length, &point));+ CHECK_EQ("323423234234", buffer.start());+ CHECK_EQ(6, point);++ CHECK(FastFixedDtoa(12345678.901234, 4, buffer, &length, &point));+ CHECK_EQ("123456789012", buffer.start());+ CHECK_EQ(8, point);++ CHECK(FastFixedDtoa(98765.432109, 5, buffer, &length, &point));+ CHECK_EQ("9876543211", buffer.start());+ CHECK_EQ(5, point);++ CHECK(FastFixedDtoa(42, 20, buffer, &length, &point));+ CHECK_EQ("42", buffer.start());+ CHECK_EQ(2, point);++ CHECK(FastFixedDtoa(0.5, 0, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(1, point);++ CHECK(FastFixedDtoa(1e-23, 10, buffer, &length, &point));+ CHECK_EQ("", buffer.start());+ CHECK_EQ(-10, point);++ CHECK(FastFixedDtoa(1e-123, 2, buffer, &length, &point));+ CHECK_EQ("", buffer.start());+ CHECK_EQ(-2, point);++ CHECK(FastFixedDtoa(1e-123, 0, buffer, &length, &point));+ CHECK_EQ("", buffer.start());+ CHECK_EQ(0, point);++ CHECK(FastFixedDtoa(1e-23, 20, buffer, &length, &point));+ CHECK_EQ("", buffer.start());+ CHECK_EQ(-20, point);++ CHECK(FastFixedDtoa(1e-21, 20, buffer, &length, &point));+ CHECK_EQ("", buffer.start());+ CHECK_EQ(-20, point);++ CHECK(FastFixedDtoa(1e-22, 20, buffer, &length, &point));+ CHECK_EQ("", buffer.start());+ CHECK_EQ(-20, point);++ CHECK(FastFixedDtoa(6e-21, 20, buffer, &length, &point));+ CHECK_EQ("1", buffer.start());+ CHECK_EQ(-19, point);++ CHECK(FastFixedDtoa(9.1193616301674545152000000e+19, 0,+ buffer, &length, &point));+ CHECK_EQ("91193616301674545152", buffer.start());+ CHECK_EQ(20, point);++ CHECK(FastFixedDtoa(4.8184662102767651659096515e-04, 19,+ buffer, &length, &point));+ CHECK_EQ("4818466210276765", buffer.start());+ CHECK_EQ(-3, point);++ CHECK(FastFixedDtoa(1.9023164229540652612705182e-23, 8,+ buffer, &length, &point));+ CHECK_EQ("", buffer.start());+ CHECK_EQ(-8, point);++ CHECK(FastFixedDtoa(1000000000000000128.0, 0,+ buffer, &length, &point));+ CHECK_EQ("1000000000000000128", buffer.start());+ CHECK_EQ(19, point);+}+++TEST(FastFixedDtoaGayFixed) {+ char buffer_container[kBufferSize];+ Vector<char> buffer(buffer_container, kBufferSize);+ bool status;+ int length;+ int point;++ Vector<const PrecomputedFixed> precomputed =+ PrecomputedFixedRepresentations();+ for (int i = 0; i < precomputed.length(); ++i) {+ const PrecomputedFixed current_test = precomputed[i];+ double v = current_test.v;+ int number_digits = current_test.number_digits;+ status = FastFixedDtoa(v, number_digits,+ buffer, &length, &point);+ CHECK(status);+ CHECK_EQ(current_test.decimal_point, point);+ CHECK(number_digits >= length - point);+ CHECK_EQ(current_test.representation, buffer.start());+ }+}
+ double-conversion/test/cctest/test-strtod.cc view
@@ -0,0 +1,452 @@+// Copyright 2006-2008 the V8 project authors. All rights reserved.++#include <stdlib.h>++#include "bignum.h"+#include "cctest.h"+#include "diy-fp.h"+#include "double.h"+#include "strtod.h"+#include "utils.h"++using namespace double_conversion;++static Vector<const char> StringToVector(const char* str) {+ return Vector<const char>(str, strlen(str));+}+++static double StrtodChar(const char* str, int exponent) {+ return Strtod(StringToVector(str), exponent);+}+++TEST(Strtod) {+ Vector<const char> vector;++ vector = StringToVector("0");+ CHECK_EQ(0.0, Strtod(vector, 1));+ CHECK_EQ(0.0, Strtod(vector, 2));+ CHECK_EQ(0.0, Strtod(vector, -2));+ CHECK_EQ(0.0, Strtod(vector, -999));+ CHECK_EQ(0.0, Strtod(vector, +999));++ vector = StringToVector("1");+ CHECK_EQ(1.0, Strtod(vector, 0));+ CHECK_EQ(10.0, Strtod(vector, 1));+ CHECK_EQ(100.0, Strtod(vector, 2));+ CHECK_EQ(1e20, Strtod(vector, 20));+ CHECK_EQ(1e22, Strtod(vector, 22));+ CHECK_EQ(1e23, Strtod(vector, 23));+ CHECK_EQ(1e35, Strtod(vector, 35));+ CHECK_EQ(1e36, Strtod(vector, 36));+ CHECK_EQ(1e37, Strtod(vector, 37));+ CHECK_EQ(1e-1, Strtod(vector, -1));+ CHECK_EQ(1e-2, Strtod(vector, -2));+ CHECK_EQ(1e-5, Strtod(vector, -5));+ CHECK_EQ(1e-20, Strtod(vector, -20));+ CHECK_EQ(1e-22, Strtod(vector, -22));+ CHECK_EQ(1e-23, Strtod(vector, -23));+ CHECK_EQ(1e-25, Strtod(vector, -25));+ CHECK_EQ(1e-39, Strtod(vector, -39));++ vector = StringToVector("2");+ CHECK_EQ(2.0, Strtod(vector, 0));+ CHECK_EQ(20.0, Strtod(vector, 1));+ CHECK_EQ(200.0, Strtod(vector, 2));+ CHECK_EQ(2e20, Strtod(vector, 20));+ CHECK_EQ(2e22, Strtod(vector, 22));+ CHECK_EQ(2e23, Strtod(vector, 23));+ CHECK_EQ(2e35, Strtod(vector, 35));+ CHECK_EQ(2e36, Strtod(vector, 36));+ CHECK_EQ(2e37, Strtod(vector, 37));+ CHECK_EQ(2e-1, Strtod(vector, -1));+ CHECK_EQ(2e-2, Strtod(vector, -2));+ CHECK_EQ(2e-5, Strtod(vector, -5));+ CHECK_EQ(2e-20, Strtod(vector, -20));+ CHECK_EQ(2e-22, Strtod(vector, -22));+ CHECK_EQ(2e-23, Strtod(vector, -23));+ CHECK_EQ(2e-25, Strtod(vector, -25));+ CHECK_EQ(2e-39, Strtod(vector, -39));++ vector = StringToVector("9");+ CHECK_EQ(9.0, Strtod(vector, 0));+ CHECK_EQ(90.0, Strtod(vector, 1));+ CHECK_EQ(900.0, Strtod(vector, 2));+ CHECK_EQ(9e20, Strtod(vector, 20));+ CHECK_EQ(9e22, Strtod(vector, 22));+ CHECK_EQ(9e23, Strtod(vector, 23));+ CHECK_EQ(9e35, Strtod(vector, 35));+ CHECK_EQ(9e36, Strtod(vector, 36));+ CHECK_EQ(9e37, Strtod(vector, 37));+ CHECK_EQ(9e-1, Strtod(vector, -1));+ CHECK_EQ(9e-2, Strtod(vector, -2));+ CHECK_EQ(9e-5, Strtod(vector, -5));+ CHECK_EQ(9e-20, Strtod(vector, -20));+ CHECK_EQ(9e-22, Strtod(vector, -22));+ CHECK_EQ(9e-23, Strtod(vector, -23));+ CHECK_EQ(9e-25, Strtod(vector, -25));+ CHECK_EQ(9e-39, Strtod(vector, -39));++ vector = StringToVector("12345");+ CHECK_EQ(12345.0, Strtod(vector, 0));+ CHECK_EQ(123450.0, Strtod(vector, 1));+ CHECK_EQ(1234500.0, Strtod(vector, 2));+ CHECK_EQ(12345e20, Strtod(vector, 20));+ CHECK_EQ(12345e22, Strtod(vector, 22));+ CHECK_EQ(12345e23, Strtod(vector, 23));+ CHECK_EQ(12345e30, Strtod(vector, 30));+ CHECK_EQ(12345e31, Strtod(vector, 31));+ CHECK_EQ(12345e32, Strtod(vector, 32));+ CHECK_EQ(12345e35, Strtod(vector, 35));+ CHECK_EQ(12345e36, Strtod(vector, 36));+ CHECK_EQ(12345e37, Strtod(vector, 37));+ CHECK_EQ(12345e-1, Strtod(vector, -1));+ CHECK_EQ(12345e-2, Strtod(vector, -2));+ CHECK_EQ(12345e-5, Strtod(vector, -5));+ CHECK_EQ(12345e-20, Strtod(vector, -20));+ CHECK_EQ(12345e-22, Strtod(vector, -22));+ CHECK_EQ(12345e-23, Strtod(vector, -23));+ CHECK_EQ(12345e-25, Strtod(vector, -25));+ CHECK_EQ(12345e-39, Strtod(vector, -39));++ vector = StringToVector("12345678901234");+ CHECK_EQ(12345678901234.0, Strtod(vector, 0));+ CHECK_EQ(123456789012340.0, Strtod(vector, 1));+ CHECK_EQ(1234567890123400.0, Strtod(vector, 2));+ CHECK_EQ(12345678901234e20, Strtod(vector, 20));+ CHECK_EQ(12345678901234e22, Strtod(vector, 22));+ CHECK_EQ(12345678901234e23, Strtod(vector, 23));+ CHECK_EQ(12345678901234e30, Strtod(vector, 30));+ CHECK_EQ(12345678901234e31, Strtod(vector, 31));+ CHECK_EQ(12345678901234e32, Strtod(vector, 32));+ CHECK_EQ(12345678901234e35, Strtod(vector, 35));+ CHECK_EQ(12345678901234e36, Strtod(vector, 36));+ CHECK_EQ(12345678901234e37, Strtod(vector, 37));+ CHECK_EQ(12345678901234e-1, Strtod(vector, -1));+ CHECK_EQ(12345678901234e-2, Strtod(vector, -2));+ CHECK_EQ(12345678901234e-5, Strtod(vector, -5));+ CHECK_EQ(12345678901234e-20, Strtod(vector, -20));+ CHECK_EQ(12345678901234e-22, Strtod(vector, -22));+ CHECK_EQ(12345678901234e-23, Strtod(vector, -23));+ CHECK_EQ(12345678901234e-25, Strtod(vector, -25));+ CHECK_EQ(12345678901234e-39, Strtod(vector, -39));++ vector = StringToVector("123456789012345");+ CHECK_EQ(123456789012345.0, Strtod(vector, 0));+ CHECK_EQ(1234567890123450.0, Strtod(vector, 1));+ CHECK_EQ(12345678901234500.0, Strtod(vector, 2));+ CHECK_EQ(123456789012345e20, Strtod(vector, 20));+ CHECK_EQ(123456789012345e22, Strtod(vector, 22));+ CHECK_EQ(123456789012345e23, Strtod(vector, 23));+ CHECK_EQ(123456789012345e35, Strtod(vector, 35));+ CHECK_EQ(123456789012345e36, Strtod(vector, 36));+ CHECK_EQ(123456789012345e37, Strtod(vector, 37));+ CHECK_EQ(123456789012345e39, Strtod(vector, 39));+ CHECK_EQ(123456789012345e-1, Strtod(vector, -1));+ CHECK_EQ(123456789012345e-2, Strtod(vector, -2));+ CHECK_EQ(123456789012345e-5, Strtod(vector, -5));+ CHECK_EQ(123456789012345e-20, Strtod(vector, -20));+ CHECK_EQ(123456789012345e-22, Strtod(vector, -22));+ CHECK_EQ(123456789012345e-23, Strtod(vector, -23));+ CHECK_EQ(123456789012345e-25, Strtod(vector, -25));+ CHECK_EQ(123456789012345e-39, Strtod(vector, -39));++ CHECK_EQ(0.0, StrtodChar("0", 12345));+ CHECK_EQ(0.0, StrtodChar("", 1324));+ CHECK_EQ(0.0, StrtodChar("000000000", 123));+ CHECK_EQ(0.0, StrtodChar("2", -324));+ CHECK_EQ(4e-324, StrtodChar("3", -324));+ // It would be more readable to put non-zero literals on the left side (i.e.+ // CHECK_EQ(1e-325, StrtodChar("1", -325))), but then Gcc complains that+ // they are truncated to zero.+ CHECK_EQ(0.0, StrtodChar("1", -325));+ CHECK_EQ(0.0, StrtodChar("1", -325));+ CHECK_EQ(0.0, StrtodChar("20000", -328));+ CHECK_EQ(40000e-328, StrtodChar("30000", -328));+ CHECK_EQ(0.0, StrtodChar("10000", -329));+ CHECK_EQ(0.0, StrtodChar("90000", -329));+ CHECK_EQ(0.0, StrtodChar("000000001", -325));+ CHECK_EQ(0.0, StrtodChar("000000001", -325));+ CHECK_EQ(0.0, StrtodChar("0000000020000", -328));+ CHECK_EQ(40000e-328, StrtodChar("00000030000", -328));+ CHECK_EQ(0.0, StrtodChar("0000000010000", -329));+ CHECK_EQ(0.0, StrtodChar("0000000090000", -329));++ // It would be more readable to put the literals (and not Double::Infinity())+ // on the left side (i.e. CHECK_EQ(1e309, StrtodChar("1", 309))), but then Gcc+ // complains that the floating constant exceeds range of 'double'.+ CHECK_EQ(Double::Infinity(), StrtodChar("1", 309));+ CHECK_EQ(1e308, StrtodChar("1", 308));+ CHECK_EQ(1234e305, StrtodChar("1234", 305));+ CHECK_EQ(1234e304, StrtodChar("1234", 304));+ CHECK_EQ(Double::Infinity(), StrtodChar("18", 307));+ CHECK_EQ(17e307, StrtodChar("17", 307));+ CHECK_EQ(Double::Infinity(), StrtodChar("0000001", 309));+ CHECK_EQ(1e308, StrtodChar("00000001", 308));+ CHECK_EQ(1234e305, StrtodChar("00000001234", 305));+ CHECK_EQ(1234e304, StrtodChar("000000001234", 304));+ CHECK_EQ(Double::Infinity(), StrtodChar("0000000018", 307));+ CHECK_EQ(17e307, StrtodChar("0000000017", 307));+ CHECK_EQ(Double::Infinity(), StrtodChar("1000000", 303));+ CHECK_EQ(1e308, StrtodChar("100000", 303));+ CHECK_EQ(1234e305, StrtodChar("123400000", 300));+ CHECK_EQ(1234e304, StrtodChar("123400000", 299));+ CHECK_EQ(Double::Infinity(), StrtodChar("180000000", 300));+ CHECK_EQ(17e307, StrtodChar("170000000", 300));+ CHECK_EQ(Double::Infinity(), StrtodChar("00000001000000", 303));+ CHECK_EQ(1e308, StrtodChar("000000000000100000", 303));+ CHECK_EQ(1234e305, StrtodChar("00000000123400000", 300));+ CHECK_EQ(1234e304, StrtodChar("0000000123400000", 299));+ CHECK_EQ(Double::Infinity(), StrtodChar("00000000180000000", 300));+ CHECK_EQ(17e307, StrtodChar("00000000170000000", 300));+ CHECK_EQ(1.7976931348623157E+308, StrtodChar("17976931348623157", 292));+ CHECK_EQ(1.7976931348623158E+308, StrtodChar("17976931348623158", 292));+ CHECK_EQ(Double::Infinity(), StrtodChar("17976931348623159", 292));++ // The following number is the result of 89255.0/1e-22. Both floating-point+ // numbers can be accurately represented with doubles. However on Linux,x86+ // the floating-point stack is set to 80bits and the double-rounding+ // introduces an error.+ CHECK_EQ(89255e-22, StrtodChar("89255", -22));++ // Some random values.+ CHECK_EQ(358416272e-33, StrtodChar("358416272", -33));+ CHECK_EQ(104110013277974872254e-225,+ StrtodChar("104110013277974872254", -225));++ CHECK_EQ(123456789e108, StrtodChar("123456789", 108));+ CHECK_EQ(123456789e109, StrtodChar("123456789", 109));+ CHECK_EQ(123456789e110, StrtodChar("123456789", 110));+ CHECK_EQ(123456789e111, StrtodChar("123456789", 111));+ CHECK_EQ(123456789e112, StrtodChar("123456789", 112));+ CHECK_EQ(123456789e113, StrtodChar("123456789", 113));+ CHECK_EQ(123456789e114, StrtodChar("123456789", 114));+ CHECK_EQ(123456789e115, StrtodChar("123456789", 115));++ CHECK_EQ(1234567890123456789012345e108,+ StrtodChar("1234567890123456789012345", 108));+ CHECK_EQ(1234567890123456789012345e109,+ StrtodChar("1234567890123456789012345", 109));+ CHECK_EQ(1234567890123456789012345e110,+ StrtodChar("1234567890123456789012345", 110));+ CHECK_EQ(1234567890123456789012345e111,+ StrtodChar("1234567890123456789012345", 111));+ CHECK_EQ(1234567890123456789012345e112,+ StrtodChar("1234567890123456789012345", 112));+ CHECK_EQ(1234567890123456789012345e113,+ StrtodChar("1234567890123456789012345", 113));+ CHECK_EQ(1234567890123456789012345e114,+ StrtodChar("1234567890123456789012345", 114));+ CHECK_EQ(1234567890123456789012345e115,+ StrtodChar("1234567890123456789012345", 115));++ CHECK_EQ(1234567890123456789052345e108,+ StrtodChar("1234567890123456789052345", 108));+ CHECK_EQ(1234567890123456789052345e109,+ StrtodChar("1234567890123456789052345", 109));+ CHECK_EQ(1234567890123456789052345e110,+ StrtodChar("1234567890123456789052345", 110));+ CHECK_EQ(1234567890123456789052345e111,+ StrtodChar("1234567890123456789052345", 111));+ CHECK_EQ(1234567890123456789052345e112,+ StrtodChar("1234567890123456789052345", 112));+ CHECK_EQ(1234567890123456789052345e113,+ StrtodChar("1234567890123456789052345", 113));+ CHECK_EQ(1234567890123456789052345e114,+ StrtodChar("1234567890123456789052345", 114));+ CHECK_EQ(1234567890123456789052345e115,+ StrtodChar("1234567890123456789052345", 115));++ CHECK_EQ(5.445618932859895e-255,+ StrtodChar("5445618932859895362967233318697132813618813095743952975"+ "4392982234069699615600475529427176366709107287468930197"+ "8628345413991790019316974825934906752493984055268219809"+ "5012176093045431437495773903922425632551857520884625114"+ "6241265881735209066709685420744388526014389929047617597"+ "0302268848374508109029268898695825171158085457567481507"+ "4162979705098246243690189880319928315307816832576838178"+ "2563074014542859888710209237525873301724479666744537857"+ "9026553346649664045621387124193095870305991178772256504"+ "4368663670643970181259143319016472430928902201239474588"+ "1392338901353291306607057623202353588698746085415097902"+ "6640064319118728664842287477491068264828851624402189317"+ "2769161449825765517353755844373640588822904791244190695"+ "2998382932630754670573838138825217065450843010498555058"+ "88186560731", -1035));++ // Boundary cases. Boundaries themselves should round to even.+ //+ // 0x1FFFFFFFFFFFF * 2^3 = 72057594037927928+ // next: 72057594037927936+ // boundary: 72057594037927932 should round up.+ CHECK_EQ(72057594037927928.0, StrtodChar("72057594037927928", 0));+ CHECK_EQ(72057594037927936.0, StrtodChar("72057594037927936", 0));+ CHECK_EQ(72057594037927936.0, StrtodChar("72057594037927932", 0));+ CHECK_EQ(72057594037927928.0, StrtodChar("7205759403792793199999", -5));+ CHECK_EQ(72057594037927936.0, StrtodChar("7205759403792793200001", -5));++ // 0x1FFFFFFFFFFFF * 2^10 = 9223372036854774784+ // next: 9223372036854775808+ // boundary: 9223372036854775296 should round up.+ CHECK_EQ(9223372036854774784.0, StrtodChar("9223372036854774784", 0));+ CHECK_EQ(9223372036854775808.0, StrtodChar("9223372036854775808", 0));+ CHECK_EQ(9223372036854775808.0, StrtodChar("9223372036854775296", 0));+ CHECK_EQ(9223372036854774784.0, StrtodChar("922337203685477529599999", -5));+ CHECK_EQ(9223372036854775808.0, StrtodChar("922337203685477529600001", -5));++ // 0x1FFFFFFFFFFFF * 2^50 = 10141204801825834086073718800384+ // next: 10141204801825835211973625643008+ // boundary: 10141204801825834649023672221696 should round up.+ CHECK_EQ(10141204801825834086073718800384.0,+ StrtodChar("10141204801825834086073718800384", 0));+ CHECK_EQ(10141204801825835211973625643008.0,+ StrtodChar("10141204801825835211973625643008", 0));+ CHECK_EQ(10141204801825835211973625643008.0,+ StrtodChar("10141204801825834649023672221696", 0));+ CHECK_EQ(10141204801825834086073718800384.0,+ StrtodChar("1014120480182583464902367222169599999", -5));+ CHECK_EQ(10141204801825835211973625643008.0,+ StrtodChar("1014120480182583464902367222169600001", -5));++ // 0x1FFFFFFFFFFFF * 2^99 = 5708990770823838890407843763683279797179383808+ // next: 5708990770823839524233143877797980545530986496+ // boundary: 5708990770823839207320493820740630171355185152+ // The boundary should round up.+ CHECK_EQ(5708990770823838890407843763683279797179383808.0,+ StrtodChar("5708990770823838890407843763683279797179383808", 0));+ CHECK_EQ(5708990770823839524233143877797980545530986496.0,+ StrtodChar("5708990770823839524233143877797980545530986496", 0));+ CHECK_EQ(5708990770823839524233143877797980545530986496.0,+ StrtodChar("5708990770823839207320493820740630171355185152", 0));+ CHECK_EQ(5708990770823838890407843763683279797179383808.0,+ StrtodChar("5708990770823839207320493820740630171355185151999", -3));+ CHECK_EQ(5708990770823839524233143877797980545530986496.0,+ StrtodChar("5708990770823839207320493820740630171355185152001", -3));++ // The following test-cases got some public attention in early 2011 when they+ // sent Java and PHP into an infinite loop.+ CHECK_EQ(2.225073858507201e-308, StrtodChar("22250738585072011", -324));+ CHECK_EQ(2.22507385850720138309e-308,+ StrtodChar("22250738585072011360574097967091319759348195463516456480"+ "23426109724822222021076945516529523908135087914149158913"+ "03962110687008643869459464552765720740782062174337998814"+ "10632673292535522868813721490129811224514518898490572223"+ "07285255133155755015914397476397983411801999323962548289"+ "01710708185069063066665599493827577257201576306269066333"+ "26475653000092458883164330377797918696120494973903778297"+ "04905051080609940730262937128958950003583799967207254304"+ "36028407889577179615094551674824347103070260914462157228"+ "98802581825451803257070188608721131280795122334262883686"+ "22321503775666622503982534335974568884423900265498198385"+ "48794829220689472168983109969836584681402285424333066033"+ "98508864458040010349339704275671864433837704860378616227"+ "71738545623065874679014086723327636718751", -1076));+}+++static int CompareBignumToDiyFp(const Bignum& bignum_digits,+ int bignum_exponent,+ DiyFp diy_fp) {+ Bignum bignum;+ bignum.AssignBignum(bignum_digits);+ Bignum other;+ other.AssignUInt64(diy_fp.f());+ if (bignum_exponent >= 0) {+ bignum.MultiplyByPowerOfTen(bignum_exponent);+ } else {+ other.MultiplyByPowerOfTen(-bignum_exponent);+ }+ if (diy_fp.e() >= 0) {+ other.ShiftLeft(diy_fp.e());+ } else {+ bignum.ShiftLeft(-diy_fp.e());+ }+ return Bignum::Compare(bignum, other);+}+++static bool CheckDouble(Vector<const char> buffer,+ int exponent,+ double to_check) {+ DiyFp lower_boundary;+ DiyFp upper_boundary;+ Bignum input_digits;+ input_digits.AssignDecimalString(buffer);+ if (to_check == 0.0) {+ const double kMinDouble = 4e-324;+ // Check that the buffer*10^exponent < (0 + kMinDouble)/2.+ Double d(kMinDouble);+ d.NormalizedBoundaries(&lower_boundary, &upper_boundary);+ return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) <= 0;+ }+ if (to_check == Double::Infinity()) {+ const double kMaxDouble = 1.7976931348623157e308;+ // Check that the buffer*10^exponent >= boundary between kMaxDouble and inf.+ Double d(kMaxDouble);+ d.NormalizedBoundaries(&lower_boundary, &upper_boundary);+ return CompareBignumToDiyFp(input_digits, exponent, upper_boundary) >= 0;+ }+ Double d(to_check);+ d.NormalizedBoundaries(&lower_boundary, &upper_boundary);+ if ((d.Significand() & 1) == 0) {+ return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) >= 0 &&+ CompareBignumToDiyFp(input_digits, exponent, upper_boundary) <= 0;+ } else {+ return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) > 0 &&+ CompareBignumToDiyFp(input_digits, exponent, upper_boundary) < 0;+ }+}+++// Copied from v8.cc and adapted to make the function deterministic.+static uint32_t DeterministicRandom() {+ // Random number generator using George Marsaglia's MWC algorithm.+ static uint32_t hi = 0;+ static uint32_t lo = 0;++ // Initialization values don't have any special meaning. (They are the result+ // of two calls to random().)+ if (hi == 0) hi = 0xbfe166e7;+ if (lo == 0) lo = 0x64d1c3c9;++ // Mix the bits.+ hi = 36969 * (hi & 0xFFFF) + (hi >> 16);+ lo = 18273 * (lo & 0xFFFF) + (lo >> 16);+ return (hi << 16) + (lo & 0xFFFF);+}+++static const int kBufferSize = 1024;+static const int kShortStrtodRandomCount = 2;+static const int kLargeStrtodRandomCount = 2;++TEST(RandomStrtod) {+ char buffer[kBufferSize];+ for (int length = 1; length < 15; length++) {+ for (int i = 0; i < kShortStrtodRandomCount; ++i) {+ int pos = 0;+ for (int j = 0; j < length; ++j) {+ buffer[pos++] = random() % 10 + '0';+ }+ int exponent = DeterministicRandom() % (25*2 + 1) - 25 - length;+ buffer[pos] = '\0';+ Vector<const char> vector(buffer, pos);+ double strtod_result = Strtod(vector, exponent);+ CHECK(CheckDouble(vector, exponent, strtod_result));+ }+ }+ for (int length = 15; length < 800; length += 2) {+ for (int i = 0; i < kLargeStrtodRandomCount; ++i) {+ int pos = 0;+ for (int j = 0; j < length; ++j) {+ buffer[pos++] = random() % 10 + '0';+ }+ int exponent = DeterministicRandom() % (308*2 + 1) - 308 - length;+ buffer[pos] = '\0';+ Vector<const char> vector(buffer, pos);+ double strtod_result = Strtod(vector, exponent);+ CHECK(CheckDouble(vector, exponent, strtod_result));+ }+ }+}
+ include/hs-double-conversion.h view
@@ -0,0 +1,24 @@+#ifndef _hs_double_conversion_h+#define _hs_double_conversion_h++#ifdef __cplusplus+extern "C"+{+#endif++#include <stddef.h>++int _hs_ToShortestLength(void);+int _hs_ToShortest(double value, uint16_t *buf);+int _hs_ToFixedLength(void);+int _hs_ToFixed(double value, uint16_t *buf, int ndigits);+int _hs_ToExponentialLength(void);+int _hs_ToExponential(double value, uint16_t *buf, int ndigits);+int _hs_ToPrecisionLength(void);+int _hs_ToPrecision(double value, uint16_t *buf, int ndigits);++#ifdef __cplusplus+}+#endif++#endif /* _hs_double_conversion_h */
+ tests/Properties.hs view
@@ -0,0 +1,11 @@+import Data.Double.Conversion+import Test.QuickCheck+import Test.Framework (defaultMain, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import qualified Data.Text as T++shortest a = (read . T.unpack . toShortest) a == a++main = defaultMain [+ testProperty "shortest" shortest+ ]
+ tests/double-conversion-tests.cabal view
@@ -0,0 +1,15 @@+name: double-conversion-tests+version: 0+cabal-version: >= 1.8+build-type: Simple++executable qc+ main-is: Properties.hs++ build-depends:+ QuickCheck,+ base,+ double-conversion,+ test-framework,+ test-framework-quickcheck2,+ text >= 0.11.0.8