Bug Summary

File:home/maarten/src/libreoffice/core/sal/rtl/math.cxx
Warning:line 669, column 23
The left operand of '==' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name math.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SAL_DLLIMPLEMENTATION -D RTL_OS="Linux" -D RTL_ARCH="X86_64" -D SRCDIR="/home/maarten/src/libreoffice/core" -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/dtoa/include/ -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/sal/inc -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sal/rtl/math.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <rtl/math.h>
21
22#include <o3tl/safeint.hxx>
23#include <osl/diagnose.h>
24#include <rtl/alloc.h>
25#include <rtl/character.hxx>
26#include <rtl/math.hxx>
27#include <rtl/strbuf.h>
28#include <rtl/string.h>
29#include <rtl/ustrbuf.h>
30#include <rtl/ustring.h>
31#include <sal/mathconf.h>
32#include <sal/types.h>
33
34#include <algorithm>
35#include <cassert>
36#include <float.h>
37#include <limits>
38#include <limits.h>
39#include <math.h>
40#include <memory>
41#include <stdlib.h>
42
43#include <dtoa.h>
44
45int const n10Count = 16;
46double const n10s[2][n10Count] = {
47 { 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8,
48 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16 },
49 { 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8,
50 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16 }
51};
52
53// return pow(10.0,nExp) optimized for exponents in the interval [-16,16]
54static double getN10Exp(int nExp)
55{
56 if (nExp < 0)
57 {
58 // && -nExp > 0 necessary for std::numeric_limits<int>::min()
59 // because -nExp = nExp
60 if (-nExp <= n10Count && -nExp > 0)
61 return n10s[1][-nExp-1];
62 return pow(10.0, static_cast<double>(nExp));
63 }
64 if (nExp > 0)
65 {
66 if (nExp <= n10Count)
67 return n10s[0][nExp-1];
68
69 return pow(10.0, static_cast<double>(nExp));
70 }
71 return 1.0;
72}
73
74namespace {
75
76double const nCorrVal[] = {
77 0, 9e-1, 9e-2, 9e-3, 9e-4, 9e-5, 9e-6, 9e-7, 9e-8,
78 9e-9, 9e-10, 9e-11, 9e-12, 9e-13, 9e-14, 9e-15
79};
80
81struct StringTraits
82{
83 typedef char Char;
84
85 typedef rtl_String String;
86
87 static void createString(rtl_String ** pString,
88 char const * pChars, sal_Int32 nLen)
89 {
90 rtl_string_newFromStr_WithLength(pString, pChars, nLen);
91 }
92
93 static void createBuffer(rtl_String ** pBuffer,
94 const sal_Int32 * pCapacity)
95 {
96 rtl_string_new_WithLength(pBuffer, *pCapacity);
97 }
98
99 static void appendChars(rtl_String ** pBuffer, sal_Int32 * pCapacity,
100 sal_Int32 * pOffset, char const * pChars,
101 sal_Int32 nLen)
102 {
103 assert(pChars)(static_cast <bool> (pChars) ? void (0) : __assert_fail
("pChars", "/home/maarten/src/libreoffice/core/sal/rtl/math.cxx"
, 103, __extension__ __PRETTY_FUNCTION__))
;
104 rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, pChars, nLen);
105 *pOffset += nLen;
106 }
107
108 static void appendAscii(rtl_String ** pBuffer, sal_Int32 * pCapacity,
109 sal_Int32 * pOffset, char const * pStr,
110 sal_Int32 nLen)
111 {
112 assert(pStr)(static_cast <bool> (pStr) ? void (0) : __assert_fail (
"pStr", "/home/maarten/src/libreoffice/core/sal/rtl/math.cxx"
, 112, __extension__ __PRETTY_FUNCTION__))
;
113 rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, pStr, nLen);
114 *pOffset += nLen;
115 }
116};
117
118struct UStringTraits
119{
120 typedef sal_Unicode Char;
121
122 typedef rtl_uString String;
123
124 static void createString(rtl_uString ** pString,
125 sal_Unicode const * pChars, sal_Int32 nLen)
126 {
127 rtl_uString_newFromStr_WithLength(pString, pChars, nLen);
128 }
129
130 static void createBuffer(rtl_uString ** pBuffer,
131 const sal_Int32 * pCapacity)
132 {
133 rtl_uString_new_WithLength(pBuffer, *pCapacity);
134 }
135
136 static void appendChars(rtl_uString ** pBuffer,
137 sal_Int32 * pCapacity, sal_Int32 * pOffset,
138 sal_Unicode const * pChars, sal_Int32 nLen)
139 {
140 assert(pChars)(static_cast <bool> (pChars) ? void (0) : __assert_fail
("pChars", "/home/maarten/src/libreoffice/core/sal/rtl/math.cxx"
, 140, __extension__ __PRETTY_FUNCTION__))
;
141 rtl_uStringbuffer_insert(pBuffer, pCapacity, *pOffset, pChars, nLen);
142 *pOffset += nLen;
143 }
144
145 static void appendAscii(rtl_uString ** pBuffer,
146 sal_Int32 * pCapacity, sal_Int32 * pOffset,
147 char const * pStr, sal_Int32 nLen)
148 {
149 rtl_uStringbuffer_insert_ascii(pBuffer, pCapacity, *pOffset, pStr,
150 nLen);
151 *pOffset += nLen;
152 }
153};
154
155/** If value (passed as absolute value) is an integer representable as double,
156 which we handle explicitly at some places.
157 */
158bool isRepresentableInteger(double fAbsValue)
159{
160 assert(fAbsValue >= 0.0)(static_cast <bool> (fAbsValue >= 0.0) ? void (0) : __assert_fail
("fAbsValue >= 0.0", "/home/maarten/src/libreoffice/core/sal/rtl/math.cxx"
, 160, __extension__ __PRETTY_FUNCTION__))
;
161 const sal_Int64 kMaxInt = (static_cast< sal_Int64 >(1) << 53) - 1;
162 if (fAbsValue <= static_cast< double >(kMaxInt))
163 {
164 sal_Int64 nInt = static_cast< sal_Int64 >(fAbsValue);
165 // Check the integer range again because double comparison may yield
166 // true within the precision range.
167 // XXX loplugin:fpcomparison complains about floating-point comparison
168 // for static_cast<double>(nInt) == fAbsValue, though we actually want
169 // this here.
170 if (nInt > kMaxInt)
171 return false;
172 double fInt = static_cast< double >(nInt);
173 return !(fInt < fAbsValue) && !(fInt > fAbsValue);
174 }
175 return false;
176}
177
178// Returns 1-based index of least significant bit in a number, or zero if number is zero
179int findFirstSetBit(unsigned n)
180{
181#if defined _WIN32
182 unsigned long pos;
183 unsigned char bNonZero = _BitScanForward(&pos, n);
184 return (bNonZero == 0) ? 0 : pos + 1;
185#else
186 return __builtin_ffs(n);
187#endif
188}
189
190/** Returns number of binary bits for fractional part of the number
191 Expects a proper non-negative double value, not +-INF, not NAN
192 */
193int getBitsInFracPart(double fAbsValue)
194{
195 assert(std::isfinite(fAbsValue) && fAbsValue >= 0.0)(static_cast <bool> (std::isfinite(fAbsValue) &&
fAbsValue >= 0.0) ? void (0) : __assert_fail ("std::isfinite(fAbsValue) && fAbsValue >= 0.0"
, "/home/maarten/src/libreoffice/core/sal/rtl/math.cxx", 195,
__extension__ __PRETTY_FUNCTION__))
;
196 if (fAbsValue == 0.0)
197 return 0;
198 auto pValParts = reinterpret_cast< const sal_math_Double * >(&fAbsValue);
199 int nExponent = pValParts->inf_parts.exponent - 1023;
200 if (nExponent >= 52)
201 return 0; // All bits in fraction are in integer part of the number
202 int nLeastSignificant = findFirstSetBit(pValParts->inf_parts.fraction_lo);
203 if (nLeastSignificant == 0)
204 {
205 nLeastSignificant = findFirstSetBit(pValParts->inf_parts.fraction_hi);
206 if (nLeastSignificant == 0)
207 nLeastSignificant = 53; // the implied leading 1 is the least significant
208 else
209 nLeastSignificant += 32;
210 }
211 int nFracSignificant = 53 - nLeastSignificant;
212 int nBitsInFracPart = nFracSignificant - nExponent;
213
214 return std::max(nBitsInFracPart, 0);
215}
216
217template< typename T >
218void doubleToString(typename T::String ** pResult,
219 sal_Int32 * pResultCapacity, sal_Int32 nResultOffset,
220 double fValue, rtl_math_StringFormat eFormat,
221 sal_Int32 nDecPlaces, typename T::Char cDecSeparator,
222 sal_Int32 const * pGroups,
223 typename T::Char cGroupSeparator,
224 bool bEraseTrailingDecZeros)
225{
226 static double const nRoundVal[] = {
227 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6,
228 0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14
229 };
230
231 // sign adjustment, instead of testing for fValue<0.0 this will also fetch
232 // -0.0
233 bool bSign = std::signbit(fValue);
234
235 if (bSign)
1
Assuming 'bSign' is false
2
Taking false branch
236 fValue = -fValue;
237
238 if (std::isnan(fValue))
3
Assuming the condition is false
4
Taking false branch
239 {
240 // #i112652# XMLSchema-2
241 sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH("NaN")((sal_Int32)((sizeof(sal_n_array_size("NaN")))-1));
242 if (!pResultCapacity)
243 {
244 pResultCapacity = &nCapacity;
245 T::createBuffer(pResult, pResultCapacity);
246 nResultOffset = 0;
247 }
248
249 T::appendAscii(pResult, pResultCapacity, &nResultOffset,
250 RTL_CONSTASCII_STRINGPARAM("NaN")(&("NaN")[0]), ((sal_Int32)(sizeof(sal_n_array_size("NaN"
)))-1)
);
251
252 return;
253 }
254
255 bool bHuge = fValue == HUGE_VAL(__builtin_huge_val ()); // g++ 3.0.1 requires it this way...
256 if (bHuge || std::isinf(fValue))
5
Assuming 'bHuge' is false
6
Assuming the condition is false
7
Taking false branch
257 {
258 // #i112652# XMLSchema-2
259 sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH("-INF")((sal_Int32)((sizeof(sal_n_array_size("-INF")))-1));
260 if (!pResultCapacity)
261 {
262 pResultCapacity = &nCapacity;
263 T::createBuffer(pResult, pResultCapacity);
264 nResultOffset = 0;
265 }
266
267 if ( bSign )
268 T::appendAscii(pResult, pResultCapacity, &nResultOffset,
269 RTL_CONSTASCII_STRINGPARAM("-")(&("-")[0]), ((sal_Int32)(sizeof(sal_n_array_size("-")))-
1)
);
270
271 T::appendAscii(pResult, pResultCapacity, &nResultOffset,
272 RTL_CONSTASCII_STRINGPARAM("INF")(&("INF")[0]), ((sal_Int32)(sizeof(sal_n_array_size("INF"
)))-1)
);
273
274 return;
275 }
276
277 // Use integer representation for integer values that fit into the
278 // mantissa (1.((2^53)-1)) with a precision of 1 for highest accuracy.
279 const sal_Int64 kMaxInt = (static_cast< sal_Int64 >(1) << 53) - 1;
280 if ((eFormat == rtl_math_StringFormat_Automatic ||
8
Assuming 'eFormat' is not equal to rtl_math_StringFormat_Automatic
281 eFormat == rtl_math_StringFormat_F) && fValue <= static_cast< double >(kMaxInt))
9
Assuming 'eFormat' is not equal to rtl_math_StringFormat_F
282 {
283 sal_Int64 nInt = static_cast< sal_Int64 >(fValue);
284 // Check the integer range again because double comparison may yield
285 // true within the precision range.
286 if (nInt <= kMaxInt && static_cast< double >(nInt) == fValue)
287 {
288 if (nDecPlaces == rtl_math_DecimalPlaces_Max)
289 nDecPlaces = 0;
290 else
291 nDecPlaces = ::std::max< sal_Int32 >(::std::min<sal_Int32>(nDecPlaces, 15), -15);
292
293 if (bEraseTrailingDecZeros && nDecPlaces > 0)
294 nDecPlaces = 0;
295
296 // Round before decimal position.
297 if (nDecPlaces < 0)
298 {
299 sal_Int64 nRounding = static_cast< sal_Int64 >(getN10Exp(-nDecPlaces - 1));
300 sal_Int64 nTemp = nInt / nRounding;
301 int nDigit = nTemp % 10;
302 nTemp /= 10;
303
304 if (nDigit >= 5)
305 ++nTemp;
306
307 nTemp *= 10;
308 nTemp *= nRounding;
309 nInt = nTemp;
310 nDecPlaces = 0;
311 }
312
313 // Max 1 sign, 16 integer digits, 15 group separators, 1 decimal
314 // separator, 15 decimals digits.
315 typename T::Char aBuf[64];
316 typename T::Char * pBuf = aBuf;
317 typename T::Char * p = pBuf;
318
319 // Backward fill.
320 size_t nGrouping = 0;
321 sal_Int32 nGroupDigits = 0;
322 do
323 {
324 typename T::Char nDigit = nInt % 10;
325 nInt /= 10;
326 *p++ = nDigit + '0';
327 if (pGroups && pGroups[nGrouping] == ++nGroupDigits && nInt > 0 && cGroupSeparator)
328 {
329 *p++ = cGroupSeparator;
330 if (pGroups[nGrouping+1])
331 ++nGrouping;
332 nGroupDigits = 0;
333 }
334 }
335 while (nInt > 0);
336 if (bSign)
337 *p++ = '-';
338
339 // Reverse buffer content.
340 sal_Int32 n = (p - pBuf) / 2;
341 for (sal_Int32 i=0; i < n; ++i)
342 {
343 ::std::swap( pBuf[i], p[-i-1]);
344 }
345
346 // Append decimals.
347 if (nDecPlaces > 0)
348 {
349 *p++ = cDecSeparator;
350 while (nDecPlaces--)
351 *p++ = '0';
352 }
353
354 if (!pResultCapacity)
355 T::createString(pResult, pBuf, p - pBuf);
356 else
357 T::appendChars(pResult, pResultCapacity, &nResultOffset, pBuf, p - pBuf);
358
359 return;
360 }
361 }
362
363 // find the exponent
364 int nExp = 0;
365 if ( fValue > 0.0 )
10
Assuming the condition is false
11
Taking false branch
366 {
367 // Cap nExp at a small value beyond which "fValue /= N10Exp" would lose precision (or N10Exp
368 // might even be zero); that will produce output with the decimal point in a non-normalized
369 // position, but the current quality of output for such small values is probably abysmal,
370 // anyway:
371 nExp = std::max(
372 static_cast< int >(floor(log10(fValue))), std::numeric_limits<double>::min_exponent10);
373 double const N10Exp = getN10Exp(nExp);
374 assert(N10Exp != 0)(static_cast <bool> (N10Exp != 0) ? void (0) : __assert_fail
("N10Exp != 0", "/home/maarten/src/libreoffice/core/sal/rtl/math.cxx"
, 374, __extension__ __PRETTY_FUNCTION__))
;
375 fValue /= N10Exp;
376 }
377
378 switch (eFormat)
12
Control jumps to the 'default' case at line 432
379 {
380 case rtl_math_StringFormat_Automatic:
381 { // E or F depending on exponent magnitude
382 int nPrec;
383 if (nExp <= -15 || nExp >= 15) // was <-16, >16 in ancient versions, which leads to inaccuracies
384 {
385 nPrec = 14;
386 eFormat = rtl_math_StringFormat_E;
387 }
388 else
389 {
390 if (nExp < 14)
391 {
392 nPrec = 15 - nExp - 1;
393 eFormat = rtl_math_StringFormat_F;
394 }
395 else
396 {
397 nPrec = 15;
398 eFormat = rtl_math_StringFormat_F;
399 }
400 }
401
402 if (nDecPlaces == rtl_math_DecimalPlaces_Max)
403 nDecPlaces = nPrec;
404 }
405 break;
406
407 case rtl_math_StringFormat_G :
408 case rtl_math_StringFormat_G1 :
409 case rtl_math_StringFormat_G2 :
410 { // G-Point, similar to sprintf %G
411 if (nDecPlaces == rtl_math_DecimalPlaces_DefaultSignificance)
412 nDecPlaces = 6;
413
414 if (nExp < -4 || nExp >= nDecPlaces)
415 {
416 nDecPlaces = std::max< sal_Int32 >(1, nDecPlaces - 1);
417
418 if (eFormat == rtl_math_StringFormat_G)
419 eFormat = rtl_math_StringFormat_E;
420 else if (eFormat == rtl_math_StringFormat_G2)
421 eFormat = rtl_math_StringFormat_E2;
422 else if (eFormat == rtl_math_StringFormat_G1)
423 eFormat = rtl_math_StringFormat_E1;
424 }
425 else
426 {
427 nDecPlaces = std::max< sal_Int32 >(0, nDecPlaces - nExp - 1);
428 eFormat = rtl_math_StringFormat_F;
429 }
430 }
431 break;
432 default:
433 break;
13
Execution continues on line 436
434 }
435
436 sal_Int32 nDigits = nDecPlaces + 1;
437
438 if (eFormat
13.1
'eFormat' is not equal to rtl_math_StringFormat_F
== rtl_math_StringFormat_F)
14
Taking false branch
439 nDigits += nExp;
440
441 // Round the number
442 if(nDigits >= 0)
15
Assuming 'nDigits' is >= 0
16
Taking true branch
443 {
444 fValue += nRoundVal[std::min<sal_Int32>(nDigits, 15)];
445 if (fValue >= 10)
17
Assuming 'fValue' is < 10
18
Taking false branch
446 {
447 fValue = 1.0;
448 nExp++;
449
450 if (eFormat == rtl_math_StringFormat_F)
451 nDigits++;
452 }
453 }
454
455 static sal_Int32 const nBufMax = 256;
456 typename T::Char aBuf[nBufMax];
457 typename T::Char * pBuf;
458 sal_Int32 nBuf = static_cast< sal_Int32 >
459 (nDigits <= 0 ? std::max< sal_Int32 >(nDecPlaces, abs(nExp))
19
Assuming 'nDigits' is > 0
20
'?' condition is false
460 : nDigits + nDecPlaces ) + 10 + (pGroups ? abs(nDigits) * 2 : 0);
21
Assuming 'pGroups' is null
22
'?' condition is false
461
462 if (nBuf > nBufMax)
23
Assuming 'nBuf' is <= 'nBufMax'
24
Taking false branch
463 {
464 pBuf = static_cast< typename T::Char * >(
465 malloc(nBuf * sizeof (typename T::Char)));
466 OSL_ENSURE(pBuf, "Out of memory")do { if (true && (!(pBuf))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sal/rtl/math.cxx"
":" "466" ": "), "%s", "Out of memory"); } } while (false)
;
467 }
468 else
469 {
470 pBuf = aBuf;
471 }
472
473 typename T::Char * p = pBuf;
474 if ( bSign
24.1
'bSign' is false
)
25
Taking false branch
475 *p++ = static_cast< typename T::Char >('-');
476
477 bool bHasDec = false;
478
479 int nDecPos;
480 // Check for F format and number < 1
481 if(eFormat
25.1
'eFormat' is not equal to rtl_math_StringFormat_F
== rtl_math_StringFormat_F)
26
Taking false branch
482 {
483 if(nExp < 0)
484 {
485 *p++ = static_cast< typename T::Char >('0');
486 if (nDecPlaces > 0)
487 {
488 *p++ = cDecSeparator;
489 bHasDec = true;
490 }
491
492 sal_Int32 i = (nDigits <= 0 ? nDecPlaces : -nExp - 1);
493
494 while((i--) > 0)
495 {
496 *p++ = static_cast< typename T::Char >('0');
497 }
498
499 nDecPos = 0;
500 }
501 else
502 {
503 nDecPos = nExp + 1;
504 }
505 }
506 else
507 {
508 nDecPos = 1;
509 }
510
511 int nGrouping = 0, nGroupSelector = 0, nGroupExceed = 0;
512 if (nDecPos
26.1
'nDecPos' is <= 1
> 1 && pGroups && pGroups[0] && cGroupSeparator)
513 {
514 while (nGrouping + pGroups[nGroupSelector] < nDecPos)
515 {
516 nGrouping += pGroups[nGroupSelector];
517 if (pGroups[nGroupSelector+1])
518 {
519 if (nGrouping + pGroups[nGroupSelector+1] >= nDecPos)
520 break; // while
521
522 ++nGroupSelector;
523 }
524 else if (!nGroupExceed)
525 {
526 nGroupExceed = nGrouping;
527 }
528 }
529 }
530
531 // print the number
532 if (nDigits
26.2
'nDigits' is > 0
> 0)
27
Taking true branch
533 {
534 for (int i = 0; ; i++)
28
Loop condition is true. Entering loop body
36
Loop condition is true. Entering loop body
535 {
536 if (i
28.1
'i' is < 15
36.1
'i' is < 15
< 15) // was 16 in ancient versions, which leads to inaccuracies
29
Taking true branch
37
Taking true branch
537 {
538 int nDigit;
539 if (nDigits-1 == 0 && i
38.1
'i' is > 0
> 0 && i
38.2
'i' is < 14
< 14)
30
Assuming the condition is false
38
Assuming the condition is true
39
Taking true branch
540 nDigit = static_cast< int >(floor( fValue + nCorrVal[15-i]));
541 else
542 nDigit = static_cast< int >(fValue + 1E-15);
543
544 if (nDigit >= 10)
31
Assuming 'nDigit' is < 10
32
Taking false branch
40
Assuming 'nDigit' is < 10
41
Taking false branch
545 { // after-treatment of up-rounding to the next decade
546 sal_Int32 sLen = static_cast< long >(p-pBuf)-1;
547 if (sLen == -1 || (sLen == 0 && bSign))
548 {
549 // Assert that no one changed the logic we rely on.
550 assert(!bSign || *pBuf == static_cast< typename T::Char >('-'))(static_cast <bool> (!bSign || *pBuf == static_cast<
typename T::Char >('-')) ? void (0) : __assert_fail ("!bSign || *pBuf == static_cast< typename T::Char >('-')"
, "/home/maarten/src/libreoffice/core/sal/rtl/math.cxx", 550,
__extension__ __PRETTY_FUNCTION__))
;
551 p = pBuf;
552 if (bSign)
553 ++p;
554 if (eFormat == rtl_math_StringFormat_F)
555 {
556 *p++ = static_cast< typename T::Char >('1');
557 *p++ = static_cast< typename T::Char >('0');
558 }
559 else
560 {
561 *p++ = static_cast< typename T::Char >('1');
562 *p++ = cDecSeparator;
563 *p++ = static_cast< typename T::Char >('0');
564 nExp++;
565 bHasDec = true;
566 }
567 }
568 else
569 {
570 for (sal_Int32 j = sLen; j >= 0; j--)
571 {
572 typename T::Char cS = pBuf[j];
573 if (j == 0 && bSign)
574 {
575 // Do not touch leading minus sign put earlier.
576 assert(cS == static_cast< typename T::Char >('-'))(static_cast <bool> (cS == static_cast< typename T::
Char >('-')) ? void (0) : __assert_fail ("cS == static_cast< typename T::Char >('-')"
, "/home/maarten/src/libreoffice/core/sal/rtl/math.cxx", 576,
__extension__ __PRETTY_FUNCTION__))
;
577 break; // for, this is the last character backwards.
578 }
579 if (cS != cDecSeparator)
580 {
581 if (cS != static_cast< typename T::Char >('9'))
582 {
583 pBuf[j] = ++cS;
584 j = -1; // break loop
585 }
586 else
587 {
588 pBuf[j] = static_cast< typename T::Char >('0');
589 if (j == 0 || (j == 1 && bSign))
590 {
591 if (eFormat == rtl_math_StringFormat_F)
592 { // insert '1'
593 typename T::Char * px = p++;
594 while (pBuf < px)
595 {
596 *px = *(px-1);
597 px--;
598 }
599
600 pBuf[0] = static_cast< typename T::Char >('1');
601 }
602 else
603 {
604 pBuf[j] = static_cast< typename T::Char >('1');
605 nExp++;
606 }
607 }
608 }
609 }
610 }
611
612 *p++ = static_cast< typename T::Char >('0');
613 }
614 fValue = 0.0;
615 }
616 else
617 {
618 *p++ = static_cast< typename T::Char >(
619 nDigit + static_cast< typename T::Char >('0') );
620 fValue = (fValue - nDigit) * 10.0;
621 }
622 }
623 else
624 {
625 *p++ = static_cast< typename T::Char >('0');
626 }
627
628 if (!--nDigits)
33
Taking false branch
42
Taking true branch
629 break; // for
43
Execution continues on line 650
630
631 if (nDecPos
33.1
'nDecPos' is 1
)
34
Taking true branch
632 {
633 if(!--nDecPos)
35
Taking true branch
634 {
635 *p++ = cDecSeparator;
636 bHasDec = true;
637 }
638 else if (nDecPos == nGrouping)
639 {
640 *p++ = cGroupSeparator;
641 nGrouping -= pGroups[nGroupSelector];
642
643 if (nGroupSelector && nGrouping < nGroupExceed)
644 --nGroupSelector;
645 }
646 }
647 }
648 }
649
650 if (!bHasDec
43.1
'bHasDec' is true
&& eFormat == rtl_math_StringFormat_F)
651 { // nDecPlaces < 0 did round the value
652 while (--nDecPos > 0)
653 { // fill before decimal point
654 if (nDecPos == nGrouping)
655 {
656 *p++ = cGroupSeparator;
657 nGrouping -= pGroups[nGroupSelector];
658
659 if (nGroupSelector && nGrouping < nGroupExceed)
660 --nGroupSelector;
661 }
662
663 *p++ = static_cast< typename T::Char >('0');
664 }
665 }
666
667 if (bEraseTrailingDecZeros && bHasDec
44.1
'bHasDec' is true
&& p
44.2
'p' is > 'pBuf'
> pBuf)
44
Assuming 'bEraseTrailingDecZeros' is true
45
Taking true branch
668 {
669 while (*(p-1) == static_cast< typename T::Char >('0'))
46
Assuming the condition is true
47
Loop condition is true. Entering loop body
48
Assuming the condition is true
49
Loop condition is true. Entering loop body
50
Assuming the condition is true
51
Loop condition is true. Entering loop body
52
The left operand of '==' is a garbage value
670 {
671 p--;
672 }
673
674 if (*(p-1) == cDecSeparator)
675 p--;
676 }
677
678 // Print the exponent ('E', followed by '+' or '-', followed by exactly
679 // three digits for rtl_math_StringFormat_E). The code in
680 // rtl_[u]str_valueOf{Float|Double} relies on this format.
681 if (eFormat == rtl_math_StringFormat_E || eFormat == rtl_math_StringFormat_E2 || eFormat == rtl_math_StringFormat_E1)
682 {
683 if (p == pBuf)
684 *p++ = static_cast< typename T::Char >('1');
685 // maybe no nDigits if nDecPlaces < 0
686
687 *p++ = static_cast< typename T::Char >('E');
688 if(nExp < 0)
689 {
690 nExp = -nExp;
691 *p++ = static_cast< typename T::Char >('-');
692 }
693 else
694 {
695 *p++ = static_cast< typename T::Char >('+');
696 }
697
698 if (eFormat == rtl_math_StringFormat_E || nExp >= 100)
699 *p++ = static_cast< typename T::Char >(
700 nExp / 100 + static_cast< typename T::Char >('0') );
701
702 nExp %= 100;
703
704 if (eFormat == rtl_math_StringFormat_E || eFormat == rtl_math_StringFormat_E2 || nExp >= 10)
705 *p++ = static_cast< typename T::Char >(
706 nExp / 10 + static_cast< typename T::Char >('0') );
707
708 *p++ = static_cast< typename T::Char >(
709 nExp % 10 + static_cast< typename T::Char >('0') );
710 }
711
712 if (!pResultCapacity)
713 T::createString(pResult, pBuf, p - pBuf);
714 else
715 T::appendChars(pResult, pResultCapacity, &nResultOffset, pBuf, p - pBuf);
716
717 if (pBuf != &aBuf[0])
718 free(pBuf);
719}
720
721}
722
723void SAL_CALL rtl_math_doubleToString(rtl_String ** pResult,
724 sal_Int32 * pResultCapacity,
725 sal_Int32 nResultOffset, double fValue,
726 rtl_math_StringFormat eFormat,
727 sal_Int32 nDecPlaces,
728 char cDecSeparator,
729 sal_Int32 const * pGroups,
730 char cGroupSeparator,
731 sal_Bool bEraseTrailingDecZeros)
732 SAL_THROW_EXTERN_C()throw ()
733{
734 doubleToString< StringTraits >(
735 pResult, pResultCapacity, nResultOffset, fValue, eFormat, nDecPlaces,
736 cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros);
737}
738
739void SAL_CALL rtl_math_doubleToUString(rtl_uString ** pResult,
740 sal_Int32 * pResultCapacity,
741 sal_Int32 nResultOffset, double fValue,
742 rtl_math_StringFormat eFormat,
743 sal_Int32 nDecPlaces,
744 sal_Unicode cDecSeparator,
745 sal_Int32 const * pGroups,
746 sal_Unicode cGroupSeparator,
747 sal_Bool bEraseTrailingDecZeros)
748 SAL_THROW_EXTERN_C()throw ()
749{
750 doubleToString< UStringTraits >(
751 pResult, pResultCapacity, nResultOffset, fValue, eFormat, nDecPlaces,
752 cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros);
753}
754
755namespace {
756
757template< typename CharT >
758double stringToDouble(CharT const * pBegin, CharT const * pEnd,
759 CharT cDecSeparator, CharT cGroupSeparator,
760 rtl_math_ConversionStatus * pStatus,
761 CharT const ** pParsedEnd)
762{
763 double fVal = 0.0;
764 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
765
766 CharT const * p0 = pBegin;
767 while (p0 != pEnd && (*p0 == CharT(' ') || *p0 == CharT('\t')))
768 {
769 ++p0;
770 }
771
772 bool bSign;
773 if (p0 != pEnd && *p0 == CharT('-'))
774 {
775 bSign = true;
776 ++p0;
777 }
778 else
779 {
780 bSign = false;
781 if (p0 != pEnd && *p0 == CharT('+'))
782 ++p0;
783 }
784
785 CharT const * p = p0;
786 bool bDone = false;
787
788 // #i112652# XMLSchema-2
789 if ((pEnd - p) >= 3)
790 {
791 if ((CharT('N') == p[0]) && (CharT('a') == p[1])
792 && (CharT('N') == p[2]))
793 {
794 p += 3;
795 rtl::math::setNan( &fVal );
796 bDone = true;
797 }
798 else if ((CharT('I') == p[0]) && (CharT('N') == p[1])
799 && (CharT('F') == p[2]))
800 {
801 p += 3;
802 fVal = HUGE_VAL(__builtin_huge_val ());
803 eStatus = rtl_math_ConversionStatus_OutOfRange;
804 bDone = true;
805 }
806 }
807
808 if (!bDone) // do not recognize e.g. NaN1.23
809 {
810 std::unique_ptr<char[]> bufInHeap;
811 std::unique_ptr<const CharT * []> bufInHeapMap;
812 constexpr int bufOnStackSize = 256;
813 char bufOnStack[bufOnStackSize];
814 const CharT* bufOnStackMap[bufOnStackSize];
815 char* buf = bufOnStack;
816 const CharT** bufmap = bufOnStackMap;
817 int bufpos = 0;
818 const size_t bufsize = pEnd - p + (bSign ? 2 : 1);
819 if (bufsize > bufOnStackSize)
820 {
821 bufInHeap = std::make_unique<char[]>(bufsize);
822 bufInHeapMap = std::make_unique<const CharT*[]>(bufsize);
823 buf = bufInHeap.get();
824 bufmap = bufInHeapMap.get();
825 }
826
827 if (bSign)
828 {
829 buf[0] = '-';
830 bufmap[0] = p; // yes, this may be the same pointer as for the next mapping
831 bufpos = 1;
832 }
833 // Put first zero to buffer for strings like "-0"
834 if (p != pEnd && *p == CharT('0'))
835 {
836 buf[bufpos] = '0';
837 bufmap[bufpos] = p;
838 ++bufpos;
839 ++p;
840 }
841 // Leading zeros and group separators between digits may be safely
842 // ignored. p0 < p implies that there was a leading 0 already,
843 // consecutive group separators may not happen as *(p+1) is checked for
844 // digit.
845 while (p != pEnd && (*p == CharT('0') || (*p == cGroupSeparator
846 && p0 < p && p+1 < pEnd && rtl::isAsciiDigit(*(p+1)))))
847 {
848 ++p;
849 }
850
851 // integer part of mantissa
852 for (; p != pEnd; ++p)
853 {
854 CharT c = *p;
855 if (rtl::isAsciiDigit(c))
856 {
857 buf[bufpos] = static_cast<char>(c);
858 bufmap[bufpos] = p;
859 ++bufpos;
860 }
861 else if (c != cGroupSeparator)
862 {
863 break;
864 }
865 else if (p == p0 || (p+1 == pEnd) || !rtl::isAsciiDigit(*(p+1)))
866 {
867 // A leading or trailing (not followed by a digit) group
868 // separator character is not a group separator.
869 break;
870 }
871 }
872
873 // fraction part of mantissa
874 if (p != pEnd && *p == cDecSeparator)
875 {
876 buf[bufpos] = '.';
877 bufmap[bufpos] = p;
878 ++bufpos;
879 ++p;
880
881 for (; p != pEnd; ++p)
882 {
883 CharT c = *p;
884 if (!rtl::isAsciiDigit(c))
885 {
886 break;
887 }
888 buf[bufpos] = static_cast<char>(c);
889 bufmap[bufpos] = p;
890 ++bufpos;
891 }
892 }
893
894 // Exponent
895 if (p != p0 && p != pEnd && (*p == CharT('E') || *p == CharT('e')))
896 {
897 buf[bufpos] = 'E';
898 bufmap[bufpos] = p;
899 ++bufpos;
900 ++p;
901 if (p != pEnd && *p == CharT('-'))
902 {
903 buf[bufpos] = '-';
904 bufmap[bufpos] = p;
905 ++bufpos;
906 ++p;
907 }
908 else if (p != pEnd && *p == CharT('+'))
909 ++p;
910
911 for (; p != pEnd; ++p)
912 {
913 CharT c = *p;
914 if (!rtl::isAsciiDigit(c))
915 break;
916
917 buf[bufpos] = static_cast<char>(c);
918 bufmap[bufpos] = p;
919 ++bufpos;
920 }
921 }
922 else if (p - p0 == 2 && p != pEnd && p[0] == CharT('#')
923 && p[-1] == cDecSeparator && p[-2] == CharT('1'))
924 {
925 if (pEnd - p >= 4 && p[1] == CharT('I') && p[2] == CharT('N')
926 && p[3] == CharT('F'))
927 {
928 // "1.#INF", "+1.#INF", "-1.#INF"
929 p += 4;
930 fVal = HUGE_VAL(__builtin_huge_val ());
931 eStatus = rtl_math_ConversionStatus_OutOfRange;
932 // Eat any further digits:
933 while (p != pEnd && rtl::isAsciiDigit(*p))
934 ++p;
935 bDone = true;
936 }
937 else if (pEnd - p >= 4 && p[1] == CharT('N') && p[2] == CharT('A')
938 && p[3] == CharT('N'))
939 {
940 // "1.#NAN", "+1.#NAN", "-1.#NAN"
941 p += 4;
942 rtl::math::setNan( &fVal );
943 if (bSign)
944 {
945 union {
946 double sd;
947 sal_math_Double md;
948 } m;
949
950 m.sd = fVal;
951 m.md.w32_parts.msw |= 0x80000000; // create negative NaN
952 fVal = m.sd;
953 bSign = false; // don't negate again
954 }
955
956 // Eat any further digits:
957 while (p != pEnd && rtl::isAsciiDigit(*p))
958 {
959 ++p;
960 }
961 bDone = true;
962 }
963 }
964
965 if (!bDone)
966 {
967 buf[bufpos] = '\0';
968 bufmap[bufpos] = p;
969 char* pCharParseEnd;
970 errno(*__errno_location ()) = 0;
971 fVal = strtod_nolocale(buf, &pCharParseEnd);
972 if (errno(*__errno_location ()) == ERANGE34)
973 eStatus = rtl_math_ConversionStatus_OutOfRange;
974 p = bufmap[pCharParseEnd - buf];
975 bSign = false;
976 }
977 }
978
979 // overflow also if more than DBL_MAX_10_EXP digits without decimal
980 // separator, or 0. and more than DBL_MIN_10_EXP digits, ...
981 bool bHuge = fVal == HUGE_VAL(__builtin_huge_val ()); // g++ 3.0.1 requires it this way...
982 if (bHuge)
983 eStatus = rtl_math_ConversionStatus_OutOfRange;
984
985 if (bSign)
986 fVal = -fVal;
987
988 if (pStatus)
989 *pStatus = eStatus;
990
991 if (pParsedEnd)
992 *pParsedEnd = p == p0 ? pBegin : p;
993
994 return fVal;
995}
996
997}
998
999double SAL_CALL rtl_math_stringToDouble(char const * pBegin,
1000 char const * pEnd,
1001 char cDecSeparator,
1002 char cGroupSeparator,
1003 rtl_math_ConversionStatus * pStatus,
1004 char const ** pParsedEnd)
1005 SAL_THROW_EXTERN_C()throw ()
1006{
1007 return stringToDouble(
1008 reinterpret_cast<unsigned char const *>(pBegin),
1009 reinterpret_cast<unsigned char const *>(pEnd),
1010 static_cast<unsigned char>(cDecSeparator),
1011 static_cast<unsigned char>(cGroupSeparator), pStatus,
1012 reinterpret_cast<unsigned char const **>(pParsedEnd));
1013}
1014
1015double SAL_CALL rtl_math_uStringToDouble(sal_Unicode const * pBegin,
1016 sal_Unicode const * pEnd,
1017 sal_Unicode cDecSeparator,
1018 sal_Unicode cGroupSeparator,
1019 rtl_math_ConversionStatus * pStatus,
1020 sal_Unicode const ** pParsedEnd)
1021 SAL_THROW_EXTERN_C()throw ()
1022{
1023 return stringToDouble(pBegin, pEnd, cDecSeparator, cGroupSeparator, pStatus,
1024 pParsedEnd);
1025}
1026
1027double SAL_CALL rtl_math_round(double fValue, int nDecPlaces,
1028 enum rtl_math_RoundingMode eMode)
1029 SAL_THROW_EXTERN_C()throw ()
1030{
1031 OSL_ASSERT(nDecPlaces >= -20 && nDecPlaces <= 20)do { if (true && (!(nDecPlaces >= -20 && nDecPlaces
<= 20))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sal/rtl/math.cxx"
":" "1031" ": "), "OSL_ASSERT: %s", "nDecPlaces >= -20 && nDecPlaces <= 20"
); } } while (false)
;
1032
1033 if (fValue == 0.0)
1034 return fValue;
1035
1036 if ( nDecPlaces == 0 && eMode == rtl_math_RoundingMode_Corrected )
1037 return std::round( fValue );
1038
1039 // sign adjustment
1040 bool bSign = std::signbit( fValue );
1041 if (bSign)
1042 fValue = -fValue;
1043
1044 double fFac = 0;
1045 if (nDecPlaces != 0)
1046 {
1047 // max 20 decimals, we don't have unlimited precision
1048 // #38810# and no overflow on fValue*=fFac
1049 if (nDecPlaces < -20 || 20 < nDecPlaces || fValue > (DBL_MAX1.7976931348623157e+308 / 1e20))
1050 return bSign ? -fValue : fValue;
1051
1052 fFac = getN10Exp(nDecPlaces);
1053 fValue *= fFac;
1054 }
1055
1056 switch ( eMode )
1057 {
1058 case rtl_math_RoundingMode_Corrected :
1059 {
1060 int nExp; // exponent for correction
1061 if ( fValue > 0.0 )
1062 nExp = static_cast<int>( floor( log10( fValue ) ) );
1063 else
1064 nExp = 0;
1065
1066 int nIndex;
1067
1068 if (nExp < 0)
1069 nIndex = 15;
1070 else if (nExp >= 14)
1071 nIndex = 0;
1072 else
1073 nIndex = 15 - nExp;
1074
1075 fValue = floor(fValue + 0.5 + nCorrVal[nIndex]);
1076 }
1077 break;
1078 case rtl_math_RoundingMode_Down:
1079 fValue = rtl::math::approxFloor(fValue);
1080 break;
1081 case rtl_math_RoundingMode_Up:
1082 fValue = rtl::math::approxCeil(fValue);
1083 break;
1084 case rtl_math_RoundingMode_Floor:
1085 fValue = bSign ? rtl::math::approxCeil(fValue)
1086 : rtl::math::approxFloor( fValue );
1087 break;
1088 case rtl_math_RoundingMode_Ceiling:
1089 fValue = bSign ? rtl::math::approxFloor(fValue)
1090 : rtl::math::approxCeil(fValue);
1091 break;
1092 case rtl_math_RoundingMode_HalfDown :
1093 {
1094 double f = floor(fValue);
1095 fValue = ((fValue - f) <= 0.5) ? f : ceil(fValue);
1096 }
1097 break;
1098 case rtl_math_RoundingMode_HalfUp:
1099 {
1100 double f = floor(fValue);
1101 fValue = ((fValue - f) < 0.5) ? f : ceil(fValue);
1102 }
1103 break;
1104 case rtl_math_RoundingMode_HalfEven:
1105#if defined FLT_ROUNDS(__builtin_flt_rounds())
1106/*
1107 Use fast version. FLT_ROUNDS may be defined to a function by some compilers!
1108
1109 DBL_EPSILON is the smallest fractional number which can be represented,
1110 its reciprocal is therefore the smallest number that cannot have a
1111 fractional part. Once you add this reciprocal to `x', its fractional part
1112 is stripped off. Simply subtracting the reciprocal back out returns `x'
1113 without its fractional component.
1114 Simple, clever, and elegant - thanks to Ross Cottrell, the original author,
1115 who placed it into public domain.
1116
1117 volatile: prevent compiler from being too smart
1118*/
1119 if (FLT_ROUNDS(__builtin_flt_rounds()) == 1)
1120 {
1121 volatile double x = fValue + 1.0 / DBL_EPSILON2.2204460492503131e-16;
1122 fValue = x - 1.0 / DBL_EPSILON2.2204460492503131e-16;
1123 }
1124 else
1125#endif // FLT_ROUNDS
1126 {
1127 double f = floor(fValue);
1128 if ((fValue - f) != 0.5)
1129 {
1130 fValue = floor( fValue + 0.5 );
1131 }
1132 else
1133 {
1134 double g = f / 2.0;
1135 fValue = (g == floor( g )) ? f : (f + 1.0);
1136 }
1137 }
1138 break;
1139 default:
1140 OSL_ASSERT(false)do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sal/rtl/math.cxx"
":" "1140" ": "), "OSL_ASSERT: %s", "false"); } } while (false
)
;
1141 break;
1142 }
1143
1144 if (nDecPlaces != 0)
1145 fValue /= fFac;
1146
1147 return bSign ? -fValue : fValue;
1148}
1149
1150double SAL_CALL rtl_math_pow10Exp(double fValue, int nExp) SAL_THROW_EXTERN_C()throw ()
1151{
1152 return fValue * getN10Exp(nExp);
1153}
1154
1155double SAL_CALL rtl_math_approxValue( double fValue ) SAL_THROW_EXTERN_C()throw ()
1156{
1157 const double fBigInt = 2199023255552.0; // 2^41 -> only 11 bits left for fractional part, fine as decimal
1158 if (fValue == 0.0 || fValue == HUGE_VAL(__builtin_huge_val ()) || !std::isfinite( fValue) || fValue > fBigInt)
1159 {
1160 // We don't handle these conditions. Bail out.
1161 return fValue;
1162 }
1163
1164 double fOrigValue = fValue;
1165
1166 bool bSign = std::signbit(fValue);
1167 if (bSign)
1168 fValue = -fValue;
1169
1170 // If the value is either integer representable as double,
1171 // or only has small number of bits in fraction part, then we need not do any approximation
1172 if (isRepresentableInteger(fValue) || getBitsInFracPart(fValue) <= 11)
1173 return fOrigValue;
1174
1175 int nExp = static_cast< int >(floor(log10(fValue)));
1176 nExp = 14 - nExp;
1177 double fExpValue = getN10Exp(nExp);
1178
1179 fValue *= fExpValue;
1180 // If the original value was near DBL_MIN we got an overflow. Restore and
1181 // bail out.
1182 if (!std::isfinite(fValue))
1183 return fOrigValue;
1184
1185 fValue = rtl_math_round(fValue, 0, rtl_math_RoundingMode_Corrected);
1186 fValue /= fExpValue;
1187
1188 // If the original value was near DBL_MAX we got an overflow. Restore and
1189 // bail out.
1190 if (!std::isfinite(fValue))
1191 return fOrigValue;
1192
1193 return bSign ? -fValue : fValue;
1194}
1195
1196bool SAL_CALL rtl_math_approxEqual(double a, double b) SAL_THROW_EXTERN_C()throw ()
1197{
1198 static const double e48 = 1.0 / (16777216.0 * 16777216.0);
1199 static const double e44 = e48 * 16.0;
1200
1201 if (a == b)
1202 return true;
1203
1204 if (a == 0.0 || b == 0.0)
1205 return false;
1206
1207 const double d = fabs(a - b);
1208 if (!std::isfinite(d))
1209 return false; // Nan or Inf involved
1210
1211 a = fabs(a);
1212 if (d > (a * e44))
1213 return false;
1214 b = fabs(b);
1215 if (d > (b * e44))
1216 return false;
1217
1218 if (isRepresentableInteger(d) && isRepresentableInteger(a) && isRepresentableInteger(b))
1219 return false; // special case for representable integers.
1220
1221 return (d < a * e48 && d < b * e48);
1222}
1223
1224double SAL_CALL rtl_math_expm1(double fValue) SAL_THROW_EXTERN_C()throw ()
1225{
1226 return expm1(fValue);
1227}
1228
1229double SAL_CALL rtl_math_log1p(double fValue) SAL_THROW_EXTERN_C()throw ()
1230{
1231#ifdef __APPLE__
1232 if (fValue == -0.0)
1233 return fValue; // macOS 10.8 libc returns 0.0 for -0.0
1234#endif
1235
1236 return log1p(fValue);
1237}
1238
1239double SAL_CALL rtl_math_atanh(double fValue) SAL_THROW_EXTERN_C()throw ()
1240#if defined __clang__1
1241 __attribute__((no_sanitize("float-divide-by-zero"))) // atahn(1) -> inf
1242#endif
1243{
1244 return 0.5 * rtl_math_log1p(2.0 * fValue / (1.0-fValue));
1245}
1246
1247/** Parent error function (erf) */
1248double SAL_CALL rtl_math_erf(double x) SAL_THROW_EXTERN_C()throw ()
1249{
1250 return erf(x);
1251}
1252
1253/** Parent complementary error function (erfc) */
1254double SAL_CALL rtl_math_erfc(double x) SAL_THROW_EXTERN_C()throw ()
1255{
1256 return erfc(x);
1257}
1258
1259/** improved accuracy of asinh for |x| large and for x near zero
1260 @see #i97605#
1261 */
1262double SAL_CALL rtl_math_asinh(double fX) SAL_THROW_EXTERN_C()throw ()
1263{
1264 if ( fX == 0.0 )
1265 return 0.0;
1266
1267 double fSign = 1.0;
1268 if ( fX < 0.0 )
1269 {
1270 fX = - fX;
1271 fSign = -1.0;
1272 }
1273
1274 if ( fX < 0.125 )
1275 return fSign * rtl_math_log1p( fX + fX*fX / (1.0 + sqrt( 1.0 + fX*fX)));
1276
1277 if ( fX < 1.25e7 )
1278 return fSign * log( fX + sqrt( 1.0 + fX*fX));
1279
1280 return fSign * log( 2.0*fX);
1281}
1282
1283/** improved accuracy of acosh for x large and for x near 1
1284 @see #i97605#
1285 */
1286double SAL_CALL rtl_math_acosh(double fX) SAL_THROW_EXTERN_C()throw ()
1287{
1288 volatile double fZ = fX - 1.0;
1289 if (fX < 1.0)
1290 {
1291 double fResult;
1292 ::rtl::math::setNan( &fResult );
1293 return fResult;
1294 }
1295 if ( fX == 1.0 )
1296 return 0.0;
1297
1298 if ( fX < 1.1 )
1299 return rtl_math_log1p( fZ + sqrt( fZ*fZ + 2.0*fZ));
1300
1301 if ( fX < 1.25e7 )
1302 return log( fX + sqrt( fX*fX - 1.0));
1303
1304 return log( 2.0*fX);
1305}
1306
1307/* vim:set shiftwidth=4 softtabstop=4 expandtab: */