diff options
author | Philipp Lohmann <pl@openoffice.org> | 2001-07-13 16:05:30 +0000 |
---|---|---|
committer | Philipp Lohmann <pl@openoffice.org> | 2001-07-13 16:05:30 +0000 |
commit | b521f61062ede11d802237690a5b4a5a7425941a (patch) | |
tree | 9befbe9e7f23a8b063d840567b4a476fe68dbfbb | |
parent | a862c2bb601d4c5a98cfefc26cff198024a2cf81 (diff) |
#89430# double to string conversion had too many rounding errors
-rw-r--r-- | sal/rtl/source/strimp.c | 152 |
1 files changed, 50 insertions, 102 deletions
diff --git a/sal/rtl/source/strimp.c b/sal/rtl/source/strimp.c index c968d680534a..acd806006c8a 100644 --- a/sal/rtl/source/strimp.c +++ b/sal/rtl/source/strimp.c @@ -2,9 +2,9 @@ * * $RCSfile: strimp.c,v $ * - * $Revision: 1.2 $ + * $Revision: 1.3 $ * - * last change: $Author: th $ $Date: 2001-04-03 12:03:57 $ + * last change: $Author: pl $ $Date: 2001-07-13 17:05:30 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -112,130 +112,78 @@ static sal_Int32 rtl_ImplFloatNumToString( sal_Char* pStr, sal_Int16 nSignificantDigits ) { sal_Char* pTempStr = pStr; - sal_Char* pEndStr; - sal_Int16 i; sal_Int16 nDigit; - sal_Int16 nDotPos; - sal_Int16 nExpDigits; - sal_Bool bExp; - sal_Bool bDotSet; - double dExp; - double dRem; + int nExp; + int nPowTen; + int nIntegralPart; + double fEpsilon; if ( d == 0.0 ) { - *pTempStr = '0'; - *pTempStr++; - *pTempStr = '.'; - *pTempStr++; - *pTempStr = '0'; - *pTempStr++; + *pTempStr++ = '0'; + *pTempStr++ = '.'; + *pTempStr++ = '0'; } else { if ( d < 0.0 ) { - *pTempStr = '-'; - *pTempStr++; + *pTempStr++ = '-'; d = -d; } - dExp = log10( d ); - bExp = sal_False; - if ( (dExp > 7) || (dExp <= -7) ) - bExp = sal_True; + nExp = (int)log10( d ); + if ( (nExp < 8) && (nExp > -7) ) + nExp = 0; - dExp = floor( dExp ); - d /= pow( 10, dExp ); - while ( d > 10 ) - { - d /= 10.0; - dExp += 1.0; - } - - if ( d < 1.0 ) - nSignificantDigits++; + d /= pow( 10, nExp ); + if( nExp < 0 && d < 1.0 ) + d *= 10.0, nExp--; - nDotPos = bExp ? 0 : (sal_Int16)dExp; - bDotSet = sal_False; - - /* handle leading zeros */ - if ( nDotPos < 0 ) + if( d >= 1.0 ) { - *pTempStr = '0'; - *pTempStr++; - *pTempStr = '.'; - *pTempStr++; - while( ++nDotPos < 0 ) - { - *pTempStr = '0'; - *pTempStr++; - } - pEndStr = pTempStr; - bDotSet = sal_True; - } - else - pEndStr = pTempStr; + nPowTen = (int)pow( 10, floor( log10( d ) ) ); + nIntegralPart = (int)d; + d -= (double)nIntegralPart; - for ( i=0; i < nSignificantDigits; i++ ) - { - nDigit = (sal_Int16)d; - *pTempStr = '0' + nDigit; - *pTempStr++; - if ( i == nDotPos && !bDotSet ) + do { - *pTempStr = '.'; - *pTempStr++; - pEndStr = pTempStr+1; /* We want one 0 behind the . */ - } - else if ( nDigit ) - pEndStr = pTempStr; - - d -= (double)nDigit; - d *= 10.0; + nDigit = nIntegralPart / nPowTen; + *pTempStr++ = nDigit + '0'; + nIntegralPart -= nPowTen * nDigit; + nPowTen /= 10; + nSignificantDigits--; + } while( nPowTen ); } - - /* Add/Kill trailing zeros */ - while ( pTempStr < pEndStr ) + else + *pTempStr++ = '0'; + *pTempStr++ = '.'; + /* avoid trailing zeros */ + fEpsilon = pow( 10, -nSignificantDigits ); + do { - *pTempStr = '0'; - pTempStr++; - } - pTempStr = pEndStr; + d *= 10, fEpsilon *= 10; + nIntegralPart = (int)d; + d -= (double)nIntegralPart; + *pTempStr++ = nIntegralPart + '0'; + } while( d >= fEpsilon && --nSignificantDigits > 0 ); - /* exponent */ - if ( bExp ) + if( nExp ) { - *pTempStr = 'E'; - *pTempStr++; - if ( dExp < 0.0 ) - { - dExp = -dExp; - *pTempStr = '-'; - *pTempStr++; - } - - nExpDigits = 1; - while ( dExp >= 10.0 ) + *pTempStr++ = 'E'; + if( nExp < 0 ) { - nExpDigits++; - dExp /= 10; + *pTempStr++ = '-'; + nExp = -nExp; } - for ( i=0; i < nExpDigits; i++ ) + nPowTen = (int)pow( 10, floor( log10( (double)nExp ) ) ); + do { - nDigit = (sal_Int16)dExp; /* sometimes if the debugger shows dExp= 2, the cast produces 1 */ - dRem = fmod( dExp, 1 ); - - /* max exponent is about 357 */ - if ( dRem >0.999 ) - nDigit++; - - *pTempStr = '0' + nDigit; - *pTempStr++; - - dExp -= (double)nDigit; - dExp *= 10.0; - } + nDigit = nExp / nPowTen; + *pTempStr++ = nDigit + '0'; + nExp -= nPowTen*nDigit; + nPowTen /= 10; + } while( nPowTen ); } } |