summaryrefslogtreecommitdiff log msg author committer range
diff options
 context: 12345678910152025303540 space: includeignore mode: unifiedssdiffstat only
author committer Tor Lillqvist 2015-02-06 20:53:59 +0200 Jan Holesovsky 2015-02-10 12:25:54 +0000 91a425313d54f3a2a61aee55786cb5ce22fae130 (patch) dfe11c1cd2654b6b6de7b0f6f550c9ce0e345c98 f262e1b1356488515972916c3e11ec210d22cdd9 (diff)
Handle zero or empty cells properly when using OpenCL for division
This is a combination of 4 commits from master: 4f4daf163e92d113b62cc19fb0b7f5ec05dce48a: Introduce SetResultError() f7c6089c0f5ac7976149d270f6d9694ef8ed7cfd: Be prepared to handle error codes encoded in NaNs ("double error") f6dfb3b4098f4554782e35fdb471ef69f2f53386: Create proper error when dividing by zero. Create a so-called "double error", i.e. a NaN with a error code payload. f5e7207053b857b6903a0ab9c161bed9ad7bcee9: Handle zero and empty cells (which also means zero) in OpenCL for division. Not sure if it makes sense to keep having OpDiv a subclass of Reduction. There is no DIV() function that would take a range of cells, so it isn't really comparable to the other Reducion subclasses. But let's keep hat as it is for now. We need to handle three cases specially in the OpenCL: Dividing by an empty cell which should produce an #DIV/0! error, dividing an empty cell by zero which also should produce #DIV/0!, and dividing an empty cell with anything else number which should produce 0. Change-Id: I86d86f652047d6f9e3c095c3ef135a8f5396b000 Reviewed-on: https://gerrit.libreoffice.org/14395 Reviewed-by: Jan Holesovsky <kendy@collabora.com> Tested-by: Jan Holesovsky <kendy@collabora.com>
-rw-r--r--sc/inc/formulacell.hxx7
-rw-r--r--sc/source/core/data/column2.cxx6
-rw-r--r--sc/source/core/data/formulacell.cxx5
-rw-r--r--sc/source/core/opencl/formulagroupcl.cxx58
-rw-r--r--sc/source/core/opencl/formulagroupcl_public.hxx21
5 files changed, 85 insertions, 12 deletions
 diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxxindex 746ca5505c32..23a1726ca10a 100644--- a/sc/inc/formulacell.hxx+++ b/sc/inc/formulacell.hxx@@ -375,7 +375,12 @@ public: svl::SharedString GetResultString() const; - void SetErrCode( sal_uInt16 n );+ /* Sets the shared code array to error state in addition to the cell result */+ void SetErrCode( sal_uInt16 n );++ /* Sets just the result to error */+ void SetResultError( sal_uInt16 n );+ bool IsHyperLinkCell() const; EditTextObject* CreateURLObject(); void GetURLResult( OUString& rURL, OUString& rCellText );diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxxindex 9b0b5efb358d..8cf3178af69f 100644--- a/sc/source/core/data/column2.cxx+++ b/sc/source/core/data/column2.cxx@@ -2671,7 +2671,11 @@ void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLe for (; pResults != pResEnd; ++pResults, ++itCell) { ScFormulaCell& rCell = **itCell;- rCell.SetResultDouble(*pResults);+ sal_uInt16 nErr = GetDoubleErrorValue(*pResults);+ if (nErr != 0)+ rCell.SetResultError(nErr);+ else+ rCell.SetResultDouble(*pResults); rCell.ResetDirty(); rCell.SetChanged(true); }diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxxindex 98bb56878e4a..896e5d2cb152 100644--- a/sc/source/core/data/formulacell.cxx+++ b/sc/source/core/data/formulacell.cxx@@ -2232,6 +2232,11 @@ void ScFormulaCell::SetErrCode( sal_uInt16 n ) aResult.SetResultError( n ); } +void ScFormulaCell::SetResultError( sal_uInt16 n )+{+ aResult.SetResultError( n );+}+ void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits ) { if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxxindex 134887664a4e..a60f9eda8b7e 100644--- a/sc/source/core/opencl/formulagroupcl.cxx+++ b/sc/source/core/opencl/formulagroupcl.cxx@@ -1607,6 +1607,11 @@ public: typedef DynamicKernelSlidingArgument StringRange; typedef ParallelReductionVectorRef ParallelNumericRange; + virtual bool HandleNaNArgument( std::stringstream&, unsigned, SubArguments& ) const+ {+ return false;+ }+ virtual void GenSlidingWindowFunction( std::stringstream& ss, const std::string& sSymName, SubArguments& vSubArguments ) SAL_OVERRIDE {@@ -1668,18 +1673,25 @@ public: } if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode()) {+ bool bNanHandled = HandleNaNArgument(ss, i, vSubArguments);+ ss << "tmpBottom = " << GetBottom() << ";\n";- ss << "if (isNan(";- ss << vSubArguments[i]->GenSlidingWindowDeclRef();- ss << "))\n";- if (ZeroReturnZero())- ss << " return 0;\n";- else++ if (!bNanHandled) {- ss << " tmp = ";- ss << Gen2("tmpBottom", "tmp") << ";\n";+ ss << "if (isNan(";+ ss << vSubArguments[i]->GenSlidingWindowDeclRef();+ ss << "))\n";+ if (ZeroReturnZero())+ ss << " return 0;\n";+ else+ {+ ss << " tmp = ";+ ss << Gen2("tmpBottom", "tmp") << ";\n";+ }+ ss << "else\n"; }- ss << "else{\n";+ ss << "{"; ss << " tmp = "; ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp"); ss << ";\n";@@ -2149,9 +2161,35 @@ public: virtual std::string GetBottom() SAL_OVERRIDE { return "1.0"; } virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const SAL_OVERRIDE {- return "(" + lhs + "/" + rhs + ")";+ return "(" + rhs + "==0 ? CreateDoubleError(errDivisionByZero) : (" + lhs + "/" + rhs + ") )"; } virtual std::string BinFuncName() const SAL_OVERRIDE { return "fdiv"; }++ virtual bool HandleNaNArgument( std::stringstream& ss, unsigned argno, SubArguments& vSubArguments ) const SAL_OVERRIDE+ {+ if (argno == 1)+ {+ ss <<+ "if (isnan(" << vSubArguments[argno]->GetName() << "[gid0])) {\n"+ " if (GetDoubleErrorValue(" << vSubArguments[argno]->GetName() << "[gid0]) == errNoValue)\n"+ " return CreateDoubleError(errDivisionByZero);\n"+ "}\n";+ return true;+ }+ else if (argno == 0)+ {+ ss <<+ "if (isnan(" << vSubArguments[argno]->GetName() << "[gid0])) {\n"+ " if (GetDoubleErrorValue(" << vSubArguments[argno]->GetName() << "[gid0]) == errNoValue) {\n"+ " if (" << vSubArguments[1]->GetName() << "[gid0] == 0)\n"+ " return CreateDoubleError(errDivisionByZero);\n"+ " return 0;\n"+ " }\n"+ "}\n";+ }+ return false;+ }+ }; class OpMin : public Reductiondiff --git a/sc/source/core/opencl/formulagroupcl_public.hxx b/sc/source/core/opencl/formulagroupcl_public.hxxindex 3b36770e6014..0ce60ce80e6b 100644--- a/sc/source/core/opencl/formulagroupcl_public.hxx+++ b/sc/source/core/opencl/formulagroupcl_public.hxx@@ -11,6 +11,27 @@ #define INCLUDED_SC_SOURCE_CORE_OPENCL_FORMULAGROUPCL_PUBLIC_HXX const char* publicFunc =+ "\n"+ "#define errIllegalFPOperation 503 // #NUM!\n"+ "#define errNoValue 519 // #VALUE!\n"+ "#define errDivisionByZero 532 // #DIV/0!\n"+ "\n"+ "double CreateDoubleError(ulong nErr)\n"+ "{\n"+ " return nan(nErr);\n"+ "}\n"+ "\n"+ "uint GetDoubleErrorValue(double fVal)\n"+ "{\n"+ " if (isfinite(fVal))\n"+ " return 0;\n"+ " if (isinf(fVal))\n"+ " return errIllegalFPOperation; // normal INF\n"+ " if (as_ulong(fVal) & 0XFFFF0000u)\n"+ " return errNoValue; // just a normal NAN\n"+ " return (as_ulong(fVal) & 0XFFFF); // any other error\n"+ "}\n"+ "\n" "int isNan(double a) { return isnan(a); }\n" "double fsum_count(double a, double b, __private int *p) {\n" " bool t = isNan(a);\n"