File: | home/maarten/src/libreoffice/core/sal/rtl/math.cxx |
Warning: | line 656, column 22 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
| ||||
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
| ||||
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)) | ||||
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
| ||||
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 < 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
| ||||
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: */ |