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