1/* Copyright JS Foundation and other contributors, http://js.foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 * 15 * This file is based on work under the following copyright and permission 16 * notice: 17 * 18 * Copyright (c) 2016 Marc Andrysco 19 * 20 * Permission is hereby granted, free of charge, to any person obtaining a copy 21 * of this software and associated documentation files (the "Software"), to deal 22 * in the Software without restriction, including without limitation the rights 23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 * copies of the Software, and to permit persons to whom the Software is 25 * furnished to do so, subject to the following conditions: 26 * 27 * The above copyright notice and this permission notice shall be included in all 28 * copies or substantial portions of the Software. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 36 * SOFTWARE. 37 */ 38 39#include <math.h> 40 41#include "ecma-helpers.h" 42 43/** \addtogroup ecma ECMA 44 * @{ 45 * 46 * \addtogroup ecmahelpers Helpers for operations with ECMA data types 47 * @{ 48 */ 49 50/** 51 * Printing Floating-Point Numbers 52 * 53 * available at http://cseweb.ucsd.edu/~mandrysc/pub/dtoa.pdf 54 */ 55 56/** 57 * Floating point format definitions (next float value) 58 */ 59#define ECMA_NEXT_FLOAT(value) (nextafter ((value), INFINITY)) 60/** 61 * Floating point format definitions (previous float value) 62 */ 63#define ECMA_PREV_FLOAT(value) (nextafter ((value), -INFINITY)) 64 65/** 66 * Value of epsilon 67 */ 68#define ERROL0_EPSILON 0.0000001 69 70/** 71 * High-precision data structure. 72 */ 73typedef struct 74{ 75 double value; /**< value */ 76 double offset; /**< offset */ 77} ecma_high_prec_t; 78 79/** 80 * Normalize the number by factoring in the error. 81 */ 82static inline void JERRY_ATTR_ALWAYS_INLINE 83ecma_normalize_high_prec_data (ecma_high_prec_t *hp_data_p) /**< [in, out] float pair */ 84{ 85 double val = hp_data_p->value; 86 87 hp_data_p->value += hp_data_p->offset; 88 hp_data_p->offset += val - hp_data_p->value; 89} /* ecma_normalize_high_prec_data */ 90 91/** 92 * Multiply the high-precision number by ten. 93 */ 94static inline void JERRY_ATTR_ALWAYS_INLINE 95ecma_multiply_high_prec_by_10 (ecma_high_prec_t *hp_data_p) /**< [in, out] high-precision number */ 96{ 97 double value = hp_data_p->value; 98 99 hp_data_p->value *= 10.0; 100 hp_data_p->offset *= 10.0; 101 102 double offset = hp_data_p->value; 103 104 offset -= value * 8.0; 105 offset -= value * 2.0; 106 107 hp_data_p->offset -= offset; 108 109 ecma_normalize_high_prec_data (hp_data_p); 110} /* ecma_multiply_high_prec_by_10 */ 111 112/** 113 * Divide the high-precision number by ten. 114 */ 115static void 116ecma_divide_high_prec_by_10 (ecma_high_prec_t *hp_data_p) /**< [in, out] high-precision number */ 117{ 118 double value = hp_data_p->value; 119 120 hp_data_p->value /= 10.0; 121 hp_data_p->offset /= 10.0; 122 123 value -= hp_data_p->value * 8.0; 124 value -= hp_data_p->value * 2.0; 125 126 hp_data_p->offset += value / 10.0; 127 128 ecma_normalize_high_prec_data (hp_data_p); 129} /* ecma_divide_high_prec_by_10 */ 130 131/** 132 * Errol0 double to ASCII conversion, guaranteed correct but possibly not optimal. 133 * 134 * @return number of generated digits 135 */ 136inline lit_utf8_size_t JERRY_ATTR_ALWAYS_INLINE 137ecma_errol0_dtoa (double val, /**< ecma number */ 138 lit_utf8_byte_t *buffer_p, /**< buffer to generate digits into */ 139 int32_t *exp_p) /**< [out] exponent */ 140{ 141 double power_of_10 = 1.0; 142 int32_t exp = 1; 143 144 /* normalize the midpoint */ 145 ecma_high_prec_t mid; 146 147 mid.value = val; 148 mid.offset = 0.0; 149 150 while (((mid.value > 10.0) || ((mid.value == 10.0) && (mid.offset >= 0.0))) && (exp < 308)) 151 { 152 exp++; 153 ecma_divide_high_prec_by_10 (&mid); 154 power_of_10 /= 10.0; 155 } 156 157 while (((mid.value < 1.0) || ((mid.value == 1.0) && (mid.offset < 0.0))) && (exp > -307)) 158 { 159 exp--; 160 ecma_multiply_high_prec_by_10 (&mid); 161 power_of_10 *= 10.0; 162 } 163 164 ecma_high_prec_t high_bound, low_bound; 165 166 high_bound.value = mid.value; 167 high_bound.offset = mid.offset; 168 169 if (ECMA_NEXT_FLOAT (val) != INFINITY) 170 { 171 high_bound.offset += (ECMA_NEXT_FLOAT (val) - val) * power_of_10 / (2.0 + ERROL0_EPSILON); 172 } 173 174 low_bound.value = mid.value; 175 low_bound.offset = mid.offset + (ECMA_PREV_FLOAT (val) - val) * power_of_10 / (2.0 + ERROL0_EPSILON); 176 177 ecma_normalize_high_prec_data (&high_bound); 178 ecma_normalize_high_prec_data (&low_bound); 179 180 /* normalized boundaries */ 181 182 while (high_bound.value > 10.0 || (high_bound.value == 10.0 && (high_bound.offset >= 0.0))) 183 { 184 exp++; 185 ecma_divide_high_prec_by_10 (&high_bound); 186 ecma_divide_high_prec_by_10 (&low_bound); 187 } 188 189 while (high_bound.value < 1.0 || (high_bound.value == 1.0 && (high_bound.offset < 0.0))) 190 { 191 exp--; 192 ecma_multiply_high_prec_by_10 (&high_bound); 193 ecma_multiply_high_prec_by_10 (&low_bound); 194 } 195 196 /* digit generation */ 197 198 lit_utf8_byte_t *dst_p = buffer_p; 199 200 while (high_bound.value != 0.0 || high_bound.offset != 0.0) 201 { 202 uint8_t high_digit = (uint8_t) high_bound.value; 203 204 if ((high_bound.value == high_digit) && (high_bound.offset < 0)) 205 { 206 high_digit = (uint8_t) (high_digit - 1u); 207 } 208 209 uint8_t low_digit = (uint8_t) low_bound.value; 210 211 if ((low_bound.value == low_digit) && (low_bound.offset < 0)) 212 { 213 low_digit = (uint8_t) (low_digit - 1u); 214 } 215 216 if (low_digit != high_digit) 217 { 218 break; 219 } 220 221 *dst_p++ = (lit_utf8_byte_t) ('0' + high_digit); 222 223 high_bound.value -= high_digit; 224 ecma_multiply_high_prec_by_10 (&high_bound); 225 226 low_bound.value -= low_digit; 227 ecma_multiply_high_prec_by_10 (&low_bound); 228 } 229 230 double mdig = (high_bound.value + low_bound.value) / 2.0 + 0.5; 231 *dst_p++ = (lit_utf8_byte_t) ('0' + (uint8_t) mdig); 232 233 *exp_p = exp; 234 235 return (lit_utf8_size_t) (dst_p - buffer_p); 236} /* ecma_errol0_dtoa */ 237 238/** 239 * @} 240 * @} 241 */ 242