[Libreoffice-commits] core.git: Branch 'libreoffice-4-4-1' - sc/inc sc/source

Tor Lillqvist tml at collabora.com
Thu Feb 12 02:31:52 PST 2015


 sc/inc/formulacell.hxx                          |    7 ++
 sc/source/core/data/column2.cxx                 |    6 ++
 sc/source/core/data/formulacell.cxx             |    5 ++
 sc/source/core/opencl/formulagroupcl.cxx        |   58 +++++++++++++++++++-----
 sc/source/core/opencl/formulagroupcl_public.hxx |   21 ++++++++
 5 files changed, 85 insertions(+), 12 deletions(-)

New commits:
commit 5b67fa0ba77286d9d9d365f28bba063bf93ef6d0
Author: Tor Lillqvist <tml at collabora.com>
Date:   Fri Feb 6 20:53:59 2015 +0200

    Handle zero or empty cells properly when using OpenCL for division
    
    This is a combination of 5 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.
    
    9cef97adadc04361640c0dafc9363e5aed5a0ddd: Avoid OpenCL compilation error in
    some cases
    
    We do need to use GenSlidingWindowDeclRef(). We can't assume it is always a
    vector element that is taking part in the calculation.
    
    Change-Id: I57790d183a3dbe52906b8986454978fe2426ca76
    Reviewed-on: https://gerrit.libreoffice.org/14404
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 746ca550..23a1726 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.cxx
index 9b0b5ef..8cf3178 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.cxx
index 98bb568..896e5d2 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.cxx
index 1348876..f4c4d68 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -1607,6 +1607,11 @@ public:
     typedef DynamicKernelSlidingArgument<DynamicKernelStringArgument> StringRange;
     typedef ParallelReductionVectorRef<VectorRef> 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]->GenSlidingWindowDeclRef() << ")) {\n"
+                "    if (GetDoubleErrorValue(" << vSubArguments[argno]->GenSlidingWindowDeclRef() << ") == errNoValue)\n"
+                "        return CreateDoubleError(errDivisionByZero);\n"
+                "}\n";
+            return true;
+        }
+        else if (argno == 0)
+        {
+            ss <<
+                "if (isnan(" << vSubArguments[argno]->GenSlidingWindowDeclRef() << ")) {\n"
+                "    if (GetDoubleErrorValue(" << vSubArguments[argno]->GenSlidingWindowDeclRef() << ") == errNoValue) {\n"
+                "        if (" << vSubArguments[1]->GenSlidingWindowDeclRef() << " == 0)\n"
+                "            return CreateDoubleError(errDivisionByZero);\n"
+                "        return 0;\n"
+                "    }\n"
+                "}\n";
+        }
+        return false;
+    }
+
 };
 
 class OpMin : public Reduction
diff --git a/sc/source/core/opencl/formulagroupcl_public.hxx b/sc/source/core/opencl/formulagroupcl_public.hxx
index 3b36770e..0ce60ce 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"


More information about the Libreoffice-commits mailing list