basic/qa/basic_coverage/test_cstr_method.vb | 43 +++++++ basic/qa/vba_tests/cstr.vb | 10 + basic/source/sbx/sbxscan.cxx | 157 +--------------------------- 3 files changed, 58 insertions(+), 152 deletions(-)
New commits: commit da0d6541b29f4dd3cd223e15be14dabc2704fb83 Author: Andreas Heinisch <andreas.heini...@yahoo.de> AuthorDate: Wed Sep 29 18:19:35 2021 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Thu Sep 30 15:12:56 2021 +0200 tdf#143575, tdf#143974 - Use rtl::math::doubleToUString to convert numbers to strings Change-Id: I1427dbd49af680a1bf386410977c9cb2b0a3961e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122831 Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de> Tested-by: Andreas Heinisch <andreas.heini...@yahoo.de> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122880 Tested-by: Jenkins diff --git a/basic/qa/basic_coverage/test_cstr_method.vb b/basic/qa/basic_coverage/test_cstr_method.vb index 53484b06fe17..6635bae746be 100644 --- a/basic/qa/basic_coverage/test_cstr_method.vb +++ b/basic/qa/basic_coverage/test_cstr_method.vb @@ -6,11 +6,48 @@ ' file, You can obtain one at http://mozilla.org/MPL/2.0/. ' -Function doUnitTest as Integer - ' CSTR - If (CStr(100) <> "100") Then +Dim passCount As Integer +Dim failCount As Integer +Dim result As String + +Function doUnitTest() As String + result = verify_testCStr() + If failCount <> 0 Or passCount = 0 Then doUnitTest = 0 Else doUnitTest = 1 End If End Function + +Function verify_testCStr() As String + + passCount = 0 + failCount = 0 + + result = "Test Results" & Chr$(10) & "============" & Chr$(10) + + ' CSTR + TestLog_ASSERT CStr(100), "100", "CStr(100)" + + ' tdf#143575 - round string to their nearest double representation + ' Without the fix in place, this test would have failed with: + ' - Expected: 691.2 + ' - Actual : 691.2000000000001 + TestLog_ASSERT CStr(691.2), "691.2", "CStr(691.2)" + ' Without the fix in place, this test would have failed with: + ' - Expected: 691.2 + ' - Actual : 691.1999999999999 + TestLog_ASSERT CStr(123.4 + 567.8), "691.2", "CStr(123.4 + 567.8)" + + result = result & Chr$(10) & "Tests passed: " & passCount & Chr$(10) & "Tests failed: " & failCount & Chr$(10) + verify_testCStr = result +End Function + +Sub TestLog_ASSERT(actual As Variant, expected As Variant, testName As String) + If expected = actual Then + passCount = passCount + 1 + Else + result = result & Chr$(10) & "Failed: " & testName & " returned " & actual & ", expected " & expected + failCount = failCount + 1 + End If +End Sub diff --git a/basic/qa/vba_tests/cstr.vb b/basic/qa/vba_tests/cstr.vb index 55e1ab049fab..dfa77b7db1f0 100644 --- a/basic/qa/vba_tests/cstr.vb +++ b/basic/qa/vba_tests/cstr.vb @@ -23,6 +23,16 @@ Sub verify_testCStr() TestUtil.AssertEqual(CStr(n), "437.324", "CStr(n)") TestUtil.AssertEqual(CStr(500), "500", "CStr(500)") + ' tdf#143575 - round string to their nearest double representation + ' Without the fix in place, this test would have failed with: + ' - Expected: 691.2 + ' - Actual : 691.2000000000001 + TestUtil.AssertEqual(CStr(691.2), "691.2", "CStr(691.2)") + ' Without the fix in place, this test would have failed with: + ' - Expected: 691.2 + ' - Actual : 691.1999999999999 + TestUtil.AssertEqual(CStr(123.4 + 567.8), "691.2", "CStr(123.4 + 567.8)") + Exit Sub errorHandler: TestUtil.ReportErrorHandler("verify_testCStr", Err, Error$, Erl) diff --git a/basic/source/sbx/sbxscan.cxx b/basic/source/sbx/sbxscan.cxx index 0a7be60432a7..2d42c2351d4f 100644 --- a/basic/source/sbx/sbxscan.cxx +++ b/basic/source/sbx/sbxscan.cxx @@ -297,134 +297,6 @@ ErrCode SbxValue::ScanNumIntnl( const OUString& rSrc, double& nVal, bool bSingle return nRetError; } - -const double roundArray[] = { - 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6, 0.5e-7, - 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,0.5e-15 }; - -/* -|* -|* void myftoa( double, char *, short, short, bool, bool ) -|* -|* description: conversion double --> ASCII -|* parameters: double the number -|* char * target buffer -|* short number of positions after decimal point -|* short range of the exponent ( 0=no E ) -|* bool true: with 1000-separators -|* bool true: output without formatting -|* - */ - -static void myftoa( double nNum, char * pBuf, short nPrec, short nExpWidth ) -{ - - short nExp = 0; - short nDig = nPrec + 1; - short nDec; // number of positions before decimal point - int i; - - sal_Unicode cDecimalSep, cThousandSep, cDecimalSepAlt; - ImpGetIntntlSep( cDecimalSep, cThousandSep, cDecimalSepAlt ); - - // compute exponent - nExp = 0; - if( nNum > 0.0 ) - { - while( nNum < 1.0 ) - { - nNum *= 10.0; - nExp--; - } - while( nNum >= 10.0 ) - { - nNum /= 10.0; - nExp++; - } - } - if( !nPrec ) - nDig = nExp + 1; - - // round number - if( (nNum += roundArray [std::min<short>( nDig, 16 )] ) >= 10.0 ) - { - nNum = 1.0; - ++nExp; - if( !nExpWidth ) ++nDig; - } - - // determine positions before decimal point - if( !nExpWidth ) - { - if( nExp < 0 ) - { - // #41691: also a 0 at bFix - *pBuf++ = '0'; - if( nPrec ) *pBuf++ = static_cast<char>(cDecimalSep); - i = -nExp - 1; - if( nDig <= 0 ) i = nPrec; - while( i-- ) *pBuf++ = '0'; - nDec = 0; - } - else - nDec = nExp+1; - } - else - nDec = 1; - - // output number - if( nDig > 0 ) - { - int digit; - for( i = 0 ; ; ++i ) - { - if( i < 16 ) - { - digit = static_cast<int>(nNum); - *pBuf++ = sal::static_int_cast< char >(digit + '0'); - nNum =( nNum - digit ) * 10.0; - } else - *pBuf++ = '0'; - if( --nDig == 0 ) break; - if( nDec ) - { - nDec--; - if( !nDec ) - *pBuf++ = static_cast<char>(cDecimalSep); - } - } - } - - // output exponent - if( nExpWidth ) - { - if( nExpWidth < 3 ) nExpWidth = 3; - nExpWidth -= 2; - *pBuf++ = 'E'; - if ( nExp < 0 ) - { - nExp = -nExp; - *pBuf++ = '-'; - } - else - *pBuf++ = '+'; - while( nExpWidth > 3 ) - { - *pBuf++ = '0'; - nExpWidth--; - } - if( nExp >= 100 || nExpWidth == 3 ) - { - *pBuf++ = sal::static_int_cast< char >(nExp/100 + '0'); - nExp %= 100; - } - if( nExp/10 || nExpWidth >= 2 ) - *pBuf++ = sal::static_int_cast< char >(nExp/10 + '0'); - *pBuf++ = sal::static_int_cast< char >(nExp%10 + '0'); - } - *pBuf = 0; -} - // The number is prepared unformattedly with the given number of // NK-positions. A leading minus is added if applicable. // This routine is public because it's also used by the Put-functions @@ -432,32 +304,19 @@ static void myftoa( double nNum, char * pBuf, short nPrec, short nExpWidth ) void ImpCvtNum( double nNum, short nPrec, OUString& rRes, bool bCoreString ) { - char *q; - char cBuf[ 40 ], *p = cBuf; - sal_Unicode cDecimalSep, cThousandSep, cDecimalSepAlt; ImpGetIntntlSep( cDecimalSep, cThousandSep, cDecimalSepAlt ); if( bCoreString ) cDecimalSep = '.'; - if( nNum < 0.0 ) { - nNum = -nNum; - *p++ = '-'; - } - double dMaxNumWithoutExp = (nPrec == 6) ? 1E6 : 1E14; - myftoa( nNum, p, nPrec,( nNum &&( nNum < 1E-1 || nNum >= dMaxNumWithoutExp ) ) ? 4:0 ); - // remove trailing zeros - for( p = cBuf; *p &&( *p != 'E' ); p++ ) {} - q = p; p--; - while( nPrec && *p == '0' ) - { - nPrec--; - p--; - } - if( *p == cDecimalSep ) p--; - while( *q ) *++p = *q++; - *++p = 0; - rRes = OUString::createFromAscii( cBuf ); + const double dMaxNumWithoutExp = (nPrec == 6) ? 1E6 : 1E14; + rtl_math_StringFormat aMathStringFormat + = (nNum && (std::abs(nNum) < 1E-1 || std::abs(nNum) >= dMaxNumWithoutExp)) + ? rtl_math_StringFormat_E2 + : rtl_math_StringFormat_F; + + // tdf#143575 - use rtl::math::doubleToUString to convert numbers to strings in basic + rRes = rtl::math::doubleToUString(nNum, aMathStringFormat, nPrec, cDecimalSep, true); } bool ImpConvStringExt( OUString& rSrc, SbxDataType eTargetType )