File: | home/maarten/src/libreoffice/core/sal/rtl/math.cxx |
Warning: | line 561, column 34 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
45 | int const n10Count = 16; | |||
46 | double 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] | |||
54 | static 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 | ||||
74 | namespace { | |||
75 | ||||
76 | double 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 | ||||
81 | struct 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 | ||||
118 | struct 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 | */ | |||
158 | bool 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 | |||
179 | int 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 | */ | |||
193 | int 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 | ||||
217 | template< typename T > | |||
218 | void 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) | |||
| ||||
236 | fValue = -fValue; | |||
237 | ||||
238 | if (std::isnan(fValue)) | |||
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)) | |||
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 || | |||
281 | eFormat == rtl_math_StringFormat_F) && fValue <= static_cast< double >(kMaxInt)) | |||
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 ) | |||
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) | |||
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; | |||
434 | } | |||
435 | ||||
436 | sal_Int32 nDigits = nDecPlaces + 1; | |||
437 | ||||
438 | if (eFormat
| |||
439 | nDigits += nExp; | |||
440 | ||||
441 | // Round the number | |||
442 | if(nDigits >= 0) | |||
443 | { | |||
444 | fValue += nRoundVal[std::min<sal_Int32>(nDigits, 15)]; | |||
445 | if (fValue >= 10) | |||
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
| |||
460 | : nDigits + nDecPlaces ) + 10 + (pGroups ? abs(nDigits) * 2 : 0); | |||
461 | ||||
462 | if (nBuf > nBufMax) | |||
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
| |||
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
| |||
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
| |||
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
| |||
533 | { | |||
534 | for (int i = 0; ; i++) | |||
535 | { | |||
536 | if (i
| |||
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
| |||
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 && 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 && 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 | ||||
723 | void 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 | ||||
739 | void 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 | ||||
755 | namespace { | |||
756 | ||||
757 | template< typename CharT > | |||
758 | double 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 | ||||
999 | double 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 | ||||
1015 | double 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 | ||||
1027 | double 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 | ||||
1150 | double SAL_CALL rtl_math_pow10Exp(double fValue, int nExp) SAL_THROW_EXTERN_C()throw () | |||
1151 | { | |||
1152 | return fValue * getN10Exp(nExp); | |||
1153 | } | |||
1154 | ||||
1155 | double 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 | ||||
1196 | bool 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 | ||||
1224 | double SAL_CALL rtl_math_expm1(double fValue) SAL_THROW_EXTERN_C()throw () | |||
1225 | { | |||
1226 | return expm1(fValue); | |||
1227 | } | |||
1228 | ||||
1229 | double 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 | ||||
1239 | double 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) */ | |||
1248 | double 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) */ | |||
1254 | double 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 | */ | |||
1262 | double 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 | */ | |||
1286 | double 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: */ |