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