• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
73 typedef 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  */
82 static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_normalize_high_prec_data(ecma_high_prec_t * hp_data_p)83 ecma_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  */
94 static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_multiply_high_prec_by_10(ecma_high_prec_t * hp_data_p)95 ecma_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  */
115 static void
ecma_divide_high_prec_by_10(ecma_high_prec_t * hp_data_p)116 ecma_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  */
136 inline lit_utf8_size_t JERRY_ATTR_ALWAYS_INLINE
ecma_errol0_dtoa(double val,lit_utf8_byte_t * buffer_p,int32_t * exp_p)137 ecma_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