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.
