tdf#137679 Use kahan summation for ScInterpreter::lcl_IterateInverse

Change-Id: I02e108ac70ddd4ea8d8d97eb4f5fbc8996dd4bd1
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114966
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/sc/inc/kahan.hxx b/sc/inc/kahan.hxx
index ffeeab0..23a29f6e 100644
--- a/sc/inc/kahan.hxx
+++ b/sc/inc/kahan.hxx
@@ -53,6 +53,16 @@ public:
        add(fSum.m_fError);
    }

    /**
      * Substracts a value to the sum using Kahan summation.
      * @param fSum
      */
    inline void subtract(const KahanSum& fSum)
    {
        add(-fSum.m_fSum);
        add(-fSum.m_fError);
    }

public:
    constexpr KahanSum operator-() const
    {
@@ -75,7 +85,7 @@ public:

    inline void operator+=(double fSum) { add(fSum); }

    inline void operator-=(const KahanSum& fSum) { add(-fSum); }
    inline void operator-=(const KahanSum& fSum) { subtract(fSum); }

    inline void operator-=(double fSum) { add(-fSum); }

@@ -86,6 +96,13 @@ public:
        return fNSum;
    }

    inline KahanSum operator+(const KahanSum& fSum) const
    {
        KahanSum fNSum(*this);
        fNSum += fSum;
        return fNSum;
    }

    inline KahanSum operator-(double fSum) const
    {
        KahanSum fNSum(*this);
@@ -93,6 +110,13 @@ public:
        return fNSum;
    }

    inline KahanSum operator-(const KahanSum& fSum) const
    {
        KahanSum fNSum(*this);
        fNSum -= fSum;
        return fNSum;
    }

    /**
      * In some parts of the code of interpr_.cxx this may be used for
      * product instead of sum. This operator shall be used for that task.
@@ -109,6 +133,20 @@ public:
        m_fError /= fDivides;
    }

    constexpr KahanSum operator*(double fTimes) const
    {
        KahanSum fSum(*this);
        fSum *= fTimes;
        return fSum;
    }

    constexpr KahanSum operator/(double fTimes) const
    {
        KahanSum fSum(*this);
        fSum /= fTimes;
        return fSum;
    }

    constexpr bool operator<(const KahanSum& fSum) const { return get() < fSum.get(); }

    constexpr bool operator<(double fSum) const { return get() < fSum; }
diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx
index 17fe633..c339a68 100644
--- a/sc/source/core/tool/interpr3.cxx
+++ b/sc/source/core/tool/interpr3.cxx
@@ -84,32 +84,36 @@ static double lcl_IterateInverse( const ScDistFunc& rFunction, double fAx, doubl

    //  find enclosing interval

    KahanSum fkAx = fAx;
    KahanSum fkBx = fBx;
    double fAy = rFunction.GetValue(fAx);
    double fBy = rFunction.GetValue(fBx);
    double fTemp;
    KahanSum fTemp;
    unsigned short nCount;
    for (nCount = 0; nCount < 1000 && !lcl_HasChangeOfSign(fAy,fBy); nCount++)
    {
        if (std::abs(fAy) <= std::abs(fBy))
        {
            fTemp = fAx;
            fAx += 2.0 * (fAx - fBx);
            if (fAx < 0.0)
                fAx = 0.0;
            fBx = fTemp;
            fTemp = fkAx;
            fkAx += (fkAx - fkBx) * 2.0;
            if (fkAx < 0.0)
                fkAx = 0.0;
            fkBx = fTemp;
            fBy = fAy;
            fAy = rFunction.GetValue(fAx);
            fAy = rFunction.GetValue(fkAx.get());
        }
        else
        {
            fTemp = fBx;
            fBx += 2.0 * (fBx - fAx);
            fAx = fTemp;
            fTemp = fkBx;
            fkBx += (fkBx - fkAx) * 2.0;
            fkAx = fTemp;
            fAy = fBy;
            fBy = rFunction.GetValue(fBx);
            fBy = rFunction.GetValue(fkBx.get());
        }
    }

    fAx = fkAx.get();
    fBx = fkBx.get();
    if (fAy == 0.0)
        return fAx;
    if (fBy == 0.0)