summaryrefslogtreecommitdiff
path: root/svl
diff options
context:
space:
mode:
authorVladimir Glazunov <vg@openoffice.org>2010-05-28 08:57:30 +0200
committerVladimir Glazunov <vg@openoffice.org>2010-05-28 08:57:30 +0200
commit314ac1b55ff305fb9552a18f4756fcdb9d2b5fdb (patch)
tree5f38890d76efd10bf0f9a525d2f2c19edcf8e06f /svl
parent5c40015cde351ed33cdb4364607b1d6c1c3f20ae (diff)
parent95d72876f31b2b0d4c398236354401ee93ac6b72 (diff)
CWS-TOOLING: integrate CWS koheiautodecimal
Diffstat (limited to 'svl')
-rw-r--r--svl/inc/svl/zforlist.hxx13
-rw-r--r--svl/inc/svl/zformat.hxx7
-rw-r--r--svl/source/numbers/zforlist.cxx20
-rw-r--r--svl/source/numbers/zformat.cxx180
-rw-r--r--svl/source/numbers/zforscan.cxx2
-rw-r--r--svl/source/numbers/zforscan.hxx6
6 files changed, 182 insertions, 46 deletions
diff --git a/svl/inc/svl/zforlist.hxx b/svl/inc/svl/zforlist.hxx
index 00f2dbe92b4c..598295797ea6 100644
--- a/svl/inc/svl/zforlist.hxx
+++ b/svl/inc/svl/zforlist.hxx
@@ -333,6 +333,17 @@ class SvNumberFormatterRegistry_Impl;
class SVL_DLLPUBLIC SvNumberFormatter
{
public:
+ /**
+ * We can't technically have an "infinite" value, so we use an arbitrary
+ * upper precision threshold to represent the "unlimited" precision.
+ */
+ static const sal_uInt16 UNLIMITED_PRECISION;
+
+ /**
+ * Precision suitable for numbers displayed in input bar, for instance
+ * Calc's formula input bar.
+ */
+ static const sal_uInt16 INPUTSTRING_PRECISION;
/// Preferred ctor with service manager and language/country enum
SvNumberFormatter(
@@ -583,7 +594,7 @@ public:
/// Return the reference date
Date* GetNullDate();
/// Return the standard decimal precision
- short GetStandardPrec();
+ sal_uInt16 GetStandardPrec();
/// Return whether zero suppression is switched on
BOOL GetNoZero() { return bNoZero; }
/** Get the type of a format (or NUMBERFORMAT_UNDEFINED if no entry),
diff --git a/svl/inc/svl/zformat.hxx b/svl/inc/svl/zformat.hxx
index 7cdcf4db518d..7c361382796a 100644
--- a/svl/inc/svl/zformat.hxx
+++ b/svl/inc/svl/zformat.hxx
@@ -236,6 +236,12 @@ public:
// in fact that could be any string used in number formats.
static void LoadString( SvStream& rStream, String& rStr );
+ /**
+ * Get output string from a numeric value that fits the number of
+ * characters specified.
+ */
+ bool GetOutputString( double fNumber, sal_uInt16 nCharCount, String& rOutString ) const;
+
BOOL GetOutputString( double fNumber, String& OutString, Color** ppColor );
BOOL GetOutputString( String& sString, String& OutString, Color** ppColor );
@@ -487,6 +493,7 @@ private:
// standard number output
SVL_DLLPRIVATE void ImpGetOutputStandard( double& fNumber, String& OutString );
+ SVL_DLLPRIVATE void ImpGetOutputStdToPrecision( double& rNumber, String& rOutString, sal_uInt16 nPrecision ) const;
// numbers in input line
SVL_DLLPRIVATE void ImpGetOutputInputLine( double fNumber, String& OutString );
diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx
index 05dab66754e1..cb66a75558c2 100644
--- a/svl/source/numbers/zforlist.cxx
+++ b/svl/source/numbers/zforlist.cxx
@@ -61,6 +61,7 @@
#include <rtl/instance.hxx>
#include <math.h>
+#include <limits>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
@@ -178,6 +179,9 @@ SV_IMPL_PTRARR( NfWSStringsDtor, String* );
/***********************Funktionen SvNumberFormatter**************************/
+const sal_uInt16 SvNumberFormatter::UNLIMITED_PRECISION = ::std::numeric_limits<sal_uInt16>::max();
+const sal_uInt16 SvNumberFormatter::INPUTSTRING_PRECISION = ::std::numeric_limits<sal_uInt16>::max()-1;
+
SvNumberFormatter::SvNumberFormatter(
const Reference< XMultiServiceFactory >& xSMgr,
LanguageType eLang )
@@ -338,7 +342,7 @@ void SvNumberFormatter::ChangeStandardPrec(short nPrec)
pFormatScanner->ChangeStandardPrec(nPrec);
}
-short SvNumberFormatter::GetStandardPrec()
+sal_uInt16 SvNumberFormatter::GetStandardPrec()
{
return pFormatScanner->GetStandardPrec();
}
@@ -1473,7 +1477,6 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
String& sOutString)
{
SvNumberformat* pFormat;
- short nOldPrec;
Color* pColor;
pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
if (!pFormat)
@@ -1483,7 +1486,8 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
short eType = pFormat->GetType() & ~NUMBERFORMAT_DEFINED;
if (eType == 0)
eType = NUMBERFORMAT_DEFINED;
- nOldPrec = -1;
+ sal_uInt16 nOldPrec = pFormatScanner->GetStandardPrec();
+ bool bPrecChanged = false;
if (eType == NUMBERFORMAT_NUMBER || eType == NUMBERFORMAT_PERCENT
|| eType == NUMBERFORMAT_CURRENCY
|| eType == NUMBERFORMAT_SCIENTIFIC
@@ -1491,8 +1495,8 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
{
if (eType != NUMBERFORMAT_PERCENT) // spaeter Sonderbehandlung %
eType = NUMBERFORMAT_NUMBER;
- nOldPrec = pFormatScanner->GetStandardPrec();
- ChangeStandardPrec(300); // Merkwert
+ ChangeStandardPrec(INPUTSTRING_PRECISION);
+ bPrecChanged = true;
}
sal_uInt32 nKey = nFIndex;
switch ( eType )
@@ -1512,12 +1516,12 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
{
if ( eType == NUMBERFORMAT_TIME && pFormat->GetFormatPrecision() )
{
- nOldPrec = pFormatScanner->GetStandardPrec();
- ChangeStandardPrec(300); // Merkwert
+ ChangeStandardPrec(INPUTSTRING_PRECISION);
+ bPrecChanged = true;
}
pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
}
- if (nOldPrec != -1)
+ if (bPrecChanged)
ChangeStandardPrec(nOldPrec);
}
diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx
index 32c65b06d2f1..707b2362f0ed 100644
--- a/svl/source/numbers/zformat.cxx
+++ b/svl/source/numbers/zformat.cxx
@@ -54,6 +54,9 @@
#include "numhead.hxx"
#include <unotools/digitgroupingiterator.hxx>
#include "nfsymbol.hxx"
+
+#include <cmath>
+
using namespace svt;
namespace {
@@ -63,6 +66,10 @@ struct Gregorian
return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gregorian"));
}
};
+
+const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary...
+const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value.
+
}
const double _D_MAX_U_LONG_ = (double) 0xffffffff; // 4294967295.0
@@ -1774,47 +1781,62 @@ void SvNumberformat::Build50Formatstring( String& rStr ) const
void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString)
{
- USHORT nStandardPrec = rScan.GetStandardPrec();
+ sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
+
if ( fabs(fNumber) > 1.0E15 ) // #58531# war E16
+ {
+ nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
OutString = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_E, nStandardPrec /*2*/,
GetFormatter().GetNumDecimalSep().GetChar(0));
+ }
else
- {
+ ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec);
+}
+
+void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, String& rOutString, sal_uInt16 nPrecision) const
+{
+ // Make sure the precision doesn't go over the maximum allowable precision.
+ nPrecision = ::std::min(UPPER_PRECISION, nPrecision);
+
#if 0
{
- // debugger test case for ANSI standard correctness
- ::rtl::OUString aTest;
- // expect 0.00123 OK
- aTest = ::rtl::math::doubleToUString( 0.001234567,
- rtl_math_StringFormat_G, 3, '.', sal_True );
- // expect 123 OK
- aTest = ::rtl::math::doubleToUString( 123.4567,
- rtl_math_StringFormat_G, 3, '.', sal_True );
- // expect 123.5 OK
- aTest = ::rtl::math::doubleToUString( 123.4567,
- rtl_math_StringFormat_G, 4, '.', sal_True );
- // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
- // 1000 with an exponent equal to significant digits)
- // Currently (24-Jan-2003) we do fail in this case and output 1000
- // instead, negligible.
- aTest = ::rtl::math::doubleToUString( 999.6,
- rtl_math_StringFormat_G, 3, '.', sal_True );
- // expect what? result is 1.2e+004
- aTest = ::rtl::math::doubleToUString( 12345.6789,
- rtl_math_StringFormat_G, -3, '.', sal_True );
+ // debugger test case for ANSI standard correctness
+ ::rtl::OUString aTest;
+ // expect 0.00123 OK
+ aTest = ::rtl::math::doubleToUString( 0.001234567,
+ rtl_math_StringFormat_G, 3, '.', sal_True );
+ // expect 123 OK
+ aTest = ::rtl::math::doubleToUString( 123.4567,
+ rtl_math_StringFormat_G, 3, '.', sal_True );
+ // expect 123.5 OK
+ aTest = ::rtl::math::doubleToUString( 123.4567,
+ rtl_math_StringFormat_G, 4, '.', sal_True );
+ // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
+ // 1000 with an exponent equal to significant digits)
+ // Currently (24-Jan-2003) we do fail in this case and output 1000
+ // instead, negligible.
+ aTest = ::rtl::math::doubleToUString( 999.6,
+ rtl_math_StringFormat_G, 3, '.', sal_True );
+ // expect what? result is 1.2e+004
+ aTest = ::rtl::math::doubleToUString( 12345.6789,
+ rtl_math_StringFormat_G, -3, '.', sal_True );
}
#endif
- OutString = ::rtl::math::doubleToUString( fNumber,
- rtl_math_StringFormat_F, nStandardPrec /*2*/,
- GetFormatter().GetNumDecimalSep().GetChar(0), sal_True );
- if (OutString.GetChar(0) == '-' &&
- OutString.GetTokenCount('0') == OutString.Len())
- OutString.EraseLeadingChars('-'); // nicht -0
- }
- ImpTransliterate( OutString, NumFor[0].GetNatNum() );
- return;
+ // We decided to strip trailing zeros unconditionally, since binary
+ // double-precision rounding error makes it impossible to determine e.g.
+ // whether 844.10000000000002273737 is what the user has typed, or the
+ // user has typed 844.1 but IEEE 754 represents it that way internally.
+
+ rOutString = ::rtl::math::doubleToUString( rNumber,
+ rtl_math_StringFormat_F, nPrecision /*2*/,
+ GetFormatter().GetNumDecimalSep().GetChar(0), true );
+ if (rOutString.GetChar(0) == '-' &&
+ rOutString.GetTokenCount('0') == rOutString.Len())
+ rOutString.EraseLeadingChars('-'); // nicht -0
+
+ ImpTransliterate( rOutString, NumFor[0].GetNatNum() );
}
void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString)
@@ -1955,6 +1977,71 @@ ULONG SvNumberformat::ImpGGTRound(ULONG x, ULONG y)
}
}
+namespace {
+
+void lcl_GetOutputStringScientific(
+ double fNumber, sal_uInt16 nCharCount, const SvNumberFormatter& rFormatter, String& rOutString)
+{
+ bool bSign = ::rtl::math::isSignBitSet(fNumber);
+
+ // 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7).
+ sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0;
+ if (nPrec && bSign)
+ // Make room for the negative sign.
+ --nPrec;
+
+ nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals.
+
+ rOutString = ::rtl::math::doubleToUString(
+ fNumber, rtl_math_StringFormat_E, nPrec, rFormatter.GetNumDecimalSep().GetChar(0));
+}
+
+}
+
+bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, String& rOutString) const
+{
+ using namespace std;
+
+ if (eType != NUMBERFORMAT_NUMBER)
+ return false;
+
+ double fTestNum = fNumber;
+ bool bSign = ::rtl::math::isSignBitSet(fTestNum);
+ if (bSign)
+ fTestNum = -fTestNum;
+
+ if (fTestNum < EXP_LOWER_BOUND)
+ {
+ lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
+ return true;
+ }
+
+ double fExp = log10(fTestNum);
+ // Values < 1.0 always have one digit before the decimal point.
+ sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1;
+
+ if (nDigitPre > 15)
+ {
+ lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
+ return true;
+ }
+
+ sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0;
+ if (nPrec && bSign)
+ // Subtract the negative sign.
+ --nPrec;
+ if (nPrec)
+ // Subtract the decimal point.
+ --nPrec;
+
+ ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec);
+ if (rOutString.Len() > nCharCount)
+ // String still wider than desired. Switch to scientific notation.
+ lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
+
+ return true;
+}
+
BOOL SvNumberformat::GetOutputString(double fNumber,
String& OutString,
Color** ppColor)
@@ -1978,16 +2065,43 @@ BOOL SvNumberformat::GetOutputString(double fNumber,
BOOL bHadStandard = FALSE;
if (bStandard) // einzelne Standardformate
{
- if (rScan.GetStandardPrec() == 300) // alle Zahlformate InputLine
+ if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // alle Zahlformate InputLine
{
ImpGetOutputInputLine(fNumber, OutString);
- return FALSE;
+ return false;
}
switch (eType)
{
case NUMBERFORMAT_NUMBER: // Standardzahlformat
+ {
+ if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION)
+ {
+ bool bSign = ::rtl::math::isSignBitSet(fNumber);
+ if (bSign)
+ fNumber = -fNumber;
+ ImpGetOutputStdToPrecision(fNumber, OutString, 10); // Use 10 decimals for general 'unlimited' format.
+ if (fNumber < EXP_LOWER_BOUND)
+ {
+ xub_StrLen nLen = OutString.Len();
+ if (!nLen)
+ return false;
+
+ if (nLen > 11)
+ {
+ sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
+ nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
+ OutString = ::rtl::math::doubleToUString( fNumber,
+ rtl_math_StringFormat_E, nStandardPrec /*2*/,
+ GetFormatter().GetNumDecimalSep().GetChar(0), true);
+ }
+ }
+ if (bSign)
+ OutString.Insert('-', 0);
+ return false;
+ }
ImpGetOutputStandard(fNumber, OutString);
bHadStandard = TRUE;
+ }
break;
case NUMBERFORMAT_DATE:
bRes |= ImpGetDateOutput(fNumber, 0, OutString);
diff --git a/svl/source/numbers/zforscan.cxx b/svl/source/numbers/zforscan.cxx
index 5ed78bd69108..fb59e4289ad1 100644
--- a/svl/source/numbers/zforscan.cxx
+++ b/svl/source/numbers/zforscan.cxx
@@ -465,7 +465,7 @@ void ImpSvNumberformatScan::ChangeNullDate(USHORT nDay, USHORT nMonth, USHORT nY
pNullDate = new Date(nDay, nMonth, nYear);
}
-void ImpSvNumberformatScan::ChangeStandardPrec(short nPrec)
+void ImpSvNumberformatScan::ChangeStandardPrec(sal_uInt16 nPrec)
{
nStandardPrec = nPrec;
}
diff --git a/svl/source/numbers/zforscan.hxx b/svl/source/numbers/zforscan.hxx
index fb9e40488e24..d623a3f50026 100644
--- a/svl/source/numbers/zforscan.hxx
+++ b/svl/source/numbers/zforscan.hxx
@@ -54,7 +54,7 @@ public:
void ChangeNullDate(USHORT nDay, USHORT nMonth, USHORT nYear);
// tauscht Referenzdatum aus
- void ChangeStandardPrec(short nPrec); // tauscht Standardprecision aus
+ void ChangeStandardPrec(sal_uInt16 nPrec); // tauscht Standardprecision aus
xub_StrLen ScanFormat( String& rString, String& rComment ); // Aufruf der Scan-Analyse
@@ -93,7 +93,7 @@ public:
InitKeywords();
return sNameStandardFormat;
}
- short GetStandardPrec() const { return nStandardPrec; }
+ sal_uInt16 GetStandardPrec() const { return nStandardPrec; }
const Color& GetRedColor() const { return StandardColor[4]; }
Color* GetColor(String& sStr); // Setzt Hauptfarben oder
// definierte Farben
@@ -158,7 +158,7 @@ private: // ---- privater Teil
// Array der Standardfarben
Date* pNullDate; // 30Dec1899
String sNameStandardFormat; // "Standard"
- short nStandardPrec; // default Precision fuer Standardformat (2)
+ sal_uInt16 nStandardPrec; // default Precision for Standardformat
SvNumberFormatter* pFormatter; // Pointer auf die Formatliste
String sStrArray[NF_MAX_FORMAT_SYMBOLS]; // Array der Symbole