1 /*
2 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "AEEStdDef.h"
31 #include "AEEstd.h"
32 #include "AEEStdErr.h"
33 #include "std_dtoa.h"
34 #include "math.h"
35
36 //
37 // Useful Macros
38 //
39 #define FAILED(b) ( (b) != AEE_SUCCESS ? TRUE : FALSE )
40 #define CLEANUP_ON_ERROR(b,l) if( FAILED( b ) ) { goto l; }
41 #define FP_POW_10(n) fp_pow_10(n)
42
43 static __inline
std_dtoa_clz32(uint32 ulVal)44 uint32 std_dtoa_clz32( uint32 ulVal )
45 //
46 // This function returns the number of leading zeroes in a uint32.
47 // This is a naive implementation that uses binary search. This could be
48 // replaced by an optimized inline assembly code.
49 //
50 {
51 if( (int)ulVal <= 0 )
52 {
53 return ( ulVal == 0 ) ? 32 : 0;
54 }
55 else
56 {
57 uint32 uRet = 28;
58 uint32 uTmp = 0;
59 uTmp = ( ulVal > 0xFFFF ) * 16; ulVal >>= uTmp, uRet -= uTmp;
60 uTmp = ( ulVal > 0xFF ) * 8; ulVal >>= uTmp, uRet -= uTmp;
61 uTmp = ( ulVal > 0xF ) * 4; ulVal >>= uTmp, uRet -= uTmp;
62 return uRet + ( ( 0x55AF >> ( ulVal * 2 ) ) & 3 );
63 }
64 }
65
66 static __inline
std_dtoa_clz64(uint64 ulVal)67 uint32 std_dtoa_clz64( uint64 ulVal )
68 //
69 // This function returns the number of leading zeroes in a uint64.
70 //
71 {
72 uint32 ulCount = 0;
73
74 if( !( ulVal >> 32 ) )
75 {
76 ulCount += 32;
77 }
78 else
79 {
80 ulVal >>= 32;
81 }
82
83 return ulCount + std_dtoa_clz32( (uint32)ulVal );
84 }
85
fp_pow_10(int nPow)86 double fp_pow_10( int nPow )
87 {
88 double dRet = 1.0;
89 int nI = 0;
90 boolean bNegative = FALSE;
91 double aTablePos[] = { 0, 1e1, 1e2, 1e4, 1e8, 1e16, 1e32, 1e64, 1e128,
92 1e256 };
93 double aTableNeg[] = { 0, 1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32, 1e-64, 1e-128,
94 1e-256 };
95 double* pTable = aTablePos;
96 int nTableSize = STD_ARRAY_SIZE( aTablePos );
97
98 if( 0 == nPow )
99 {
100 return 1.0;
101 }
102
103 if( nPow < 0 )
104 {
105 bNegative = TRUE;
106 nPow = -nPow;
107 pTable = aTableNeg;
108 nTableSize = STD_ARRAY_SIZE( aTableNeg );
109 }
110
111 for( nI = 1; nPow && (nI < nTableSize); nI++ )
112 {
113 if( nPow & 1 )
114 {
115 dRet *= pTable[nI];
116 }
117
118 nPow >>= 1;
119 }
120
121 if( nPow )
122 {
123 // Overflow. Trying to compute a large power value.
124 uint64 ulInf = STD_DTOA_FP_POSITIVE_INF;
125 dRet = bNegative ? 0 : UINT64_TO_DOUBLE( ulInf );
126 }
127
128 return dRet;
129 }
130
fp_round(double dNumber,int nPrecision)131 double fp_round( double dNumber, int nPrecision )
132 //
133 // This functions rounds dNumber to the specified precision nPrecision.
134 // For example:
135 // fp_round(2.34553, 3) = 2.346
136 // fp_round(2.34553, 4) = 2.3455
137 //
138 {
139 double dResult = dNumber;
140 double dRoundingFactor = FP_POW_10( -nPrecision ) * 0.5;
141
142 if( dNumber < 0 )
143 {
144 dResult = dNumber - dRoundingFactor;
145 }
146 else
147 {
148 dResult = dNumber + dRoundingFactor;
149 }
150
151 return dResult;
152 }
153
fp_log_10(double dNumber)154 int fp_log_10( double dNumber )
155 //
156 // This function finds the integer part of the log_10( dNumber ).
157 // The function assumes that dNumber != 0.
158 //
159 {
160 // Absorb the negative sign
161 if( dNumber < 0 )
162 {
163 dNumber = -dNumber;
164 }
165
166 return (int)( floor( log10( dNumber ) ) );
167 }
168
fp_check_special_cases(double dNumber,FloatingPointType * pNumberType)169 int fp_check_special_cases( double dNumber, FloatingPointType* pNumberType )
170 //
171 // This function evaluates the input floating-point number dNumber to check for
172 // following special cases: NaN, +/-Infinity.
173 // The evaluation is based on the IEEE Standard 754 for Floating Point Numbers
174 //
175 {
176 int nError = AEE_SUCCESS;
177 FloatingPointType NumberType = FP_TYPE_UNKOWN;
178 uint64 ullValue = 0;
179 uint64 ullSign = 0;
180 int64 n64Exponent = 0;
181 uint64 ullMantissa = 0;
182
183 ullValue = DOUBLE_TO_UINT64( dNumber );
184
185 // Extract the sign, exponent and mantissa
186 ullSign = FP_SIGN( ullValue );
187 n64Exponent = FP_EXPONENT_BIASED( ullValue );
188 ullMantissa = FP_MANTISSA_DENORM( ullValue );
189
190 //
191 // Rules for special cases are listed below:
192 // For Infinity, the following needs to be true:
193 // 1. Exponent should have all bits set to 1.
194 // 2. Mantissa should have all bits set to 0.
195 //
196 // For NaN, the following needs to be true:
197 // 1. Exponent should have all bits set to 1.
198 // 2. Mantissa should be non-zero.
199 // Note that we do not differentiate between QNaNs and SNaNs.
200 //
201 if( STD_DTOA_DP_INFINITY_EXPONENT_ID == n64Exponent )
202 {
203 if( 0 == ullMantissa )
204 {
205 // Inifinity.
206 if( ullSign )
207 {
208 NumberType = FP_TYPE_NEGATIVE_INF;
209 }
210 else
211 {
212 NumberType = FP_TYPE_POSITIVE_INF;
213 }
214 }
215 else
216 {
217 // NaN
218 NumberType = FP_TYPE_NAN;
219 }
220 }
221 else
222 {
223 // A normal number
224 NumberType = FP_TYPE_GENERAL;
225 }
226
227 // Set the output value
228 *pNumberType = NumberType;
229
230 return nError;
231 }
232
std_dtoa_decimal(double dNumber,int nPrecision,char acIntegerPart[STD_DTOA_FORMAT_INTEGER_SIZE],char acFractionPart[STD_DTOA_FORMAT_FRACTION_SIZE])233 int std_dtoa_decimal( double dNumber, int nPrecision,
234 char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ],
235 char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ] )
236 {
237 int nError = AEE_SUCCESS;
238 boolean bNegativeNumber = FALSE;
239 double dIntegerPart = 0.0;
240 double dFractionPart = 0.0;
241 double dTempIp = 0.0;
242 double dTempFp = 0.0;
243 int nMaxIntDigs = STD_DTOA_FORMAT_INTEGER_SIZE;
244 uint32 ulI = 0;
245 int nIntStartPos = 0;
246
247 // Optimization: Special case an input of 0
248 if( 0.0 == dNumber )
249 {
250 acIntegerPart[0] = '0';
251 acIntegerPart[1] = '\0';
252
253 for( ulI = 0; (ulI < STD_DTOA_FORMAT_FRACTION_SIZE - 1) && (nPrecision > 0);
254 ulI++, nPrecision-- )
255 {
256 acFractionPart[ulI] = '0';
257 }
258 acFractionPart[ ulI ] = '\0';
259
260 goto bail;
261 }
262
263 // Absorb the negative sign
264 if( dNumber < 0 )
265 {
266 acIntegerPart[0] = '-';
267 nIntStartPos = 1;
268 dNumber = -dNumber;
269 bNegativeNumber = TRUE;
270 }
271
272 // Split the input number into it's integer and fraction parts
273 dFractionPart = modf( dNumber, &dIntegerPart );
274
275 // First up, convert the integer part
276 if( 0.0 == dIntegerPart )
277 {
278 acIntegerPart[ nIntStartPos ] = '0';
279 }
280 else
281 {
282 double dRoundingConst = FP_POW_10( -STD_DTOA_PRECISION_ROUNDING_VALUE );
283 int nIntDigs = 0;
284 int nI = 0;
285
286 // Compute the number of digits in the integer part of the number
287 nIntDigs = fp_log_10( dIntegerPart ) + 1;
288
289 // For negative numbers, a '-' sign has already been written.
290 if( TRUE == bNegativeNumber )
291 {
292 nIntDigs++;
293 }
294
295 // Check for overflow
296 if( nIntDigs >= nMaxIntDigs )
297 {
298 // Overflow!
299 // Note that currently, we return a simple AEE_EFAILED for all
300 // errors.
301 nError = AEE_EFAILED;
302 goto bail;
303 }
304
305 // Null Terminate the string
306 acIntegerPart[ nIntDigs ] = '\0';
307
308 for( nI = nIntDigs - 1; nI >= nIntStartPos; nI-- )
309 {
310 dIntegerPart = dIntegerPart / 10.0;
311 dTempFp = modf( dIntegerPart, &dTempIp );
312
313 // Round it to the a specific precision
314 dTempFp = dTempFp + dRoundingConst;
315
316 // Convert the digit to a character
317 acIntegerPart[ nI ] = (int)( dTempFp * 10 ) + '0';
318 if( !MY_ISDIGIT( acIntegerPart[ nI ] ) )
319 {
320 // Overflow!
321 // Note that currently, we return a simple AEE_EFAILED for all
322 // errors.
323 nError = AEE_EFAILED;
324 goto bail;
325 }
326 dIntegerPart = dTempIp;
327 }
328 }
329
330 // Just a double check for integrity sake. This should ideally never happen.
331 // Out of bounds scenario. That is, the integer part of the input number is
332 // too large.
333 if( dIntegerPart != 0.0 )
334 {
335 // Note that currently, we return a simple AEE_EFAILED for all
336 // errors.
337 nError = AEE_EFAILED;
338 goto bail;
339 }
340
341 // Now, convert the fraction part
342 for( ulI = 0; ( nPrecision > 0 ) && ( ulI < STD_DTOA_FORMAT_FRACTION_SIZE - 1 );
343 nPrecision--, ulI++ )
344 {
345 if( 0.0 == dFractionPart )
346 {
347 acFractionPart[ ulI ] = '0';
348 }
349 else
350 {
351 double dRoundingValue = FP_POW_10( -( nPrecision +
352 STD_DTOA_PRECISION_ROUNDING_VALUE ) );
353 acFractionPart[ ulI ] = (int)( ( dFractionPart + dRoundingValue ) * 10.0 ) + '0';
354 if( !MY_ISDIGIT( acFractionPart[ ulI ] ) )
355 {
356 // Overflow!
357 // Note that currently, we return a simple AEE_EFAILED for all
358 // errors.
359 nError = AEE_EFAILED;
360 goto bail;
361 }
362
363 dFractionPart = ( dFractionPart * 10.0 ) -
364 (int)( ( dFractionPart + FP_POW_10( -nPrecision - 6 ) ) * 10.0 );
365 }
366 }
367
368
369 bail:
370
371 return nError;
372 }
373
std_dtoa_hex(double dNumber,int nPrecision,char cFormat,char acIntegerPart[STD_DTOA_FORMAT_INTEGER_SIZE],char acFractionPart[STD_DTOA_FORMAT_FRACTION_SIZE],int * pnExponent)374 int std_dtoa_hex( double dNumber, int nPrecision, char cFormat,
375 char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ],
376 char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ],
377 int* pnExponent )
378 {
379 int nError = AEE_SUCCESS;
380 uint64 ullMantissa = 0;
381 uint64 ullSign = 0;
382 int64 n64Exponent = 0;
383 static const char HexDigitsU[] = "0123456789ABCDEF";
384 static const char HexDigitsL[] = "0123456789abcde";
385 boolean bFirstDigit = TRUE;
386 int nI = 0;
387 int nF = 0;
388 uint64 ullValue = DOUBLE_TO_UINT64( dNumber );
389 int nManShift = 0;
390 const char *pcDigitArray = ( cFormat == 'A' ) ? HexDigitsU : HexDigitsL;
391 boolean bPrecisionSpecified = TRUE;
392
393 // If no precision is specified, then set the precision to be fairly
394 // large.
395 if( nPrecision < 0 )
396 {
397 nPrecision = STD_DTOA_FORMAT_FRACTION_SIZE;
398 bPrecisionSpecified = FALSE;
399 }
400 else
401 {
402 bPrecisionSpecified = TRUE;
403 }
404
405 // Extract the sign, exponent and mantissa
406 ullSign = FP_SIGN( ullValue );
407 n64Exponent = FP_EXPONENT( ullValue );
408 ullMantissa = FP_MANTISSA( ullValue );
409
410 // Write out the sign
411 if( ullSign )
412 {
413 acIntegerPart[ nI++ ] = '-';
414 }
415
416 // Optimization: Special case an input of 0
417 if( 0.0 == dNumber )
418 {
419 acIntegerPart[0] = '0';
420 acIntegerPart[1] = '\0';
421
422 for( nF = 0; (nF < STD_DTOA_FORMAT_FRACTION_SIZE - 1) && (nPrecision > 0);
423 nF++, nPrecision-- )
424 {
425 acFractionPart[nF] = '0';
426 }
427 acFractionPart[nF] = '\0';
428
429 goto bail;
430 }
431
432 // The mantissa is in lower 53 bits (52 bits + an implicit 1).
433 // If we are dealing with a denormalized number, then the implicit 1
434 // is absent. The above macros would have then set that bit to 0.
435 // Shift the mantisaa on to the highest bits.
436
437 if( 0 == ( n64Exponent + STD_DTOA_DP_EXPONENT_BIAS ) )
438 {
439 // DENORMALIZED NUMBER.
440 // A denormalized number is of the form:
441 // 0.bbb...bbb x 2^Exponent
442 // Shift the mantissa to the higher bits while discarding the leading 0
443 ullMantissa <<= 12;
444
445 // Lets update the exponent so as to make sure that the first hex value
446 // in the mantissa is non-zero, i.e., at least one of the first 4 bits is
447 // non-zero.
448 nManShift = std_dtoa_clz64( ullMantissa ) - 3;
449 if( nManShift > 0 )
450 {
451 ullMantissa <<= nManShift;
452 n64Exponent -= nManShift;
453 }
454 }
455 else
456 {
457 // NORMALIZED NUMBER.
458 // A normalized number has the following form:
459 // 1.bbb...bbb x 2^Exponent
460 // Shift the mantissa to the higher bits while retaining the leading 1
461 ullMantissa <<= 11;
462 }
463
464 // Now, lets get the decimal point out of the picture by shifting the
465 // exponent by 1.
466 n64Exponent++;
467
468 // Read the mantissa four bits at a time to form the hex output
469 for( nI = 0, nF = 0, bFirstDigit = TRUE; ullMantissa != 0;
470 ullMantissa <<= 4 )
471 {
472 uint64 ulHexVal = ullMantissa & 0xF000000000000000uLL;
473 ulHexVal >>= 60;
474 if( bFirstDigit )
475 {
476 // Write to the integral part of the number
477 acIntegerPart[ nI++ ] = pcDigitArray[ulHexVal];
478 bFirstDigit = FALSE;
479 }
480 else if( nF < nPrecision )
481 {
482 // Write to the fractional part of the number
483 acFractionPart[ nF++ ] = pcDigitArray[ulHexVal];
484 }
485 }
486
487 // Pad the fraction with trailing zeroes upto the specified precision
488 for( ; bPrecisionSpecified && (nF < nPrecision); nF++ )
489 {
490 acFractionPart[ nF ] = '0';
491 }
492
493 // Now the output is of the form;
494 // h.hhh x 2^Exponent
495 // where h is a non-zero hexadecimal number.
496 // But we were dealing with a binary fraction 0.bbb...bbb x 2^Exponent.
497 // Therefore, we need to subtract 4 from the exponent (since the shift
498 // was to the base 16 and the exponent is to the base 2).
499 n64Exponent -= 4;
500 *pnExponent = (int)n64Exponent;
501
502 bail:
503 return nError;
504 }
505