• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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