├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── cmake ├── FindDoubleConversion.cmake └── FindGMP.cmake ├── grisu ├── AUTHORS ├── CMakeLists.txt ├── COPYING ├── Changelog ├── LICENSE ├── Makefile ├── README ├── SConstruct ├── double-conversionBuildTreeSettings.cmake.in ├── double-conversionConfig.cmake.in ├── double-conversionConfigVersion.cmake.in └── src │ ├── CMakeLists.txt │ ├── SConscript │ ├── bignum-dtoa.cc │ ├── bignum-dtoa.h │ ├── bignum.cc │ ├── bignum.h │ ├── cached-powers.cc │ ├── cached-powers.h │ ├── diy-fp.cc │ ├── diy-fp.h │ ├── double-conversion.cc │ ├── double-conversion.h │ ├── fast-dtoa.cc │ ├── fast-dtoa.h │ ├── fixed-dtoa.cc │ ├── fixed-dtoa.h │ ├── ieee.h │ ├── strtod.cc │ ├── strtod.h │ └── utils.h ├── lib ├── Makefile ├── enum3.h ├── enum4.h ├── errol.c ├── errol.h ├── itoa_c.h └── lookup.h └── test ├── Makefile ├── dragon4.c ├── dragon4.h ├── interop.cpp ├── main.c └── proof.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Other 32 | run.sh 33 | 34 | # vim 35 | *~ 36 | .*.swp 37 | 38 | # compiler 39 | *.s 40 | 41 | # generated files 42 | config.h 43 | 44 | # cmake 45 | build/ 46 | Makefile 47 | /*.cmake 48 | CMakeCache.txt 49 | CMakeFiles/ 50 | install_manifest.txt 51 | 52 | # ctest 53 | *.log 54 | Testing/ 55 | DartConfiguration.tcl 56 | 57 | # Visual Studio 58 | /*.vcxproj 59 | /*.vcxproj.filters 60 | /*.vcxproj.user 61 | /*.dir/ 62 | /*.sln 63 | /*.suo 64 | /*.sdf 65 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.3) 2 | project(Errol) 3 | enable_testing() 4 | 5 | include(CTest) 6 | 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 8 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY build) 9 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY build) 10 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY test) 11 | set(CMAKE_C_STANDARD 11) 12 | set(CMAKE_CXX_STANDARD 14) 13 | 14 | 15 | if(MINGW) 16 | add_definitions(-DMINGW_HAS_SECURE_API) 17 | endif() 18 | 19 | if(NOT MSVC) 20 | add_definitions(-Wall) 21 | set(CMAKE_C_EXTENSIONS OFF) 22 | set(CMAKE_CXX_EXTENSIONS OFF) 23 | else() 24 | foreach(flagvar CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE 25 | CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) 26 | string(REGEX REPLACE "/MD" "/MT" ${flagvar} "${${flagvar}}") 27 | string(REGEX REPLACE "/MDd" "/MTd" ${flagvar} "${${flagvar}}") 28 | endforeach() 29 | endif() 30 | 31 | include_directories(lib) 32 | 33 | file(GLOB errol_srcs lib/*.c) 34 | file(GLOB tests_srcs test/*.c test/*.cpp) 35 | 36 | add_library(errol ${errol_srcs}) 37 | 38 | if(BUILD_TESTING) 39 | find_package(DoubleConversion REQUIRED) 40 | find_package(GMP REQUIRED) 41 | include_directories(${DOUBLE_CONVERSION_INCLUDE_DIRS}) 42 | include_directories(${GMP_INCLUDE_DIR}) 43 | add_executable(run ${tests_srcs}) 44 | target_link_libraries(run errol) 45 | target_link_libraries(run ${DOUBLE_CONVERSION_LIBRARIES}) 46 | target_link_libraries(run ${GMP_LIBRARIES}) 47 | add_test(test4 test/run --fuzz4=100000) 48 | endif() 49 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Marc Andrysco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Performance Evaluation Correction 2 | 3 | Our original evaluation of Errol against the prior work of Grisu3 was 4 | erroneous. The evaluation indicates a 2x speed improvement over Grisu3. 5 | However, corrected performance measurements show a 2x speed loss to Grisu3. 6 | 7 | Early on in our research, we wrote benchmarks to test our algorithm in 8 | relation to the previous algorithms Dragon4 and Grisu3. The build system for 9 | Grisu3 available for download did not compile Grisu3 with optimizations turned 10 | on. We thought this may be the case and attempted to configure the Grisu3 11 | build system to on turn compiler optimizations. Unfortunately, we got this 12 | step wrong because of our unfamiliarity with the SCons build system used in 13 | the Grisu3 build. Furthermore, our misconfiguration bug did not cause any 14 | errors, and so we thought that optimizations were already enabled in the 15 | default configuration -- when in reality it was not. The Artifact Evaluation 16 | Committee ran our benchmarks and reproduced our timing numbers, but they 17 | reproduced the same incorrect numbers that we collected. This is not 18 | surprising, since they ran our build script did not turn on optimizations, and 19 | there were no visible errors that would hint at a problem. 20 | 21 | The mistake was discovered when Florian Loitsch, author of the Grisu3 22 | algorithm, attempted to replicate our results. He alerted us to the 23 | discrepancy, and we immediately confirmed the corrected results. We then 24 | informed the POPL PC chair of the mistake, and the PC chair advised us to 25 | create a page like this one and update the PDF paper and corresponding talk. 26 | 27 | An updated version of the paper is available here: 28 | [https://cseweb.ucsd.edu/~mandrysc/pub/dtoa.pdf](https://cseweb.ucsd.edu/~mandrysc/pub/dtoa.pdf). 29 | -------------------------------------------------------------------------------- /cmake/FindDoubleConversion.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find DoubleConversion 2 | # Once done this will define 3 | # DOUBLE_CONVERSION_FOUND - System has LibXml2 4 | # DOUBLE_CONVERSION_INCLUDE_DIRS - The LibXml2 include directories 5 | # DOUBLE_CONVERSION_LIBRARIES - The libraries needed to use LibXml2 6 | 7 | find_path(DOUBLE_CONVERSION_INCLUDE_DIR double-conversion/double-conversion.h) 8 | find_library(DOUBLE_CONVERSION_LIBRARY NAMES double-conversion) 9 | 10 | include(FindPackageHandleStandardArgs) 11 | find_package_handle_standard_args(DoubleConversion DEFAULT_MSG 12 | DOUBLE_CONVERSION_LIBRARY DOUBLE_CONVERSION_INCLUDE_DIR) 13 | 14 | mark_as_advanced(DOUBLE_CONVERSION_INCLUDE_DIR DOUBLE_CONVERSION_LIBRARY ) 15 | 16 | set(DOUBLE_CONVERSION_LIBRARIES ${DOUBLE_CONVERSION_LIBRARY} ) 17 | set(DOUBLE_CONVERSION_INCLUDE_DIRS ${DOUBLE_CONVERSION_INCLUDE_DIR} ) 18 | -------------------------------------------------------------------------------- /cmake/FindGMP.cmake: -------------------------------------------------------------------------------- 1 | # Try to find the GMP librairies 2 | # GMP_FOUND - system has GMP lib 3 | # GMP_INCLUDE_DIR - the GMP include directory 4 | # GMP_LIBRARIES - Libraries needed to use GMP 5 | 6 | # Copyright (c) 2006, Laurent Montel, 7 | # 8 | # Redistribution and use is allowed according to the terms of the BSD license. 9 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 10 | 11 | if (GMP_INCLUDE_DIR AND GMP_LIBRARIES) 12 | # Already in cache, be silent 13 | set(GMP_FIND_QUIETLY TRUE) 14 | endif (GMP_INCLUDE_DIR AND GMP_LIBRARIES) 15 | 16 | find_path(GMP_INCLUDE_DIR NAMES gmp.h ) 17 | find_library(GMP_LIBRARIES NAMES gmp libgmp ) 18 | find_library(GMPXX_LIBRARIES NAMES gmpxx libgmpxx ) 19 | MESSAGE(STATUS "GMP libs: " ${GMP_LIBRARIES} " " ${GMPXX_LIBRARIES} ) 20 | 21 | include(FindPackageHandleStandardArgs) 22 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMP DEFAULT_MSG GMP_INCLUDE_DIR GMP_LIBRARIES) 23 | 24 | mark_as_advanced(GMP_INCLUDE_DIR GMP_LIBRARIES) 25 | -------------------------------------------------------------------------------- /grisu/AUTHORS: -------------------------------------------------------------------------------- 1 | # Below is a list of people and organizations that have contributed 2 | # to the double-conversion project. Names should be added to the 3 | # list like so: 4 | # 5 | # Name/Organization 6 | 7 | Google Inc. 8 | Mozilla Foundation 9 | 10 | Jeff Muizelaar 11 | Mike Hommey 12 | Martin Olsson 13 | Kent Williams 14 | Elan Ruusamäe 15 | -------------------------------------------------------------------------------- /grisu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(double-conversion) 3 | 4 | # pick a version # 5 | set(double-conversion_VERSION 6 | 1.1.1) 7 | 8 | # set paths for install -- empty initially 9 | # Offer the user the choice of overriding the installation directories 10 | set(INSTALL_BIN_DIR CACHE PATH "Installation directory for libraries") 11 | set(INSTALL_LIB_DIR CACHE PATH "Installation directory for libraries") 12 | set(INSTALL_INCLUDE_DIR CACHE PATH "Installation directory for include") 13 | # set suffix for CMake files used for packaging 14 | if(WIN32 AND NOT CYGWIN) 15 | set(INSTALL_CMAKE_DIR CMake) 16 | else() 17 | set(INSTALL_CMAKE_DIR lib/CMake/double-conversion) 18 | endif() 19 | 20 | # Make relative paths absolute (needed later) 21 | foreach(p LIB BIN INCLUDE CMAKE) 22 | set(var INSTALL_${p}_DIR) 23 | if(NOT IS_ABSOLUTE "${${var}}") 24 | set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") 25 | endif() 26 | endforeach() 27 | 28 | # 29 | # set up include dirs 30 | include_directories("${PROJECT_SOURCE_DIR}/src" 31 | "${PROJECT_BINARY_DIR}" 32 | ) 33 | 34 | # Add src subdirectory 35 | add_subdirectory(src) 36 | 37 | # 38 | # set up testing if requested 39 | option(BUILD_TESTING "Build test programs" OFF) 40 | if(BUILD_TESTING) 41 | enable_testing() 42 | include(CTest) 43 | add_subdirectory(test) 44 | endif() 45 | 46 | # 47 | # mention the library target as export library 48 | export(TARGETS double-conversion 49 | FILE "${PROJECT_BINARY_DIR}/double-conversionLibraryDepends.cmake") 50 | 51 | # 52 | # set this build as an importable package 53 | export(PACKAGE double-conversion) 54 | 55 | # 56 | # make a cmake file -- in this case, all that needs defining 57 | # is double-conversion_INCLUDE_DIRS 58 | configure_file(double-conversionBuildTreeSettings.cmake.in 59 | "${PROJECT_BINARY_DIR}/double-conversionBuildTreeSettings.cmake" 60 | @ONLY) 61 | 62 | # 63 | # determine where include is relative to the CMake dir in 64 | # in installed tree 65 | file(RELATIVE_PATH CONF_REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" 66 | "${INSTALL_INCLUDE_DIR}") 67 | 68 | # 69 | # sets up config to be used by CMake find_package 70 | configure_file(double-conversionConfig.cmake.in 71 | "${PROJECT_BINARY_DIR}/double-conversionConfig.cmake" 72 | @ONLY) 73 | # 74 | # Export version # checked by find_package 75 | configure_file(double-conversionConfigVersion.cmake.in 76 | "${PROJECT_BINARY_DIR}/double-conversionConfigVersion.cmake" 77 | @ONLY) 78 | # 79 | # install config files for find_package 80 | install(FILES 81 | "${PROJECT_BINARY_DIR}/double-conversionConfig.cmake" 82 | "${PROJECT_BINARY_DIR}/double-conversionConfigVersion.cmake" 83 | DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) 84 | 85 | 86 | # 87 | # generates install cmake files to find libraries in installation. 88 | install(EXPORT double-conversionLibraryDepends DESTINATION 89 | "${INSTALL_CMAKE_DIR}" COMPONENT dev) 90 | -------------------------------------------------------------------------------- /grisu/COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2006-2011, the V8 project authors. All rights reserved. 2 | Redistribution and use in source and binary forms, with or without 3 | modification, are permitted provided that the following conditions are 4 | met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above 9 | copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | * Neither the name of Google Inc. nor the names of its 13 | contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /grisu/Changelog: -------------------------------------------------------------------------------- 1 | 2014-01-12: 2 | Tagged v2.0.1. 3 | Fix compilation for ARMv8 64bit (used wrong define). 4 | Improved SConstruct file. Thanks to Milan Bouchet-Valat and Elan Ruusamäe. 5 | Fixed lots of warnings (especially on Windows). Thanks to Greg Smith. 6 | 7 | 2013-11-09: 8 | Tagged v2.0.0. 9 | String-to-Double|Float: ALLOW_LEADING_SPACES and similar flags now include 10 | new-lines, tabs and all Unicode whitespace characters. 11 | 12 | 2013-11-09: 13 | Tagged v1.1.2. 14 | Add support for ARM 64 and OsX ppc. 15 | Rewrite tests so they pass under Visual Studio. 16 | Add CMake build system support. 17 | Fix warnings. 18 | 19 | 2012-06-10: 20 | Tagged v1.1.1. 21 | Null terminate exponent buffer (only an issue when asserts are enabled). 22 | Support more architectures. 23 | 24 | 2012-02-05: 25 | Merged in Single-branch with single-precision support. 26 | Tagged v1.1 (based on b28450f33e1db493948a535d8f84e88fa211bd10). 27 | 28 | 2012-02-05: 29 | Tagged v1.0 (based on eda0196e9ac8fcdf59e92cb62885ee0af5391969). 30 | -------------------------------------------------------------------------------- /grisu/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2006-2011, the V8 project authors. All rights reserved. 2 | Redistribution and use in source and binary forms, with or without 3 | modification, are permitted provided that the following conditions are 4 | met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above 9 | copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | * Neither the name of Google Inc. nor the names of its 13 | contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /grisu/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | scons optimize=1 prefix=. install 3 | scons -c 4 | 5 | test: 6 | ./run_tests --list | tr -d '<' | xargs ./run_tests 7 | 8 | .PHONY: test all 9 | -------------------------------------------------------------------------------- /grisu/README: -------------------------------------------------------------------------------- 1 | http://code.google.com/p/double-conversion 2 | 3 | This project (double-conversion) provides binary-decimal and decimal-binary 4 | routines for IEEE doubles. 5 | 6 | The library consists of efficient conversion routines that have been extracted 7 | from the V8 JavaScript engine. The code has been refactored and improved so that 8 | it can be used more easily in other projects. 9 | 10 | There is extensive documentation in src/double-conversion.h. Other examples can 11 | be found in test/cctest/test-conversions.cc. 12 | -------------------------------------------------------------------------------- /grisu/SConstruct: -------------------------------------------------------------------------------- 1 | # vim:ft=python 2 | import os 3 | 4 | double_conversion_sources = ['src/' + x for x in SConscript('src/SConscript')] 5 | double_conversion_headers = ['src/' + x for x in [ 6 | 'bignum.h', 7 | 'cached-powers.h', 8 | 'diy-fp.h', 9 | 'double-conversion.h', 10 | 'fast-dtoa.h', 11 | 'fixed-dtoa.h', 12 | 'ieee.h', 13 | 'strtod.h', 14 | 'utils.h']] 15 | 16 | library_name = 'double-conversion' 17 | DESTDIR = ARGUMENTS.get('DESTDIR', '') 18 | prefix = ARGUMENTS.get('prefix', '/usr/local') 19 | lib = ARGUMENTS.get('libsuffix', 'lib') 20 | libdir = os.path.join(DESTDIR + prefix, lib) 21 | incdir = os.path.join(DESTDIR + prefix, 'include', library_name) 22 | 23 | env = Environment(CPPPATH='#/src', LIBS=['m', 'stdc++'], 24 | CXXFLAGS=ARGUMENTS.get('CXXFLAGS', '')) 25 | debug = ARGUMENTS.get('debug', 0) 26 | optimize = ARGUMENTS.get('optimize', 0) 27 | env.Replace(CXX = ARGUMENTS.get('CXX', 'g++')) 28 | 29 | # for shared lib, requires scons 2.3.0 30 | env['SHLIBVERSION'] = '1.0.0' 31 | 32 | CCFLAGS = [] 33 | if int(debug): 34 | CCFLAGS.append(ARGUMENTS.get('CXXFLAGS', '-g -Wall -Werror')) 35 | if int(optimize): 36 | CCFLAGS.append(ARGUMENTS.get('CXXFLAGS', '-O3')) 37 | 38 | env.Append(CCFLAGS = " ".join(CCFLAGS)) 39 | 40 | double_conversion_shared_objects = [ 41 | env.SharedObject(src) for src in double_conversion_sources] 42 | double_conversion_static_objects = [ 43 | env.StaticObject(src) for src in double_conversion_sources] 44 | 45 | static_lib = env.StaticLibrary(library_name, double_conversion_static_objects) 46 | 47 | env.Install(libdir, static_lib) 48 | env.Install(incdir, double_conversion_headers) 49 | 50 | env.Alias('install', [incdir, libdir]) 51 | -------------------------------------------------------------------------------- /grisu/double-conversionBuildTreeSettings.cmake.in: -------------------------------------------------------------------------------- 1 | set(double-conversion_INCLUDE_DIRS 2 | "@PROJECT_SOURCE_DIR@/src") 3 | -------------------------------------------------------------------------------- /grisu/double-conversionConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # - Config file for the double-conversion package 2 | # It defines the following variables 3 | # double-conversion_INCLUDE_DIRS 4 | # double-conversion_LIBRARIES 5 | 6 | get_filename_component(double-conversion_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 7 | 8 | if(EXISTS "${double-conversion_CMAKE_DIR}/CMakeCache.txt") 9 | include("${double-conversion_CMAKE_DIR}/double-conversionBuildTreeSettings.cmake") 10 | else() 11 | set(double-conversion_INCLUDE_DIRS 12 | "${double-conversion_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@/include/double-conversion") 13 | endif() 14 | 15 | include("${double-conversion_CMAKE_DIR}/double-conversionLibraryDepends.cmake") 16 | 17 | set(double-conversion_LIBRARIES double-conversion) 18 | -------------------------------------------------------------------------------- /grisu/double-conversionConfigVersion.cmake.in: -------------------------------------------------------------------------------- 1 | set(PACKAGE_VERSION "@double-conversion_VERSION@") 2 | 3 | # Check whether the requested PACKAGE_FIND_VERSION is compatible 4 | if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") 5 | set(PACKAGE_VERSION_COMPATIBLE FALSE) 6 | else() 7 | set(PACKAGE_VERSION_COMPATIBLE TRUE) 8 | if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") 9 | set(PACKAGE_VERSION_EXACT TRUE) 10 | endif() 11 | endif() 12 | -------------------------------------------------------------------------------- /grisu/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(headers 3 | bignum.h 4 | cached-powers.h 5 | diy-fp.h 6 | double-conversion.h 7 | fast-dtoa.h 8 | fixed-dtoa.h 9 | ieee.h 10 | strtod.h 11 | utils.h 12 | ) 13 | 14 | add_library(double-conversion 15 | bignum.cc 16 | bignum-dtoa.cc 17 | cached-powers.cc 18 | diy-fp.cc 19 | double-conversion.cc 20 | fast-dtoa.cc 21 | fixed-dtoa.cc 22 | strtod.cc 23 | ${headers} 24 | ) 25 | 26 | # 27 | # associates the list of headers with the library 28 | # for the purposes of installation/import into other projects 29 | set_target_properties(double-conversion 30 | PROPERTIES PUBLIC_HEADER "${headers}") 31 | 32 | # 33 | # install command to set up library install 34 | # given the above PUBLIC_HEADER property set, this 35 | # pulls along all the header files with the library. 36 | install(TARGETS double-conversion 37 | EXPORT double-conversionLibraryDepends 38 | RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin 39 | LIBRARY DESTINATION "${INSTALL_LIB_DIR}/lib" COMPONENT shlib 40 | ARCHIVE DESTINATION "${INSTALL_LIB_DIR}/lib" COMPONENT lib 41 | PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}/include/double-conversion" 42 | COMPONENT dev) 43 | -------------------------------------------------------------------------------- /grisu/src/SConscript: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | double_conversion_sources = [ 3 | 'bignum.cc', 4 | 'bignum-dtoa.cc', 5 | 'cached-powers.cc', 6 | 'diy-fp.cc', 7 | 'double-conversion.cc', 8 | 'fast-dtoa.cc', 9 | 'fixed-dtoa.cc', 10 | 'strtod.cc' 11 | ] 12 | Return('double_conversion_sources') 13 | -------------------------------------------------------------------------------- /grisu/src/bignum-dtoa.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_BIGNUM_DTOA_H_ 29 | #define DOUBLE_CONVERSION_BIGNUM_DTOA_H_ 30 | 31 | #include "utils.h" 32 | 33 | namespace double_conversion { 34 | 35 | enum BignumDtoaMode { 36 | // Return the shortest correct representation. 37 | // For example the output of 0.299999999999999988897 is (the less accurate but 38 | // correct) 0.3. 39 | BIGNUM_DTOA_SHORTEST, 40 | // Same as BIGNUM_DTOA_SHORTEST but for single-precision floats. 41 | BIGNUM_DTOA_SHORTEST_SINGLE, 42 | // Return a fixed number of digits after the decimal point. 43 | // For instance fixed(0.1, 4) becomes 0.1000 44 | // If the input number is big, the output will be big. 45 | BIGNUM_DTOA_FIXED, 46 | // Return a fixed number of digits, no matter what the exponent is. 47 | BIGNUM_DTOA_PRECISION 48 | }; 49 | 50 | // Converts the given double 'v' to ascii. 51 | // The result should be interpreted as buffer * 10^(point-length). 52 | // The buffer will be null-terminated. 53 | // 54 | // The input v must be > 0 and different from NaN, and Infinity. 55 | // 56 | // The output depends on the given mode: 57 | // - SHORTEST: produce the least amount of digits for which the internal 58 | // identity requirement is still satisfied. If the digits are printed 59 | // (together with the correct exponent) then reading this number will give 60 | // 'v' again. The buffer will choose the representation that is closest to 61 | // 'v'. If there are two at the same distance, than the number is round up. 62 | // In this mode the 'requested_digits' parameter is ignored. 63 | // - FIXED: produces digits necessary to print a given number with 64 | // 'requested_digits' digits after the decimal point. The produced digits 65 | // might be too short in which case the caller has to fill the gaps with '0's. 66 | // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. 67 | // Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns 68 | // buffer="2", point=0. 69 | // Note: the length of the returned buffer has no meaning wrt the significance 70 | // of its digits. That is, just because it contains '0's does not mean that 71 | // any other digit would not satisfy the internal identity requirement. 72 | // - PRECISION: produces 'requested_digits' where the first digit is not '0'. 73 | // Even though the length of produced digits usually equals 74 | // 'requested_digits', the function is allowed to return fewer digits, in 75 | // which case the caller has to fill the missing digits with '0's. 76 | // Halfway cases are again rounded up. 77 | // 'BignumDtoa' expects the given buffer to be big enough to hold all digits 78 | // and a terminating null-character. 79 | void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, 80 | Vector buffer, int* length, int* point); 81 | 82 | } // namespace double_conversion 83 | 84 | #endif // DOUBLE_CONVERSION_BIGNUM_DTOA_H_ 85 | -------------------------------------------------------------------------------- /grisu/src/bignum.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #include "bignum.h" 29 | #include "utils.h" 30 | 31 | namespace double_conversion { 32 | 33 | Bignum::Bignum() 34 | : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) { 35 | for (int i = 0; i < kBigitCapacity; ++i) { 36 | bigits_[i] = 0; 37 | } 38 | } 39 | 40 | 41 | template 42 | static int BitSize(S value) { 43 | (void) value; // Mark variable as used. 44 | return 8 * sizeof(value); 45 | } 46 | 47 | // Guaranteed to lie in one Bigit. 48 | void Bignum::AssignUInt16(uint16_t value) { 49 | ASSERT(kBigitSize >= BitSize(value)); 50 | Zero(); 51 | if (value == 0) return; 52 | 53 | EnsureCapacity(1); 54 | bigits_[0] = value; 55 | used_digits_ = 1; 56 | } 57 | 58 | 59 | void Bignum::AssignUInt64(uint64_t value) { 60 | const int kUInt64Size = 64; 61 | 62 | Zero(); 63 | if (value == 0) return; 64 | 65 | int needed_bigits = kUInt64Size / kBigitSize + 1; 66 | EnsureCapacity(needed_bigits); 67 | for (int i = 0; i < needed_bigits; ++i) { 68 | bigits_[i] = value & kBigitMask; 69 | value = value >> kBigitSize; 70 | } 71 | used_digits_ = needed_bigits; 72 | Clamp(); 73 | } 74 | 75 | 76 | void Bignum::AssignBignum(const Bignum& other) { 77 | exponent_ = other.exponent_; 78 | for (int i = 0; i < other.used_digits_; ++i) { 79 | bigits_[i] = other.bigits_[i]; 80 | } 81 | // Clear the excess digits (if there were any). 82 | for (int i = other.used_digits_; i < used_digits_; ++i) { 83 | bigits_[i] = 0; 84 | } 85 | used_digits_ = other.used_digits_; 86 | } 87 | 88 | 89 | static uint64_t ReadUInt64(Vector buffer, 90 | int from, 91 | int digits_to_read) { 92 | uint64_t result = 0; 93 | for (int i = from; i < from + digits_to_read; ++i) { 94 | int digit = buffer[i] - '0'; 95 | ASSERT(0 <= digit && digit <= 9); 96 | result = result * 10 + digit; 97 | } 98 | return result; 99 | } 100 | 101 | 102 | void Bignum::AssignDecimalString(Vector value) { 103 | // 2^64 = 18446744073709551616 > 10^19 104 | const int kMaxUint64DecimalDigits = 19; 105 | Zero(); 106 | int length = value.length(); 107 | int pos = 0; 108 | // Let's just say that each digit needs 4 bits. 109 | while (length >= kMaxUint64DecimalDigits) { 110 | uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits); 111 | pos += kMaxUint64DecimalDigits; 112 | length -= kMaxUint64DecimalDigits; 113 | MultiplyByPowerOfTen(kMaxUint64DecimalDigits); 114 | AddUInt64(digits); 115 | } 116 | uint64_t digits = ReadUInt64(value, pos, length); 117 | MultiplyByPowerOfTen(length); 118 | AddUInt64(digits); 119 | Clamp(); 120 | } 121 | 122 | 123 | static int HexCharValue(char c) { 124 | if ('0' <= c && c <= '9') return c - '0'; 125 | if ('a' <= c && c <= 'f') return 10 + c - 'a'; 126 | ASSERT('A' <= c && c <= 'F'); 127 | return 10 + c - 'A'; 128 | } 129 | 130 | 131 | void Bignum::AssignHexString(Vector value) { 132 | Zero(); 133 | int length = value.length(); 134 | 135 | int needed_bigits = length * 4 / kBigitSize + 1; 136 | EnsureCapacity(needed_bigits); 137 | int string_index = length - 1; 138 | for (int i = 0; i < needed_bigits - 1; ++i) { 139 | // These bigits are guaranteed to be "full". 140 | Chunk current_bigit = 0; 141 | for (int j = 0; j < kBigitSize / 4; j++) { 142 | current_bigit += HexCharValue(value[string_index--]) << (j * 4); 143 | } 144 | bigits_[i] = current_bigit; 145 | } 146 | used_digits_ = needed_bigits - 1; 147 | 148 | Chunk most_significant_bigit = 0; // Could be = 0; 149 | for (int j = 0; j <= string_index; ++j) { 150 | most_significant_bigit <<= 4; 151 | most_significant_bigit += HexCharValue(value[j]); 152 | } 153 | if (most_significant_bigit != 0) { 154 | bigits_[used_digits_] = most_significant_bigit; 155 | used_digits_++; 156 | } 157 | Clamp(); 158 | } 159 | 160 | 161 | void Bignum::AddUInt64(uint64_t operand) { 162 | if (operand == 0) return; 163 | Bignum other; 164 | other.AssignUInt64(operand); 165 | AddBignum(other); 166 | } 167 | 168 | 169 | void Bignum::AddBignum(const Bignum& other) { 170 | ASSERT(IsClamped()); 171 | ASSERT(other.IsClamped()); 172 | 173 | // If this has a greater exponent than other append zero-bigits to this. 174 | // After this call exponent_ <= other.exponent_. 175 | Align(other); 176 | 177 | // There are two possibilities: 178 | // aaaaaaaaaaa 0000 (where the 0s represent a's exponent) 179 | // bbbbb 00000000 180 | // ---------------- 181 | // ccccccccccc 0000 182 | // or 183 | // aaaaaaaaaa 0000 184 | // bbbbbbbbb 0000000 185 | // ----------------- 186 | // cccccccccccc 0000 187 | // In both cases we might need a carry bigit. 188 | 189 | EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_); 190 | Chunk carry = 0; 191 | int bigit_pos = other.exponent_ - exponent_; 192 | ASSERT(bigit_pos >= 0); 193 | for (int i = 0; i < other.used_digits_; ++i) { 194 | Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry; 195 | bigits_[bigit_pos] = sum & kBigitMask; 196 | carry = sum >> kBigitSize; 197 | bigit_pos++; 198 | } 199 | 200 | while (carry != 0) { 201 | Chunk sum = bigits_[bigit_pos] + carry; 202 | bigits_[bigit_pos] = sum & kBigitMask; 203 | carry = sum >> kBigitSize; 204 | bigit_pos++; 205 | } 206 | used_digits_ = Max(bigit_pos, used_digits_); 207 | ASSERT(IsClamped()); 208 | } 209 | 210 | 211 | void Bignum::SubtractBignum(const Bignum& other) { 212 | ASSERT(IsClamped()); 213 | ASSERT(other.IsClamped()); 214 | // We require this to be bigger than other. 215 | ASSERT(LessEqual(other, *this)); 216 | 217 | Align(other); 218 | 219 | int offset = other.exponent_ - exponent_; 220 | Chunk borrow = 0; 221 | int i; 222 | for (i = 0; i < other.used_digits_; ++i) { 223 | ASSERT((borrow == 0) || (borrow == 1)); 224 | Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow; 225 | bigits_[i + offset] = difference & kBigitMask; 226 | borrow = difference >> (kChunkSize - 1); 227 | } 228 | while (borrow != 0) { 229 | Chunk difference = bigits_[i + offset] - borrow; 230 | bigits_[i + offset] = difference & kBigitMask; 231 | borrow = difference >> (kChunkSize - 1); 232 | ++i; 233 | } 234 | Clamp(); 235 | } 236 | 237 | 238 | void Bignum::ShiftLeft(int shift_amount) { 239 | if (used_digits_ == 0) return; 240 | exponent_ += shift_amount / kBigitSize; 241 | int local_shift = shift_amount % kBigitSize; 242 | EnsureCapacity(used_digits_ + 1); 243 | BigitsShiftLeft(local_shift); 244 | } 245 | 246 | 247 | void Bignum::MultiplyByUInt32(uint32_t factor) { 248 | if (factor == 1) return; 249 | if (factor == 0) { 250 | Zero(); 251 | return; 252 | } 253 | if (used_digits_ == 0) return; 254 | 255 | // The product of a bigit with the factor is of size kBigitSize + 32. 256 | // Assert that this number + 1 (for the carry) fits into double chunk. 257 | ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1); 258 | DoubleChunk carry = 0; 259 | for (int i = 0; i < used_digits_; ++i) { 260 | DoubleChunk product = static_cast(factor) * bigits_[i] + carry; 261 | bigits_[i] = static_cast(product & kBigitMask); 262 | carry = (product >> kBigitSize); 263 | } 264 | while (carry != 0) { 265 | EnsureCapacity(used_digits_ + 1); 266 | bigits_[used_digits_] = carry & kBigitMask; 267 | used_digits_++; 268 | carry >>= kBigitSize; 269 | } 270 | } 271 | 272 | 273 | void Bignum::MultiplyByUInt64(uint64_t factor) { 274 | if (factor == 1) return; 275 | if (factor == 0) { 276 | Zero(); 277 | return; 278 | } 279 | ASSERT(kBigitSize < 32); 280 | uint64_t carry = 0; 281 | uint64_t low = factor & 0xFFFFFFFF; 282 | uint64_t high = factor >> 32; 283 | for (int i = 0; i < used_digits_; ++i) { 284 | uint64_t product_low = low * bigits_[i]; 285 | uint64_t product_high = high * bigits_[i]; 286 | uint64_t tmp = (carry & kBigitMask) + product_low; 287 | bigits_[i] = tmp & kBigitMask; 288 | carry = (carry >> kBigitSize) + (tmp >> kBigitSize) + 289 | (product_high << (32 - kBigitSize)); 290 | } 291 | while (carry != 0) { 292 | EnsureCapacity(used_digits_ + 1); 293 | bigits_[used_digits_] = carry & kBigitMask; 294 | used_digits_++; 295 | carry >>= kBigitSize; 296 | } 297 | } 298 | 299 | 300 | void Bignum::MultiplyByPowerOfTen(int exponent) { 301 | const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d); 302 | const uint16_t kFive1 = 5; 303 | const uint16_t kFive2 = kFive1 * 5; 304 | const uint16_t kFive3 = kFive2 * 5; 305 | const uint16_t kFive4 = kFive3 * 5; 306 | const uint16_t kFive5 = kFive4 * 5; 307 | const uint16_t kFive6 = kFive5 * 5; 308 | const uint32_t kFive7 = kFive6 * 5; 309 | const uint32_t kFive8 = kFive7 * 5; 310 | const uint32_t kFive9 = kFive8 * 5; 311 | const uint32_t kFive10 = kFive9 * 5; 312 | const uint32_t kFive11 = kFive10 * 5; 313 | const uint32_t kFive12 = kFive11 * 5; 314 | const uint32_t kFive13 = kFive12 * 5; 315 | const uint32_t kFive1_to_12[] = 316 | { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6, 317 | kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 }; 318 | 319 | ASSERT(exponent >= 0); 320 | if (exponent == 0) return; 321 | if (used_digits_ == 0) return; 322 | 323 | // We shift by exponent at the end just before returning. 324 | int remaining_exponent = exponent; 325 | while (remaining_exponent >= 27) { 326 | MultiplyByUInt64(kFive27); 327 | remaining_exponent -= 27; 328 | } 329 | while (remaining_exponent >= 13) { 330 | MultiplyByUInt32(kFive13); 331 | remaining_exponent -= 13; 332 | } 333 | if (remaining_exponent > 0) { 334 | MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]); 335 | } 336 | ShiftLeft(exponent); 337 | } 338 | 339 | 340 | void Bignum::Square() { 341 | ASSERT(IsClamped()); 342 | int product_length = 2 * used_digits_; 343 | EnsureCapacity(product_length); 344 | 345 | // Comba multiplication: compute each column separately. 346 | // Example: r = a2a1a0 * b2b1b0. 347 | // r = 1 * a0b0 + 348 | // 10 * (a1b0 + a0b1) + 349 | // 100 * (a2b0 + a1b1 + a0b2) + 350 | // 1000 * (a2b1 + a1b2) + 351 | // 10000 * a2b2 352 | // 353 | // In the worst case we have to accumulate nb-digits products of digit*digit. 354 | // 355 | // Assert that the additional number of bits in a DoubleChunk are enough to 356 | // sum up used_digits of Bigit*Bigit. 357 | if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) { 358 | UNIMPLEMENTED(); 359 | } 360 | DoubleChunk accumulator = 0; 361 | // First shift the digits so we don't overwrite them. 362 | int copy_offset = used_digits_; 363 | for (int i = 0; i < used_digits_; ++i) { 364 | bigits_[copy_offset + i] = bigits_[i]; 365 | } 366 | // We have two loops to avoid some 'if's in the loop. 367 | for (int i = 0; i < used_digits_; ++i) { 368 | // Process temporary digit i with power i. 369 | // The sum of the two indices must be equal to i. 370 | int bigit_index1 = i; 371 | int bigit_index2 = 0; 372 | // Sum all of the sub-products. 373 | while (bigit_index1 >= 0) { 374 | Chunk chunk1 = bigits_[copy_offset + bigit_index1]; 375 | Chunk chunk2 = bigits_[copy_offset + bigit_index2]; 376 | accumulator += static_cast(chunk1) * chunk2; 377 | bigit_index1--; 378 | bigit_index2++; 379 | } 380 | bigits_[i] = static_cast(accumulator) & kBigitMask; 381 | accumulator >>= kBigitSize; 382 | } 383 | for (int i = used_digits_; i < product_length; ++i) { 384 | int bigit_index1 = used_digits_ - 1; 385 | int bigit_index2 = i - bigit_index1; 386 | // Invariant: sum of both indices is again equal to i. 387 | // Inner loop runs 0 times on last iteration, emptying accumulator. 388 | while (bigit_index2 < used_digits_) { 389 | Chunk chunk1 = bigits_[copy_offset + bigit_index1]; 390 | Chunk chunk2 = bigits_[copy_offset + bigit_index2]; 391 | accumulator += static_cast(chunk1) * chunk2; 392 | bigit_index1--; 393 | bigit_index2++; 394 | } 395 | // The overwritten bigits_[i] will never be read in further loop iterations, 396 | // because bigit_index1 and bigit_index2 are always greater 397 | // than i - used_digits_. 398 | bigits_[i] = static_cast(accumulator) & kBigitMask; 399 | accumulator >>= kBigitSize; 400 | } 401 | // Since the result was guaranteed to lie inside the number the 402 | // accumulator must be 0 now. 403 | ASSERT(accumulator == 0); 404 | 405 | // Don't forget to update the used_digits and the exponent. 406 | used_digits_ = product_length; 407 | exponent_ *= 2; 408 | Clamp(); 409 | } 410 | 411 | 412 | void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) { 413 | ASSERT(base != 0); 414 | ASSERT(power_exponent >= 0); 415 | if (power_exponent == 0) { 416 | AssignUInt16(1); 417 | return; 418 | } 419 | Zero(); 420 | int shifts = 0; 421 | // We expect base to be in range 2-32, and most often to be 10. 422 | // It does not make much sense to implement different algorithms for counting 423 | // the bits. 424 | while ((base & 1) == 0) { 425 | base >>= 1; 426 | shifts++; 427 | } 428 | int bit_size = 0; 429 | int tmp_base = base; 430 | while (tmp_base != 0) { 431 | tmp_base >>= 1; 432 | bit_size++; 433 | } 434 | int final_size = bit_size * power_exponent; 435 | // 1 extra bigit for the shifting, and one for rounded final_size. 436 | EnsureCapacity(final_size / kBigitSize + 2); 437 | 438 | // Left to Right exponentiation. 439 | int mask = 1; 440 | while (power_exponent >= mask) mask <<= 1; 441 | 442 | // The mask is now pointing to the bit above the most significant 1-bit of 443 | // power_exponent. 444 | // Get rid of first 1-bit; 445 | mask >>= 2; 446 | uint64_t this_value = base; 447 | 448 | bool delayed_multipliciation = false; 449 | const uint64_t max_32bits = 0xFFFFFFFF; 450 | while (mask != 0 && this_value <= max_32bits) { 451 | this_value = this_value * this_value; 452 | // Verify that there is enough space in this_value to perform the 453 | // multiplication. The first bit_size bits must be 0. 454 | if ((power_exponent & mask) != 0) { 455 | uint64_t base_bits_mask = 456 | ~((static_cast(1) << (64 - bit_size)) - 1); 457 | bool high_bits_zero = (this_value & base_bits_mask) == 0; 458 | if (high_bits_zero) { 459 | this_value *= base; 460 | } else { 461 | delayed_multipliciation = true; 462 | } 463 | } 464 | mask >>= 1; 465 | } 466 | AssignUInt64(this_value); 467 | if (delayed_multipliciation) { 468 | MultiplyByUInt32(base); 469 | } 470 | 471 | // Now do the same thing as a bignum. 472 | while (mask != 0) { 473 | Square(); 474 | if ((power_exponent & mask) != 0) { 475 | MultiplyByUInt32(base); 476 | } 477 | mask >>= 1; 478 | } 479 | 480 | // And finally add the saved shifts. 481 | ShiftLeft(shifts * power_exponent); 482 | } 483 | 484 | 485 | // Precondition: this/other < 16bit. 486 | uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) { 487 | ASSERT(IsClamped()); 488 | ASSERT(other.IsClamped()); 489 | ASSERT(other.used_digits_ > 0); 490 | 491 | // Easy case: if we have less digits than the divisor than the result is 0. 492 | // Note: this handles the case where this == 0, too. 493 | if (BigitLength() < other.BigitLength()) { 494 | return 0; 495 | } 496 | 497 | Align(other); 498 | 499 | uint16_t result = 0; 500 | 501 | // Start by removing multiples of 'other' until both numbers have the same 502 | // number of digits. 503 | while (BigitLength() > other.BigitLength()) { 504 | // This naive approach is extremely inefficient if `this` divided by other 505 | // is big. This function is implemented for doubleToString where 506 | // the result should be small (less than 10). 507 | ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16)); 508 | ASSERT(bigits_[used_digits_ - 1] < 0x10000); 509 | // Remove the multiples of the first digit. 510 | // Example this = 23 and other equals 9. -> Remove 2 multiples. 511 | result += static_cast(bigits_[used_digits_ - 1]); 512 | SubtractTimes(other, bigits_[used_digits_ - 1]); 513 | } 514 | 515 | ASSERT(BigitLength() == other.BigitLength()); 516 | 517 | // Both bignums are at the same length now. 518 | // Since other has more than 0 digits we know that the access to 519 | // bigits_[used_digits_ - 1] is safe. 520 | Chunk this_bigit = bigits_[used_digits_ - 1]; 521 | Chunk other_bigit = other.bigits_[other.used_digits_ - 1]; 522 | 523 | if (other.used_digits_ == 1) { 524 | // Shortcut for easy (and common) case. 525 | int quotient = this_bigit / other_bigit; 526 | bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient; 527 | ASSERT(quotient < 0x10000); 528 | result += static_cast(quotient); 529 | Clamp(); 530 | return result; 531 | } 532 | 533 | int division_estimate = this_bigit / (other_bigit + 1); 534 | ASSERT(division_estimate < 0x10000); 535 | result += static_cast(division_estimate); 536 | SubtractTimes(other, division_estimate); 537 | 538 | if (other_bigit * (division_estimate + 1) > this_bigit) { 539 | // No need to even try to subtract. Even if other's remaining digits were 0 540 | // another subtraction would be too much. 541 | return result; 542 | } 543 | 544 | while (LessEqual(other, *this)) { 545 | SubtractBignum(other); 546 | result++; 547 | } 548 | return result; 549 | } 550 | 551 | 552 | template 553 | static int SizeInHexChars(S number) { 554 | ASSERT(number > 0); 555 | int result = 0; 556 | while (number != 0) { 557 | number >>= 4; 558 | result++; 559 | } 560 | return result; 561 | } 562 | 563 | 564 | static char HexCharOfValue(int value) { 565 | ASSERT(0 <= value && value <= 16); 566 | if (value < 10) return static_cast(value + '0'); 567 | return static_cast(value - 10 + 'A'); 568 | } 569 | 570 | 571 | bool Bignum::ToHexString(char* buffer, int buffer_size) const { 572 | ASSERT(IsClamped()); 573 | // Each bigit must be printable as separate hex-character. 574 | ASSERT(kBigitSize % 4 == 0); 575 | const int kHexCharsPerBigit = kBigitSize / 4; 576 | 577 | if (used_digits_ == 0) { 578 | if (buffer_size < 2) return false; 579 | buffer[0] = '0'; 580 | buffer[1] = '\0'; 581 | return true; 582 | } 583 | // We add 1 for the terminating '\0' character. 584 | int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit + 585 | SizeInHexChars(bigits_[used_digits_ - 1]) + 1; 586 | if (needed_chars > buffer_size) return false; 587 | int string_index = needed_chars - 1; 588 | buffer[string_index--] = '\0'; 589 | for (int i = 0; i < exponent_; ++i) { 590 | for (int j = 0; j < kHexCharsPerBigit; ++j) { 591 | buffer[string_index--] = '0'; 592 | } 593 | } 594 | for (int i = 0; i < used_digits_ - 1; ++i) { 595 | Chunk current_bigit = bigits_[i]; 596 | for (int j = 0; j < kHexCharsPerBigit; ++j) { 597 | buffer[string_index--] = HexCharOfValue(current_bigit & 0xF); 598 | current_bigit >>= 4; 599 | } 600 | } 601 | // And finally the last bigit. 602 | Chunk most_significant_bigit = bigits_[used_digits_ - 1]; 603 | while (most_significant_bigit != 0) { 604 | buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF); 605 | most_significant_bigit >>= 4; 606 | } 607 | return true; 608 | } 609 | 610 | 611 | Bignum::Chunk Bignum::BigitAt(int index) const { 612 | if (index >= BigitLength()) return 0; 613 | if (index < exponent_) return 0; 614 | return bigits_[index - exponent_]; 615 | } 616 | 617 | 618 | int Bignum::Compare(const Bignum& a, const Bignum& b) { 619 | ASSERT(a.IsClamped()); 620 | ASSERT(b.IsClamped()); 621 | int bigit_length_a = a.BigitLength(); 622 | int bigit_length_b = b.BigitLength(); 623 | if (bigit_length_a < bigit_length_b) return -1; 624 | if (bigit_length_a > bigit_length_b) return +1; 625 | for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) { 626 | Chunk bigit_a = a.BigitAt(i); 627 | Chunk bigit_b = b.BigitAt(i); 628 | if (bigit_a < bigit_b) return -1; 629 | if (bigit_a > bigit_b) return +1; 630 | // Otherwise they are equal up to this digit. Try the next digit. 631 | } 632 | return 0; 633 | } 634 | 635 | 636 | int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) { 637 | ASSERT(a.IsClamped()); 638 | ASSERT(b.IsClamped()); 639 | ASSERT(c.IsClamped()); 640 | if (a.BigitLength() < b.BigitLength()) { 641 | return PlusCompare(b, a, c); 642 | } 643 | if (a.BigitLength() + 1 < c.BigitLength()) return -1; 644 | if (a.BigitLength() > c.BigitLength()) return +1; 645 | // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than 646 | // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one 647 | // of 'a'. 648 | if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) { 649 | return -1; 650 | } 651 | 652 | Chunk borrow = 0; 653 | // Starting at min_exponent all digits are == 0. So no need to compare them. 654 | int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_); 655 | for (int i = c.BigitLength() - 1; i >= min_exponent; --i) { 656 | Chunk chunk_a = a.BigitAt(i); 657 | Chunk chunk_b = b.BigitAt(i); 658 | Chunk chunk_c = c.BigitAt(i); 659 | Chunk sum = chunk_a + chunk_b; 660 | if (sum > chunk_c + borrow) { 661 | return +1; 662 | } else { 663 | borrow = chunk_c + borrow - sum; 664 | if (borrow > 1) return -1; 665 | borrow <<= kBigitSize; 666 | } 667 | } 668 | if (borrow == 0) return 0; 669 | return -1; 670 | } 671 | 672 | 673 | void Bignum::Clamp() { 674 | while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) { 675 | used_digits_--; 676 | } 677 | if (used_digits_ == 0) { 678 | // Zero. 679 | exponent_ = 0; 680 | } 681 | } 682 | 683 | 684 | bool Bignum::IsClamped() const { 685 | return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0; 686 | } 687 | 688 | 689 | void Bignum::Zero() { 690 | for (int i = 0; i < used_digits_; ++i) { 691 | bigits_[i] = 0; 692 | } 693 | used_digits_ = 0; 694 | exponent_ = 0; 695 | } 696 | 697 | 698 | void Bignum::Align(const Bignum& other) { 699 | if (exponent_ > other.exponent_) { 700 | // If "X" represents a "hidden" digit (by the exponent) then we are in the 701 | // following case (a == this, b == other): 702 | // a: aaaaaaXXXX or a: aaaaaXXX 703 | // b: bbbbbbX b: bbbbbbbbXX 704 | // We replace some of the hidden digits (X) of a with 0 digits. 705 | // a: aaaaaa000X or a: aaaaa0XX 706 | int zero_digits = exponent_ - other.exponent_; 707 | EnsureCapacity(used_digits_ + zero_digits); 708 | for (int i = used_digits_ - 1; i >= 0; --i) { 709 | bigits_[i + zero_digits] = bigits_[i]; 710 | } 711 | for (int i = 0; i < zero_digits; ++i) { 712 | bigits_[i] = 0; 713 | } 714 | used_digits_ += zero_digits; 715 | exponent_ -= zero_digits; 716 | ASSERT(used_digits_ >= 0); 717 | ASSERT(exponent_ >= 0); 718 | } 719 | } 720 | 721 | 722 | void Bignum::BigitsShiftLeft(int shift_amount) { 723 | ASSERT(shift_amount < kBigitSize); 724 | ASSERT(shift_amount >= 0); 725 | Chunk carry = 0; 726 | for (int i = 0; i < used_digits_; ++i) { 727 | Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount); 728 | bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask; 729 | carry = new_carry; 730 | } 731 | if (carry != 0) { 732 | bigits_[used_digits_] = carry; 733 | used_digits_++; 734 | } 735 | } 736 | 737 | 738 | void Bignum::SubtractTimes(const Bignum& other, int factor) { 739 | ASSERT(exponent_ <= other.exponent_); 740 | if (factor < 3) { 741 | for (int i = 0; i < factor; ++i) { 742 | SubtractBignum(other); 743 | } 744 | return; 745 | } 746 | Chunk borrow = 0; 747 | int exponent_diff = other.exponent_ - exponent_; 748 | for (int i = 0; i < other.used_digits_; ++i) { 749 | DoubleChunk product = static_cast(factor) * other.bigits_[i]; 750 | DoubleChunk remove = borrow + product; 751 | Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask); 752 | bigits_[i + exponent_diff] = difference & kBigitMask; 753 | borrow = static_cast((difference >> (kChunkSize - 1)) + 754 | (remove >> kBigitSize)); 755 | } 756 | for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) { 757 | if (borrow == 0) return; 758 | Chunk difference = bigits_[i] - borrow; 759 | bigits_[i] = difference & kBigitMask; 760 | borrow = difference >> (kChunkSize - 1); 761 | } 762 | Clamp(); 763 | } 764 | 765 | 766 | } // namespace double_conversion 767 | -------------------------------------------------------------------------------- /grisu/src/bignum.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_BIGNUM_H_ 29 | #define DOUBLE_CONVERSION_BIGNUM_H_ 30 | 31 | #include "utils.h" 32 | 33 | namespace double_conversion { 34 | 35 | class Bignum { 36 | public: 37 | // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately. 38 | // This bignum can encode much bigger numbers, since it contains an 39 | // exponent. 40 | static const int kMaxSignificantBits = 3584; 41 | 42 | Bignum(); 43 | void AssignUInt16(uint16_t value); 44 | void AssignUInt64(uint64_t value); 45 | void AssignBignum(const Bignum& other); 46 | 47 | void AssignDecimalString(Vector value); 48 | void AssignHexString(Vector value); 49 | 50 | void AssignPowerUInt16(uint16_t base, int exponent); 51 | 52 | void AddUInt16(uint16_t operand); 53 | void AddUInt64(uint64_t operand); 54 | void AddBignum(const Bignum& other); 55 | // Precondition: this >= other. 56 | void SubtractBignum(const Bignum& other); 57 | 58 | void Square(); 59 | void ShiftLeft(int shift_amount); 60 | void MultiplyByUInt32(uint32_t factor); 61 | void MultiplyByUInt64(uint64_t factor); 62 | void MultiplyByPowerOfTen(int exponent); 63 | void Times10() { return MultiplyByUInt32(10); } 64 | // Pseudocode: 65 | // int result = this / other; 66 | // this = this % other; 67 | // In the worst case this function is in O(this/other). 68 | uint16_t DivideModuloIntBignum(const Bignum& other); 69 | 70 | bool ToHexString(char* buffer, int buffer_size) const; 71 | 72 | // Returns 73 | // -1 if a < b, 74 | // 0 if a == b, and 75 | // +1 if a > b. 76 | static int Compare(const Bignum& a, const Bignum& b); 77 | static bool Equal(const Bignum& a, const Bignum& b) { 78 | return Compare(a, b) == 0; 79 | } 80 | static bool LessEqual(const Bignum& a, const Bignum& b) { 81 | return Compare(a, b) <= 0; 82 | } 83 | static bool Less(const Bignum& a, const Bignum& b) { 84 | return Compare(a, b) < 0; 85 | } 86 | // Returns Compare(a + b, c); 87 | static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c); 88 | // Returns a + b == c 89 | static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) { 90 | return PlusCompare(a, b, c) == 0; 91 | } 92 | // Returns a + b <= c 93 | static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) { 94 | return PlusCompare(a, b, c) <= 0; 95 | } 96 | // Returns a + b < c 97 | static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) { 98 | return PlusCompare(a, b, c) < 0; 99 | } 100 | private: 101 | typedef uint32_t Chunk; 102 | typedef uint64_t DoubleChunk; 103 | 104 | static const int kChunkSize = sizeof(Chunk) * 8; 105 | static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8; 106 | // With bigit size of 28 we loose some bits, but a double still fits easily 107 | // into two chunks, and more importantly we can use the Comba multiplication. 108 | static const int kBigitSize = 28; 109 | static const Chunk kBigitMask = (1 << kBigitSize) - 1; 110 | // Every instance allocates kBigitLength chunks on the stack. Bignums cannot 111 | // grow. There are no checks if the stack-allocated space is sufficient. 112 | static const int kBigitCapacity = kMaxSignificantBits / kBigitSize; 113 | 114 | void EnsureCapacity(int size) { 115 | if (size > kBigitCapacity) { 116 | UNREACHABLE(); 117 | } 118 | } 119 | void Align(const Bignum& other); 120 | void Clamp(); 121 | bool IsClamped() const; 122 | void Zero(); 123 | // Requires this to have enough capacity (no tests done). 124 | // Updates used_digits_ if necessary. 125 | // shift_amount must be < kBigitSize. 126 | void BigitsShiftLeft(int shift_amount); 127 | // BigitLength includes the "hidden" digits encoded in the exponent. 128 | int BigitLength() const { return used_digits_ + exponent_; } 129 | Chunk BigitAt(int index) const; 130 | void SubtractTimes(const Bignum& other, int factor); 131 | 132 | Chunk bigits_buffer_[kBigitCapacity]; 133 | // A vector backed by bigits_buffer_. This way accesses to the array are 134 | // checked for out-of-bounds errors. 135 | Vector bigits_; 136 | int used_digits_; 137 | // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize). 138 | int exponent_; 139 | 140 | DISALLOW_COPY_AND_ASSIGN(Bignum); 141 | }; 142 | 143 | } // namespace double_conversion 144 | 145 | #endif // DOUBLE_CONVERSION_BIGNUM_H_ 146 | -------------------------------------------------------------------------------- /grisu/src/cached-powers.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "utils.h" 33 | 34 | #include "cached-powers.h" 35 | 36 | namespace double_conversion { 37 | 38 | struct CachedPower { 39 | uint64_t significand; 40 | int16_t binary_exponent; 41 | int16_t decimal_exponent; 42 | }; 43 | 44 | static const CachedPower kCachedPowers[] = { 45 | {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348}, 46 | {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340}, 47 | {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332}, 48 | {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324}, 49 | {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316}, 50 | {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308}, 51 | {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300}, 52 | {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292}, 53 | {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284}, 54 | {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276}, 55 | {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268}, 56 | {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260}, 57 | {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252}, 58 | {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244}, 59 | {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236}, 60 | {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228}, 61 | {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220}, 62 | {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212}, 63 | {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204}, 64 | {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196}, 65 | {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188}, 66 | {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180}, 67 | {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172}, 68 | {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164}, 69 | {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156}, 70 | {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148}, 71 | {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140}, 72 | {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132}, 73 | {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124}, 74 | {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116}, 75 | {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108}, 76 | {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100}, 77 | {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92}, 78 | {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84}, 79 | {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76}, 80 | {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68}, 81 | {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60}, 82 | {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52}, 83 | {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44}, 84 | {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36}, 85 | {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28}, 86 | {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20}, 87 | {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12}, 88 | {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4}, 89 | {UINT64_2PART_C(0x9c400000, 00000000), -50, 4}, 90 | {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12}, 91 | {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20}, 92 | {UINT64_2PART_C(0x813f3978, f8940984), 30, 28}, 93 | {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36}, 94 | {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44}, 95 | {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52}, 96 | {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60}, 97 | {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68}, 98 | {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76}, 99 | {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84}, 100 | {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92}, 101 | {UINT64_2PART_C(0x924d692c, a61be758), 269, 100}, 102 | {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108}, 103 | {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116}, 104 | {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124}, 105 | {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132}, 106 | {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140}, 107 | {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148}, 108 | {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156}, 109 | {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164}, 110 | {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172}, 111 | {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180}, 112 | {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188}, 113 | {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196}, 114 | {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204}, 115 | {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212}, 116 | {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220}, 117 | {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228}, 118 | {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236}, 119 | {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244}, 120 | {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252}, 121 | {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260}, 122 | {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268}, 123 | {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276}, 124 | {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284}, 125 | {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292}, 126 | {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300}, 127 | {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308}, 128 | {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316}, 129 | {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324}, 130 | {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332}, 131 | {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340}, 132 | }; 133 | 134 | static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers); 135 | static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent. 136 | static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10) 137 | // Difference between the decimal exponents in the table above. 138 | const int PowersOfTenCache::kDecimalExponentDistance = 8; 139 | const int PowersOfTenCache::kMinDecimalExponent = -348; 140 | const int PowersOfTenCache::kMaxDecimalExponent = 340; 141 | 142 | void PowersOfTenCache::GetCachedPowerForBinaryExponentRange( 143 | int min_exponent, 144 | int max_exponent, 145 | DiyFp* power, 146 | int* decimal_exponent) { 147 | int kQ = DiyFp::kSignificandSize; 148 | double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10); 149 | int foo = kCachedPowersOffset; 150 | int index = 151 | (foo + static_cast(k) - 1) / kDecimalExponentDistance + 1; 152 | ASSERT(0 <= index && index < kCachedPowersLength); 153 | CachedPower cached_power = kCachedPowers[index]; 154 | ASSERT(min_exponent <= cached_power.binary_exponent); 155 | (void) max_exponent; // Mark variable as used. 156 | ASSERT(cached_power.binary_exponent <= max_exponent); 157 | *decimal_exponent = cached_power.decimal_exponent; 158 | *power = DiyFp(cached_power.significand, cached_power.binary_exponent); 159 | } 160 | 161 | 162 | void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent, 163 | DiyFp* power, 164 | int* found_exponent) { 165 | ASSERT(kMinDecimalExponent <= requested_exponent); 166 | ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance); 167 | int index = 168 | (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance; 169 | CachedPower cached_power = kCachedPowers[index]; 170 | *power = DiyFp(cached_power.significand, cached_power.binary_exponent); 171 | *found_exponent = cached_power.decimal_exponent; 172 | ASSERT(*found_exponent <= requested_exponent); 173 | ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance); 174 | } 175 | 176 | } // namespace double_conversion 177 | -------------------------------------------------------------------------------- /grisu/src/cached-powers.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_CACHED_POWERS_H_ 29 | #define DOUBLE_CONVERSION_CACHED_POWERS_H_ 30 | 31 | #include "diy-fp.h" 32 | 33 | namespace double_conversion { 34 | 35 | class PowersOfTenCache { 36 | public: 37 | 38 | // Not all powers of ten are cached. The decimal exponent of two neighboring 39 | // cached numbers will differ by kDecimalExponentDistance. 40 | static const int kDecimalExponentDistance; 41 | 42 | static const int kMinDecimalExponent; 43 | static const int kMaxDecimalExponent; 44 | 45 | // Returns a cached power-of-ten with a binary exponent in the range 46 | // [min_exponent; max_exponent] (boundaries included). 47 | static void GetCachedPowerForBinaryExponentRange(int min_exponent, 48 | int max_exponent, 49 | DiyFp* power, 50 | int* decimal_exponent); 51 | 52 | // Returns a cached power of ten x ~= 10^k such that 53 | // k <= decimal_exponent < k + kCachedPowersDecimalDistance. 54 | // The given decimal_exponent must satisfy 55 | // kMinDecimalExponent <= requested_exponent, and 56 | // requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance. 57 | static void GetCachedPowerForDecimalExponent(int requested_exponent, 58 | DiyFp* power, 59 | int* found_exponent); 60 | }; 61 | 62 | } // namespace double_conversion 63 | 64 | #endif // DOUBLE_CONVERSION_CACHED_POWERS_H_ 65 | -------------------------------------------------------------------------------- /grisu/src/diy-fp.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | 29 | #include "diy-fp.h" 30 | #include "utils.h" 31 | 32 | namespace double_conversion { 33 | 34 | void DiyFp::Multiply(const DiyFp& other) { 35 | // Simply "emulates" a 128 bit multiplication. 36 | // However: the resulting number only contains 64 bits. The least 37 | // significant 64 bits are only used for rounding the most significant 64 38 | // bits. 39 | const uint64_t kM32 = 0xFFFFFFFFU; 40 | uint64_t a = f_ >> 32; 41 | uint64_t b = f_ & kM32; 42 | uint64_t c = other.f_ >> 32; 43 | uint64_t d = other.f_ & kM32; 44 | uint64_t ac = a * c; 45 | uint64_t bc = b * c; 46 | uint64_t ad = a * d; 47 | uint64_t bd = b * d; 48 | uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32); 49 | // By adding 1U << 31 to tmp we round the final result. 50 | // Halfway cases will be round up. 51 | tmp += 1U << 31; 52 | uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); 53 | e_ += other.e_ + 64; 54 | f_ = result_f; 55 | } 56 | 57 | } // namespace double_conversion 58 | -------------------------------------------------------------------------------- /grisu/src/diy-fp.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_DIY_FP_H_ 29 | #define DOUBLE_CONVERSION_DIY_FP_H_ 30 | 31 | #include "utils.h" 32 | 33 | namespace double_conversion { 34 | 35 | // This "Do It Yourself Floating Point" class implements a floating-point number 36 | // with a uint64 significand and an int exponent. Normalized DiyFp numbers will 37 | // have the most significant bit of the significand set. 38 | // Multiplication and Subtraction do not normalize their results. 39 | // DiyFp are not designed to contain special doubles (NaN and Infinity). 40 | class DiyFp { 41 | public: 42 | static const int kSignificandSize = 64; 43 | 44 | DiyFp() : f_(0), e_(0) {} 45 | DiyFp(uint64_t f, int e) : f_(f), e_(e) {} 46 | 47 | // this = this - other. 48 | // The exponents of both numbers must be the same and the significand of this 49 | // must be bigger than the significand of other. 50 | // The result will not be normalized. 51 | void Subtract(const DiyFp& other) { 52 | ASSERT(e_ == other.e_); 53 | ASSERT(f_ >= other.f_); 54 | f_ -= other.f_; 55 | } 56 | 57 | // Returns a - b. 58 | // The exponents of both numbers must be the same and this must be bigger 59 | // than other. The result will not be normalized. 60 | static DiyFp Minus(const DiyFp& a, const DiyFp& b) { 61 | DiyFp result = a; 62 | result.Subtract(b); 63 | return result; 64 | } 65 | 66 | 67 | // this = this * other. 68 | void Multiply(const DiyFp& other); 69 | 70 | // returns a * b; 71 | static DiyFp Times(const DiyFp& a, const DiyFp& b) { 72 | DiyFp result = a; 73 | result.Multiply(b); 74 | return result; 75 | } 76 | 77 | void Normalize() { 78 | ASSERT(f_ != 0); 79 | uint64_t f = f_; 80 | int e = e_; 81 | 82 | // This method is mainly called for normalizing boundaries. In general 83 | // boundaries need to be shifted by 10 bits. We thus optimize for this case. 84 | const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000); 85 | while ((f & k10MSBits) == 0) { 86 | f <<= 10; 87 | e -= 10; 88 | } 89 | while ((f & kUint64MSB) == 0) { 90 | f <<= 1; 91 | e--; 92 | } 93 | f_ = f; 94 | e_ = e; 95 | } 96 | 97 | static DiyFp Normalize(const DiyFp& a) { 98 | DiyFp result = a; 99 | result.Normalize(); 100 | return result; 101 | } 102 | 103 | uint64_t f() const { return f_; } 104 | int e() const { return e_; } 105 | 106 | void set_f(uint64_t new_value) { f_ = new_value; } 107 | void set_e(int new_value) { e_ = new_value; } 108 | 109 | private: 110 | static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000); 111 | 112 | uint64_t f_; 113 | int e_; 114 | }; 115 | 116 | } // namespace double_conversion 117 | 118 | #endif // DOUBLE_CONVERSION_DIY_FP_H_ 119 | -------------------------------------------------------------------------------- /grisu/src/fast-dtoa.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_FAST_DTOA_H_ 29 | #define DOUBLE_CONVERSION_FAST_DTOA_H_ 30 | 31 | #include "utils.h" 32 | 33 | namespace double_conversion { 34 | 35 | enum FastDtoaMode { 36 | // Computes the shortest representation of the given input. The returned 37 | // result will be the most accurate number of this length. Longer 38 | // representations might be more accurate. 39 | FAST_DTOA_SHORTEST, 40 | // Same as FAST_DTOA_SHORTEST but for single-precision floats. 41 | FAST_DTOA_SHORTEST_SINGLE, 42 | // Computes a representation where the precision (number of digits) is 43 | // given as input. The precision is independent of the decimal point. 44 | FAST_DTOA_PRECISION 45 | }; 46 | 47 | // FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not 48 | // include the terminating '\0' character. 49 | static const int kFastDtoaMaximalLength = 17; 50 | // Same for single-precision numbers. 51 | static const int kFastDtoaMaximalSingleLength = 9; 52 | 53 | // Provides a decimal representation of v. 54 | // The result should be interpreted as buffer * 10^(point - length). 55 | // 56 | // Precondition: 57 | // * v must be a strictly positive finite double. 58 | // 59 | // Returns true if it succeeds, otherwise the result can not be trusted. 60 | // There will be *length digits inside the buffer followed by a null terminator. 61 | // If the function returns true and mode equals 62 | // - FAST_DTOA_SHORTEST, then 63 | // the parameter requested_digits is ignored. 64 | // The result satisfies 65 | // v == (double) (buffer * 10^(point - length)). 66 | // The digits in the buffer are the shortest representation possible. E.g. 67 | // if 0.099999999999 and 0.1 represent the same double then "1" is returned 68 | // with point = 0. 69 | // The last digit will be closest to the actual v. That is, even if several 70 | // digits might correctly yield 'v' when read again, the buffer will contain 71 | // the one closest to v. 72 | // - FAST_DTOA_PRECISION, then 73 | // the buffer contains requested_digits digits. 74 | // the difference v - (buffer * 10^(point-length)) is closest to zero for 75 | // all possible representations of requested_digits digits. 76 | // If there are two values that are equally close, then FastDtoa returns 77 | // false. 78 | // For both modes the buffer must be large enough to hold the result. 79 | bool FastDtoa(double d, 80 | FastDtoaMode mode, 81 | int requested_digits, 82 | Vector buffer, 83 | int* length, 84 | int* decimal_point); 85 | 86 | } // namespace double_conversion 87 | 88 | #endif // DOUBLE_CONVERSION_FAST_DTOA_H_ 89 | -------------------------------------------------------------------------------- /grisu/src/fixed-dtoa.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #include 29 | 30 | #include "fixed-dtoa.h" 31 | #include "ieee.h" 32 | 33 | namespace double_conversion { 34 | 35 | // Represents a 128bit type. This class should be replaced by a native type on 36 | // platforms that support 128bit integers. 37 | class UInt128 { 38 | public: 39 | UInt128() : high_bits_(0), low_bits_(0) { } 40 | UInt128(uint64_t high, uint64_t low) : high_bits_(high), low_bits_(low) { } 41 | 42 | void Multiply(uint32_t multiplicand) { 43 | uint64_t accumulator; 44 | 45 | accumulator = (low_bits_ & kMask32) * multiplicand; 46 | uint32_t part = static_cast(accumulator & kMask32); 47 | accumulator >>= 32; 48 | accumulator = accumulator + (low_bits_ >> 32) * multiplicand; 49 | low_bits_ = (accumulator << 32) + part; 50 | accumulator >>= 32; 51 | accumulator = accumulator + (high_bits_ & kMask32) * multiplicand; 52 | part = static_cast(accumulator & kMask32); 53 | accumulator >>= 32; 54 | accumulator = accumulator + (high_bits_ >> 32) * multiplicand; 55 | high_bits_ = (accumulator << 32) + part; 56 | ASSERT((accumulator >> 32) == 0); 57 | } 58 | 59 | void Shift(int shift_amount) { 60 | ASSERT(-64 <= shift_amount && shift_amount <= 64); 61 | if (shift_amount == 0) { 62 | return; 63 | } else if (shift_amount == -64) { 64 | high_bits_ = low_bits_; 65 | low_bits_ = 0; 66 | } else if (shift_amount == 64) { 67 | low_bits_ = high_bits_; 68 | high_bits_ = 0; 69 | } else if (shift_amount <= 0) { 70 | high_bits_ <<= -shift_amount; 71 | high_bits_ += low_bits_ >> (64 + shift_amount); 72 | low_bits_ <<= -shift_amount; 73 | } else { 74 | low_bits_ >>= shift_amount; 75 | low_bits_ += high_bits_ << (64 - shift_amount); 76 | high_bits_ >>= shift_amount; 77 | } 78 | } 79 | 80 | // Modifies *this to *this MOD (2^power). 81 | // Returns *this DIV (2^power). 82 | int DivModPowerOf2(int power) { 83 | if (power >= 64) { 84 | int result = static_cast(high_bits_ >> (power - 64)); 85 | high_bits_ -= static_cast(result) << (power - 64); 86 | return result; 87 | } else { 88 | uint64_t part_low = low_bits_ >> power; 89 | uint64_t part_high = high_bits_ << (64 - power); 90 | int result = static_cast(part_low + part_high); 91 | high_bits_ = 0; 92 | low_bits_ -= part_low << power; 93 | return result; 94 | } 95 | } 96 | 97 | bool IsZero() const { 98 | return high_bits_ == 0 && low_bits_ == 0; 99 | } 100 | 101 | int BitAt(int position) { 102 | if (position >= 64) { 103 | return static_cast(high_bits_ >> (position - 64)) & 1; 104 | } else { 105 | return static_cast(low_bits_ >> position) & 1; 106 | } 107 | } 108 | 109 | private: 110 | static const uint64_t kMask32 = 0xFFFFFFFF; 111 | // Value == (high_bits_ << 64) + low_bits_ 112 | uint64_t high_bits_; 113 | uint64_t low_bits_; 114 | }; 115 | 116 | 117 | static const int kDoubleSignificandSize = 53; // Includes the hidden bit. 118 | 119 | 120 | static void FillDigits32FixedLength(uint32_t number, int requested_length, 121 | Vector buffer, int* length) { 122 | for (int i = requested_length - 1; i >= 0; --i) { 123 | buffer[(*length) + i] = '0' + number % 10; 124 | number /= 10; 125 | } 126 | *length += requested_length; 127 | } 128 | 129 | 130 | static void FillDigits32(uint32_t number, Vector buffer, int* length) { 131 | int number_length = 0; 132 | // We fill the digits in reverse order and exchange them afterwards. 133 | while (number != 0) { 134 | int digit = number % 10; 135 | number /= 10; 136 | buffer[(*length) + number_length] = static_cast('0' + digit); 137 | number_length++; 138 | } 139 | // Exchange the digits. 140 | int i = *length; 141 | int j = *length + number_length - 1; 142 | while (i < j) { 143 | char tmp = buffer[i]; 144 | buffer[i] = buffer[j]; 145 | buffer[j] = tmp; 146 | i++; 147 | j--; 148 | } 149 | *length += number_length; 150 | } 151 | 152 | 153 | static void FillDigits64FixedLength(uint64_t number, 154 | Vector buffer, int* length) { 155 | const uint32_t kTen7 = 10000000; 156 | // For efficiency cut the number into 3 uint32_t parts, and print those. 157 | uint32_t part2 = static_cast(number % kTen7); 158 | number /= kTen7; 159 | uint32_t part1 = static_cast(number % kTen7); 160 | uint32_t part0 = static_cast(number / kTen7); 161 | 162 | FillDigits32FixedLength(part0, 3, buffer, length); 163 | FillDigits32FixedLength(part1, 7, buffer, length); 164 | FillDigits32FixedLength(part2, 7, buffer, length); 165 | } 166 | 167 | 168 | static void FillDigits64(uint64_t number, Vector buffer, int* length) { 169 | const uint32_t kTen7 = 10000000; 170 | // For efficiency cut the number into 3 uint32_t parts, and print those. 171 | uint32_t part2 = static_cast(number % kTen7); 172 | number /= kTen7; 173 | uint32_t part1 = static_cast(number % kTen7); 174 | uint32_t part0 = static_cast(number / kTen7); 175 | 176 | if (part0 != 0) { 177 | FillDigits32(part0, buffer, length); 178 | FillDigits32FixedLength(part1, 7, buffer, length); 179 | FillDigits32FixedLength(part2, 7, buffer, length); 180 | } else if (part1 != 0) { 181 | FillDigits32(part1, buffer, length); 182 | FillDigits32FixedLength(part2, 7, buffer, length); 183 | } else { 184 | FillDigits32(part2, buffer, length); 185 | } 186 | } 187 | 188 | 189 | static void RoundUp(Vector buffer, int* length, int* decimal_point) { 190 | // An empty buffer represents 0. 191 | if (*length == 0) { 192 | buffer[0] = '1'; 193 | *decimal_point = 1; 194 | *length = 1; 195 | return; 196 | } 197 | // Round the last digit until we either have a digit that was not '9' or until 198 | // we reached the first digit. 199 | buffer[(*length) - 1]++; 200 | for (int i = (*length) - 1; i > 0; --i) { 201 | if (buffer[i] != '0' + 10) { 202 | return; 203 | } 204 | buffer[i] = '0'; 205 | buffer[i - 1]++; 206 | } 207 | // If the first digit is now '0' + 10, we would need to set it to '0' and add 208 | // a '1' in front. However we reach the first digit only if all following 209 | // digits had been '9' before rounding up. Now all trailing digits are '0' and 210 | // we simply switch the first digit to '1' and update the decimal-point 211 | // (indicating that the point is now one digit to the right). 212 | if (buffer[0] == '0' + 10) { 213 | buffer[0] = '1'; 214 | (*decimal_point)++; 215 | } 216 | } 217 | 218 | 219 | // The given fractionals number represents a fixed-point number with binary 220 | // point at bit (-exponent). 221 | // Preconditions: 222 | // -128 <= exponent <= 0. 223 | // 0 <= fractionals * 2^exponent < 1 224 | // The buffer holds the result. 225 | // The function will round its result. During the rounding-process digits not 226 | // generated by this function might be updated, and the decimal-point variable 227 | // might be updated. If this function generates the digits 99 and the buffer 228 | // already contained "199" (thus yielding a buffer of "19999") then a 229 | // rounding-up will change the contents of the buffer to "20000". 230 | static void FillFractionals(uint64_t fractionals, int exponent, 231 | int fractional_count, Vector buffer, 232 | int* length, int* decimal_point) { 233 | ASSERT(-128 <= exponent && exponent <= 0); 234 | // 'fractionals' is a fixed-point number, with binary point at bit 235 | // (-exponent). Inside the function the non-converted remainder of fractionals 236 | // is a fixed-point number, with binary point at bit 'point'. 237 | if (-exponent <= 64) { 238 | // One 64 bit number is sufficient. 239 | ASSERT(fractionals >> 56 == 0); 240 | int point = -exponent; 241 | for (int i = 0; i < fractional_count; ++i) { 242 | if (fractionals == 0) break; 243 | // Instead of multiplying by 10 we multiply by 5 and adjust the point 244 | // location. This way the fractionals variable will not overflow. 245 | // Invariant at the beginning of the loop: fractionals < 2^point. 246 | // Initially we have: point <= 64 and fractionals < 2^56 247 | // After each iteration the point is decremented by one. 248 | // Note that 5^3 = 125 < 128 = 2^7. 249 | // Therefore three iterations of this loop will not overflow fractionals 250 | // (even without the subtraction at the end of the loop body). At this 251 | // time point will satisfy point <= 61 and therefore fractionals < 2^point 252 | // and any further multiplication of fractionals by 5 will not overflow. 253 | fractionals *= 5; 254 | point--; 255 | int digit = static_cast(fractionals >> point); 256 | ASSERT(digit <= 9); 257 | buffer[*length] = static_cast('0' + digit); 258 | (*length)++; 259 | fractionals -= static_cast(digit) << point; 260 | } 261 | // If the first bit after the point is set we have to round up. 262 | if (((fractionals >> (point - 1)) & 1) == 1) { 263 | RoundUp(buffer, length, decimal_point); 264 | } 265 | } else { // We need 128 bits. 266 | ASSERT(64 < -exponent && -exponent <= 128); 267 | UInt128 fractionals128 = UInt128(fractionals, 0); 268 | fractionals128.Shift(-exponent - 64); 269 | int point = 128; 270 | for (int i = 0; i < fractional_count; ++i) { 271 | if (fractionals128.IsZero()) break; 272 | // As before: instead of multiplying by 10 we multiply by 5 and adjust the 273 | // point location. 274 | // This multiplication will not overflow for the same reasons as before. 275 | fractionals128.Multiply(5); 276 | point--; 277 | int digit = fractionals128.DivModPowerOf2(point); 278 | ASSERT(digit <= 9); 279 | buffer[*length] = static_cast('0' + digit); 280 | (*length)++; 281 | } 282 | if (fractionals128.BitAt(point - 1) == 1) { 283 | RoundUp(buffer, length, decimal_point); 284 | } 285 | } 286 | } 287 | 288 | 289 | // Removes leading and trailing zeros. 290 | // If leading zeros are removed then the decimal point position is adjusted. 291 | static void TrimZeros(Vector buffer, int* length, int* decimal_point) { 292 | while (*length > 0 && buffer[(*length) - 1] == '0') { 293 | (*length)--; 294 | } 295 | int first_non_zero = 0; 296 | while (first_non_zero < *length && buffer[first_non_zero] == '0') { 297 | first_non_zero++; 298 | } 299 | if (first_non_zero != 0) { 300 | for (int i = first_non_zero; i < *length; ++i) { 301 | buffer[i - first_non_zero] = buffer[i]; 302 | } 303 | *length -= first_non_zero; 304 | *decimal_point -= first_non_zero; 305 | } 306 | } 307 | 308 | 309 | bool FastFixedDtoa(double v, 310 | int fractional_count, 311 | Vector buffer, 312 | int* length, 313 | int* decimal_point) { 314 | const uint32_t kMaxUInt32 = 0xFFFFFFFF; 315 | uint64_t significand = Double(v).Significand(); 316 | int exponent = Double(v).Exponent(); 317 | // v = significand * 2^exponent (with significand a 53bit integer). 318 | // If the exponent is larger than 20 (i.e. we may have a 73bit number) then we 319 | // don't know how to compute the representation. 2^73 ~= 9.5*10^21. 320 | // If necessary this limit could probably be increased, but we don't need 321 | // more. 322 | if (exponent > 20) return false; 323 | if (fractional_count > 20) return false; 324 | *length = 0; 325 | // At most kDoubleSignificandSize bits of the significand are non-zero. 326 | // Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero 327 | // bits: 0..11*..0xxx..53*..xx 328 | if (exponent + kDoubleSignificandSize > 64) { 329 | // The exponent must be > 11. 330 | // 331 | // We know that v = significand * 2^exponent. 332 | // And the exponent > 11. 333 | // We simplify the task by dividing v by 10^17. 334 | // The quotient delivers the first digits, and the remainder fits into a 64 335 | // bit number. 336 | // Dividing by 10^17 is equivalent to dividing by 5^17*2^17. 337 | const uint64_t kFive17 = UINT64_2PART_C(0xB1, A2BC2EC5); // 5^17 338 | uint64_t divisor = kFive17; 339 | int divisor_power = 17; 340 | uint64_t dividend = significand; 341 | uint32_t quotient; 342 | uint64_t remainder; 343 | // Let v = f * 2^e with f == significand and e == exponent. 344 | // Then need q (quotient) and r (remainder) as follows: 345 | // v = q * 10^17 + r 346 | // f * 2^e = q * 10^17 + r 347 | // f * 2^e = q * 5^17 * 2^17 + r 348 | // If e > 17 then 349 | // f * 2^(e-17) = q * 5^17 + r/2^17 350 | // else 351 | // f = q * 5^17 * 2^(17-e) + r/2^e 352 | if (exponent > divisor_power) { 353 | // We only allow exponents of up to 20 and therefore (17 - e) <= 3 354 | dividend <<= exponent - divisor_power; 355 | quotient = static_cast(dividend / divisor); 356 | remainder = (dividend % divisor) << divisor_power; 357 | } else { 358 | divisor <<= divisor_power - exponent; 359 | quotient = static_cast(dividend / divisor); 360 | remainder = (dividend % divisor) << exponent; 361 | } 362 | FillDigits32(quotient, buffer, length); 363 | FillDigits64FixedLength(remainder, buffer, length); 364 | *decimal_point = *length; 365 | } else if (exponent >= 0) { 366 | // 0 <= exponent <= 11 367 | significand <<= exponent; 368 | FillDigits64(significand, buffer, length); 369 | *decimal_point = *length; 370 | } else if (exponent > -kDoubleSignificandSize) { 371 | // We have to cut the number. 372 | uint64_t integrals = significand >> -exponent; 373 | uint64_t fractionals = significand - (integrals << -exponent); 374 | if (integrals > kMaxUInt32) { 375 | FillDigits64(integrals, buffer, length); 376 | } else { 377 | FillDigits32(static_cast(integrals), buffer, length); 378 | } 379 | *decimal_point = *length; 380 | FillFractionals(fractionals, exponent, fractional_count, 381 | buffer, length, decimal_point); 382 | } else if (exponent < -128) { 383 | // This configuration (with at most 20 digits) means that all digits must be 384 | // 0. 385 | ASSERT(fractional_count <= 20); 386 | buffer[0] = '\0'; 387 | *length = 0; 388 | *decimal_point = -fractional_count; 389 | } else { 390 | *decimal_point = 0; 391 | FillFractionals(significand, exponent, fractional_count, 392 | buffer, length, decimal_point); 393 | } 394 | TrimZeros(buffer, length, decimal_point); 395 | buffer[*length] = '\0'; 396 | if ((*length) == 0) { 397 | // The string is empty and the decimal_point thus has no importance. Mimick 398 | // Gay's dtoa and and set it to -fractional_count. 399 | *decimal_point = -fractional_count; 400 | } 401 | return true; 402 | } 403 | 404 | } // namespace double_conversion 405 | -------------------------------------------------------------------------------- /grisu/src/fixed-dtoa.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_FIXED_DTOA_H_ 29 | #define DOUBLE_CONVERSION_FIXED_DTOA_H_ 30 | 31 | #include "utils.h" 32 | 33 | namespace double_conversion { 34 | 35 | // Produces digits necessary to print a given number with 36 | // 'fractional_count' digits after the decimal point. 37 | // The buffer must be big enough to hold the result plus one terminating null 38 | // character. 39 | // 40 | // The produced digits might be too short in which case the caller has to fill 41 | // the gaps with '0's. 42 | // Example: FastFixedDtoa(0.001, 5, ...) is allowed to return buffer = "1", and 43 | // decimal_point = -2. 44 | // Halfway cases are rounded towards +/-Infinity (away from 0). The call 45 | // FastFixedDtoa(0.15, 2, ...) thus returns buffer = "2", decimal_point = 0. 46 | // The returned buffer may contain digits that would be truncated from the 47 | // shortest representation of the input. 48 | // 49 | // This method only works for some parameters. If it can't handle the input it 50 | // returns false. The output is null-terminated when the function succeeds. 51 | bool FastFixedDtoa(double v, int fractional_count, 52 | Vector buffer, int* length, int* decimal_point); 53 | 54 | } // namespace double_conversion 55 | 56 | #endif // DOUBLE_CONVERSION_FIXED_DTOA_H_ 57 | -------------------------------------------------------------------------------- /grisu/src/ieee.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_DOUBLE_H_ 29 | #define DOUBLE_CONVERSION_DOUBLE_H_ 30 | 31 | #include "diy-fp.h" 32 | 33 | namespace double_conversion { 34 | 35 | // We assume that doubles and uint64_t have the same endianness. 36 | static uint64_t double_to_uint64(double d) { return BitCast(d); } 37 | static double uint64_to_double(uint64_t d64) { return BitCast(d64); } 38 | static uint32_t float_to_uint32(float f) { return BitCast(f); } 39 | static float uint32_to_float(uint32_t d32) { return BitCast(d32); } 40 | 41 | // Helper functions for doubles. 42 | class Double { 43 | public: 44 | static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000); 45 | static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000); 46 | static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); 47 | static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000); 48 | static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit. 49 | static const int kSignificandSize = 53; 50 | 51 | Double() : d64_(0) {} 52 | explicit Double(double d) : d64_(double_to_uint64(d)) {} 53 | explicit Double(uint64_t d64) : d64_(d64) {} 54 | explicit Double(DiyFp diy_fp) 55 | : d64_(DiyFpToUint64(diy_fp)) {} 56 | 57 | // The value encoded by this Double must be greater or equal to +0.0. 58 | // It must not be special (infinity, or NaN). 59 | DiyFp AsDiyFp() const { 60 | ASSERT(Sign() > 0); 61 | ASSERT(!IsSpecial()); 62 | return DiyFp(Significand(), Exponent()); 63 | } 64 | 65 | // The value encoded by this Double must be strictly greater than 0. 66 | DiyFp AsNormalizedDiyFp() const { 67 | ASSERT(value() > 0.0); 68 | uint64_t f = Significand(); 69 | int e = Exponent(); 70 | 71 | // The current double could be a denormal. 72 | while ((f & kHiddenBit) == 0) { 73 | f <<= 1; 74 | e--; 75 | } 76 | // Do the final shifts in one go. 77 | f <<= DiyFp::kSignificandSize - kSignificandSize; 78 | e -= DiyFp::kSignificandSize - kSignificandSize; 79 | return DiyFp(f, e); 80 | } 81 | 82 | // Returns the double's bit as uint64. 83 | uint64_t AsUint64() const { 84 | return d64_; 85 | } 86 | 87 | // Returns the next greater double. Returns +infinity on input +infinity. 88 | double NextDouble() const { 89 | if (d64_ == kInfinity) return Double(kInfinity).value(); 90 | if (Sign() < 0 && Significand() == 0) { 91 | // -0.0 92 | return 0.0; 93 | } 94 | if (Sign() < 0) { 95 | return Double(d64_ - 1).value(); 96 | } else { 97 | return Double(d64_ + 1).value(); 98 | } 99 | } 100 | 101 | double PreviousDouble() const { 102 | if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity(); 103 | if (Sign() < 0) { 104 | return Double(d64_ + 1).value(); 105 | } else { 106 | if (Significand() == 0) return -0.0; 107 | return Double(d64_ - 1).value(); 108 | } 109 | } 110 | 111 | int Exponent() const { 112 | if (IsDenormal()) return kDenormalExponent; 113 | 114 | uint64_t d64 = AsUint64(); 115 | int biased_e = 116 | static_cast((d64 & kExponentMask) >> kPhysicalSignificandSize); 117 | return biased_e - kExponentBias; 118 | } 119 | 120 | uint64_t Significand() const { 121 | uint64_t d64 = AsUint64(); 122 | uint64_t significand = d64 & kSignificandMask; 123 | if (!IsDenormal()) { 124 | return significand + kHiddenBit; 125 | } else { 126 | return significand; 127 | } 128 | } 129 | 130 | // Returns true if the double is a denormal. 131 | bool IsDenormal() const { 132 | uint64_t d64 = AsUint64(); 133 | return (d64 & kExponentMask) == 0; 134 | } 135 | 136 | // We consider denormals not to be special. 137 | // Hence only Infinity and NaN are special. 138 | bool IsSpecial() const { 139 | uint64_t d64 = AsUint64(); 140 | return (d64 & kExponentMask) == kExponentMask; 141 | } 142 | 143 | bool IsNan() const { 144 | uint64_t d64 = AsUint64(); 145 | return ((d64 & kExponentMask) == kExponentMask) && 146 | ((d64 & kSignificandMask) != 0); 147 | } 148 | 149 | bool IsInfinite() const { 150 | uint64_t d64 = AsUint64(); 151 | return ((d64 & kExponentMask) == kExponentMask) && 152 | ((d64 & kSignificandMask) == 0); 153 | } 154 | 155 | int Sign() const { 156 | uint64_t d64 = AsUint64(); 157 | return (d64 & kSignMask) == 0? 1: -1; 158 | } 159 | 160 | // Precondition: the value encoded by this Double must be greater or equal 161 | // than +0.0. 162 | DiyFp UpperBoundary() const { 163 | ASSERT(Sign() > 0); 164 | return DiyFp(Significand() * 2 + 1, Exponent() - 1); 165 | } 166 | 167 | // Computes the two boundaries of this. 168 | // The bigger boundary (m_plus) is normalized. The lower boundary has the same 169 | // exponent as m_plus. 170 | // Precondition: the value encoded by this Double must be greater than 0. 171 | void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const { 172 | ASSERT(value() > 0.0); 173 | DiyFp v = this->AsDiyFp(); 174 | DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1)); 175 | DiyFp m_minus; 176 | if (LowerBoundaryIsCloser()) { 177 | m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2); 178 | } else { 179 | m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1); 180 | } 181 | m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e())); 182 | m_minus.set_e(m_plus.e()); 183 | *out_m_plus = m_plus; 184 | *out_m_minus = m_minus; 185 | } 186 | 187 | bool LowerBoundaryIsCloser() const { 188 | // The boundary is closer if the significand is of the form f == 2^p-1 then 189 | // the lower boundary is closer. 190 | // Think of v = 1000e10 and v- = 9999e9. 191 | // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but 192 | // at a distance of 1e8. 193 | // The only exception is for the smallest normal: the largest denormal is 194 | // at the same distance as its successor. 195 | // Note: denormals have the same exponent as the smallest normals. 196 | bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0); 197 | return physical_significand_is_zero && (Exponent() != kDenormalExponent); 198 | } 199 | 200 | double value() const { return uint64_to_double(d64_); } 201 | 202 | // Returns the significand size for a given order of magnitude. 203 | // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude. 204 | // This function returns the number of significant binary digits v will have 205 | // once it's encoded into a double. In almost all cases this is equal to 206 | // kSignificandSize. The only exceptions are denormals. They start with 207 | // leading zeroes and their effective significand-size is hence smaller. 208 | static int SignificandSizeForOrderOfMagnitude(int order) { 209 | if (order >= (kDenormalExponent + kSignificandSize)) { 210 | return kSignificandSize; 211 | } 212 | if (order <= kDenormalExponent) return 0; 213 | return order - kDenormalExponent; 214 | } 215 | 216 | static double Infinity() { 217 | return Double(kInfinity).value(); 218 | } 219 | 220 | static double NaN() { 221 | return Double(kNaN).value(); 222 | } 223 | 224 | private: 225 | static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; 226 | static const int kDenormalExponent = -kExponentBias + 1; 227 | static const int kMaxExponent = 0x7FF - kExponentBias; 228 | static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000); 229 | static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000); 230 | 231 | const uint64_t d64_; 232 | 233 | static uint64_t DiyFpToUint64(DiyFp diy_fp) { 234 | uint64_t significand = diy_fp.f(); 235 | int exponent = diy_fp.e(); 236 | while (significand > kHiddenBit + kSignificandMask) { 237 | significand >>= 1; 238 | exponent++; 239 | } 240 | if (exponent >= kMaxExponent) { 241 | return kInfinity; 242 | } 243 | if (exponent < kDenormalExponent) { 244 | return 0; 245 | } 246 | while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) { 247 | significand <<= 1; 248 | exponent--; 249 | } 250 | uint64_t biased_exponent; 251 | if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) { 252 | biased_exponent = 0; 253 | } else { 254 | biased_exponent = static_cast(exponent + kExponentBias); 255 | } 256 | return (significand & kSignificandMask) | 257 | (biased_exponent << kPhysicalSignificandSize); 258 | } 259 | 260 | DISALLOW_COPY_AND_ASSIGN(Double); 261 | }; 262 | 263 | class Single { 264 | public: 265 | static const uint32_t kSignMask = 0x80000000; 266 | static const uint32_t kExponentMask = 0x7F800000; 267 | static const uint32_t kSignificandMask = 0x007FFFFF; 268 | static const uint32_t kHiddenBit = 0x00800000; 269 | static const int kPhysicalSignificandSize = 23; // Excludes the hidden bit. 270 | static const int kSignificandSize = 24; 271 | 272 | Single() : d32_(0) {} 273 | explicit Single(float f) : d32_(float_to_uint32(f)) {} 274 | explicit Single(uint32_t d32) : d32_(d32) {} 275 | 276 | // The value encoded by this Single must be greater or equal to +0.0. 277 | // It must not be special (infinity, or NaN). 278 | DiyFp AsDiyFp() const { 279 | ASSERT(Sign() > 0); 280 | ASSERT(!IsSpecial()); 281 | return DiyFp(Significand(), Exponent()); 282 | } 283 | 284 | // Returns the single's bit as uint64. 285 | uint32_t AsUint32() const { 286 | return d32_; 287 | } 288 | 289 | int Exponent() const { 290 | if (IsDenormal()) return kDenormalExponent; 291 | 292 | uint32_t d32 = AsUint32(); 293 | int biased_e = 294 | static_cast((d32 & kExponentMask) >> kPhysicalSignificandSize); 295 | return biased_e - kExponentBias; 296 | } 297 | 298 | uint32_t Significand() const { 299 | uint32_t d32 = AsUint32(); 300 | uint32_t significand = d32 & kSignificandMask; 301 | if (!IsDenormal()) { 302 | return significand + kHiddenBit; 303 | } else { 304 | return significand; 305 | } 306 | } 307 | 308 | // Returns true if the single is a denormal. 309 | bool IsDenormal() const { 310 | uint32_t d32 = AsUint32(); 311 | return (d32 & kExponentMask) == 0; 312 | } 313 | 314 | // We consider denormals not to be special. 315 | // Hence only Infinity and NaN are special. 316 | bool IsSpecial() const { 317 | uint32_t d32 = AsUint32(); 318 | return (d32 & kExponentMask) == kExponentMask; 319 | } 320 | 321 | bool IsNan() const { 322 | uint32_t d32 = AsUint32(); 323 | return ((d32 & kExponentMask) == kExponentMask) && 324 | ((d32 & kSignificandMask) != 0); 325 | } 326 | 327 | bool IsInfinite() const { 328 | uint32_t d32 = AsUint32(); 329 | return ((d32 & kExponentMask) == kExponentMask) && 330 | ((d32 & kSignificandMask) == 0); 331 | } 332 | 333 | int Sign() const { 334 | uint32_t d32 = AsUint32(); 335 | return (d32 & kSignMask) == 0? 1: -1; 336 | } 337 | 338 | // Computes the two boundaries of this. 339 | // The bigger boundary (m_plus) is normalized. The lower boundary has the same 340 | // exponent as m_plus. 341 | // Precondition: the value encoded by this Single must be greater than 0. 342 | void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const { 343 | ASSERT(value() > 0.0); 344 | DiyFp v = this->AsDiyFp(); 345 | DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1)); 346 | DiyFp m_minus; 347 | if (LowerBoundaryIsCloser()) { 348 | m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2); 349 | } else { 350 | m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1); 351 | } 352 | m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e())); 353 | m_minus.set_e(m_plus.e()); 354 | *out_m_plus = m_plus; 355 | *out_m_minus = m_minus; 356 | } 357 | 358 | // Precondition: the value encoded by this Single must be greater or equal 359 | // than +0.0. 360 | DiyFp UpperBoundary() const { 361 | ASSERT(Sign() > 0); 362 | return DiyFp(Significand() * 2 + 1, Exponent() - 1); 363 | } 364 | 365 | bool LowerBoundaryIsCloser() const { 366 | // The boundary is closer if the significand is of the form f == 2^p-1 then 367 | // the lower boundary is closer. 368 | // Think of v = 1000e10 and v- = 9999e9. 369 | // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but 370 | // at a distance of 1e8. 371 | // The only exception is for the smallest normal: the largest denormal is 372 | // at the same distance as its successor. 373 | // Note: denormals have the same exponent as the smallest normals. 374 | bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0); 375 | return physical_significand_is_zero && (Exponent() != kDenormalExponent); 376 | } 377 | 378 | float value() const { return uint32_to_float(d32_); } 379 | 380 | static float Infinity() { 381 | return Single(kInfinity).value(); 382 | } 383 | 384 | static float NaN() { 385 | return Single(kNaN).value(); 386 | } 387 | 388 | private: 389 | static const int kExponentBias = 0x7F + kPhysicalSignificandSize; 390 | static const int kDenormalExponent = -kExponentBias + 1; 391 | static const int kMaxExponent = 0xFF - kExponentBias; 392 | static const uint32_t kInfinity = 0x7F800000; 393 | static const uint32_t kNaN = 0x7FC00000; 394 | 395 | const uint32_t d32_; 396 | 397 | DISALLOW_COPY_AND_ASSIGN(Single); 398 | }; 399 | 400 | } // namespace double_conversion 401 | 402 | #endif // DOUBLE_CONVERSION_DOUBLE_H_ 403 | -------------------------------------------------------------------------------- /grisu/src/strtod.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #include 29 | #include 30 | 31 | #include "strtod.h" 32 | #include "bignum.h" 33 | #include "cached-powers.h" 34 | #include "ieee.h" 35 | 36 | namespace double_conversion { 37 | 38 | // 2^53 = 9007199254740992. 39 | // Any integer with at most 15 decimal digits will hence fit into a double 40 | // (which has a 53bit significand) without loss of precision. 41 | static const int kMaxExactDoubleIntegerDecimalDigits = 15; 42 | // 2^64 = 18446744073709551616 > 10^19 43 | static const int kMaxUint64DecimalDigits = 19; 44 | 45 | // Max double: 1.7976931348623157 x 10^308 46 | // Min non-zero double: 4.9406564584124654 x 10^-324 47 | // Any x >= 10^309 is interpreted as +infinity. 48 | // Any x <= 10^-324 is interpreted as 0. 49 | // Note that 2.5e-324 (despite being smaller than the min double) will be read 50 | // as non-zero (equal to the min non-zero double). 51 | static const int kMaxDecimalPower = 309; 52 | static const int kMinDecimalPower = -324; 53 | 54 | // 2^64 = 18446744073709551616 55 | static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); 56 | 57 | 58 | static const double exact_powers_of_ten[] = { 59 | 1.0, // 10^0 60 | 10.0, 61 | 100.0, 62 | 1000.0, 63 | 10000.0, 64 | 100000.0, 65 | 1000000.0, 66 | 10000000.0, 67 | 100000000.0, 68 | 1000000000.0, 69 | 10000000000.0, // 10^10 70 | 100000000000.0, 71 | 1000000000000.0, 72 | 10000000000000.0, 73 | 100000000000000.0, 74 | 1000000000000000.0, 75 | 10000000000000000.0, 76 | 100000000000000000.0, 77 | 1000000000000000000.0, 78 | 10000000000000000000.0, 79 | 100000000000000000000.0, // 10^20 80 | 1000000000000000000000.0, 81 | // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22 82 | 10000000000000000000000.0 83 | }; 84 | static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten); 85 | 86 | // Maximum number of significant digits in the decimal representation. 87 | // In fact the value is 772 (see conversions.cc), but to give us some margin 88 | // we round up to 780. 89 | static const int kMaxSignificantDecimalDigits = 780; 90 | 91 | static Vector TrimLeadingZeros(Vector buffer) { 92 | for (int i = 0; i < buffer.length(); i++) { 93 | if (buffer[i] != '0') { 94 | return buffer.SubVector(i, buffer.length()); 95 | } 96 | } 97 | return Vector(buffer.start(), 0); 98 | } 99 | 100 | 101 | static Vector TrimTrailingZeros(Vector buffer) { 102 | for (int i = buffer.length() - 1; i >= 0; --i) { 103 | if (buffer[i] != '0') { 104 | return buffer.SubVector(0, i + 1); 105 | } 106 | } 107 | return Vector(buffer.start(), 0); 108 | } 109 | 110 | 111 | static void CutToMaxSignificantDigits(Vector buffer, 112 | int exponent, 113 | char* significant_buffer, 114 | int* significant_exponent) { 115 | for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) { 116 | significant_buffer[i] = buffer[i]; 117 | } 118 | // The input buffer has been trimmed. Therefore the last digit must be 119 | // different from '0'. 120 | ASSERT(buffer[buffer.length() - 1] != '0'); 121 | // Set the last digit to be non-zero. This is sufficient to guarantee 122 | // correct rounding. 123 | significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; 124 | *significant_exponent = 125 | exponent + (buffer.length() - kMaxSignificantDecimalDigits); 126 | } 127 | 128 | 129 | // Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits. 130 | // If possible the input-buffer is reused, but if the buffer needs to be 131 | // modified (due to cutting), then the input needs to be copied into the 132 | // buffer_copy_space. 133 | static void TrimAndCut(Vector buffer, int exponent, 134 | char* buffer_copy_space, int space_size, 135 | Vector* trimmed, int* updated_exponent) { 136 | Vector left_trimmed = TrimLeadingZeros(buffer); 137 | Vector right_trimmed = TrimTrailingZeros(left_trimmed); 138 | exponent += left_trimmed.length() - right_trimmed.length(); 139 | if (right_trimmed.length() > kMaxSignificantDecimalDigits) { 140 | (void) space_size; // Mark variable as used. 141 | ASSERT(space_size >= kMaxSignificantDecimalDigits); 142 | CutToMaxSignificantDigits(right_trimmed, exponent, 143 | buffer_copy_space, updated_exponent); 144 | *trimmed = Vector(buffer_copy_space, 145 | kMaxSignificantDecimalDigits); 146 | } else { 147 | *trimmed = right_trimmed; 148 | *updated_exponent = exponent; 149 | } 150 | } 151 | 152 | 153 | // Reads digits from the buffer and converts them to a uint64. 154 | // Reads in as many digits as fit into a uint64. 155 | // When the string starts with "1844674407370955161" no further digit is read. 156 | // Since 2^64 = 18446744073709551616 it would still be possible read another 157 | // digit if it was less or equal than 6, but this would complicate the code. 158 | static uint64_t ReadUint64(Vector buffer, 159 | int* number_of_read_digits) { 160 | uint64_t result = 0; 161 | int i = 0; 162 | while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { 163 | int digit = buffer[i++] - '0'; 164 | ASSERT(0 <= digit && digit <= 9); 165 | result = 10 * result + digit; 166 | } 167 | *number_of_read_digits = i; 168 | return result; 169 | } 170 | 171 | 172 | // Reads a DiyFp from the buffer. 173 | // The returned DiyFp is not necessarily normalized. 174 | // If remaining_decimals is zero then the returned DiyFp is accurate. 175 | // Otherwise it has been rounded and has error of at most 1/2 ulp. 176 | static void ReadDiyFp(Vector buffer, 177 | DiyFp* result, 178 | int* remaining_decimals) { 179 | int read_digits; 180 | uint64_t significand = ReadUint64(buffer, &read_digits); 181 | if (buffer.length() == read_digits) { 182 | *result = DiyFp(significand, 0); 183 | *remaining_decimals = 0; 184 | } else { 185 | // Round the significand. 186 | if (buffer[read_digits] >= '5') { 187 | significand++; 188 | } 189 | // Compute the binary exponent. 190 | int exponent = 0; 191 | *result = DiyFp(significand, exponent); 192 | *remaining_decimals = buffer.length() - read_digits; 193 | } 194 | } 195 | 196 | 197 | static bool DoubleStrtod(Vector trimmed, 198 | int exponent, 199 | double* result) { 200 | #if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) 201 | // On x86 the floating-point stack can be 64 or 80 bits wide. If it is 202 | // 80 bits wide (as is the case on Linux) then double-rounding occurs and the 203 | // result is not accurate. 204 | // We know that Windows32 uses 64 bits and is therefore accurate. 205 | // Note that the ARM simulator is compiled for 32bits. It therefore exhibits 206 | // the same problem. 207 | return false; 208 | #endif 209 | if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { 210 | int read_digits; 211 | // The trimmed input fits into a double. 212 | // If the 10^exponent (resp. 10^-exponent) fits into a double too then we 213 | // can compute the result-double simply by multiplying (resp. dividing) the 214 | // two numbers. 215 | // This is possible because IEEE guarantees that floating-point operations 216 | // return the best possible approximation. 217 | if (exponent < 0 && -exponent < kExactPowersOfTenSize) { 218 | // 10^-exponent fits into a double. 219 | *result = static_cast(ReadUint64(trimmed, &read_digits)); 220 | ASSERT(read_digits == trimmed.length()); 221 | *result /= exact_powers_of_ten[-exponent]; 222 | return true; 223 | } 224 | if (0 <= exponent && exponent < kExactPowersOfTenSize) { 225 | // 10^exponent fits into a double. 226 | *result = static_cast(ReadUint64(trimmed, &read_digits)); 227 | ASSERT(read_digits == trimmed.length()); 228 | *result *= exact_powers_of_ten[exponent]; 229 | return true; 230 | } 231 | int remaining_digits = 232 | kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); 233 | if ((0 <= exponent) && 234 | (exponent - remaining_digits < kExactPowersOfTenSize)) { 235 | // The trimmed string was short and we can multiply it with 236 | // 10^remaining_digits. As a result the remaining exponent now fits 237 | // into a double too. 238 | *result = static_cast(ReadUint64(trimmed, &read_digits)); 239 | ASSERT(read_digits == trimmed.length()); 240 | *result *= exact_powers_of_ten[remaining_digits]; 241 | *result *= exact_powers_of_ten[exponent - remaining_digits]; 242 | return true; 243 | } 244 | } 245 | return false; 246 | } 247 | 248 | 249 | // Returns 10^exponent as an exact DiyFp. 250 | // The given exponent must be in the range [1; kDecimalExponentDistance[. 251 | static DiyFp AdjustmentPowerOfTen(int exponent) { 252 | ASSERT(0 < exponent); 253 | ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance); 254 | // Simply hardcode the remaining powers for the given decimal exponent 255 | // distance. 256 | ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8); 257 | switch (exponent) { 258 | case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60); 259 | case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57); 260 | case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54); 261 | case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50); 262 | case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47); 263 | case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44); 264 | case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40); 265 | default: 266 | UNREACHABLE(); 267 | } 268 | } 269 | 270 | 271 | // If the function returns true then the result is the correct double. 272 | // Otherwise it is either the correct double or the double that is just below 273 | // the correct double. 274 | static bool DiyFpStrtod(Vector buffer, 275 | int exponent, 276 | double* result) { 277 | DiyFp input; 278 | int remaining_decimals; 279 | ReadDiyFp(buffer, &input, &remaining_decimals); 280 | // Since we may have dropped some digits the input is not accurate. 281 | // If remaining_decimals is different than 0 than the error is at most 282 | // .5 ulp (unit in the last place). 283 | // We don't want to deal with fractions and therefore keep a common 284 | // denominator. 285 | const int kDenominatorLog = 3; 286 | const int kDenominator = 1 << kDenominatorLog; 287 | // Move the remaining decimals into the exponent. 288 | exponent += remaining_decimals; 289 | int error = (remaining_decimals == 0 ? 0 : kDenominator / 2); 290 | 291 | int old_e = input.e(); 292 | input.Normalize(); 293 | error <<= old_e - input.e(); 294 | 295 | ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent); 296 | if (exponent < PowersOfTenCache::kMinDecimalExponent) { 297 | *result = 0.0; 298 | return true; 299 | } 300 | DiyFp cached_power; 301 | int cached_decimal_exponent; 302 | PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent, 303 | &cached_power, 304 | &cached_decimal_exponent); 305 | 306 | if (cached_decimal_exponent != exponent) { 307 | int adjustment_exponent = exponent - cached_decimal_exponent; 308 | DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent); 309 | input.Multiply(adjustment_power); 310 | if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) { 311 | // The product of input with the adjustment power fits into a 64 bit 312 | // integer. 313 | ASSERT(DiyFp::kSignificandSize == 64); 314 | } else { 315 | // The adjustment power is exact. There is hence only an error of 0.5. 316 | error += kDenominator / 2; 317 | } 318 | } 319 | 320 | input.Multiply(cached_power); 321 | // The error introduced by a multiplication of a*b equals 322 | // error_a + error_b + error_a*error_b/2^64 + 0.5 323 | // Substituting a with 'input' and b with 'cached_power' we have 324 | // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp), 325 | // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64 326 | int error_b = kDenominator / 2; 327 | int error_ab = (error == 0 ? 0 : 1); // We round up to 1. 328 | int fixed_error = kDenominator / 2; 329 | error += error_b + error_ab + fixed_error; 330 | 331 | old_e = input.e(); 332 | input.Normalize(); 333 | error <<= old_e - input.e(); 334 | 335 | // See if the double's significand changes if we add/subtract the error. 336 | int order_of_magnitude = DiyFp::kSignificandSize + input.e(); 337 | int effective_significand_size = 338 | Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude); 339 | int precision_digits_count = 340 | DiyFp::kSignificandSize - effective_significand_size; 341 | if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) { 342 | // This can only happen for very small denormals. In this case the 343 | // half-way multiplied by the denominator exceeds the range of an uint64. 344 | // Simply shift everything to the right. 345 | int shift_amount = (precision_digits_count + kDenominatorLog) - 346 | DiyFp::kSignificandSize + 1; 347 | input.set_f(input.f() >> shift_amount); 348 | input.set_e(input.e() + shift_amount); 349 | // We add 1 for the lost precision of error, and kDenominator for 350 | // the lost precision of input.f(). 351 | error = (error >> shift_amount) + 1 + kDenominator; 352 | precision_digits_count -= shift_amount; 353 | } 354 | // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too. 355 | ASSERT(DiyFp::kSignificandSize == 64); 356 | ASSERT(precision_digits_count < 64); 357 | uint64_t one64 = 1; 358 | uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1; 359 | uint64_t precision_bits = input.f() & precision_bits_mask; 360 | uint64_t half_way = one64 << (precision_digits_count - 1); 361 | precision_bits *= kDenominator; 362 | half_way *= kDenominator; 363 | DiyFp rounded_input(input.f() >> precision_digits_count, 364 | input.e() + precision_digits_count); 365 | if (precision_bits >= half_way + error) { 366 | rounded_input.set_f(rounded_input.f() + 1); 367 | } 368 | // If the last_bits are too close to the half-way case than we are too 369 | // inaccurate and round down. In this case we return false so that we can 370 | // fall back to a more precise algorithm. 371 | 372 | *result = Double(rounded_input).value(); 373 | if (half_way - error < precision_bits && precision_bits < half_way + error) { 374 | // Too imprecise. The caller will have to fall back to a slower version. 375 | // However the returned number is guaranteed to be either the correct 376 | // double, or the next-lower double. 377 | return false; 378 | } else { 379 | return true; 380 | } 381 | } 382 | 383 | 384 | // Returns 385 | // - -1 if buffer*10^exponent < diy_fp. 386 | // - 0 if buffer*10^exponent == diy_fp. 387 | // - +1 if buffer*10^exponent > diy_fp. 388 | // Preconditions: 389 | // buffer.length() + exponent <= kMaxDecimalPower + 1 390 | // buffer.length() + exponent > kMinDecimalPower 391 | // buffer.length() <= kMaxDecimalSignificantDigits 392 | static int CompareBufferWithDiyFp(Vector buffer, 393 | int exponent, 394 | DiyFp diy_fp) { 395 | ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); 396 | ASSERT(buffer.length() + exponent > kMinDecimalPower); 397 | ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); 398 | // Make sure that the Bignum will be able to hold all our numbers. 399 | // Our Bignum implementation has a separate field for exponents. Shifts will 400 | // consume at most one bigit (< 64 bits). 401 | // ln(10) == 3.3219... 402 | ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); 403 | Bignum buffer_bignum; 404 | Bignum diy_fp_bignum; 405 | buffer_bignum.AssignDecimalString(buffer); 406 | diy_fp_bignum.AssignUInt64(diy_fp.f()); 407 | if (exponent >= 0) { 408 | buffer_bignum.MultiplyByPowerOfTen(exponent); 409 | } else { 410 | diy_fp_bignum.MultiplyByPowerOfTen(-exponent); 411 | } 412 | if (diy_fp.e() > 0) { 413 | diy_fp_bignum.ShiftLeft(diy_fp.e()); 414 | } else { 415 | buffer_bignum.ShiftLeft(-diy_fp.e()); 416 | } 417 | return Bignum::Compare(buffer_bignum, diy_fp_bignum); 418 | } 419 | 420 | 421 | // Returns true if the guess is the correct double. 422 | // Returns false, when guess is either correct or the next-lower double. 423 | static bool ComputeGuess(Vector trimmed, int exponent, 424 | double* guess) { 425 | if (trimmed.length() == 0) { 426 | *guess = 0.0; 427 | return true; 428 | } 429 | if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) { 430 | *guess = Double::Infinity(); 431 | return true; 432 | } 433 | if (exponent + trimmed.length() <= kMinDecimalPower) { 434 | *guess = 0.0; 435 | return true; 436 | } 437 | 438 | if (DoubleStrtod(trimmed, exponent, guess) || 439 | DiyFpStrtod(trimmed, exponent, guess)) { 440 | return true; 441 | } 442 | if (*guess == Double::Infinity()) { 443 | return true; 444 | } 445 | return false; 446 | } 447 | 448 | double Strtod(Vector buffer, int exponent) { 449 | char copy_buffer[kMaxSignificantDecimalDigits]; 450 | Vector trimmed; 451 | int updated_exponent; 452 | TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, 453 | &trimmed, &updated_exponent); 454 | exponent = updated_exponent; 455 | 456 | double guess; 457 | bool is_correct = ComputeGuess(trimmed, exponent, &guess); 458 | if (is_correct) return guess; 459 | 460 | DiyFp upper_boundary = Double(guess).UpperBoundary(); 461 | int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); 462 | if (comparison < 0) { 463 | return guess; 464 | } else if (comparison > 0) { 465 | return Double(guess).NextDouble(); 466 | } else if ((Double(guess).Significand() & 1) == 0) { 467 | // Round towards even. 468 | return guess; 469 | } else { 470 | return Double(guess).NextDouble(); 471 | } 472 | } 473 | 474 | float Strtof(Vector buffer, int exponent) { 475 | char copy_buffer[kMaxSignificantDecimalDigits]; 476 | Vector trimmed; 477 | int updated_exponent; 478 | TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, 479 | &trimmed, &updated_exponent); 480 | exponent = updated_exponent; 481 | 482 | double double_guess; 483 | bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); 484 | 485 | float float_guess = static_cast(double_guess); 486 | if (float_guess == double_guess) { 487 | // This shortcut triggers for integer values. 488 | return float_guess; 489 | } 490 | 491 | // We must catch double-rounding. Say the double has been rounded up, and is 492 | // now a boundary of a float, and rounds up again. This is why we have to 493 | // look at previous too. 494 | // Example (in decimal numbers): 495 | // input: 12349 496 | // high-precision (4 digits): 1235 497 | // low-precision (3 digits): 498 | // when read from input: 123 499 | // when rounded from high precision: 124. 500 | // To do this we simply look at the neigbors of the correct result and see 501 | // if they would round to the same float. If the guess is not correct we have 502 | // to look at four values (since two different doubles could be the correct 503 | // double). 504 | 505 | double double_next = Double(double_guess).NextDouble(); 506 | double double_previous = Double(double_guess).PreviousDouble(); 507 | 508 | float f1 = static_cast(double_previous); 509 | float f2 = float_guess; 510 | float f3 = static_cast(double_next); 511 | float f4; 512 | if (is_correct) { 513 | f4 = f3; 514 | } else { 515 | double double_next2 = Double(double_next).NextDouble(); 516 | f4 = static_cast(double_next2); 517 | } 518 | (void) f2; // Mark variable as used. 519 | ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4); 520 | 521 | // If the guess doesn't lie near a single-precision boundary we can simply 522 | // return its float-value. 523 | if (f1 == f4) { 524 | return float_guess; 525 | } 526 | 527 | ASSERT((f1 != f2 && f2 == f3 && f3 == f4) || 528 | (f1 == f2 && f2 != f3 && f3 == f4) || 529 | (f1 == f2 && f2 == f3 && f3 != f4)); 530 | 531 | // guess and next are the two possible canditates (in the same way that 532 | // double_guess was the lower candidate for a double-precision guess). 533 | float guess = f1; 534 | float next = f4; 535 | DiyFp upper_boundary; 536 | if (guess == 0.0f) { 537 | float min_float = 1e-45f; 538 | upper_boundary = Double(static_cast(min_float) / 2).AsDiyFp(); 539 | } else { 540 | upper_boundary = Single(guess).UpperBoundary(); 541 | } 542 | int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); 543 | if (comparison < 0) { 544 | return guess; 545 | } else if (comparison > 0) { 546 | return next; 547 | } else if ((Single(guess).Significand() & 1) == 0) { 548 | // Round towards even. 549 | return guess; 550 | } else { 551 | return next; 552 | } 553 | } 554 | 555 | } // namespace double_conversion 556 | -------------------------------------------------------------------------------- /grisu/src/strtod.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_STRTOD_H_ 29 | #define DOUBLE_CONVERSION_STRTOD_H_ 30 | 31 | #include "utils.h" 32 | 33 | namespace double_conversion { 34 | 35 | // The buffer must only contain digits in the range [0-9]. It must not 36 | // contain a dot or a sign. It must not start with '0', and must not be empty. 37 | double Strtod(Vector buffer, int exponent); 38 | 39 | // The buffer must only contain digits in the range [0-9]. It must not 40 | // contain a dot or a sign. It must not start with '0', and must not be empty. 41 | float Strtof(Vector buffer, int exponent); 42 | 43 | } // namespace double_conversion 44 | 45 | #endif // DOUBLE_CONVERSION_STRTOD_H_ 46 | -------------------------------------------------------------------------------- /grisu/src/utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 the V8 project authors. All rights reserved. 2 | // Redistribution and use in source and binary forms, with or without 3 | // modification, are permitted provided that the following conditions are 4 | // met: 5 | // 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above 9 | // copyright notice, this list of conditions and the following 10 | // disclaimer in the documentation and/or other materials provided 11 | // with the distribution. 12 | // * Neither the name of Google Inc. nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #ifndef DOUBLE_CONVERSION_UTILS_H_ 29 | #define DOUBLE_CONVERSION_UTILS_H_ 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #ifndef ASSERT 36 | #define ASSERT(condition) \ 37 | assert(condition); 38 | #endif 39 | #ifndef UNIMPLEMENTED 40 | #define UNIMPLEMENTED() (abort()) 41 | #endif 42 | #ifndef UNREACHABLE 43 | #define UNREACHABLE() (abort()) 44 | #endif 45 | 46 | // Double operations detection based on target architecture. 47 | // Linux uses a 80bit wide floating point stack on x86. This induces double 48 | // rounding, which in turn leads to wrong results. 49 | // An easy way to test if the floating-point operations are correct is to 50 | // evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then 51 | // the result is equal to 89255e-22. 52 | // The best way to test this, is to create a division-function and to compare 53 | // the output of the division with the expected result. (Inlining must be 54 | // disabled.) 55 | // On Linux,x86 89255e-22 != Div_double(89255.0/1e22) 56 | #if defined(_M_X64) || defined(__x86_64__) || \ 57 | defined(__ARMEL__) || defined(__avr32__) || \ 58 | defined(__hppa__) || defined(__ia64__) || \ 59 | defined(__mips__) || \ 60 | defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ 61 | defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ 62 | defined(__SH4__) || defined(__alpha__) || \ 63 | defined(_MIPS_ARCH_MIPS32R2) || \ 64 | defined(__AARCH64EL__) 65 | #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 66 | #elif defined(_M_IX86) || defined(__i386__) || defined(__i386) 67 | #if defined(_WIN32) 68 | // Windows uses a 64bit wide floating point stack. 69 | #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 70 | #else 71 | #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 72 | #endif // _WIN32 73 | #else 74 | #error Target architecture was not detected as supported by Double-Conversion. 75 | #endif 76 | 77 | #if defined(__GNUC__) 78 | #define DOUBLE_CONVERSION_UNUSED __attribute__((unused)) 79 | #else 80 | #define DOUBLE_CONVERSION_UNUSED 81 | #endif 82 | 83 | #if defined(_WIN32) && !defined(__MINGW32__) 84 | 85 | typedef signed char int8_t; 86 | typedef unsigned char uint8_t; 87 | typedef short int16_t; // NOLINT 88 | typedef unsigned short uint16_t; // NOLINT 89 | typedef int int32_t; 90 | typedef unsigned int uint32_t; 91 | typedef __int64 int64_t; 92 | typedef unsigned __int64 uint64_t; 93 | // intptr_t and friends are defined in crtdefs.h through stdio.h. 94 | 95 | #else 96 | 97 | #include 98 | 99 | #endif 100 | 101 | typedef uint16_t uc16; 102 | 103 | // The following macro works on both 32 and 64-bit platforms. 104 | // Usage: instead of writing 0x1234567890123456 105 | // write UINT64_2PART_C(0x12345678,90123456); 106 | #define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) 107 | 108 | 109 | // The expression ARRAY_SIZE(a) is a compile-time constant of type 110 | // size_t which represents the number of elements of the given 111 | // array. You should only use ARRAY_SIZE on statically allocated 112 | // arrays. 113 | #ifndef ARRAY_SIZE 114 | #define ARRAY_SIZE(a) \ 115 | ((sizeof(a) / sizeof(*(a))) / \ 116 | static_cast(!(sizeof(a) % sizeof(*(a))))) 117 | #endif 118 | 119 | // A macro to disallow the evil copy constructor and operator= functions 120 | // This should be used in the private: declarations for a class 121 | #ifndef DISALLOW_COPY_AND_ASSIGN 122 | #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ 123 | TypeName(const TypeName&); \ 124 | void operator=(const TypeName&) 125 | #endif 126 | 127 | // A macro to disallow all the implicit constructors, namely the 128 | // default constructor, copy constructor and operator= functions. 129 | // 130 | // This should be used in the private: declarations for a class 131 | // that wants to prevent anyone from instantiating it. This is 132 | // especially useful for classes containing only static methods. 133 | #ifndef DISALLOW_IMPLICIT_CONSTRUCTORS 134 | #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ 135 | TypeName(); \ 136 | DISALLOW_COPY_AND_ASSIGN(TypeName) 137 | #endif 138 | 139 | namespace double_conversion { 140 | 141 | static const int kCharSize = sizeof(char); 142 | 143 | // Returns the maximum of the two parameters. 144 | template 145 | static T Max(T a, T b) { 146 | return a < b ? b : a; 147 | } 148 | 149 | 150 | // Returns the minimum of the two parameters. 151 | template 152 | static T Min(T a, T b) { 153 | return a < b ? a : b; 154 | } 155 | 156 | 157 | inline int StrLength(const char* string) { 158 | size_t length = strlen(string); 159 | ASSERT(length == static_cast(static_cast(length))); 160 | return static_cast(length); 161 | } 162 | 163 | // This is a simplified version of V8's Vector class. 164 | template 165 | class Vector { 166 | public: 167 | Vector() : start_(NULL), length_(0) {} 168 | Vector(T* data, int length) : start_(data), length_(length) { 169 | ASSERT(length == 0 || (length > 0 && data != NULL)); 170 | } 171 | 172 | // Returns a vector using the same backing storage as this one, 173 | // spanning from and including 'from', to but not including 'to'. 174 | Vector SubVector(int from, int to) { 175 | ASSERT(to <= length_); 176 | ASSERT(from < to); 177 | ASSERT(0 <= from); 178 | return Vector(start() + from, to - from); 179 | } 180 | 181 | // Returns the length of the vector. 182 | int length() const { return length_; } 183 | 184 | // Returns whether or not the vector is empty. 185 | bool is_empty() const { return length_ == 0; } 186 | 187 | // Returns the pointer to the start of the data in the vector. 188 | T* start() const { return start_; } 189 | 190 | // Access individual vector elements - checks bounds in debug mode. 191 | T& operator[](int index) const { 192 | ASSERT(0 <= index && index < length_); 193 | return start_[index]; 194 | } 195 | 196 | T& first() { return start_[0]; } 197 | 198 | T& last() { return start_[length_ - 1]; } 199 | 200 | private: 201 | T* start_; 202 | int length_; 203 | }; 204 | 205 | 206 | // Helper class for building result strings in a character buffer. The 207 | // purpose of the class is to use safe operations that checks the 208 | // buffer bounds on all operations in debug mode. 209 | class StringBuilder { 210 | public: 211 | StringBuilder(char* buffer, int size) 212 | : buffer_(buffer, size), position_(0) { } 213 | 214 | ~StringBuilder() { if (!is_finalized()) Finalize(); } 215 | 216 | int size() const { return buffer_.length(); } 217 | 218 | // Get the current position in the builder. 219 | int position() const { 220 | ASSERT(!is_finalized()); 221 | return position_; 222 | } 223 | 224 | // Reset the position. 225 | void Reset() { position_ = 0; } 226 | 227 | // Add a single character to the builder. It is not allowed to add 228 | // 0-characters; use the Finalize() method to terminate the string 229 | // instead. 230 | void AddCharacter(char c) { 231 | ASSERT(c != '\0'); 232 | ASSERT(!is_finalized() && position_ < buffer_.length()); 233 | buffer_[position_++] = c; 234 | } 235 | 236 | // Add an entire string to the builder. Uses strlen() internally to 237 | // compute the length of the input string. 238 | void AddString(const char* s) { 239 | AddSubstring(s, StrLength(s)); 240 | } 241 | 242 | // Add the first 'n' characters of the given string 's' to the 243 | // builder. The input string must have enough characters. 244 | void AddSubstring(const char* s, int n) { 245 | ASSERT(!is_finalized() && position_ + n < buffer_.length()); 246 | ASSERT(static_cast(n) <= strlen(s)); 247 | memmove(&buffer_[position_], s, n * kCharSize); 248 | position_ += n; 249 | } 250 | 251 | 252 | // Add character padding to the builder. If count is non-positive, 253 | // nothing is added to the builder. 254 | void AddPadding(char c, int count) { 255 | for (int i = 0; i < count; i++) { 256 | AddCharacter(c); 257 | } 258 | } 259 | 260 | // Finalize the string by 0-terminating it and returning the buffer. 261 | char* Finalize() { 262 | ASSERT(!is_finalized() && position_ < buffer_.length()); 263 | buffer_[position_] = '\0'; 264 | // Make sure nobody managed to add a 0-character to the 265 | // buffer while building the string. 266 | ASSERT(strlen(buffer_.start()) == static_cast(position_)); 267 | position_ = -1; 268 | ASSERT(is_finalized()); 269 | return buffer_.start(); 270 | } 271 | 272 | private: 273 | Vector buffer_; 274 | int position_; 275 | 276 | bool is_finalized() const { return position_ < 0; } 277 | 278 | DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); 279 | }; 280 | 281 | // The type-based aliasing rule allows the compiler to assume that pointers of 282 | // different types (for some definition of different) never alias each other. 283 | // Thus the following code does not work: 284 | // 285 | // float f = foo(); 286 | // int fbits = *(int*)(&f); 287 | // 288 | // The compiler 'knows' that the int pointer can't refer to f since the types 289 | // don't match, so the compiler may cache f in a register, leaving random data 290 | // in fbits. Using C++ style casts makes no difference, however a pointer to 291 | // char data is assumed to alias any other pointer. This is the 'memcpy 292 | // exception'. 293 | // 294 | // Bit_cast uses the memcpy exception to move the bits from a variable of one 295 | // type of a variable of another type. Of course the end result is likely to 296 | // be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) 297 | // will completely optimize BitCast away. 298 | // 299 | // There is an additional use for BitCast. 300 | // Recent gccs will warn when they see casts that may result in breakage due to 301 | // the type-based aliasing rule. If you have checked that there is no breakage 302 | // you can use BitCast to cast one pointer type to another. This confuses gcc 303 | // enough that it can no longer see that you have cast one pointer type to 304 | // another thus avoiding the warning. 305 | template 306 | inline Dest BitCast(const Source& source) { 307 | // Compile time assertion: sizeof(Dest) == sizeof(Source) 308 | // A compile error here means your Dest and Source have different sizes. 309 | DOUBLE_CONVERSION_UNUSED 310 | typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; 311 | 312 | Dest dest; 313 | memmove(&dest, &source, sizeof(dest)); 314 | return dest; 315 | } 316 | 317 | template 318 | inline Dest BitCast(Source* source) { 319 | return BitCast(reinterpret_cast(source)); 320 | } 321 | 322 | } // namespace double_conversion 323 | 324 | #endif // DOUBLE_CONVERSION_UTILS_H_ 325 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | ## Parameters 2 | 3 | CC = gcc 4 | LD = gcc 5 | CFLAGS = -g -O3 -Wall -Werror -fpic 6 | LDFLAGS = -lm 7 | AR = ar rcs 8 | 9 | LIB = liberrol.a 10 | DYN = liberrol.so 11 | OBJ = errol.o 12 | SRC = errol.c 13 | INC = errol.h lookup.h enum3.h enum4.h 14 | DIST = Makefile $(SRC) $(INC) 15 | VER = 1.0 16 | PKG = errol 17 | 18 | ## Build rules 19 | 20 | all: $(LIB) $(DYN) 21 | 22 | $(LIB): $(OBJ) 23 | $(AR) $@ $^ 24 | 25 | $(DYN): $(OBJ) 26 | $(LD) $^ -o $@ -shared $(LDFLAGS) 27 | 28 | errol.o: errol.c Makefile $(INC) 29 | $(CC) -c $< -o $@ $(CFLAGS) 30 | 31 | ## Clean rules 32 | 33 | clean: 34 | rm -rf liberrol.a liberrol.so $(OBJ) 35 | 36 | ## Distribute rules 37 | 38 | dist: 39 | rm -rf $(PKG) 40 | mkdir $(PKG) 41 | cp $(DIST) $(PKG) 42 | tar -zcf $(PKG).tar.gz $(PKG) 43 | rm -rf $(PKG) 44 | 45 | ## Phony 46 | 47 | .PHONY: all clean dist 48 | -------------------------------------------------------------------------------- /lib/errol.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "errol.h" 9 | #include "itoa_c.h" 10 | 11 | /* 12 | * floating point format definitions 13 | */ 14 | 15 | typedef double fpnum_t; 16 | 17 | static inline double fpnext(double val) 18 | { 19 | errol_bits_t bits = { val }; 20 | bits.i++; 21 | return bits.d; 22 | } 23 | 24 | static inline double fpprev(double val) 25 | { 26 | errol_bits_t bits = { val }; 27 | bits.i--; 28 | return bits.d; 29 | } 30 | 31 | static inline __uint128_t fpeint(double from) 32 | { 33 | errol_bits_t bits = { from }; 34 | assert((bits.i & ((1ULL << 52) - 1)) == 0 && (bits.i >> 52) >= 1023); 35 | 36 | return (__uint128_t)1 << ((bits.i >> 52) - 1023); 37 | } 38 | 39 | #define ERROL0_EPSILON 0.0000001 40 | #define ERROL1_EPSILON 8.77e-15 41 | 42 | 43 | /** 44 | * High-precision data structure. 45 | * @val, off: The value and offset. 46 | */ 47 | 48 | struct hp_t { 49 | fpnum_t val, off; 50 | }; 51 | 52 | 53 | /* 54 | * lookup table data 55 | */ 56 | 57 | #include "lookup.h" 58 | #include "enum3.h" 59 | #include "enum4.h" 60 | 61 | /* 62 | * high-precision constants 63 | */ 64 | 65 | /* 66 | * local function declarations 67 | */ 68 | 69 | static void inline hp_normalize(struct hp_t *hp); 70 | static void inline hp_mul10(struct hp_t *hp); 71 | static void inline hp_div10(struct hp_t *hp); 72 | static struct hp_t hp_prod(struct hp_t in, double val); 73 | static int inline mismatch10(uint64_t a, uint64_t b); 74 | static int inline table_lower_bound(uint64_t *table, int n, uint64_t k); 75 | 76 | /* 77 | * inline function instantiations 78 | */ 79 | 80 | extern inline char *u32toa(uint32_t value, char *buffer); 81 | extern inline char *u64toa(uint64_t value, char *buffer); 82 | 83 | /* 84 | * intrinsics 85 | */ 86 | 87 | extern __uint128_t __udivmodti4(__uint128_t a, __uint128_t b, 88 | __uint128_t* rem); 89 | 90 | 91 | /** 92 | * Errol0 double to ASCII conversion, guaranteed correct but possibly not 93 | * optimal. Useful for embedded systems. 94 | * @val: The value. 95 | * @buf: The output buffer. 96 | * &returns: The exponent. 97 | */ 98 | 99 | int errol0_dtoa(double val, char *buf) 100 | { 101 | double ten; 102 | int exp; 103 | struct hp_t mid, inhi, inlo; 104 | 105 | if(val == DBL_MAX) { 106 | strcpy(buf, "17976931348623157"); 107 | return 309; 108 | } 109 | 110 | ten = 1.0; 111 | exp = 1; 112 | 113 | /* normalize the midpoint */ 114 | 115 | mid.val = val; 116 | mid.off = 0.0; 117 | 118 | while(((mid.val > 10.0) || ((mid.val == 10.0) && (mid.off >= 0.0))) && (exp < 308)) 119 | exp++, hp_div10(&mid), ten /= 10.0; 120 | 121 | while(((mid.val < 1.0) || ((mid.val == 1.0) && (mid.off < 0.0))) && (exp > -307)) 122 | exp--, hp_mul10(&mid), ten *= 10.0; 123 | 124 | inhi.val = mid.val; 125 | inhi.off = mid.off + (fpnext(val) - val) * ten / (2.0 + ERROL0_EPSILON); 126 | inlo.val = mid.val; 127 | inlo.off = mid.off + (fpprev(val) - val) * ten / (2.0 + ERROL0_EPSILON); 128 | 129 | hp_normalize(&inhi); 130 | hp_normalize(&inlo); 131 | 132 | /* normalized boundaries */ 133 | 134 | while(inhi.val > 10.0 || (inhi.val == 10.0 && (inhi.off >= 0.0))) 135 | exp++, hp_div10(&inhi), hp_div10(&inlo); 136 | 137 | while(inhi.val < 1.0 || (inhi.val == 1.0 && (inhi.off < 0.0))) 138 | exp--, hp_mul10(&inhi), hp_mul10(&inlo); 139 | 140 | /* digit generation */ 141 | 142 | while(inhi.val != 0.0 || inhi.off != 0.0) { 143 | uint8_t ldig, hdig = 0; 144 | 145 | hdig = (uint8_t)(inhi.val); 146 | if((inhi.val == hdig) && (inhi.off < 0)) 147 | hdig -= 1; 148 | 149 | ldig = (uint8_t)(inlo.val); 150 | if((inlo.val == ldig) && (inlo.off < 0)) 151 | ldig -= 1; 152 | 153 | if(ldig != hdig) 154 | break; 155 | 156 | *buf++ = hdig + '0'; 157 | 158 | inhi.val -= hdig; 159 | hp_mul10(&inhi); 160 | 161 | inlo.val -= ldig; 162 | hp_mul10(&inlo); 163 | } 164 | 165 | double mdig = (inhi.val + inlo.val) / 2.0 + 0.5; 166 | *buf++ = (uint8_t)(mdig) + '0'; 167 | *buf = '\0'; 168 | 169 | return exp; 170 | } 171 | 172 | /** 173 | * Errol double to ASCII conversion. 174 | * @val: The value. 175 | * @buf: The output buffer. 176 | * @opt: The optimality flag. 177 | * &returns: The exponent. 178 | */ 179 | 180 | int errol1_dtoa(double val, char *buf, bool *opt) 181 | { 182 | double ten, lten; 183 | int e; 184 | int exp; 185 | struct hp_t mid, inhi, inlo, outhi, outlo; 186 | 187 | if(val == DBL_MAX) { 188 | strcpy(buf, "17976931348623157"); 189 | return 309; 190 | } 191 | 192 | /* normalize the midpoint */ 193 | 194 | frexp(val, &e); 195 | exp = 307 + (double)e*0.30103; 196 | if(exp < 20) 197 | exp = 20; 198 | else if(exp >= LOOKUP_TABLE_LEN) 199 | exp = LOOKUP_TABLE_LEN - 1; 200 | 201 | mid = lookup_table[exp]; 202 | mid = hp_prod(mid, val); 203 | lten = lookup_table[exp].val; 204 | ten = 1.0; 205 | 206 | exp -= 307; 207 | 208 | while((mid.val > 10.0) || ((mid.val == 10.0 && mid.off >= 0.0))) 209 | exp++, hp_div10(&mid), ten /= 10.0; 210 | 211 | while((mid.val < 1.0) || ((mid.val == 1.0) && (mid.off < 0.0))) 212 | exp--, hp_mul10(&mid), ten *= 10.0; 213 | 214 | inhi.val = mid.val; 215 | inhi.off = mid.off + (fpnext(val) - val) * lten * ten / (2.0 + ERROL1_EPSILON); 216 | inlo.val = mid.val; 217 | inlo.off = mid.off + (fpprev(val) - val) * lten * ten / (2.0 + ERROL1_EPSILON); 218 | outhi.val = mid.val; 219 | outhi.off = mid.off + (fpnext(val) - val) * lten * ten / (2.0 - ERROL1_EPSILON); 220 | outlo.val = mid.val; 221 | outlo.off = mid.off + (fpprev(val) - val) * lten * ten / (2.0 - ERROL1_EPSILON); 222 | 223 | hp_normalize(&inhi); 224 | hp_normalize(&inlo); 225 | hp_normalize(&outhi); 226 | hp_normalize(&outlo); 227 | 228 | /* normalized boundaries */ 229 | 230 | while(inhi.val > 10.0 || (inhi.val == 10.0 && inhi.off >= 0.0)) 231 | exp++, hp_div10(&inhi), hp_div10(&inlo), hp_div10(&outhi), hp_div10(&outlo); 232 | 233 | while(inhi.val < 1.0 || (inhi.val == 1.0 && inhi.off < 0.0)) 234 | exp--, hp_mul10(&inhi), hp_mul10(&inlo), hp_mul10(&outhi), hp_mul10(&outlo); 235 | 236 | /* digit generation */ 237 | 238 | *opt = true; 239 | 240 | while(inhi.val != 0.0 || inhi.off != 0.0) { 241 | uint8_t ldig, hdig; 242 | 243 | hdig = (uint8_t)inhi.val; 244 | if((inhi.val == hdig) && (inhi.off < 0)) 245 | hdig -= 1; 246 | 247 | ldig = (uint8_t)inlo.val; 248 | if((inlo.val == ldig) && (inlo.off < 0)) 249 | ldig -= 1; 250 | 251 | if(ldig != hdig) 252 | break; 253 | 254 | *buf++ = hdig + '0'; 255 | inhi.val -= hdig; 256 | inlo.val -= ldig; 257 | hp_mul10(&inhi); 258 | hp_mul10(&inlo); 259 | 260 | hdig = (uint8_t)outhi.val; 261 | if((outhi.val == hdig) && (outhi.off < 0)) 262 | hdig -= 1; 263 | 264 | ldig = (uint8_t)outlo.val; 265 | if((outlo.val == ldig) && (outlo.off < 0)) 266 | ldig -= 1; 267 | 268 | if(ldig != hdig) 269 | *opt = false; 270 | 271 | outhi.val -= hdig; 272 | outlo.val -= ldig; 273 | hp_mul10(&outhi); 274 | hp_mul10(&outlo); 275 | } 276 | 277 | double mdig = (inhi.val + inlo.val) / 2.0 + 0.5; 278 | *buf++ = (uint8_t)mdig + '0'; 279 | *buf = '\0'; 280 | 281 | return exp; 282 | } 283 | 284 | /** 285 | * Errol2 double to ASCII conversion. 286 | * @val: The value. 287 | * @buf: The output buffer. 288 | * @opt: The optimality flag. 289 | * &returns: The exponent. 290 | */ 291 | 292 | int errol2_dtoa(double val, char *buf, bool *opt) 293 | { 294 | if((val <= 9.007199254740992e15) || (val >= 3.40282366920938e38)) 295 | return errol1_dtoa(val, buf, opt); 296 | 297 | int8_t i, j; 298 | int exp; 299 | errol_bits_t bits; 300 | char lstr[42], hstr[42], mstr[41]; 301 | uint64_t l64, m64, h64; 302 | __uint128_t low, mid, high, pow19 = (__uint128_t)1e19; 303 | 304 | mid = (__uint128_t)val; 305 | low = mid - fpeint((fpnext(val) - val) / 2.0); 306 | high = mid + fpeint((val - fpprev(val)) / 2.0); 307 | 308 | bits.d = val; 309 | if(bits.i & 0x1) 310 | high--; 311 | else 312 | low--; 313 | 314 | i = 39; 315 | lstr[41] = hstr[41] = mstr[40] = '\0'; 316 | lstr[40] = hstr[40] = '5'; 317 | while(high != 0) { 318 | __uint128_t tmp1; 319 | low = __udivmodti4(low, pow19, &tmp1); 320 | l64 = tmp1; 321 | mid = __udivmodti4(mid, pow19, &tmp1); 322 | m64 = tmp1; 323 | high = __udivmodti4(high, pow19, &tmp1); 324 | h64 = tmp1; 325 | 326 | for(j = 0; ((high != 0) && (j < 19)) || ((high == 0) && (h64 != 0)); j++, i--) { 327 | lstr[i] = '0' + l64 % (uint64_t)10; 328 | mstr[i] = '0' + m64 % (uint64_t)10; 329 | hstr[i] = '0' + h64 % (uint64_t)10; 330 | 331 | l64 /= 10; 332 | m64 /= 10; 333 | h64 /= 10; 334 | } 335 | } 336 | 337 | exp = 39 - i++; 338 | 339 | do 340 | *buf++ = hstr[i++]; 341 | while(hstr[i] != '\0' && hstr[i] == lstr[i]); 342 | 343 | *buf++ = mstr[i] + ((mstr[i+1] >= '5') ? 1 : 0); 344 | 345 | *buf = '\0'; 346 | *opt = true; 347 | 348 | return exp; 349 | } 350 | 351 | 352 | /** 353 | * Corrected Errol3 double to ASCII conversion. 354 | * @val: The value. 355 | * @buf: The output buffer. 356 | * &returns: The exponent. 357 | */ 358 | 359 | int errol3_dtoa(double val, char *buf) 360 | { 361 | errol_bits_t k = { val }; 362 | 363 | int n = sizeof(errol_enum3) / sizeof(uint64_t); 364 | int i = table_lower_bound(errol_enum3, n, k.i); 365 | if (i < n && errol_enum3[i] == k.i) 366 | { 367 | strcpy(buf, errol_enum3_data[i].str); 368 | return errol_enum3_data[i].exp; 369 | } 370 | 371 | return errol3u_dtoa(val, buf); 372 | } 373 | 374 | /** 375 | * Uncorrected Errol3 double to ASCII conversion. 376 | * @val: The value. 377 | * @buf: The output buffer. 378 | * &returns: The exponent. 379 | */ 380 | 381 | int errol3u_dtoa(double val, char *buf) 382 | { 383 | int e; 384 | double ten, lten; 385 | int exp; 386 | struct hp_t mid; 387 | struct hp_t high = { val, 0.0 }; 388 | struct hp_t low = { val, 0.0 }; 389 | 390 | /* check if in integer or fixed range */ 391 | 392 | if((val > 9.007199254740992e15) && (val < 3.40282366920938e+38)) 393 | return errol_int(val, buf); 394 | else if((val >= 16.0) && (val <= 9.007199254740992e15)) 395 | return errol_fixed(val, buf); 396 | 397 | /* normalize the midpoint */ 398 | 399 | frexp(val, &e); 400 | exp = 307 + (double)e*0.30103; 401 | if(exp < 20) 402 | exp = 20; 403 | else if(exp >= LOOKUP_TABLE_LEN) 404 | exp = LOOKUP_TABLE_LEN - 1; 405 | 406 | mid = lookup_table[exp]; 407 | mid = hp_prod(mid, val); 408 | lten = lookup_table[exp].val; 409 | ten = 1.0; 410 | 411 | exp -= 307; 412 | 413 | while(mid.val > 10.0 || (mid.val == 10.0 && mid.off >= 0.0)) 414 | exp++, hp_div10(&mid), ten /= 10.0; 415 | 416 | while(mid.val < 1.0 || (mid.val == 1.0 && mid.off < 0.0)) 417 | exp--, hp_mul10(&mid), ten *= 10.0; 418 | 419 | /* compute boundaries */ 420 | 421 | high.val = mid.val; 422 | high.off = mid.off + (fpnext(val) - val) * lten * ten / 2.0; 423 | low.val = mid.val; 424 | low.off = mid.off + (fpprev(val) - val) * lten * ten / 2.0; 425 | 426 | hp_normalize(&high); 427 | hp_normalize(&low); 428 | 429 | /* normalized boundaries */ 430 | 431 | while(high.val > 10.0 || (high.val == 10.0 && high.off >= 0.0)) 432 | exp++, hp_div10(&high), hp_div10(&low); 433 | 434 | while(high.val < 1.0 || (high.val == 1.0 && high.off < 0.0)) 435 | exp--, hp_mul10(&high), hp_mul10(&low); 436 | 437 | /* digit generation */ 438 | 439 | while(true) { 440 | int8_t ldig, hdig; 441 | 442 | hdig = (uint8_t)(high.val); 443 | if((high.val == hdig) && (high.off < 0)) 444 | hdig -= 1; 445 | 446 | ldig = (uint8_t)(low.val); 447 | if((low.val == ldig) && (low.off < 0)) 448 | ldig -= 1; 449 | 450 | if(ldig != hdig) 451 | break; 452 | 453 | *buf++ = hdig + '0'; 454 | high.val -= hdig; 455 | low.val -= ldig; 456 | hp_mul10(&high); 457 | hp_mul10(&low); 458 | } 459 | 460 | double tmp = (high.val + low.val) / 2.0; 461 | uint8_t mdig = tmp + 0.5; 462 | if((mdig - tmp) == 0.5 && (mdig & 0x1)) 463 | mdig--; 464 | 465 | *buf++ = mdig + '0'; 466 | *buf = '\0'; 467 | 468 | return exp; 469 | } 470 | 471 | /** 472 | * Corrected Errol4 double to ASCII conversion. 473 | * @val: The value. 474 | * @buf: The output buffer. 475 | * &returns: The exponent. 476 | */ 477 | 478 | int errol4_dtoa(double val, char *buf) 479 | { 480 | errol_bits_t k = { val }; 481 | 482 | int n = sizeof(errol_enum4) / sizeof(uint64_t); 483 | int i = table_lower_bound(errol_enum4, n, k.i); 484 | if (i < n && errol_enum4[i] == k.i) 485 | { 486 | strcpy(buf, errol_enum4_data[i].str); 487 | return errol_enum4_data[i].exp; 488 | } 489 | 490 | return errol4u_dtoa(val, buf); 491 | } 492 | 493 | /** 494 | * Uncorrected Errol4 double to ASCII conversion. 495 | * @val: The value. 496 | * @buf: The output buffer. 497 | * &returns: The exponent. 498 | */ 499 | 500 | int errol4u_dtoa(double val, char *buf) 501 | { 502 | int e; 503 | int exp; 504 | struct hp_t mid; 505 | double ten, lten; 506 | 507 | /* check if in integer or fixed range */ 508 | 509 | if((val >= 1.80143985094820e+16) && (val < 3.40282366920938e+38)) 510 | return errol_int(val, buf); 511 | else if((val >= 16.0) && (val <= 9.007199254740992e15)) 512 | return errol_fixed(val, buf); 513 | 514 | /* normalize the midpoint */ 515 | 516 | frexp(val, &e); 517 | exp = 290 + (double)e*0.30103; 518 | if(exp < 20) 519 | exp = 20; 520 | else if(exp >= LOOKUP_TABLE_LEN) 521 | exp = LOOKUP_TABLE_LEN - 1; 522 | 523 | mid = lookup_table[exp]; 524 | lten = mid.val; 525 | mid = hp_prod(mid, val); 526 | 527 | ten = 1.0; 528 | exp -= 290; 529 | 530 | if(mid.val < 1.00000000000000016e+17) { 531 | /* 532 | TODO 533 | frexp(val, &e); 534 | exp = 290 + (double)e*0.30103; 535 | 536 | mid = hp_prod(mid, val); 537 | lten *= mid.val; 538 | mid = hp_prod(mid, val); 539 | */ 540 | } 541 | 542 | while(mid.val < 1.00000000000000016e+17) 543 | exp--, hp_mul10(&mid), ten *= 10.0; 544 | 545 | double diff = (fpnext(val) - val) * lten * ten / 2.0; 546 | uint64_t val64 = (uint64_t)mid.val; 547 | uint64_t lo64 = val64 + (uint64_t)floor(mid.off - diff); 548 | uint64_t mid64; 549 | uint64_t hi64 = val64 + (uint64_t)floor(mid.off + diff); 550 | 551 | if(hi64 >= 1e18) 552 | exp++; 553 | 554 | uint64_t iten; 555 | for(iten = 1; ; iten *= 10) { 556 | lo64 /= 10; 557 | hi64 /= 10; 558 | 559 | if(lo64 == hi64) 560 | break; 561 | } 562 | 563 | mid64 = (val64 + (uint64_t)floor(mid.off + iten * 0.5)) / iten; 564 | 565 | if (hi64 > 0) 566 | buf = u64toa(hi64, buf); 567 | *buf++ = mid64 % 10 + '0'; 568 | *buf = '\0'; 569 | 570 | return exp; 571 | } 572 | 573 | 574 | /** 575 | * Integer conversion algorithm, guaranteed correct, optimal, and best. 576 | * @val: The val. 577 | * @buf: The output buffer. 578 | * &return: The exponent. 579 | */ 580 | 581 | int errol_int(double val, char *buf) 582 | { 583 | int exp; 584 | errol_bits_t bits; 585 | __uint128_t low, mid, high; 586 | static __uint128_t pow19 = (__uint128_t)1e19; 587 | 588 | assert((val > 9.007199254740992e15) && val < (3.40282366920938e38)); 589 | 590 | mid = (__uint128_t)val; 591 | low = mid - fpeint((fpnext(val) - val) / 2.0); 592 | high = mid + fpeint((val - fpprev(val)) / 2.0); 593 | 594 | bits.d = val; 595 | if(bits.i & 0x1) 596 | high--; 597 | else 598 | low--; 599 | 600 | __uint128_t tmp1, tmp2; 601 | __udivmodti4(__udivmodti4(low, pow19, &tmp1), pow19, &tmp2); 602 | uint64_t l64 = tmp1; 603 | uint64_t lf = tmp2; 604 | __udivmodti4(__udivmodti4(high, pow19, &tmp1), pow19, &tmp2); 605 | uint64_t h64 = tmp1; 606 | uint64_t hf = tmp2; 607 | 608 | if (lf != hf) 609 | { 610 | l64 = lf; 611 | h64 = hf; 612 | mid = __udivmodti4(mid, pow19 / 10, NULL); 613 | } 614 | 615 | int mi = mismatch10(l64, h64); 616 | uint64_t x = 1; 617 | for (int i = (lf == hf); i < mi; i++) 618 | x *= 10; 619 | uint64_t m64 = __udivmodti4(mid, x, NULL); 620 | 621 | if (lf != hf) 622 | mi += 19; 623 | 624 | char *p = u64toa(m64, buf) - 1; 625 | 626 | if (mi != 0) 627 | p[-1] += (*p >= '5'); 628 | else 629 | ++p; 630 | 631 | exp = p - buf + mi; 632 | *p = '\0'; 633 | 634 | return exp; 635 | } 636 | 637 | /** 638 | * Fixed point conversion algorithm, guaranteed correct, optimal, and best. 639 | * @val: The val. 640 | * @buf: The output buffer. 641 | * &return: The exponent. 642 | */ 643 | 644 | int errol_fixed(double val, char *buf) 645 | { 646 | char *p; 647 | int j, exp; 648 | double n, mid, lo, hi; 649 | uint64_t u; 650 | 651 | assert((val >= 16.0) && (val <= 9.007199254740992e15)); 652 | 653 | u = (uint64_t)val; 654 | n = (double)u; 655 | 656 | mid = val - n; 657 | lo = ((fpprev(val) - n) + mid) / 2.0; 658 | hi = ((fpnext(val) - n) + mid) / 2.0; 659 | 660 | p = u64toa(u, buf); 661 | j = exp = p - buf; 662 | buf[j] = '\0'; 663 | 664 | if(mid != 0.0) { 665 | while(mid != 0.0) { 666 | int ldig, mdig, hdig; 667 | 668 | lo *= 10.0; 669 | ldig = (int)lo; 670 | lo -= ldig; 671 | 672 | mid *= 10.0; 673 | mdig = (int)mid; 674 | mid -= mdig; 675 | 676 | hi *= 10.0; 677 | hdig = (int)hi; 678 | hi -= hdig; 679 | 680 | buf[j++] = mdig + '0'; 681 | 682 | if(hdig != ldig || j > 50) 683 | break; 684 | } 685 | 686 | if(mid > 0.5) 687 | buf[j-1]++; 688 | else if((mid == 0.5) && (buf[j-1] & 0x1)) 689 | buf[j-1]++; 690 | } 691 | else { 692 | while(buf[j-1] == '0') { 693 | buf[j-1] = '\0'; 694 | j--; 695 | } 696 | } 697 | 698 | buf[j] = '\0'; 699 | 700 | return exp; 701 | } 702 | 703 | 704 | /** 705 | * Normalize the number by factoring in the error. 706 | * @hp: The float pair. 707 | */ 708 | 709 | static inline void hp_normalize(struct hp_t *hp) 710 | { 711 | fpnum_t val = hp->val; 712 | 713 | hp->val += hp->off; 714 | hp->off += val - hp->val; 715 | } 716 | 717 | /** 718 | * Multiply the high-precision number by ten. 719 | * @hp: The high-precision number 720 | */ 721 | 722 | static inline void hp_mul10(struct hp_t *hp) 723 | { 724 | fpnum_t off, val = hp->val; 725 | 726 | hp->val *= 10.0; 727 | hp->off *= 10.0; 728 | 729 | off = hp->val; 730 | off -= val * 8.0; 731 | off -= val * 2.0; 732 | 733 | hp->off -= off; 734 | 735 | hp_normalize(hp); 736 | } 737 | 738 | /** 739 | * Divide the high-precision number by ten. 740 | * @hp: The high-precision number 741 | */ 742 | 743 | static inline void hp_div10(struct hp_t *hp) 744 | { 745 | double val = hp->val; 746 | 747 | hp->val /= 10.0; 748 | hp->off /= 10.0; 749 | 750 | val -= hp->val * 8.0; 751 | val -= hp->val * 2.0; 752 | 753 | hp->off += val / 10.0; 754 | 755 | hp_normalize(hp); 756 | } 757 | 758 | static inline double gethi(double in) 759 | { 760 | errol_bits_t v = { .d = in }; 761 | 762 | //v.i += 0x0000000004000000; 763 | v.i &= 0xFFFFFFFFF8000000; 764 | 765 | return v.d; 766 | } 767 | 768 | /** 769 | * Split a double into two halves. 770 | * @val: The double. 771 | * @hi: The high bits. 772 | * @lo: The low bits. 773 | */ 774 | 775 | static inline void split(double val, double *hi, double *lo) 776 | { 777 | //double t = (134217728.0 + 1.0) * val; 778 | 779 | //*hi = t - (t - val); 780 | //if(*hi != gethi(val)) 781 | //*lo = val - *hi; 782 | 783 | *hi = gethi(val); 784 | *lo = val - *hi; 785 | } 786 | 787 | /** 788 | * Compute the product of an HP number and a double. 789 | * @in: The HP number. 790 | * @val: The double. 791 | * &returns: The HP number. 792 | */ 793 | 794 | static struct hp_t hp_prod(struct hp_t in, double val) 795 | { 796 | double p, hi, lo, e; 797 | 798 | double hi2, lo2; 799 | split(in.val, &hi, &lo); 800 | split(val, &hi2, &lo2); 801 | 802 | p = in.val * val; 803 | e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2; 804 | 805 | return (struct hp_t){ p, in.off * val + e }; 806 | } 807 | 808 | /** 809 | * Given two different integers with the same length in terms of the number 810 | * of decimal digits, index the digits from the right-most position starting 811 | * from zero, find the first index where the digits in the two integers 812 | * divergent starting from the highest index. 813 | * @a: Integer a. 814 | * @b: Integer b. 815 | * &returns: An index within [0, 19). 816 | */ 817 | 818 | static inline int mismatch10(uint64_t a, uint64_t b) 819 | { 820 | uint64_t pow10 = 10000000000U; 821 | uint64_t af = a / pow10; 822 | uint64_t bf = b / pow10; 823 | int i = 0; 824 | 825 | if (af != bf) 826 | { 827 | i = 10; 828 | a = af; 829 | b = bf; 830 | } 831 | 832 | for (;; ++i) 833 | { 834 | a /= 10; 835 | b /= 10; 836 | 837 | if (a == b) 838 | return i; 839 | } 840 | } 841 | 842 | /** 843 | * Find the insertion point for a key in a level-order array. 844 | * @table: The target array. 845 | * @n: Array size. 846 | * @k: The key to find. 847 | * &returns: The insertion point. 848 | */ 849 | 850 | static inline int table_lower_bound(uint64_t *table, int n, uint64_t k) 851 | { 852 | int i = n, j = 0; 853 | 854 | while (j < n) 855 | { 856 | if (table[j] < k) 857 | j = 2 * j + 2; 858 | else 859 | { 860 | i = j; 861 | j = 2 * j + 1; 862 | } 863 | } 864 | 865 | return i; 866 | } 867 | -------------------------------------------------------------------------------- /lib/errol.h: -------------------------------------------------------------------------------- 1 | #ifndef ERROL_H 2 | #define ERROL_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /* 9 | * common headers 10 | */ 11 | 12 | #include 13 | 14 | /* 15 | * errol declarations 16 | */ 17 | 18 | #define ERR_LEN 512 19 | #define ERR_DEPTH 4 20 | 21 | int errol0_dtoa(double val, char *buf); 22 | int errol1_dtoa(double val, char *buf, bool *opt); 23 | int errol2_dtoa(double val, char *buf, bool *opt); 24 | int errol3_dtoa(double val, char *buf); 25 | int errol3u_dtoa(double val, char *buf); 26 | int errol4_dtoa(double val, char *buf); 27 | int errol4u_dtoa(double val, char *buf); 28 | 29 | int errol_int(double val, char *buf); 30 | int errol_fixed(double val, char *buf); 31 | 32 | struct errol_err_t { 33 | double val; 34 | char str[18]; 35 | int exp; 36 | }; 37 | 38 | struct errol_slab_t { 39 | char str[18]; 40 | int exp; 41 | }; 42 | 43 | typedef union { 44 | double d; 45 | uint64_t i; 46 | } errol_bits_t; 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /lib/itoa_c.h: -------------------------------------------------------------------------------- 1 | // Modified from 2 | // https://github.com/miloyip/rapidjson/blob/master/include/rapidjson/internal/itoa.h 3 | // 4 | // Tencent is pleased to support the open source community by making RapidJSON available. 5 | // 6 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 7 | // 8 | // Licensed under the MIT License (the "License"); you may not use this file except 9 | // in compliance with the License. You may obtain a copy of the License at 10 | // 11 | // http://opensource.org/licenses/MIT 12 | // 13 | // Unless required by applicable law or agreed to in writing, software distributed 14 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 15 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 16 | // specific language governing permissions and limitations under the License. 17 | 18 | #ifndef ITOA_C_H 19 | #define ITOA_C_H 20 | 21 | #include 22 | 23 | const char cDigitsLut[200] = { 24 | '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', 25 | '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', 26 | '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', 27 | '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', 28 | '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', 29 | '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', 30 | '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', 31 | '4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', 32 | '5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2', 33 | '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', 34 | '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', 35 | '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', 36 | '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', 37 | '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', 38 | '9', '8', '9', '9' 39 | }; 40 | 41 | inline char *u32toa(uint32_t value, char *buffer) 42 | { 43 | if (value < 10000) 44 | { 45 | const uint32_t d1 = (value / 100) << 1; 46 | const uint32_t d2 = (value % 100) << 1; 47 | 48 | if (value >= 1000) 49 | *buffer++ = cDigitsLut[d1]; 50 | if (value >= 100) 51 | *buffer++ = cDigitsLut[d1 + 1]; 52 | if (value >= 10) 53 | *buffer++ = cDigitsLut[d2]; 54 | *buffer++ = cDigitsLut[d2 + 1]; 55 | } 56 | else if (value < 100000000) 57 | { 58 | // value = bbbbcccc 59 | const uint32_t b = value / 10000; 60 | const uint32_t c = value % 10000; 61 | 62 | const uint32_t d1 = (b / 100) << 1; 63 | const uint32_t d2 = (b % 100) << 1; 64 | 65 | const uint32_t d3 = (c / 100) << 1; 66 | const uint32_t d4 = (c % 100) << 1; 67 | 68 | if (value >= 10000000) 69 | *buffer++ = cDigitsLut[d1]; 70 | if (value >= 1000000) 71 | *buffer++ = cDigitsLut[d1 + 1]; 72 | if (value >= 100000) 73 | *buffer++ = cDigitsLut[d2]; 74 | *buffer++ = cDigitsLut[d2 + 1]; 75 | 76 | *buffer++ = cDigitsLut[d3]; 77 | *buffer++ = cDigitsLut[d3 + 1]; 78 | *buffer++ = cDigitsLut[d4]; 79 | *buffer++ = cDigitsLut[d4 + 1]; 80 | } 81 | else 82 | { 83 | // value = aabbbbcccc in decimal 84 | 85 | const uint32_t a = value / 100000000; // 1 to 42 86 | value %= 100000000; 87 | 88 | if (a >= 10) 89 | { 90 | const unsigned i = a << 1; 91 | *buffer++ = cDigitsLut[i]; 92 | *buffer++ = cDigitsLut[i + 1]; 93 | } 94 | else 95 | *buffer++ = (char)('0' + (char)(a)); 96 | 97 | const uint32_t b = value / 10000; // 0 to 9999 98 | const uint32_t c = value % 10000; // 0 to 9999 99 | 100 | const uint32_t d1 = (b / 100) << 1; 101 | const uint32_t d2 = (b % 100) << 1; 102 | 103 | const uint32_t d3 = (c / 100) << 1; 104 | const uint32_t d4 = (c % 100) << 1; 105 | 106 | *buffer++ = cDigitsLut[d1]; 107 | *buffer++ = cDigitsLut[d1 + 1]; 108 | *buffer++ = cDigitsLut[d2]; 109 | *buffer++ = cDigitsLut[d2 + 1]; 110 | *buffer++ = cDigitsLut[d3]; 111 | *buffer++ = cDigitsLut[d3 + 1]; 112 | *buffer++ = cDigitsLut[d4]; 113 | *buffer++ = cDigitsLut[d4 + 1]; 114 | } 115 | return buffer; 116 | } 117 | 118 | inline char *u64toa(uint64_t value, char *buffer) 119 | { 120 | const uint64_t kTen8 = 100000000; 121 | const uint64_t kTen9 = kTen8 * 10; 122 | const uint64_t kTen10 = kTen8 * 100; 123 | const uint64_t kTen11 = kTen8 * 1000; 124 | const uint64_t kTen12 = kTen8 * 10000; 125 | const uint64_t kTen13 = kTen8 * 100000; 126 | const uint64_t kTen14 = kTen8 * 1000000; 127 | const uint64_t kTen15 = kTen8 * 10000000; 128 | const uint64_t kTen16 = kTen8 * kTen8; 129 | 130 | if (value < kTen8) 131 | { 132 | uint32_t v = (uint32_t)(value); 133 | if (v < 10000) 134 | { 135 | const uint32_t d1 = (v / 100) << 1; 136 | const uint32_t d2 = (v % 100) << 1; 137 | 138 | if (v >= 1000) 139 | *buffer++ = cDigitsLut[d1]; 140 | if (v >= 100) 141 | *buffer++ = cDigitsLut[d1 + 1]; 142 | if (v >= 10) 143 | *buffer++ = cDigitsLut[d2]; 144 | *buffer++ = cDigitsLut[d2 + 1]; 145 | } 146 | else 147 | { 148 | // value = bbbbcccc 149 | const uint32_t b = v / 10000; 150 | const uint32_t c = v % 10000; 151 | 152 | const uint32_t d1 = (b / 100) << 1; 153 | const uint32_t d2 = (b % 100) << 1; 154 | 155 | const uint32_t d3 = (c / 100) << 1; 156 | const uint32_t d4 = (c % 100) << 1; 157 | 158 | if (value >= 10000000) 159 | *buffer++ = cDigitsLut[d1]; 160 | if (value >= 1000000) 161 | *buffer++ = cDigitsLut[d1 + 1]; 162 | if (value >= 100000) 163 | *buffer++ = cDigitsLut[d2]; 164 | *buffer++ = cDigitsLut[d2 + 1]; 165 | 166 | *buffer++ = cDigitsLut[d3]; 167 | *buffer++ = cDigitsLut[d3 + 1]; 168 | *buffer++ = cDigitsLut[d4]; 169 | *buffer++ = cDigitsLut[d4 + 1]; 170 | } 171 | } 172 | else if (value < kTen16) 173 | { 174 | const uint32_t v0 = (uint32_t)(value / kTen8); 175 | const uint32_t v1 = (uint32_t)(value % kTen8); 176 | 177 | const uint32_t b0 = v0 / 10000; 178 | const uint32_t c0 = v0 % 10000; 179 | 180 | const uint32_t d1 = (b0 / 100) << 1; 181 | const uint32_t d2 = (b0 % 100) << 1; 182 | 183 | const uint32_t d3 = (c0 / 100) << 1; 184 | const uint32_t d4 = (c0 % 100) << 1; 185 | 186 | const uint32_t b1 = v1 / 10000; 187 | const uint32_t c1 = v1 % 10000; 188 | 189 | const uint32_t d5 = (b1 / 100) << 1; 190 | const uint32_t d6 = (b1 % 100) << 1; 191 | 192 | const uint32_t d7 = (c1 / 100) << 1; 193 | const uint32_t d8 = (c1 % 100) << 1; 194 | 195 | if (value >= kTen15) 196 | *buffer++ = cDigitsLut[d1]; 197 | if (value >= kTen14) 198 | *buffer++ = cDigitsLut[d1 + 1]; 199 | if (value >= kTen13) 200 | *buffer++ = cDigitsLut[d2]; 201 | if (value >= kTen12) 202 | *buffer++ = cDigitsLut[d2 + 1]; 203 | if (value >= kTen11) 204 | *buffer++ = cDigitsLut[d3]; 205 | if (value >= kTen10) 206 | *buffer++ = cDigitsLut[d3 + 1]; 207 | if (value >= kTen9) 208 | *buffer++ = cDigitsLut[d4]; 209 | if (value >= kTen8) 210 | *buffer++ = cDigitsLut[d4 + 1]; 211 | 212 | *buffer++ = cDigitsLut[d5]; 213 | *buffer++ = cDigitsLut[d5 + 1]; 214 | *buffer++ = cDigitsLut[d6]; 215 | *buffer++ = cDigitsLut[d6 + 1]; 216 | *buffer++ = cDigitsLut[d7]; 217 | *buffer++ = cDigitsLut[d7 + 1]; 218 | *buffer++ = cDigitsLut[d8]; 219 | *buffer++ = cDigitsLut[d8 + 1]; 220 | } 221 | else 222 | { 223 | const uint32_t a = (uint32_t)(value / kTen16); // 1 to 1844 224 | value %= kTen16; 225 | 226 | if (a < 10) 227 | *buffer++ = (char)('0' + (char)(a)); 228 | else if (a < 100) 229 | { 230 | const uint32_t i = a << 1; 231 | *buffer++ = cDigitsLut[i]; 232 | *buffer++ = cDigitsLut[i + 1]; 233 | } 234 | else if (a < 1000) 235 | { 236 | *buffer++ = (char)('0' + (char)(a / 100)); 237 | 238 | const uint32_t i = (a % 100) << 1; 239 | *buffer++ = cDigitsLut[i]; 240 | *buffer++ = cDigitsLut[i + 1]; 241 | } 242 | else 243 | { 244 | const uint32_t i = (a / 100) << 1; 245 | const uint32_t j = (a % 100) << 1; 246 | *buffer++ = cDigitsLut[i]; 247 | *buffer++ = cDigitsLut[i + 1]; 248 | *buffer++ = cDigitsLut[j]; 249 | *buffer++ = cDigitsLut[j + 1]; 250 | } 251 | 252 | const uint32_t v0 = (uint32_t)(value / kTen8); 253 | const uint32_t v1 = (uint32_t)(value % kTen8); 254 | 255 | const uint32_t b0 = v0 / 10000; 256 | const uint32_t c0 = v0 % 10000; 257 | 258 | const uint32_t d1 = (b0 / 100) << 1; 259 | const uint32_t d2 = (b0 % 100) << 1; 260 | 261 | const uint32_t d3 = (c0 / 100) << 1; 262 | const uint32_t d4 = (c0 % 100) << 1; 263 | 264 | const uint32_t b1 = v1 / 10000; 265 | const uint32_t c1 = v1 % 10000; 266 | 267 | const uint32_t d5 = (b1 / 100) << 1; 268 | const uint32_t d6 = (b1 % 100) << 1; 269 | 270 | const uint32_t d7 = (c1 / 100) << 1; 271 | const uint32_t d8 = (c1 % 100) << 1; 272 | 273 | *buffer++ = cDigitsLut[d1]; 274 | *buffer++ = cDigitsLut[d1 + 1]; 275 | *buffer++ = cDigitsLut[d2]; 276 | *buffer++ = cDigitsLut[d2 + 1]; 277 | *buffer++ = cDigitsLut[d3]; 278 | *buffer++ = cDigitsLut[d3 + 1]; 279 | *buffer++ = cDigitsLut[d4]; 280 | *buffer++ = cDigitsLut[d4 + 1]; 281 | *buffer++ = cDigitsLut[d5]; 282 | *buffer++ = cDigitsLut[d5 + 1]; 283 | *buffer++ = cDigitsLut[d6]; 284 | *buffer++ = cDigitsLut[d6 + 1]; 285 | *buffer++ = cDigitsLut[d7]; 286 | *buffer++ = cDigitsLut[d7 + 1]; 287 | *buffer++ = cDigitsLut[d8]; 288 | *buffer++ = cDigitsLut[d8 + 1]; 289 | } 290 | 291 | return buffer; 292 | } 293 | 294 | #endif 295 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | ## Parameters 2 | 3 | CC = gcc 4 | CXX = g++ 5 | LD = g++ 6 | CFLAGS = -g -O2 -Wall -Werror -I../lib 7 | CXXFLAGS= -g -O2 -std=c++11 -Wall -Werror -I../lib -I../grisu/include 8 | LDFLAGS = -L../lib -L../grisu/lib -static -lerrol -ldouble-conversion -lm -lgmp 9 | AR = ar rcs 10 | 11 | BIN = errol-test 12 | OBJ = main.o proof.o interop.o dragon4.o 13 | SRC = main.c proof.c interop.cpp dragon4.c 14 | INC = dragon4.h 15 | DEP = ../lib/liberrol.so 16 | DIST = Makefile $(SRC) $(INC) 17 | VER = 1.0 18 | PKG = errol_test 19 | 20 | ## Build rules 21 | 22 | all: $(BIN) 23 | 24 | $(BIN): $(OBJ) 25 | $(LD) $^ -o $@ $(LDFLAGS) 26 | 27 | main.o: main.c Makefile $(INC) $(DEP) 28 | proof.o: proof.c Makefile $(INC) $(DEP) 29 | interop.o: interop.cpp Makefile $(INC) $(DEP) 30 | dragon4.o: dragon4.c Makefile $(INC) $(DEP) 31 | 32 | ## Clean rules 33 | 34 | clean: 35 | rm -rf $(BIN) $(OBJ) 36 | 37 | ## Distribute rules 38 | 39 | dist: 40 | mkdir $(PKG) 41 | cp $(DIST) $(PKG) 42 | tar -zcf $(PKG).tar.gz $(PKG) 43 | rm -rf $(PKG) 44 | 45 | ## Phony 46 | 47 | .PHONY: all clean dist 48 | -------------------------------------------------------------------------------- /test/dragon4.h: -------------------------------------------------------------------------------- 1 | #ifndef DRAGON4_H 2 | #define DRAGON4_H 3 | 4 | /* 5 | * dragon4 function declarations 6 | */ 7 | 8 | extern "C" char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve); 9 | extern "C" void freedtoa(char *s); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /test/interop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "dragon4.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * namespaces 12 | */ 13 | 14 | using namespace double_conversion; 15 | 16 | 17 | /** 18 | * Read the time source clock. 19 | * &returns: The source clock as a 64-bit unsignd integer. 20 | */ 21 | 22 | static inline uint64_t rdtsc() 23 | { 24 | uint32_t a, d; 25 | 26 | __asm__ __volatile__( 27 | "rdtscp;" 28 | : "=a" (a), "=d" (d) 29 | : 30 | : "%rcx", "%rbx", "memory"); 31 | 32 | return ((uint64_t)a) | (((uint64_t)d) << 32); 33 | } 34 | 35 | 36 | /** 37 | * Retrieve a 64-bit seed from CPU. 38 | * &returns: An integer with an unpredictable value. 39 | */ 40 | 41 | extern "C" uint_fast64_t get_seed() 42 | { 43 | #if defined(__RDRND__) 44 | unsigned long long v; 45 | _rdrand64_step(&v); 46 | return v; 47 | #else 48 | return rdtsc() ^ (uint_fast64_t(std::random_device{}()) << 32); 49 | #endif 50 | } 51 | 52 | 53 | /** 54 | * Initialize the global random engine. 55 | * &returns: The engine. 56 | */ 57 | 58 | inline std::mt19937_64& global_rng() 59 | { 60 | static std::mt19937_64 e{ get_seed() }; 61 | return e; 62 | } 63 | 64 | 65 | /** 66 | * Create a random double value. 67 | * @upper: Minimum floating point value. 68 | * @lower: Maximum floating point value. 69 | * &returns: The random double. 70 | */ 71 | 72 | extern "C" double rndval(double lower, double upper) 73 | { 74 | errol_bits_t a = { lower }, b = { upper }; 75 | std::uniform_int_distribution dist(a.i, b.i); 76 | errol_bits_t r = { .i = dist(global_rng()) }; 77 | return r.d; 78 | } 79 | 80 | 81 | /** 82 | * Seed the global random engine. 83 | * @value: The seed to use. 84 | */ 85 | 86 | extern "C" void reseed(uint_fast64_t value) 87 | { 88 | global_rng().seed(value); 89 | } 90 | 91 | 92 | /** 93 | * Benchmark decimal to string using Grisu. 94 | * @val: The value. 95 | * @suc: The success flag. 96 | * &returns: The number of cycles. 97 | */ 98 | 99 | extern "C" uint32_t grisu_bench(double val, bool *suc) 100 | { 101 | bool chk; 102 | static const int kBufferSize = 100; 103 | char buf[kBufferSize]; 104 | Vector buffer(buf, kBufferSize); 105 | int length, point; 106 | uint64_t tm; 107 | 108 | tm = rdtsc(); 109 | chk = FastDtoa(val, FAST_DTOA_SHORTEST, 0, buffer, &length, &point); 110 | tm = rdtsc() - tm; 111 | 112 | if(suc) 113 | *suc = chk; 114 | 115 | return tm; 116 | } 117 | 118 | /** 119 | * Benchmark decimal to string using Grisu. 120 | * @val: The value. 121 | * @suc: The success flag. 122 | * &returns: The number of cycles. 123 | */ 124 | 125 | extern "C" int grisu3_proc(double val, char *buf, bool *suc) 126 | { 127 | bool chk; 128 | Vector buffer(buf, 100); 129 | int length, point; 130 | 131 | chk = FastDtoa(val, FAST_DTOA_SHORTEST, 0, buffer, &length, &point); 132 | if(suc) 133 | *suc = chk; 134 | 135 | return point; 136 | } 137 | 138 | 139 | /** 140 | * Benchmark decimal to string using Dragon4. 141 | * @val: The value. 142 | * @suc: The success flag. 143 | * &returns: The number of cycles. 144 | */ 145 | 146 | extern "C" uint32_t dragon4_bench(double val, bool *suc) 147 | { 148 | uint64_t tm; 149 | char *str; 150 | int pt, sign; 151 | 152 | tm = rdtsc(); 153 | str = dtoa(val, 0, 24, &pt, &sign, NULL); 154 | tm = rdtsc() - tm; 155 | 156 | freedtoa(str); 157 | 158 | if(suc) 159 | *suc = true; 160 | 161 | return tm; 162 | } 163 | 164 | /** 165 | * Process the drangon4 algorithm. 166 | * @val: The double value. 167 | * @buf: The output buffer. 168 | * &returns: The exponent. 169 | */ 170 | 171 | extern "C" int dragon4_proc(double val, char *buf) 172 | { 173 | char *str; 174 | int pt, sign; 175 | 176 | str = dtoa(val, 0, 24, &pt, &sign, NULL); 177 | strcpy(buf, str); 178 | freedtoa(str); 179 | 180 | return pt; 181 | } 182 | 183 | /** 184 | * Check the length of the dragon4 algorithm. 185 | * @val: The double value. 186 | * &returns: The length, guaranteed to be shortest. 187 | */ 188 | 189 | extern "C" uint32_t dragon4_len(double val) 190 | { 191 | char buf[32]; 192 | 193 | dragon4_proc(val, buf); 194 | 195 | return strlen(buf); 196 | } 197 | 198 | 199 | /** 200 | * Check Errol. 201 | * @n: The version. 202 | * @val: The value. 203 | * &returns: True if correct, false otherwise. 204 | */ 205 | 206 | extern "C" bool errolN_check(unsigned int n, double val) 207 | { 208 | bool opt; 209 | char errol[32], dragon[32]; 210 | 211 | switch(n) { 212 | case 0: errol0_dtoa(val, errol); break; 213 | case 1: errol1_dtoa(val, errol, &opt); break; 214 | case 2: errol2_dtoa(val, errol, &opt); break; 215 | case 3: errol3_dtoa(val, errol); break; 216 | case 4: errol4_dtoa(val, errol); break; 217 | } 218 | 219 | dragon4_proc(val, dragon); 220 | 221 | return strcmp(errol, dragon) == 0; 222 | } 223 | 224 | /** 225 | * Check uncorrected Errol. 226 | * @n: The version. 227 | * @val: The value. 228 | * &returns: True if correct, false otherwise. 229 | */ 230 | 231 | extern "C" bool errolNu_check(unsigned int n, double val) 232 | { 233 | char errol[32], dragon[32]; 234 | 235 | switch(n) { 236 | case 3: errol3u_dtoa(val, errol); break; 237 | case 4: errol4u_dtoa(val, errol); break; 238 | } 239 | 240 | dragon4_proc(val, dragon); 241 | 242 | return strcmp(errol, dragon) == 0; 243 | } 244 | 245 | /** 246 | * Process Errol. 247 | * @n: The version. 248 | * @val: The value. 249 | * @buf: The output buffer. 250 | * @opt: The optimality flag. 251 | * &returns: The exponent. 252 | */ 253 | 254 | extern "C" int errolN_proc(unsigned int n, double val, char *buf, bool *opt) 255 | { 256 | *opt = true; 257 | 258 | switch(n) { 259 | case 0: return errol0_dtoa(val, buf); 260 | case 1: return errol1_dtoa(val, buf, opt); 261 | case 2: return errol2_dtoa(val, buf, opt); 262 | case 3: return errol3_dtoa(val, buf); 263 | case 4: return errol4_dtoa(val, buf); 264 | } 265 | 266 | assert(false); 267 | 268 | return 0; 269 | } 270 | 271 | /** 272 | * Benchmark Errol. 273 | * @val: The value. 274 | * @suc: The success flag. 275 | * &returns: The number of cycles. 276 | */ 277 | 278 | extern "C" uint32_t errolN_bench(unsigned int n, double val, bool *suc) 279 | { 280 | uint64_t tm; 281 | char buf[100]; 282 | bool opt = true; 283 | 284 | switch(n) { 285 | case 0: 286 | tm = rdtsc(); 287 | errol0_dtoa(val, buf); 288 | tm = rdtsc() - tm; 289 | break; 290 | 291 | case 1: 292 | tm = rdtsc(); 293 | errol1_dtoa(val, buf, &opt); 294 | tm = rdtsc() - tm; 295 | break; 296 | 297 | case 2: 298 | tm = rdtsc(); 299 | errol2_dtoa(val, buf, &opt); 300 | tm = rdtsc() - tm; 301 | break; 302 | 303 | case 3: 304 | tm = rdtsc(); 305 | errol3_dtoa(val, buf); 306 | tm = rdtsc() - tm; 307 | break; 308 | 309 | case 4: 310 | tm = rdtsc(); 311 | errol4_dtoa(val, buf); 312 | tm = rdtsc() - tm; 313 | break; 314 | 315 | default: 316 | assert(true); 317 | tm = 0; 318 | } 319 | 320 | if(suc) 321 | *suc = opt; 322 | 323 | return tm; 324 | } 325 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | /* 17 | * local function declarations 18 | */ 19 | 20 | static bool opt_long(char ***arg, const char *pre, char **value); 21 | static bool opt_num(char ***arg, const char *pre, int *num); 22 | static bool opt_real(char ***arg, const char *pre, double *num); 23 | 24 | static int intsort(const void *left, const void *right); 25 | static int err_t_sort(const void *left, const void *right); 26 | 27 | static double chk_conv(double val, const char *str, int exp, bool *cor, bool *opt, bool *best); 28 | 29 | static void table_add(struct errol_err_t[static 1024], int i, double val); 30 | static void table_enum(unsigned int ver, bool bld); 31 | static void table_to_tree(struct errol_err_t *table, int n); 32 | 33 | /* 34 | * interop function declarations 35 | */ 36 | 37 | double rndval(double lower, double upper); 38 | void reseed(uint_fast64_t value); 39 | uint_fast64_t get_seed(); 40 | 41 | int grisu3_proc(double val, char *buf, bool *suc); 42 | uint32_t grisu_bench(double val, bool *suc); 43 | 44 | int dragon4_proc(double val, char *buf); 45 | uint32_t dragon4_bench(double val, bool *suc); 46 | 47 | bool errolN_check(unsigned int n, double val); 48 | bool errolNu_check(unsigned int n, double val); 49 | int errolN_proc(unsigned int n, double val, char *buf, bool *opt); 50 | uint32_t errolN_bench(unsigned int n, double val, bool *suc); 51 | 52 | /* 53 | * proof function declarations 54 | */ 55 | 56 | int64_t *proof_enum(mpz_t delta, mpz_t m0, mpz_t alpha, mpz_t tau, unsigned int p); 57 | 58 | 59 | /** 60 | * Main entry point. 61 | * @argc: The number of arguments. 62 | * @argv: The argument array. 63 | * &returns: The error code. 64 | */ 65 | 66 | int main(int argc, char **argv) 67 | { 68 | char **arg; 69 | bool quiet = false, enum3 = false, enum4 = false, check3 = false, check4 = false; 70 | int n, perf = 0, fuzz[5] = { 0, 0, 0, 0, 0 }; 71 | double lower = nextafter(0.0, DBL_MIN), upper = DBL_MAX; 72 | 73 | for(arg = argv + 1; *arg != NULL; ) { 74 | if(opt_num(&arg, "fuzz0", &n)) 75 | fuzz[0] = n; 76 | else if(opt_num(&arg, "fuzz1", &n)) 77 | fuzz[1] = n; 78 | else if(opt_num(&arg, "fuzz2", &n)) 79 | fuzz[2] = n; 80 | else if(opt_num(&arg, "fuzz3", &n)) 81 | fuzz[3] = n; 82 | else if(opt_num(&arg, "fuzz4", &n)) 83 | fuzz[4] = n; 84 | else if(opt_num(&arg, "perf", &n)) 85 | perf = n; 86 | else if(opt_real(&arg, "lower", &lower)) 87 | ; 88 | else if(opt_real(&arg, "upper", &upper)) 89 | ; 90 | else if(opt_long(&arg, "enum3", NULL)) 91 | enum3 = true; 92 | else if(opt_long(&arg, "enum4", NULL)) 93 | enum4 = true; 94 | else if(opt_long(&arg, "check3", NULL)) 95 | check3 = true; 96 | else if(opt_long(&arg, "check4", NULL)) 97 | check4 = true; 98 | else 99 | fprintf(stderr, "Invalid option '%s'.\n", *arg), abort(); 100 | } 101 | 102 | if(!(0 < lower) || !(upper <= DBL_MAX) || !(lower <= upper)) { 103 | fprintf(stderr, "Invalid interval [%g, %g].\n", lower, upper); 104 | exit(1); 105 | } 106 | 107 | rndval(lower, upper); 108 | 109 | for(n = 0; n < 5; n++) { 110 | unsigned int i, nfail = 0, subopt = 0, notbest = 0; 111 | 112 | if(fuzz[n] == 0) 113 | continue; 114 | 115 | for(i = 0; i < fuzz[n]; i++) { 116 | int exp; 117 | char str[32]; 118 | double val, chk; 119 | bool cor, opt, best; 120 | 121 | if((i % 1000) == 0) { 122 | printf("\x1b[G\x1b[KFuzzing Errol%u... %uk/%uk %2.2f%%", n, i / 1000, fuzz[n] / 1000, 100.0 * (double)i / (double)fuzz[n]); 123 | fflush(stdout); 124 | } 125 | 126 | val = rndval(lower, upper); 127 | exp = errolN_proc(n, val, str, &opt); 128 | chk = chk_conv(val, str, exp, &cor, &opt, &best); 129 | 130 | nfail += (cor ? 0 : 1); 131 | subopt += (opt ? 0 : 1); 132 | notbest += (best ? 0 : 1); 133 | 134 | if(!best && !quiet) { 135 | int dragon4exp; 136 | char dragon4str[128]; 137 | 138 | dragon4exp = dragon4_proc(val, dragon4str); 139 | fprintf(stderr, "Conversion failed. Expected 0.%se%d. Actual 0.%se%d. Read as %.17e.\n", dragon4str, dragon4exp, str, exp, chk); 140 | } 141 | } 142 | 143 | printf("\x1b[G\x1b[KFuzzing Errol%u done on %u numbers, %u failures (%.3f%%), %u suboptimal (%.3f%%), %u notbest (%.3f%%)\n", n, fuzz[n], nfail, 100.0 * (double)nfail / (double)fuzz[n], subopt, 100.0 * (double)subopt / (double)fuzz[n], notbest, 100.0 * (double)notbest / (double)fuzz[n]); 144 | } 145 | 146 | if(perf > 0) { 147 | #define N 100 148 | #define Nlow (N / 10) 149 | #define Nhigh (N - Nlow) 150 | #define Nsize (Nhigh - Nlow) 151 | 152 | uint_fast64_t seed = get_seed(); 153 | uint32_t dragon4 = 0, grisu3 = 0, errol[5] = { 0, 0, 0, 0, 0 }, adj3 = 0; 154 | unsigned int i, j; 155 | static uint32_t dragon4all[20000][N], grisu3all[20000][N], errolNall[5][20000][N], adj3all[20000][N]; 156 | 157 | if(perf > 20000) 158 | fprintf(stderr, "Cannot support more than 20k performance numberss.\n"), abort(); 159 | 160 | for(j = 0; j < N; j++) { 161 | reseed(seed); 162 | for(i = 0; i < perf; i++) { 163 | double val; 164 | bool suc; 165 | 166 | val = rndval(lower, upper); 167 | 168 | dragon4all[i][j] = dragon4_bench(val, &suc); 169 | errolNall[0][i][j] = errolN_bench(0, val, &suc); 170 | errolNall[1][i][j] = errolN_bench(1, val, &suc); 171 | errolNall[2][i][j] = errolN_bench(2, val, &suc); 172 | errolNall[3][i][j] = errolN_bench(3, val, &suc); 173 | errolNall[4][i][j] = errolN_bench(4, val, &suc); 174 | grisu3all[i][j] = grisu_bench(val, &suc); 175 | adj3all[i][j] = suc ? grisu3all[i][j] : dragon4all[i][j]; 176 | } 177 | } 178 | 179 | reseed(seed); 180 | 181 | for(i = 0; i < perf; i++) { 182 | double val = rndval(lower, upper); 183 | uint32_t dragon4tm = 0, grisu3tm = 0, errolNtm[5] = { 0, 0, 0, 0, 0 }, adj3tm = 0; 184 | 185 | qsort(dragon4all[i], N, sizeof(uint32_t), intsort); 186 | qsort(errolNall[0][i], N, sizeof(uint32_t), intsort); 187 | qsort(errolNall[1][i], N, sizeof(uint32_t), intsort); 188 | qsort(errolNall[2][i], N, sizeof(uint32_t), intsort); 189 | qsort(errolNall[3][i], N, sizeof(uint32_t), intsort); 190 | qsort(errolNall[4][i], N, sizeof(uint32_t), intsort); 191 | qsort(grisu3all[i], N, sizeof(uint32_t), intsort); 192 | qsort(adj3all[i], N, sizeof(uint32_t), intsort); 193 | 194 | for(j = Nlow; j < Nhigh; j++) { 195 | dragon4tm += dragon4all[i][j]; 196 | errolNtm[0] += errolNall[0][i][j]; 197 | errolNtm[1] += errolNall[1][i][j]; 198 | errolNtm[2] += errolNall[2][i][j]; 199 | errolNtm[3] += errolNall[3][i][j]; 200 | errolNtm[4] += errolNall[4][i][j]; 201 | grisu3tm += grisu3all[i][j]; 202 | adj3tm += adj3all[i][j]; 203 | } 204 | 205 | dragon4 += dragon4tm /= Nsize; 206 | errol[0] += errolNtm[0] /= Nsize; 207 | errol[1] += errolNtm[1] /= Nsize; 208 | errol[2] += errolNtm[2] /= Nsize; 209 | errol[3] += errolNtm[3] /= Nsize; 210 | errol[4] += errolNtm[4] /= Nsize; 211 | grisu3 += grisu3tm /= Nsize; 212 | adj3 += adj3tm /= Nsize; 213 | 214 | fprintf(stderr, "%.18e\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\n", val, errolNtm[0], errolNtm[1], errolNtm[2], errolNtm[3], errolNtm[4], grisu3tm, dragon4tm, adj3tm); 215 | } 216 | 217 | printf("\x1b[G\x1b[KBenchmarking done,\n"); 218 | printf("==== Absolute Results ====\n"); 219 | printf("Errol0 %u cycles\n", errol[0] / perf); 220 | printf("Errol1 %u cycles\n", errol[1] / perf); 221 | printf("Errol2 %u cycles\n", errol[2] / perf); 222 | printf("Errol3 %u cycles\n", errol[3] / perf); 223 | printf("Errol4 %u cycles\n", errol[4] / perf); 224 | printf("Grisu3 %u cycles\n", grisu3 / perf); 225 | printf("Dragon4 %u cycles\n", dragon4 / perf); 226 | printf("Grisu3 w/fallback %u cycles\n", adj3 / perf); 227 | printf("==== Relative Speedup of Errol3 ====\n"); 228 | printf("Grisu3 %.2fx\n", (double)grisu3 / (double)errol[3]); 229 | printf("Dragon4 %.2fx\n", (double)dragon4 / (double)errol[3]); 230 | printf("Grisu3 w/fallback %.2fx\n", (double)adj3 / (double)errol[3]); 231 | printf("==== Relative Speedup of Errol4 ====\n"); 232 | printf("Grisu3 %.2fx\n", (double)grisu3 / (double)errol[4]); 233 | printf("Dragon4 %.2fx\n", (double)dragon4 / (double)errol[4]); 234 | printf("Grisu3 w/fallback %.2fx\n", (double)adj3 / (double)errol[4]); 235 | } 236 | 237 | if(enum3) 238 | table_enum(3, true); 239 | 240 | if(enum4) 241 | table_enum(4, true); 242 | 243 | if(check3) 244 | table_enum(3, false); 245 | 246 | if(check4) 247 | table_enum(4, false); 248 | 249 | return 0; 250 | } 251 | 252 | 253 | /** 254 | * Retrieve a long argument. 255 | * @arg: The argument pointer. 256 | * @pre: The option to match. 257 | * @parameter: Optional. The parameter pointer. 258 | * &returns: True if matched with argument incremented. 259 | */ 260 | 261 | static bool opt_long(char ***arg, const char *pre, char **param) 262 | { 263 | char *str = **arg + 2; 264 | 265 | while(true) { 266 | if(*pre == '\0') 267 | break; 268 | 269 | if(*pre++ != *str++) 270 | return false; 271 | } 272 | 273 | if(param != NULL) { 274 | if(*str == '\0') 275 | *param = *(++(*arg)); 276 | else if(*str == '=') { 277 | *param = str + 1; 278 | } 279 | else 280 | fprintf(stderr, "Option '--%s' expected argument.\n", **arg + 2), abort(); 281 | } 282 | else { 283 | if(*str == '=') 284 | fprintf(stderr, "Unexpected argument to option '--%s'.\n", **arg + 2), abort(); 285 | else if(*str != '\0') 286 | return false; 287 | } 288 | 289 | (*arg)++; 290 | 291 | return true; 292 | } 293 | 294 | /** 295 | * Retrieve an integer argument. 296 | * @arg: The argument pointer. 297 | * @pre: The option to match. 298 | * @parameter: The parameter pointer. 299 | * &returns: True if matched with argument incremented. 300 | */ 301 | 302 | static bool opt_num(char ***arg, const char *pre, int *num) 303 | { 304 | unsigned long val; 305 | char *param, *endptr; 306 | 307 | if(!opt_long(arg, pre, ¶m)) 308 | return false; 309 | 310 | errno = 0; 311 | val = strtol(param, &endptr, 0); 312 | if((val == 0) && (errno == 0)) 313 | fprintf(stderr, "Parameter cannot be zero.\n"), abort(); 314 | 315 | if((*endptr == 'k') || (*endptr == 'K')) 316 | val *= 1000, endptr++; 317 | else if((*endptr == 'm') || (*endptr == 'M')) 318 | val *= 1000000, endptr++; 319 | 320 | if(((val == 0) && (errno != 0)) || (*endptr != '\0')) 321 | fprintf(stderr, "Invalid %s parameter '%s'.\n", pre, param), abort(); 322 | else if(val > INT_MAX) 323 | fprintf(stderr, "Number too large '%s'.\n", param), abort(); 324 | 325 | *num = val; 326 | 327 | return true; 328 | } 329 | 330 | /** 331 | * Retrieve a floating point argument. 332 | * @arg: The argument pointer. 333 | * @pre: The option to match. 334 | * @parameter: The parameter pointer. 335 | * &returns: True if matched with argument incremented. 336 | */ 337 | 338 | static bool opt_real(char ***arg, const char *pre, double *num) 339 | { 340 | double val; 341 | char *param, *endptr; 342 | 343 | if(!opt_long(arg, pre, ¶m)) 344 | return false; 345 | 346 | errno = 0; 347 | val = strtod(param, &endptr); 348 | 349 | if((errno != 0) || (*endptr != '\0')) 350 | fprintf(stderr, "Invalid %s parameter '%s'.\n", pre, param), abort(); 351 | 352 | *num = val; 353 | 354 | return true; 355 | } 356 | 357 | 358 | /** 359 | * Sort integers. 360 | * @left: The left pointer. 361 | * @right: The right pointer. 362 | * &returns: The order. 363 | */ 364 | 365 | static int intsort(const void *left, const void *right) 366 | { 367 | if(*(const uint32_t *)left > *(const uint32_t *)right) 368 | return -1; 369 | else if(*(const uint32_t *)left < *(const uint32_t *)right) 370 | return 1; 371 | else 372 | return 0; 373 | } 374 | 375 | /** 376 | * Sort errol_err_t in terms of bit patterns of the floating points. 377 | * @left: The left pointer. 378 | * @right: The right pointer. 379 | * &returns: The order. 380 | */ 381 | 382 | static int err_t_sort(const void *left, const void *right) 383 | { 384 | errol_bits_t l = { ((struct errol_err_t *)left)->val }; 385 | errol_bits_t r = { ((struct errol_err_t *)right)->val }; 386 | 387 | if (l.i < r.i) 388 | return -1; 389 | else if (l.i == r.i) 390 | return 0; 391 | else 392 | return 1; 393 | } 394 | 395 | 396 | /** 397 | * Check a conversion. 398 | * @val: The value. 399 | * @str: The string. 400 | * @exp: The exponent. 401 | * @cor: The correct flag. 402 | * @opt: The optimal flag. 403 | * @best: The best flag. 404 | * &returns: The actual value. 405 | */ 406 | 407 | static double chk_conv(double val, const char *str, int exp, bool *cor, bool *opt, bool *best) 408 | { 409 | double chk; 410 | int dragon4exp; 411 | char dragon4[32], full[snprintf(NULL, 0, "0.%se%d", str, exp) + 1]; 412 | 413 | dragon4exp = dragon4_proc(val, dragon4); 414 | 415 | sprintf(full, "0.%se%d", str, exp); 416 | sscanf(full, "%lf", &chk); 417 | 418 | *cor = (val == chk); 419 | *opt = (*cor && (strlen(str) == strlen(dragon4))); 420 | *best = (*opt && (exp == dragon4exp) && !strcmp(str, dragon4)); 421 | 422 | return chk; 423 | } 424 | 425 | 426 | /** 427 | * Add to the table. 428 | * @table: The table. 429 | * @i: Insertion point. 430 | * @val: The value. 431 | */ 432 | 433 | static void table_add(struct errol_err_t table[static 1024], int i, double val) 434 | { 435 | table[i] = (struct errol_err_t){ val }; 436 | table[i].exp = dragon4_proc(table[i].val, table[i].str); 437 | } 438 | 439 | /** 440 | * Process the enumeration algorithm. 441 | * @ver: The version. 442 | * @bld: Whether to build the table or check it. 443 | */ 444 | 445 | static void table_enum(unsigned int ver, bool bld) 446 | { 447 | int i, e, n, p, exp, cnt = 0; 448 | int64_t *arr; 449 | mpz_t delta, m0, alpha, tau, t; 450 | struct errol_err_t table[1024] = {{ 0 }}; 451 | static unsigned int D = 17, P = 52; 452 | 453 | assert((ver == 3) || (ver == 4)); 454 | 455 | mpz_inits(delta, m0, alpha, tau, t, NULL); 456 | 457 | //for(e = -1022; e < 4; e++) { 458 | for(e = -1074; e <= 4; e++) { 459 | mpz_t t0, t1; 460 | 461 | /* bits of precision */ 462 | p = (e >= -1022) ? P : (e + 1074); 463 | 464 | /* log10(5^{-e+p+1}2^{p+1}) - D + 2 */ 465 | n = floor((-e+p+1)*log10(5.0) + (p+1)*log10(2.0)) - D + 2; 466 | 467 | /* common constants */ 468 | mpz_inits(t0, t1, NULL); 469 | mpz_ui_pow_ui(t0, 5, -e+p+1-n); 470 | mpz_ui_pow_ui(t1, 2, P-1); 471 | 472 | /* Δ = 2^{1-P}5^{-e+p+1-n} */ 473 | mpz_mul_ui(delta, t0, 79); 474 | 475 | /* α = 2*5^{-e+p+1-n}*/ 476 | mpz_mul_ui(alpha, t0, 2); 477 | mpz_mul(alpha, alpha, t1); 478 | 479 | /* τ = 2^n */ 480 | mpz_ui_pow_ui(tau, 2, n); 481 | mpz_mul(tau, tau, t1); 482 | 483 | /* m0 = 2^{p+1} 5^{-e+p+1-n} + 5^{e+p+1-n} */ 484 | mpz_ui_pow_ui(t, 2, p+1); 485 | mpz_mul(m0, t0, t); 486 | mpz_add(m0, m0, t0); 487 | mpz_mul(m0, m0, t1); 488 | 489 | /* 490 | gmp_printf("e %d\n", e); 491 | gmp_printf("p %d\n", p); 492 | gmp_printf("n %u\n", n); 493 | gmp_printf("α %Zd\n", alpha); 494 | gmp_printf("Δ %Zd\n", delta); 495 | gmp_printf("τ %Zd\n", tau); 496 | gmp_printf("m0 %Zd\n", m0); 497 | */ 498 | 499 | /* find possible failures */ 500 | arr = proof_enum(delta, m0, alpha, tau, p); 501 | 502 | for(i = 0; arr[i] >= 0; i++) { 503 | double v; 504 | 505 | v = ldexp(1.0, e) + ldexp(arr[i], e-52); 506 | if(!(bld ? errolNu_check : errolN_check)(ver, v)) 507 | table_add(table, cnt++, v); 508 | 509 | v = ldexp(1.0, e) + ldexp(arr[i]+1, e-52); 510 | if(!(bld ? errolNu_check : errolN_check)(ver, v)) 511 | table_add(table, cnt++, v); 512 | } 513 | 514 | free(arr); 515 | 516 | mpz_clears(t0, t1, NULL); 517 | } 518 | 519 | for(int e = 128; e <= 1023; e++) { 520 | unsigned int p = P; 521 | 522 | /* log10(2^{e+1}) - D + 2 */ 523 | n = floor((e+1.0)*log10(2.0)) - D + 2; 524 | 525 | /* Δ = 2^(e-p-n) 79ϵ = 79 2^{e-2p-n) */ 526 | exp = e - 2*p - n; 527 | mpz_ui_pow_ui(delta, 2, (exp > 0) ? exp : 0); 528 | mpz_mul_ui(delta, delta, 179); 529 | 530 | /* α = 2^(e-p-n) */ 531 | mpz_ui_pow_ui(alpha, 2, e - p - n); 532 | 533 | /* τ = 5^n */ 534 | mpz_ui_pow_ui(tau, 5, n); 535 | 536 | /* m0 = 2^(e-n) + 2^(e-p-1-n) */ 537 | mpz_ui_pow_ui(m0, 2, e-n); 538 | mpz_ui_pow_ui(t, 2, e-p-n-1); 539 | mpz_add(m0, m0, t); 540 | 541 | /* 542 | gmp_printf("e %d\n", e); 543 | gmp_printf("p %d\n", p); 544 | gmp_printf("n %u\n", n); 545 | gmp_printf("α %Zd\n", alpha); 546 | gmp_printf("Δ %Zd\n", delta); 547 | gmp_printf("τ %Zd\n", tau); 548 | */ 549 | 550 | /* find possible failures */ 551 | arr = proof_enum(delta, m0, alpha, tau, p); 552 | 553 | for(i = 0; arr[i] >= 0; i++) { 554 | double v; 555 | 556 | v = ldexp(1.0, e) + ldexp(arr[i], e-52); 557 | if(!(bld ? errolNu_check : errolN_check)(ver, v)) 558 | table_add(table, cnt++, v); 559 | 560 | v = ldexp(1.0, e) + ldexp(arr[i]+1, e-52); 561 | if(!(bld ? errolNu_check : errolN_check)(ver, v)) 562 | table_add(table, cnt++, v); 563 | } 564 | 565 | free(arr); 566 | } 567 | 568 | mpz_clears(delta, m0, alpha, tau, t, NULL); 569 | 570 | if(!(bld ? errolNu_check : errolN_check)(ver, DBL_MIN)) 571 | table_add(table, cnt++, DBL_MIN); 572 | 573 | if(!(bld ? errolNu_check : errolN_check)(ver, DBL_MAX)) 574 | table_add(table, cnt++, DBL_MAX); 575 | 576 | if(bld) { 577 | FILE *file; 578 | 579 | qsort(table, cnt, sizeof(struct errol_err_t), err_t_sort); 580 | table_to_tree(table, cnt); 581 | 582 | file = fopen((ver == 3) ? "enum3.h" : "enum4.h", "w"); 583 | fprintf(file, "static uint64_t errol_enum%d[%d] = {\n", ver, cnt); 584 | 585 | for(i = 0; i < cnt; i++) { 586 | errol_bits_t bits = { table[i].val }; 587 | fprintf(file, "\t%#.16" PRIx64 ",\n", bits.i); 588 | } 589 | 590 | fprintf(file, "};\n"); 591 | fprintf(file, "static struct errol_slab_t errol_enum%d_data[%d] = {\n", ver, cnt); 592 | 593 | for(i = 0; i < cnt; i++) { 594 | fprintf(file, "\t{ \"%s\", %d },\n", table[i].str, table[i].exp); 595 | } 596 | 597 | fprintf(file, "};\n"); 598 | fclose(file); 599 | } 600 | else { 601 | for(i = 0; i < 1024; i++) { 602 | if(table[i].val != 0.0) 603 | printf("Failed value %.17e\n", table[i].val); 604 | 605 | if(table[i].val != 0.0) 606 | printf("Failed value %.17e\n", table[i].val); 607 | } 608 | } 609 | 610 | printf("Enumerating Errol%u%s, %u failures\n", ver, bld ? "u" : "", cnt); 611 | } 612 | 613 | /** 614 | * Calculate the index of the root node when reordering a sorted array to 615 | * the level-order of a binary search tree. 616 | * @n: Array size. 617 | * &returns: The index. 618 | */ 619 | 620 | static inline int table_root(int n) 621 | { 622 | if (n <= 1) 623 | return 0; 624 | int i = 2; 625 | while (i <= n) 626 | i *= 2; 627 | int a = i / 2 - 1; 628 | int b = n - i / 4; 629 | return a < b ? a : b; 630 | } 631 | 632 | /** 633 | * Insert all elements in a sorted array to another array in level-order. 634 | * @table: The destination. 635 | * @i: Insertion point. 636 | * @from: The source. 637 | * @n: Array size. 638 | */ 639 | 640 | static void table_to_tree_iter(struct errol_err_t *table, int i, 641 | struct errol_err_t *from, int n) 642 | { 643 | if (n > 0) 644 | { 645 | int h = table_root(n); 646 | table[i] = from[h]; 647 | table_to_tree_iter(table, 2 * i + 1, from, h); 648 | table_to_tree_iter(table, 2 * i + 2, from + h + 1, n - h - 1); 649 | } 650 | } 651 | 652 | /** 653 | * Reorder a sorted array to the level-order of a binary search tree. 654 | * @table: The input array. 655 | * @n: Array size. 656 | */ 657 | 658 | static void table_to_tree(struct errol_err_t *table, int n) 659 | { 660 | struct errol_err_t from[1024]; 661 | memcpy(from, table, n * sizeof(struct errol_err_t)); 662 | table_to_tree_iter(table, 0, from, n); 663 | } 664 | -------------------------------------------------------------------------------- /test/proof.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | /** 11 | * Shift structure. 12 | * @idx: The index. 13 | * @val: The value. 14 | */ 15 | 16 | struct shift_t { 17 | uint64_t idx; 18 | mpz_t val; 19 | }; 20 | 21 | /** 22 | * List structure. 23 | * @arr: The array of shifts. 24 | * @len: The length. 25 | */ 26 | 27 | struct list_t { 28 | struct shift_t *arr; 29 | unsigned int len; 30 | }; 31 | 32 | struct point_t { 33 | uint64_t idx; 34 | mpz_t val; 35 | }; 36 | 37 | struct set_t { 38 | struct point_t *arr; 39 | unsigned int len; 40 | }; 41 | 42 | 43 | /* 44 | * local function declarations 45 | */ 46 | 47 | static struct list_t list_init(void); 48 | static void list_destroy(struct list_t *list); 49 | static void list_add(struct list_t *list, uint64_t idx, mpz_t val); 50 | static struct shift_t *list_last(struct list_t *list); 51 | static struct shift_t *list_smaller(struct list_t *list, mpz_t val); 52 | static struct shift_t *list_atmost(struct list_t *list, mpz_t val); 53 | 54 | static int64_t *arr_new(unsigned int *len); 55 | static void arr_add(int64_t **arr, unsigned int *len, int64_t idx); 56 | 57 | static struct set_t set_init(void); 58 | static void set_destroy(struct set_t *set); 59 | static void set_add(struct set_t *set, uint64_t idx, mpz_t val); 60 | 61 | 62 | int64_t *proof_enum(mpz_t delta, mpz_t m0, mpz_t alpha, mpz_t tau, unsigned int p) 63 | { 64 | mpz_t t, v; 65 | int64_t *arr; 66 | uint64_t idx; 67 | unsigned int len; 68 | struct shift_t *shift; 69 | struct list_t up, down; 70 | 71 | mpz_inits(t, v, NULL); 72 | 73 | up = list_init(); 74 | down = list_init(); 75 | 76 | /* optimal list construction */ 77 | 78 | mpz_mod(t, alpha, tau); 79 | list_add(&up, 1, t); 80 | 81 | mpz_sub(t, t, tau); 82 | list_add(&down, 1, t); 83 | 84 | while(true) { 85 | if(list_last(&up)->idx <= list_last(&down)->idx) { 86 | mpz_sub(t, list_last(&down)->val, list_last(&up)->val); 87 | 88 | shift = list_smaller(&down, t); 89 | assert(shift != NULL); 90 | 91 | idx = list_last(&up)->idx + shift->idx; 92 | mpz_add(t, list_last(&up)->val, shift->val); 93 | 94 | if(mpz_sgn(t) >= 0) 95 | list_add(&up, idx, t); 96 | 97 | if(mpz_sgn(t) <= 0) 98 | list_add(&down, idx, t); 99 | } 100 | else { 101 | mpz_sub(t, list_last(&up)->val, list_last(&down)->val); 102 | 103 | shift = list_smaller(&up, t); 104 | assert(shift != NULL); 105 | 106 | idx = list_last(&down)->idx + shift->idx; 107 | mpz_add(t, list_last(&down)->val, shift->val); 108 | 109 | if(mpz_sgn(t) >= 0) 110 | list_add(&up, idx, t); 111 | 112 | if(mpz_sgn(t) <= 0) 113 | list_add(&down, idx, t); 114 | 115 | } 116 | 117 | if((idx >= (1ul << p)) || (mpz_cmp_si(t, 0) == 0)) 118 | break; 119 | } 120 | 121 | /* search algorithm */ 122 | 123 | idx = 0; 124 | mpz_mod(v, m0, tau); 125 | mpz_sub(t, v, tau); 126 | if(mpz_cmpabs(t, v) < 0) 127 | mpz_set(v, t); 128 | 129 | while(true) { 130 | if((mpz_cmpabs(v, delta) <= 0) || (idx >= (1ul << p))) 131 | break; 132 | 133 | if(mpz_sgn(v) < 0) { 134 | mpz_mul_ui(t, v, 2); 135 | 136 | shift = list_atmost(&up, t); 137 | if(shift == NULL) 138 | break; 139 | } 140 | else { 141 | mpz_mul_ui(t, v, 2); 142 | 143 | shift = list_atmost(&down, t); 144 | if(shift == NULL) 145 | break; 146 | } 147 | 148 | idx += shift->idx; 149 | mpz_add(v, v, shift->val); 150 | } 151 | 152 | /* exhaustively enumerate */ 153 | 154 | arr = arr_new(&len); 155 | 156 | if((idx < (1ul << p)) && (shift != NULL)) { 157 | int i, j; 158 | struct set_t set; 159 | 160 | set = set_init(); 161 | set_add(&set, idx, v); 162 | 163 | idx = 0; 164 | 165 | for(i = 0; i < set.len; i++) { 166 | arr_add(&arr, &len, set.arr[i].idx); 167 | 168 | if(mpz_cmpabs(set.arr[i].val, delta) > 0) 169 | printf("ERR\n"), abort(); 170 | 171 | for(j = up.len - 1; j >= 0; j--) { 172 | idx = set.arr[i].idx + up.arr[j].idx; 173 | if(idx >= (1ul << p)) 174 | continue; 175 | 176 | mpz_add(v, set.arr[i].val, up.arr[j].val); 177 | if(mpz_cmpabs(v, delta) > 0) 178 | break; 179 | 180 | set_add(&set, idx, v); 181 | } 182 | 183 | for(j = down.len - 1; j >= 0; j--) { 184 | idx = set.arr[i].idx + down.arr[j].idx; 185 | if(idx >= (1ul << p)) 186 | continue; 187 | 188 | mpz_add(v, set.arr[i].val, down.arr[j].val); 189 | if(mpz_cmpabs(v, delta) > 0) 190 | break; 191 | 192 | set_add(&set, idx, v); 193 | } 194 | } 195 | 196 | set_destroy(&set); 197 | } 198 | 199 | list_destroy(&up); 200 | list_destroy(&down); 201 | 202 | mpz_clears(t, v, NULL); 203 | 204 | return arr; 205 | } 206 | 207 | 208 | /** 209 | * Initialize an empty shift list. 210 | * &returns: The list. 211 | */ 212 | 213 | static struct list_t list_init(void) 214 | { 215 | return (struct list_t){ malloc(0), 0 }; 216 | } 217 | 218 | /** 219 | * Destroy a list of shifts. 220 | * @list: The list. 221 | */ 222 | 223 | static void list_destroy(struct list_t *list) 224 | { 225 | unsigned int i; 226 | 227 | for(i = 0; i < list->len; i++) 228 | mpz_clear(list->arr[i].val); 229 | 230 | free(list->arr); 231 | } 232 | 233 | /** 234 | * Add a shift to end of the sorted list. 235 | * @list: The list. 236 | * @idx: The index. 237 | * @val: The value. 238 | */ 239 | 240 | static void list_add(struct list_t *list, uint64_t idx, mpz_t val) 241 | { 242 | unsigned int n = list->len; 243 | 244 | assert((list->len == 0) || (list_last(list)->idx < idx)); 245 | assert((list->len == 0) || (mpz_cmp(list_last(list)->val, val) * mpz_sgn(val) >= 0)); 246 | 247 | list->len++; 248 | list->arr = realloc(list->arr, list->len * sizeof(struct shift_t)); 249 | list->arr[n].idx = idx; 250 | mpz_init_set(list->arr[n].val, val); 251 | } 252 | 253 | /** 254 | * Retrieve the last shift from the list. 255 | * @list: The list. 256 | * &returns: The last shift. 257 | */ 258 | 259 | static struct shift_t *list_last(struct list_t *list) 260 | { 261 | return &list->arr[list->len - 1]; 262 | } 263 | 264 | /** 265 | * Find the number smaller than the value. 266 | * @list: The list. 267 | * @val: The value. 268 | * &returns: The shift, if it exists. 269 | */ 270 | 271 | static struct shift_t *list_smaller(struct list_t *list, mpz_t val) 272 | { 273 | int l, h, m, cmp; 274 | 275 | l = 0; 276 | h = list->len - 1; 277 | 278 | while(l <= h) { 279 | m = (l + h) / 2; 280 | cmp = mpz_cmpabs(list->arr[m].val, val); 281 | if(cmp > 0) 282 | l = m + 1; 283 | else if(cmp < 0) 284 | h = m - 1; 285 | else 286 | return (m < list->len-1) ? &list->arr[m+1] : NULL; 287 | } 288 | 289 | return (l < list->len) ? &list->arr[l] : NULL; 290 | } 291 | 292 | /** 293 | * Find the number at most the value. 294 | * @list: The list. 295 | * @val: The value. 296 | * &returns: The shift, if it exists. 297 | */ 298 | 299 | static struct shift_t *list_atmost(struct list_t *list, mpz_t val) 300 | { 301 | int l, h, m, cmp; 302 | 303 | l = 0; 304 | h = list->len - 1; 305 | 306 | while(l <= h) { 307 | m = (l + h) / 2; 308 | cmp = mpz_cmpabs(list->arr[m].val, val); 309 | if(cmp > 0) 310 | l = m + 1; 311 | else if(cmp < 0) 312 | h = m - 1; 313 | else 314 | return &list->arr[m+1]; 315 | } 316 | 317 | return (l < list->len) ? &list->arr[l] : NULL; 318 | } 319 | 320 | 321 | /** 322 | * Create an index array. 323 | * @len: The array length pointer. 324 | * &returns: The empty array. 325 | */ 326 | 327 | static int64_t *arr_new(unsigned int *len) 328 | { 329 | int64_t *arr; 330 | 331 | arr = malloc(sizeof(int64_t)); 332 | arr[0] = -1; 333 | 334 | *len = 0; 335 | 336 | return arr; 337 | } 338 | 339 | /** 340 | * Add to index array. 341 | * @arr: The array pointer. 342 | * @len: the length pointer. 343 | * @idx: The index to add. 344 | */ 345 | 346 | static void arr_add(int64_t **arr, unsigned int *len, int64_t idx) 347 | { 348 | (*arr) = realloc(*arr, (*len + 2) * sizeof(int64_t)); 349 | (*arr)[*len+0] = idx; 350 | (*arr)[*len+1] = -1; 351 | (*len)++; 352 | } 353 | 354 | 355 | /** 356 | * Initialize the exhaustive set. 357 | * &returns: The set. 358 | */ 359 | 360 | static struct set_t set_init(void) 361 | { 362 | return (struct set_t){ malloc(0), 0 }; 363 | } 364 | 365 | /** 366 | * Destroy the exhaustive set. 367 | * @set: The set. 368 | */ 369 | 370 | static void set_destroy(struct set_t *set) 371 | { 372 | unsigned int i; 373 | 374 | for(i = 0; i < set->len; i++) 375 | mpz_clear(set->arr[i].val); 376 | } 377 | 378 | static void set_add(struct set_t *set, uint64_t idx, mpz_t val) 379 | { 380 | unsigned int i; 381 | 382 | for(i = 0; i < set->len; i++) { 383 | if(set->arr[i].idx == idx) 384 | return; 385 | } 386 | 387 | set->arr = realloc(set->arr, (set->len + 1) * sizeof(struct point_t)); 388 | set->arr[set->len].idx = idx; 389 | mpz_init(set->arr[set->len].val); 390 | mpz_set(set->arr[set->len].val, val); 391 | set->len++; 392 | } 393 | --------------------------------------------------------------------------------