https://bugs.documentfoundation.org/show_bug.cgi?id=174265

--- Comment #2 from [email protected] ---
I asked an codex to investigate the root cause and suggest a simple fix. I
don't expect it to meet your quality requirements, but I hope it saves you
time.

-----

Source analysis identifies a defect in SearchMatrixForValue(): binary sort
direction is derived from match mode, although XLOOKUP/XMATCH allow these
options independently. The proposed correction finds the insertion position
using search direction, then selects the smaller/larger neighbor independently
in the shared helper.

Commit f7039822c7ad (2024-01-31) omitted some combinations; aa4b18b72074
(2025-07-09, bug 167171) introduced the current wrong-number variant. These are
source-history findings, not a binary bisect. Bug 161592 uses a separate
range-search path.

Locally patched 27.2.0.0.alpha0+ master 7528c0d40601, macOS 27.0.1 ARM64: the
attachment passes three load/hard-recalculation cycles per threading setting.
All 9,984 matrix/vertical-range assertions and 20 existing parallelism tests
pass. Reverting restores the failures. Patched Linux was not tested.


--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -14117,55 +14117,47 @@
         case LookupSearchMode::BinaryAscending:
         case LookupSearchMode::BinaryDescending:
             {
-                // binary search for non-equality mode (the source data is
sorted)
-                bool bAscOrder = (rEntry.eOp == SC_LESS_EQUAL);
-                SCSIZE nFirst = 0, nLast = nMatCount-1, nHitIndex = 0;
-                for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen =
nLast-nFirst)
-                {
-                    SCSIZE nMid = nFirst + nLen/2;
-                    sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, aMatAcc,
rParam, rEntry, bMatchWholeCell);
-                    if (nCmp == 0)
+                // Sort order and approximate-match policy are independent.
+                const bool ascending = vsa.eSearchMode ==
LookupSearchMode::BinaryAscending;
+                SCSIZE searchBegin = 0;
+                SCSIZE searchEnd = nMatCount;
+                while (searchBegin < searchEnd)
+                {
+                    SCSIZE middle = searchBegin + (searchEnd - searchBegin) /
2;
+                    const sal_Int32 comparison = lcl_CompareMatrix2Query(
+                        middle, aMatAcc, rParam, rEntry, bMatchWholeCell);
+                    if (comparison == 0)
                     {
-                        // exact match.  find the last item with the same
value.
-                        lcl_GetLastMatch( nMid, aMatAcc, nMatCount);
-                        vsa.nHitIndex = nMid+1;
-                        return true;
-                    }
-                    if (nLen == 1) // first and last items are next to each
other.
-                    {
-                        if (nCmp < 0)
-                            nHitIndex = bAscOrder ? nLast : nFirst;
-                        else
-                            nHitIndex = bAscOrder ? nFirst : nLast;
+                        // Preserve the existing last-equal-item policy.
+                        lcl_GetLastMatch(middle, aMatAcc, nMatCount);
+                        vsa.nHitIndex = middle + 1;
-                        break;
+                        return true;
                     }
-                    if (nCmp < 0)
+                    if ((comparison < 0) == ascending)
+                        searchBegin = middle + 1;
+                    else
+                        searchEnd = middle;
+                }
+
+                if (vsa.nHitIndex == 0)
+                {
+                    // searchBegin is the insertion position. Choose its
+                    // predecessor or successor by value, not by sort order.
+                    switch (vsa.eMatchMode)
                     {
-                        if (bAscOrder)
-                            nFirst = nMid;
-                        else
-                            nLast = nMid;
+                        case exactorS:
+                            vsa.nHitIndex = ascending ? searchBegin
+                                : (searchBegin < nMatCount ? searchBegin + 1 :
0);
+                            break;
+                        case exactorG:
+                            vsa.nHitIndex = ascending
+                                ? (searchBegin < nMatCount ? searchBegin + 1 :
0)
+                                : searchBegin;
+                            break;
+                        default:
+                            break;
                     }
-                    else
-                    {
-                        if (bAscOrder)
-                            nLast = nMid;
-                        else
-                            nFirst = nMid;
-                    }
-                }
-                if (nHitIndex == nMatCount-1) // last item
-                {
-                    sal_Int32 nCmp = lcl_CompareMatrix2Query( nHitIndex,
aMatAcc, rParam, rEntry, bMatchWholeCell);
-                    if ((bAscOrder && nCmp <= 0) || (!bAscOrder && nCmp >= 0))
-                    {
-                        // either the last item is an exact match or the real
-                        // hit is beyond the last item.
-                        vsa.nHitIndex = nHitIndex+1;
-                        return true;
-                    }
-                }
-                vsa.nHitIndex = nHitIndex;
+                }
             }
             break;

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to