Bug Summary

File:home/maarten/src/libreoffice/core/sal/rtl/math.cxx
Warning:line 656, column 22
Dereference of null pointer

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 'case rtl_math_StringFormat_G:' at line 407
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)
13
Assuming 'nDecPlaces' is not equal to rtl_math_DecimalPlaces_DefaultSignificance
14
Taking false branch
412 nDecPlaces = 6;
413
414 if (nExp < -4 || nExp >= nDecPlaces)
15
Assuming 'nExp' is < 'nDecPlaces'
16
Taking false branch
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;
17
Execution continues on line 436
432 default:
433 break;
434 }
435
436 sal_Int32 nDigits = nDecPlaces + 1;
437
438 if (eFormat
17.1
'eFormat' is equal to rtl_math_StringFormat_F
== rtl_math_StringFormat_F)
18
Taking true branch
439 nDigits += nExp;
440
441 // Round the number
442 if(nDigits
18.1
'nDigits' is >= 0
>= 0)
19
Taking true branch
443 {
444 fValue += nRoundVal[std::min<sal_Int32>(nDigits, 15)];
445 if (fValue >= 10)
20
Assuming 'fValue' is >= 10
21
Taking true branch
446 {
447 fValue = 1.0;
448 nExp++;
449
450 if (eFormat
21.1
'eFormat' is equal to rtl_math_StringFormat_F
== rtl_math_StringFormat_F)
22
Taking true branch
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))
23
Assuming 'nDigits' is <= 0
24
'?' condition is true
460 : nDigits + nDecPlaces ) + 10 + (pGroups ? abs(nDigits) * 2 : 0);
25
Assuming 'pGroups' is non-null
26
'?' condition is true
461
462 if (nBuf > nBufMax)
27
Assuming 'nBuf' is > 'nBufMax'
28
Taking true 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)
;
29
Assuming 'pBuf' is null
30
Taking true branch
31
Loop condition is false. Exiting loop
467 }
468 else
469 {
470 pBuf = aBuf;
471 }
472
473 typename T::Char * p = pBuf;
474 if ( bSign
31.1
'bSign' is false
)
32
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
32.1
'eFormat' is equal to rtl_math_StringFormat_F
== rtl_math_StringFormat_F)
33
Taking true branch
482 {
483 if(nExp
33.1
'nExp' is >= 0
< 0)
34
Taking false branch
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
34.1
'nDecPos' is > 1
> 1 && pGroups
34.2
'pGroups' is non-null
&& pGroups[0] && cGroupSeparator)
35
Assuming the condition is true
36
Assuming 'cGroupSeparator' is not equal to 0
37
Taking true branch
513 {
514 while (nGrouping + pGroups[nGroupSelector] < nDecPos)
38
Assuming the condition is true
39
Loop condition is true. Entering loop body
515 {
516 nGrouping += pGroups[nGroupSelector];
517 if (pGroups[nGroupSelector+1])
40
Assuming the condition is true
41
Taking true branch
518 {
519 if (nGrouping + pGroups[nGroupSelector+1] >= nDecPos)
42
Assuming the condition is true
43
Taking true branch
520 break; // while
44
Execution continues on line 532
521
522 ++nGroupSelector;
523 }
524 else if (!nGroupExceed)
525 {
526 nGroupExceed = nGrouping;
527 }
528 }
529 }
530
531 // print the number
532 if (nDigits
44.1
'nDigits' is <= 0
> 0)
45
Taking false branch
533 {
534 for (int i = 0; ; i++)
535 {
536 if (i < 15) // was 16 in ancient versions, which leads to inaccuracies
537 {
538 int nDigit;
539 if (nDigits-1 == 0 && i > 0 && i < 14)
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)
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)
629 break; // for
630
631 if (nDecPos)
632 {
633 if(!--nDecPos)
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
45.1
'bHasDec' is false
&& eFormat
45.2
'eFormat' is equal to rtl_math_StringFormat_F
== rtl_math_StringFormat_F)
46
Taking true branch
651 { // nDecPlaces < 0 did round the value
652 while (--nDecPos > 0)
47
Loop condition is true. Entering loop body
653 { // fill before decimal point
654 if (nDecPos == nGrouping)
48
Assuming 'nDecPos' is equal to 'nGrouping'
49
Taking true branch
655 {
656 *p++ = cGroupSeparator;
50
Null pointer value stored to 'p'
51
Dereference of null pointer
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 && p > pBuf)
668 {
669 while (*(p-1) == static_cast< typename T::Char >('0'))
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: */