diff options
Diffstat (limited to 'sc/source/core/tool')
-rw-r--r-- | sc/source/core/tool/address.cxx | 8 | ||||
-rw-r--r-- | sc/source/core/tool/compiler.cxx | 47 | ||||
-rw-r--r-- | sc/source/core/tool/dbcolect.cxx | 23 | ||||
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 260 | ||||
-rw-r--r-- | sc/source/core/tool/interpr3.cxx | 252 | ||||
-rwxr-xr-x | sc/source/core/tool/interpr4.cxx | 48 | ||||
-rw-r--r-- | sc/source/core/tool/token.cxx | 25 |
7 files changed, 423 insertions, 240 deletions
diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx index 26a194b731ef..e24a4ff4158e 100644 --- a/sc/source/core/tool/address.cxx +++ b/sc/source/core/tool/address.cxx @@ -1648,8 +1648,8 @@ void ScAddress::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc, // External Reference, same as in ScCompiler::MakeTabStr() if( aTabName.GetChar(0) == '\'' ) { // "'Doc'#Tab" - xub_StrLen nPos = ScGlobal::FindUnquoted( aTabName, SC_COMPILER_FILE_TAB_SEP); - if (nPos != STRING_NOTFOUND && nPos > 0 && aTabName.GetChar(nPos-1) == '\'') + xub_StrLen nPos = ScCompiler::GetDocTabPos( aTabName); + if (nPos != STRING_NOTFOUND) { aDocName = aTabName.Copy( 0, nPos + 1 ); aTabName.Erase( 0, nPos + 1 ); @@ -1731,8 +1731,8 @@ lcl_Split_DocTab( const ScDocument* pDoc, SCTAB nTab, // External reference, same as in ScCompiler::MakeTabStr() if ( rTabName.GetChar(0) == '\'' ) { // "'Doc'#Tab" - xub_StrLen nPos = ScGlobal::FindUnquoted( rTabName, SC_COMPILER_FILE_TAB_SEP); - if (nPos != STRING_NOTFOUND && nPos > 0 && rTabName.GetChar(nPos-1) == '\'') + xub_StrLen nPos = ScCompiler::GetDocTabPos( rTabName); + if (nPos != STRING_NOTFOUND) { rDocName = rTabName.Copy( 0, nPos + 1 ); rTabName.Erase( 0, nPos + 1 ); diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 3dd25801532f..31964eff34be 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -855,18 +855,14 @@ struct ConventionOOO_A1 : public Convention_A1 aString = ScGlobal::GetRscString(STR_NO_REF_TABLE); else { - if ( aString.GetChar(0) == '\'' ) - { // "'Doc'#Tab" - xub_StrLen nPos = ScGlobal::FindUnquoted( aString, SC_COMPILER_FILE_TAB_SEP); - if (nPos != STRING_NOTFOUND && nPos > 0 && aString.GetChar(nPos-1) == '\'') - { - aDoc = aString.Copy( 0, nPos + 1 ); - aString.Erase( 0, nPos + 1 ); - aDoc = INetURLObject::decode( aDoc, INET_HEX_ESCAPE, + // "'Doc'#Tab" + xub_StrLen nPos = ScCompiler::GetDocTabPos( aString); + if (nPos != STRING_NOTFOUND) + { + aDoc = aString.Copy( 0, nPos + 1 ); + aString.Erase( 0, nPos + 1 ); + aDoc = INetURLObject::decode( aDoc, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS ); - } - else - aDoc.Erase(); } else aDoc.Erase(); @@ -1203,18 +1199,15 @@ struct ConventionXL } // Cheesy hack to unparse the OOO style "'Doc'#Tab" - if ( rTabName.GetChar(0) == '\'' ) + xub_StrLen nPos = ScCompiler::GetDocTabPos( rTabName); + if (nPos != STRING_NOTFOUND) { - xub_StrLen nPos = ScGlobal::FindUnquoted( rTabName, SC_COMPILER_FILE_TAB_SEP); - if (nPos != STRING_NOTFOUND && nPos > 0 && rTabName.GetChar(nPos-1) == '\'') - { - rDocName = rTabName.Copy( 0, nPos ); - // TODO : More research into how XL escapes the doc path - rDocName = INetURLObject::decode( rDocName, INET_HEX_ESCAPE, + rDocName = rTabName.Copy( 0, nPos ); + // TODO : More research into how XL escapes the doc path + rDocName = INetURLObject::decode( rDocName, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS ); - rTabName.Erase( 0, nPos + 1 ); - bHasDoc = true; - } + rTabName.Erase( 0, nPos + 1 ); + bHasDoc = true; } // XL uses the same sheet name quoting conventions in both modes @@ -1872,6 +1865,18 @@ void ScCompiler::CheckTabQuotes( String& rString, } } + +xub_StrLen ScCompiler::GetDocTabPos( const String& rString ) +{ + if (rString.GetChar(0) != '\'') + return STRING_NOTFOUND; + xub_StrLen nPos = ScGlobal::FindUnquoted( rString, SC_COMPILER_FILE_TAB_SEP); + // it must be 'Doc'# + if (nPos != STRING_NOTFOUND && rString.GetChar(nPos-1) != '\'') + nPos = STRING_NOTFOUND; + return nPos; +} + //--------------------------------------------------------------------------- void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv ) diff --git a/sc/source/core/tool/dbcolect.cxx b/sc/source/core/tool/dbcolect.cxx index 800716bef3b6..baf2c3de8c2a 100644 --- a/sc/source/core/tool/dbcolect.cxx +++ b/sc/source/core/tool/dbcolect.cxx @@ -2,7 +2,7 @@ * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright 2000, 2010 Oracle and/or its affiliates. + * Copyright 2000, 2011 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * @@ -753,6 +753,27 @@ ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCO return pNoNameData; // "unbenannt" nur zurueck, wenn sonst nichts gefunden } +ScDBData* ScDBCollection::GetFilterDBAtTable(SCTAB nTab) const +{ + ScDBData* pDataEmpty = NULL; + if (pItems) + { + for (sal_uInt16 i = 0; i < nCount; i++) + { + ScDBData* pDBTemp = (ScDBData*)pItems[i]; + if ( pDBTemp->nTable == nTab ) + { + sal_Bool bFilter = pDBTemp->HasAutoFilter() || pDBTemp->HasQueryParam(); + + if ( bFilter ) + return pDBTemp; + } + } + } + + return pDataEmpty; +} + sal_Bool ScDBCollection::SearchName( const String& rName, sal_uInt16& rIndex ) const { ScDBData aDataObj( rName, 0,0,0,0,0 ); diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 7e015e12d16e..c507c3970bb1 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -653,6 +653,7 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp if ( !rComp.bEmpty[1] && rComp.bVal[1] && !::rtl::math::isFinite( rComp.nVal[1])) return rComp.nVal[1]; + size_t nStringQuery = 0; // 0:=no, 1:=0, 2:=1 double fRes = 0; if ( rComp.bEmpty[ 0 ] ) { @@ -709,16 +710,22 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp } } else - fRes = -1; // number is less than string + { + fRes = -1; // number is less than string + nStringQuery = 2; // 1+1 + } } else if( rComp.bVal[ 1 ] ) - fRes = 1; // number is less than string + { + fRes = 1; // string is greater than number + nStringQuery = 1; // 0+1 + } else { // Both strings. if (pOptions) { - // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually + // All similar to ScTable::ValidQuery(), *rComp.pVal[1] actually // is/must be identical to *rEntry.pStr, which is essential for // regex to work through GetSearchTextPtr(). ScQueryEntry& rEntry = pOptions->aQueryEntry; @@ -768,6 +775,20 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp fRes = (double) ScGlobal::GetCaseCollator()->compareString( *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] ); } + if (nStringQuery && pOptions) + { + const ScQueryEntry& rEntry = pOptions->aQueryEntry; + if (!rEntry.bQueryByString && rEntry.pStr->Len() && + (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)) + { + // As in ScTable::ValidQuery() match a numeric string for a + // number query that originated from a string, e.g. in SUMIF + // and COUNTIF. Transliteration is not needed here. + bool bEqual = rComp.pVal[nStringQuery-1]->Equals( *rEntry.pStr); + // match => fRes=0, else fRes=1 + fRes = (rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual; + } + } return fRes; } @@ -6223,7 +6244,7 @@ void ScInterpreter::ScDBVarP() } -ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument* pDoc, +FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos, ScDocument* pDoc, const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1, const ScRefAddress* pRefAd2 ) { @@ -6265,7 +6286,7 @@ ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument rExtInfo.maTabName, nSheets); ScCompiler aComp( pDoc, rPos, *pTokenArray); aComp.CompileTokenArray(); - return pTokenArray; + return new FormulaSubroutineToken( pTokenArray); } @@ -6294,15 +6315,10 @@ void ScInterpreter::ScIndirect() { if (aExtInfo.mbExternal) { - /* TODO: future versions should implement a proper subroutine - * token. This procedure here is a minimally invasive fix for - * #i101645# in OOo3.1.1 */ - // Push a subroutine on the instruction code stack that - // resolves the external reference as the next instruction. - aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok, + // Push a subroutine that resolves the external reference as + // the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, aExtInfo, aRefAd, &aRefAd2)); - // Signal subroutine call to interpreter. - PushTempToken( new FormulaUnknownToken( ocCall)); } else PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(), @@ -6314,15 +6330,10 @@ void ScInterpreter::ScIndirect() { if (aExtInfo.mbExternal) { - /* TODO: future versions should implement a proper subroutine - * token. This procedure here is a minimally invasive fix for - * #i101645# in OOo3.1.1 */ - // Push a subroutine on the instruction code stack that - // resolves the external reference as the next instruction. - aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok, + // Push a subroutine that resolves the external reference as + // the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, aExtInfo, aRefAd, NULL)); - // Signal subroutine call to interpreter. - PushTempToken( new FormulaUnknownToken( ocCall)); } else PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() ); @@ -6441,9 +6452,27 @@ void ScInterpreter::ScAddressFunc() const ScAddress aAdr( nCol, nRow, 0); aAdr.Format( aRefStr, nFlags, pDok, aDetails ); - if( nParamCount >= 5 ) + if( nParamCount >= 5 && sTabStr.Len() ) { - ScCompiler::CheckTabQuotes( sTabStr, eConv); + String aDoc; + if (eConv == FormulaGrammar::CONV_OOO) + { + // Isolate Tab from 'Doc'#Tab + xub_StrLen nPos = ScCompiler::GetDocTabPos( sTabStr); + if (nPos != STRING_NOTFOUND) + { + if (sTabStr.GetChar(nPos+1) == '$') + ++nPos; // also split 'Doc'#$Tab + aDoc = sTabStr.Copy( 0, nPos+1); + sTabStr.Erase( 0, nPos+1); + } + } + /* TODO: yet unsupported external reference in CONV_XL_R1C1 syntax may + * need some extra handling to isolate Tab from Doc. */ + if (sTabStr.GetChar(0) != '\'' || sTabStr.GetChar(sTabStr.Len()-1) != '\'') + ScCompiler::CheckTabQuotes( sTabStr, eConv); + if (aDoc.Len()) + sTabStr.Insert( aDoc, 0); sTabStr += static_cast<sal_Unicode>(eConv == FormulaGrammar::CONV_XL_R1C1 ? '!' : '.'); sTabStr += aRefStr; PushString( sTabStr ); @@ -6453,6 +6482,24 @@ void ScInterpreter::ScAddressFunc() } +FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos, + ScDocument* pDoc, const FormulaTokenRef& xExtRef ) +{ + // The exact usage (which cell range) of the external table can't be + // detected during the store-to-file cycle, mark it as permanently + // referenced so it gets stored even if not directly referenced anywhere. + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + pRefMgr->setCacheTableReferencedPermanently( + static_cast<const ScToken*>(xExtRef.get())->GetIndex(), + static_cast<const ScToken*>(xExtRef.get())->GetString(), 1); + ScTokenArray* pTokenArray = new ScTokenArray; + pTokenArray->AddToken( *xExtRef); + ScCompiler aComp( pDoc, rPos, *pTokenArray); + aComp.CompileTokenArray(); + return new FormulaSubroutineToken( pTokenArray); +} + + void ScInterpreter::ScOffset() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOffset" ); @@ -6477,54 +6524,129 @@ void ScInterpreter::ScOffset() PushIllegalArgument(); return; } - if (GetStackType() == svSingleRef) - { - PopSingleRef(nCol1, nRow1, nTab1); - if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0)) - { - nCol1 = (SCCOL)((long) nCol1 + nColPlus); - nRow1 = (SCROW)((long) nRow1 + nRowPlus); - if (!ValidCol(nCol1) || !ValidRow(nRow1)) - PushIllegalArgument(); - else - PushSingleRef(nCol1, nRow1, nTab1); - } - else - { - if (nColNew < 0) - nColNew = 1; - if (nRowNew < 0) - nRowNew = 1; - nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 wird veraendert! - nRow1 = (SCROW)((long)nRow1+nRowPlus); - nCol2 = (SCCOL)((long)nCol1+nColNew-1); - nRow2 = (SCROW)((long)nRow1+nRowNew-1); - if (!ValidCol(nCol1) || !ValidRow(nRow1) || - !ValidCol(nCol2) || !ValidRow(nRow2)) - PushIllegalArgument(); - else - PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); - } - } - else if (GetStackType() == svDoubleRef) + FormulaTokenRef xExtRef; + switch (GetStackType()) { - PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); - if (nColNew < 0) - nColNew = nCol2 - nCol1 + 1; - if (nRowNew < 0) - nRowNew = nRow2 - nRow1 + 1; - nCol1 = (SCCOL)((long)nCol1+nColPlus); - nRow1 = (SCROW)((long)nRow1+nRowPlus); - nCol2 = (SCCOL)((long)nCol1+nColNew-1); - nRow2 = (SCROW)((long)nRow1+nRowNew-1); - if (!ValidCol(nCol1) || !ValidRow(nRow1) || - !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2) - PushIllegalArgument(); - else - PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); + case svExternalSingleRef: + xExtRef = PopToken()->Clone(); + // fallthru + case svSingleRef: + { + if (xExtRef) + { + ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef(); + rData.CalcAbsIfRel( aPos); + nCol1 = rData.nCol; + nRow1 = rData.nRow; + nTab1 = rData.nTab; + } + else + PopSingleRef( nCol1, nRow1, nTab1); + if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0)) + { + nCol1 = (SCCOL)((long) nCol1 + nColPlus); + nRow1 = (SCROW)((long) nRow1 + nRowPlus); + if (!ValidCol(nCol1) || !ValidRow(nRow1)) + PushIllegalArgument(); + else if (xExtRef) + { + ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef(); + rData.nCol = nCol1; + rData.nRow = nRow1; + rData.nTab = nTab1; + rData.CalcRelFromAbs( aPos); + // Push a subroutine that resolves the external + // reference as the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); + } + else + PushSingleRef(nCol1, nRow1, nTab1); + } + else + { + if (nColNew < 0) + nColNew = 1; + if (nRowNew < 0) + nRowNew = 1; + nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 is modified + nRow1 = (SCROW)((long)nRow1+nRowPlus); + nCol2 = (SCCOL)((long)nCol1+nColNew-1); + nRow2 = (SCROW)((long)nRow1+nRowNew-1); + if (!ValidCol(nCol1) || !ValidRow(nRow1) || + !ValidCol(nCol2) || !ValidRow(nRow2)) + PushIllegalArgument(); + else if (xExtRef) + { + // Convert SingleRef to DoubleRef. + xExtRef = new ScExternalDoubleRefToken( + *static_cast<const ScExternalSingleRefToken*>(xExtRef.get())); + ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); + rData.Ref1.nCol = nCol1; + rData.Ref1.nRow = nRow1; + rData.Ref1.nTab = nTab1; + rData.Ref2.nCol = nCol2; + rData.Ref2.nRow = nRow2; + rData.Ref2.nTab = nTab1; + rData.CalcRelFromAbs( aPos); + // Push a subroutine that resolves the external + // reference as the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); + } + else + PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); + } + } + break; + case svExternalDoubleRef: + xExtRef = PopToken()->Clone(); + // fallthru + case svDoubleRef: + { + if (xExtRef) + { + ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); + rData.CalcAbsIfRel( aPos); + nCol1 = rData.Ref1.nCol; + nRow1 = rData.Ref1.nRow; + nTab1 = rData.Ref1.nTab; + nCol2 = rData.Ref2.nCol; + nRow2 = rData.Ref2.nRow; + nTab2 = rData.Ref2.nTab; + } + else + PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + if (nColNew < 0) + nColNew = nCol2 - nCol1 + 1; + if (nRowNew < 0) + nRowNew = nRow2 - nRow1 + 1; + nCol1 = (SCCOL)((long)nCol1+nColPlus); + nRow1 = (SCROW)((long)nRow1+nRowPlus); + nCol2 = (SCCOL)((long)nCol1+nColNew-1); + nRow2 = (SCROW)((long)nRow1+nRowNew-1); + if (!ValidCol(nCol1) || !ValidRow(nRow1) || + !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2) + PushIllegalArgument(); + else if (xExtRef) + { + ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); + rData.Ref1.nCol = nCol1; + rData.Ref1.nRow = nRow1; + rData.Ref1.nTab = nTab1; + rData.Ref2.nCol = nCol2; + rData.Ref2.nRow = nRow2; + rData.Ref2.nTab = nTab1; + rData.CalcRelFromAbs( aPos); + // Push a subroutine that resolves the external + // reference as the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); + } + else + PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); + } + break; + default: + PushIllegalParameter(); } - else - PushIllegalParameter(); } } diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx index dfcce4c06c3f..ef1a18b65def 100644 --- a/sc/source/core/tool/interpr3.cxx +++ b/sc/source/core/tool/interpr3.cxx @@ -949,17 +949,18 @@ double ScInterpreter::GetBetaDistPDF(double fX, double fA, double fB) const double fLogDblMin = log( ::std::numeric_limits<double>::min()); double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5); double fLogX = log(fX); - double fAm1 = fA-1.0; - double fBm1 = fB-1.0; + double fAm1LogX = (fA-1.0) * fLogX; + double fBm1LogY = (fB-1.0) * fLogY; double fLogBeta = GetLogBeta(fA,fB); // check whether parts over- or underflow - if ( fAm1 * fLogX < fLogDblMax && fAm1 * fLogX > fLogDblMin - && fBm1 * fLogY < fLogDblMax && fBm1* fLogY > fLogDblMin - && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin ) + if ( fAm1LogX < fLogDblMax && fAm1LogX > fLogDblMin + && fBm1LogY < fLogDblMax && fBm1LogY > fLogDblMin + && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin + && fAm1LogX + fBm1LogY < fLogDblMax && fAm1LogX + fBm1LogY > fLogDblMin) return pow(fX,fA-1.0) * pow(0.5-fX+0.5,fB-1.0) / GetBeta(fA,fB); else // need logarithm; // might overflow as a whole, but seldom, not worth to pre-detect it - return exp((fA-1.0)*fLogX + (fB-1.0)* fLogY - fLogBeta); + return exp( fAm1LogX + fBm1LogY - fLogBeta); } @@ -1226,121 +1227,106 @@ void ScInterpreter::ScVariationen2() } } -void ScInterpreter::ScB() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScB" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 4 ) ) - return ; - if (nParamCount == 3) - { - double x = ::rtl::math::approxFloor(GetDouble()); - double p = GetDouble(); - double n = ::rtl::math::approxFloor(GetDouble()); - if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0) - PushIllegalArgument(); - else + +double ScInterpreter::GetBinomDistPMF(double x, double n, double p) +// used in ScB and ScBinomDist +// preconditions: 0.0 <= x <= n, 0.0 < p < 1.0; x,n integral although double { - double q = 1.0 - p; + double q = (0.5 - p) + 0.5; double fFactor = pow(q, n); - if (fFactor == 0.0) + if (fFactor <=::std::numeric_limits<double>::min()) { fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); + if (fFactor <= ::std::numeric_limits<double>::min()) + return GetBetaDistPDF(p, x+1.0, n-x+1.0)/(n+1.0); else { - sal_uLong max = (sal_uLong) (n - x); - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) + sal_uInt32 max = static_cast<sal_uInt32>(n - x); + for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++) fFactor *= (n-i)/(i+1)*q/p; - PushDouble(fFactor); + return fFactor; } } else { - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) + sal_uInt32 max = static_cast<sal_uInt32>(x); + for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++) fFactor *= (n-i)/(i+1)*p/q; - PushDouble(fFactor); - } + return fFactor; } } - else if (nParamCount == 4) - { - double xe = GetDouble(); - double xs = GetDouble(); - double p = GetDouble(); - double n = GetDouble(); -// alter Stand 300-SC -// if ((xs < n) && (xe < n) && (p < 1.0)) -// { -// double Varianz = sqrt(n * p * (1.0 - p)); -// xs = fabs(xs - (n * p /* / 2.0 STE */ )); -// xe = fabs(xe - (n * p /* / 2.0 STE */ )); -//// STE double nVal = gauss((xs + 0.5) / Varianz) + gauss((xe + 0.5) / Varianz); -// double nVal = fabs(gauss(xs / Varianz) - gauss(xe / Varianz)); -// PushDouble(nVal); -// } - bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n); - if ( bIsValidX && 0.0 < p && p < 1.0 ) - { - double q = 1.0 - p; - double fFactor = pow(q, n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else + +double lcl_GetBinomDistRange(double n, double xs,double xe, + double fFactor /* q^n */, double p, double q) +//preconditions: 0.0 <= xs < xe <= n; xs,xe,n integral although double { - double fSum = 0.0; - sal_uLong max; - if (xe < (sal_uLong) n) - max = (sal_uLong) (n-xe)-1; - else - max = 0; - sal_uLong i; - for (i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*q/p; - if (xs < (sal_uLong) n) - max = (sal_uLong) (n-xs); - else - fSum = fFactor; - for (; i < max && fFactor > 0.0; i++) + sal_uInt32 i; + double fSum; + // skip summands index 0 to xs-1, start sum with index xs + sal_uInt32 nXs = static_cast<sal_uInt32>( xs ); + for (i = 1; i <= nXs && fFactor > 0.0; i++) + fFactor *= (n-i+1)/i * p/q; + fSum = fFactor; // Summand xs + sal_uInt32 nXe = static_cast<sal_uInt32>(xe); + for (i = nXs+1; i <= nXe && fFactor > 0.0; i++) { - fFactor *= (n-i)/(i+1)*q/p; + fFactor *= (n-i+1)/i * p/q; fSum += fFactor; } - PushDouble(fSum); + return (fSum>1.0) ? 1.0 : fSum; } + +void ScInterpreter::ScB() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScB" ); + sal_uInt8 nParamCount = GetByte(); + if ( !MustHaveParamCount( nParamCount, 3, 4 ) ) + return ; + if (nParamCount == 3) // mass function + { + double x = ::rtl::math::approxFloor(GetDouble()); + double p = GetDouble(); + double n = ::rtl::math::approxFloor(GetDouble()); + if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0) + PushIllegalArgument(); + else + if (p == 0.0) + PushDouble( (x == 0.0) ? 1.0 : 0.0 ); + else + if ( p == 1.0) + PushDouble( (x == n) ? 1.0 : 0.0); + else + PushDouble(GetBinomDistPMF(x,n,p)); } else + { // nParamCount == 4 + double xe = ::rtl::math::approxFloor(GetDouble()); + double xs = ::rtl::math::approxFloor(GetDouble()); + double p = GetDouble(); + double n = ::rtl::math::approxFloor(GetDouble()); + double q = (0.5 - p) + 0.5; + bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n); + if ( bIsValidX && 0.0 < p && p < 1.0) { - sal_uLong max; - double fSum; - if ( (sal_uLong) xs == 0) + if (xs == xe) // mass function + PushDouble(GetBinomDistPMF(xs,n,p)); + else { - fSum = fFactor; - max = 0; - } + double fFactor = pow(q, n); + if (fFactor > ::std::numeric_limits<double>::min()) + PushDouble(lcl_GetBinomDistRange(n,xs,xe,fFactor,p,q)); else { - max = (sal_uLong) xs-1; - fSum = 0.0; + fFactor = pow(p, n); + if (fFactor > ::std::numeric_limits<double>::min()) + { + // sum from j=xs to xe {(n choose j) * p^j * q^(n-j)} + // = sum from i = n-xe to n-xs { (n choose i) * q^i * p^(n-i)} + PushDouble(lcl_GetBinomDistRange(n,n-xe,n-xs,fFactor,q,p)); } - sal_uLong i; - for (i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*p/q; - if ((sal_uLong)xe == 0) // beide 0 - fSum = fFactor; else - max = (sal_uLong) xe; - for (; i < max && fFactor > 0.0; i++) - { - fFactor *= (n-i)/(i+1)*p/q; - fSum += fFactor; + PushDouble(GetBetaDist(q,n-xe,xe+1.0)-GetBetaDist(q,n-xs+1,xs) ); } - PushDouble(fSum); } } else @@ -1365,77 +1351,63 @@ void ScInterpreter::ScBinomDist() RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBinomDist" ); if ( MustHaveParamCount( GetByte(), 4 ) ) { - double kum = GetDouble(); // 0 oder 1 - double p = GetDouble(); // p - double n = ::rtl::math::approxFloor(GetDouble()); // n - double x = ::rtl::math::approxFloor(GetDouble()); // x - double fFactor, q, fSum; + bool bIsCum = GetBool(); // false=mass function; true=cumulative + double p = GetDouble(); + double n = ::rtl::math::approxFloor(GetDouble()); + double x = ::rtl::math::approxFloor(GetDouble()); + double q = (0.5 - p) + 0.5; // get one bit more for p near 1.0 + double fFactor, fSum; if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0) - PushIllegalArgument(); - else if (kum == 0.0) // Dichte { - q = 1.0 - p; - fFactor = pow(q, n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else - { - sal_uLong max = (sal_uLong) (n - x); - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*q/p; - PushDouble(fFactor); - } + PushIllegalArgument(); + return; } - else + if ( p == 0.0) { - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*p/q; - PushDouble(fFactor); + PushDouble( (x==0.0 || bIsCum) ? 1.0 : 0.0 ); + return; } + if ( p == 1.0) + { + PushDouble( (x==n) ? 1.0 : 0.0); + return; } - else // Verteilung + if (!bIsCum) + PushDouble( GetBinomDistPMF(x,n,p)); + else { - if (n == x) + if (x == n) PushDouble(1.0); else { - q = 1.0 - p; fFactor = pow(q, n); - if (fFactor == 0.0) + if (x == 0.0) + PushDouble(fFactor); + else + if (fFactor <= ::std::numeric_limits<double>::min()) { fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); + if (fFactor <= ::std::numeric_limits<double>::min()) + PushDouble(GetBetaDist(q,n-x,x+1.0)); else { + if (fFactor > fMachEps) + { fSum = 1.0 - fFactor; - sal_uLong max = (sal_uLong) (n - x) - 1; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) + sal_uInt32 max = static_cast<sal_uInt32> (n - x) - 1; + for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++) { fFactor *= (n-i)/(i+1)*q/p; fSum -= fFactor; } - if (fSum < 0.0) - PushDouble(0.0); - else - PushDouble(fSum); - } + PushDouble( (fSum < 0.0) ? 0.0 : fSum ); } else - { - fSum = fFactor; - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - { - fFactor *= (n-i)/(i+1)*p/q; - fSum += fFactor; + PushDouble(lcl_GetBinomDistRange(n,n-x,n,fFactor,q,p)); } - PushDouble(fSum); } + else + PushDouble( lcl_GetBinomDistRange(n,0.0,x,fFactor,p,q)) ; } } } diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index e3cd6239191e..439e0375a8b9 100755 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -3181,6 +3181,14 @@ void ScInterpreter::ScColRowNameAuto() void ScInterpreter::ScExternalRef() { + const FormulaToken* pNextOp = aCode.PeekNextOperator(); + if (pNextOp && pNextOp->GetOpCode() == ocOffset) + { + // Handled by OFFSET function. + PushTempToken( *pCur); + return; + } + ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager(); const String* pFile = pRefMgr->getExternalFileName(pCur->GetIndex()); if (!pFile) @@ -3324,6 +3332,21 @@ void ScInterpreter::GlobalExit() // static } +// A ::std::vector<FormulaTokenRef> is not possible, a push_back() attempts to +// use a FormulaToken(const FormulaTokenRef&) ctor. Reinvent wheel.. +struct FormulaTokenRefPtr +{ + FormulaToken* mp; + FormulaTokenRefPtr() : mp(0) {} + FormulaTokenRefPtr( FormulaToken* p ) : mp(p) { if (mp) mp->IncRef(); } + FormulaTokenRefPtr( const FormulaTokenRefPtr & r ) : mp(r.mp) { if (mp) mp->IncRef(); } + ~FormulaTokenRefPtr() { if (mp) mp->DecRef(); } + FormulaTokenRefPtr& operator=( const FormulaTokenRefPtr & r ) + { if (r.mp) r.mp->IncRef(); if (mp) mp->DecRef(); mp = r.mp; return *this; } +}; +typedef ::std::vector< FormulaTokenRefPtr > FormulaTokenDtor; + + StackVar ScInterpreter::Interpret() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Interpret" ); @@ -3342,6 +3365,7 @@ StackVar ScInterpreter::Interpret() pJumpMatrix = NULL; glSubTotal = sal_False; ScTokenMatrixMap::const_iterator aTokenMatrixMapIter; + ::boost::scoped_ptr< FormulaTokenDtor > pTokenDtor; // Once upon a time we used to have FP exceptions on, and there was a // Windows printer driver that kept switching off exceptions, so we had to @@ -3724,13 +3748,27 @@ StackVar ScInterpreter::Interpret() default : PushError( errUnknownOpCode); break; } - // If the function signalled that it pushed a subroutine on the - // instruction code stack instead of a result, continue with + // If the function pushed a subroutine as result, continue with // execution of the subroutine. - if (sp > nStackBase && pStack[sp-1]->GetOpCode() == ocCall) + if (sp > nStackBase && pStack[sp-1]->GetOpCode() == ocCall && pStack[sp-1]->GetType() == svSubroutine) { - Pop(); - continue; // while( ( pCur = aCode.Next() ) != NULL ... + FormulaTokenRef xTok = PopToken(); + const FormulaSubroutineToken* pSub = dynamic_cast<FormulaSubroutineToken*>(xTok.get()); + if (pSub) + { + // Remember token for late destruction. + if (!pTokenDtor) + pTokenDtor.reset( new FormulaTokenDtor); + pTokenDtor->push_back( FormulaTokenDtor::value_type( xTok)); + // Continue with execution of subroutine. + aCode.Push( pSub->GetTokenArray()); + continue; // while( ( pCur = aCode.Next() ) != NULL ... + } + else + { + DBG_ERRORFILE( "ScInterpreter::Interpret: ocCall svSubroutine, but no FormulaSubroutineToken?!?"); + PushError( errNoCode); + } } // Remember result matrix in case it could be reused. diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index a270969e100c..83ee5d365e63 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -561,6 +561,9 @@ sal_Bool ScToken::Is3DRef() const if ( GetSingleRef().IsFlag3D() ) return sal_True; break; + case svExternalSingleRef: + case svExternalDoubleRef: + return sal_True; default: { // added to avoid warnings @@ -922,6 +925,14 @@ ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefTok { } +ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalSingleRefToken& r ) : + ScToken( svExternalDoubleRef, ocExternalRef), + mnFileId( r.GetIndex()), + maTabName( r.GetString()) +{ + maDoubleRef.Ref1 = maDoubleRef.Ref2 = r.GetSingleRef(); +} + ScExternalDoubleRefToken::~ScExternalDoubleRefToken() { } @@ -1825,6 +1836,20 @@ void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos, } } break; + case svExternalDoubleRef: + { + ScSingleRefData& rRef2 = static_cast<ScToken*>(pCode[j])->GetSingleRef2(); + rRef2.CalcAbsIfRel( rOldPos ); + rRef2.CalcRelFromAbs( rNewPos ); + } + //! fallthru + case svExternalSingleRef: + { + ScSingleRefData& rRef1 = static_cast<ScToken*>(pCode[j])->GetSingleRef(); + rRef1.CalcAbsIfRel( rOldPos ); + rRef1.CalcRelFromAbs( rNewPos ); + } + break; default: { // added to avoid warnings |