svl/source/numbers/zformat.cxx |   12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

New commits:
commit 2b27652d2d7bd675fa355fb904755bf5fb312348
Author:     Noel Grandin <[email protected]>
AuthorDate: Mon Jan 26 20:12:37 2026 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Tue Jan 27 08:38:36 2026 +0100

    tdf#167892 fix hang formatting very small number on windows
    
    Workaround undefined behaviour where llvm/gcc produces different
    code from MSVC, resulting in oscillation in this algorithm.
    
    regression from
      commit 44d17f8feca372acd41142d1b607d3360282bf30
      Author: Eike Rathke <[email protected]>
      Date:   Tue Oct 13 21:41:45 2020 +0200
      Resolves: tdf#137453 Implicit conversion from sal_uInt64 to sal_Int32 is 
bad..
    
    Change-Id: I486e8caabcbf582cf94b47547efc89d1b206503e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198163
    Reviewed-by: Noel Grandin <[email protected]>
    Tested-by: Jenkins

diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx
index 9d617058f436..8253bd4e9429 100644
--- a/svl/source/numbers/zformat.cxx
+++ b/svl/source/numbers/zformat.cxx
@@ -2853,7 +2853,7 @@ double SvNumberformat::GetRoundFractionValue ( double 
fNumber ) const
 void SvNumberformat::ImpGetFractionElements ( double& fNumber, sal_uInt16 nIx,
                                               double& fIntPart, sal_Int64& 
nFrac, sal_Int64& nDiv ) const
 {
-    if ( fNumber < 0.0 )
+    if (fNumber < 0.0)
         fNumber = -fNumber;
     fIntPart = floor(fNumber); // Integral part
     fNumber -= fIntPart;         // Fractional part
@@ -2884,9 +2884,17 @@ void SvNumberformat::ImpGetFractionElements ( double& 
fNumber, sal_uInt16 nIx,
         {
             double fTemp = 1.0 / fRemainder;             // 64bits precision 
required when fRemainder is very weak
             nPartialDenom = static_cast<sal_Int64>(floor(fTemp));   // due to 
floating point notation with double precision
+#ifdef _WIN32
+            // The fTemp value may be out of range for sal_Int64 (e.g. 1e+19), 
and the result of
+            // casting that is undefined. In practice, gcc/llvm gives us a 
large positive number, but MSVC may create
+            // a large negative number, which will make this algorithm 
oscillate, so apply a correction that makes
+            // MSVC end up with the same thing. There is probably a better 
algorithm to be used here.
+            if (nPartialDenom < 0)
+                nPartialDenom = -(nPartialDenom+1);
+#endif
             fRemainder = fTemp - static_cast<double>(nPartialDenom);
             nDivNext = nPartialDenom * nDiv + nDivPrev;
-            if ( nDivNext <= nBasis )  // continue loop
+            if (nDivNext <= nBasis) // continue loop
             {
                 nFracNext = nPartialDenom * nFrac + nFracPrev;
                 nFracPrev = nFrac;

Reply via email to