/src/libreoffice/include/rtl/math.hxx
Line | Count | Source |
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 | | /* |
21 | | * This file is part of LibreOffice published API. |
22 | | */ |
23 | | |
24 | | #ifndef INCLUDED_RTL_MATH_HXX |
25 | | #define INCLUDED_RTL_MATH_HXX |
26 | | |
27 | | #include "rtl/math.h" |
28 | | #include "rtl/strbuf.hxx" |
29 | | #include "rtl/string.hxx" |
30 | | #include "rtl/ustring.hxx" |
31 | | #include "rtl/ustrbuf.hxx" |
32 | | #include "sal/mathconf.h" |
33 | | #include "sal/types.h" |
34 | | |
35 | | #include <cstddef> |
36 | | #include <math.h> |
37 | | |
38 | | namespace rtl { |
39 | | |
40 | | namespace math { |
41 | | |
42 | | /** A wrapper around rtl_math_doubleToString. |
43 | | */ |
44 | | inline rtl::OString doubleToString(double fValue, rtl_math_StringFormat eFormat, |
45 | | sal_Int32 nDecPlaces, |
46 | | char cDecSeparator, |
47 | | sal_Int32 const * pGroups, |
48 | | char cGroupSeparator, |
49 | | bool bEraseTrailingDecZeros = false) |
50 | 0 | { |
51 | 0 | rtl::OString aResult; |
52 | 0 | rtl_math_doubleToString(&aResult.pData, NULL, 0, fValue, eFormat, nDecPlaces, |
53 | 0 | cDecSeparator, pGroups, cGroupSeparator, |
54 | 0 | bEraseTrailingDecZeros); |
55 | 0 | return aResult; |
56 | 0 | } |
57 | | |
58 | | /** A wrapper around rtl_math_doubleToString, with no grouping. |
59 | | */ |
60 | | inline rtl::OString doubleToString(double fValue, rtl_math_StringFormat eFormat, |
61 | | sal_Int32 nDecPlaces, |
62 | | char cDecSeparator, |
63 | | bool bEraseTrailingDecZeros = false) |
64 | 2.34k | { |
65 | 2.34k | rtl::OString aResult; |
66 | 2.34k | rtl_math_doubleToString(&aResult.pData, NULL, 0, fValue, eFormat, nDecPlaces, |
67 | 2.34k | cDecSeparator, NULL, 0, bEraseTrailingDecZeros); |
68 | 2.34k | return aResult; |
69 | 2.34k | } |
70 | | |
71 | | /** A wrapper around rtl_math_doubleToString that appends to an |
72 | | rtl::OStringBuffer. |
73 | | |
74 | | @since LibreOffice 5.4 |
75 | | */ |
76 | | inline void doubleToStringBuffer( |
77 | | rtl::OStringBuffer& rBuffer, double fValue, rtl_math_StringFormat eFormat, |
78 | | sal_Int32 nDecPlaces, char cDecSeparator, sal_Int32 const * pGroups, |
79 | | char cGroupSeparator, bool bEraseTrailingDecZeros = false) |
80 | 0 | { |
81 | 0 | rtl_String ** pData; |
82 | 0 | sal_Int32 * pCapacity; |
83 | 0 | rBuffer.accessInternals(&pData, &pCapacity); |
84 | 0 | rtl_math_doubleToString( |
85 | 0 | pData, pCapacity, rBuffer.getLength(), fValue, eFormat, nDecPlaces, |
86 | 0 | cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros); |
87 | 0 | } |
88 | | |
89 | | /** A wrapper around rtl_math_doubleToString that appends to an |
90 | | rtl::OStringBuffer, with no grouping. |
91 | | |
92 | | @since LibreOffice 5.4 |
93 | | */ |
94 | | inline void doubleToStringBuffer( |
95 | | rtl::OStringBuffer& rBuffer, double fValue, rtl_math_StringFormat eFormat, |
96 | | sal_Int32 nDecPlaces, char cDecSeparator, |
97 | | bool bEraseTrailingDecZeros = false) |
98 | 1.48M | { |
99 | 1.48M | rtl_String ** pData; |
100 | 1.48M | sal_Int32 * pCapacity; |
101 | 1.48M | rBuffer.accessInternals(&pData, &pCapacity); |
102 | 1.48M | rtl_math_doubleToString( |
103 | 1.48M | pData, pCapacity, rBuffer.getLength(), fValue, eFormat, nDecPlaces, |
104 | 1.48M | cDecSeparator, NULL, 0, bEraseTrailingDecZeros); |
105 | 1.48M | } |
106 | | |
107 | | /** A wrapper around rtl_math_doubleToUString. |
108 | | */ |
109 | | inline rtl::OUString doubleToUString(double fValue, |
110 | | rtl_math_StringFormat eFormat, |
111 | | sal_Int32 nDecPlaces, |
112 | | sal_Unicode cDecSeparator, |
113 | | sal_Int32 const * pGroups, |
114 | | sal_Unicode cGroupSeparator, |
115 | | bool bEraseTrailingDecZeros = false) |
116 | 0 | { |
117 | 0 | rtl::OUString aResult; |
118 | 0 | rtl_math_doubleToUString(&aResult.pData, NULL, 0, fValue, eFormat, nDecPlaces, |
119 | 0 | cDecSeparator, pGroups, cGroupSeparator, |
120 | 0 | bEraseTrailingDecZeros); |
121 | 0 | return aResult; |
122 | 0 | } |
123 | | |
124 | | /** A wrapper around rtl_math_doubleToUString, with no grouping. |
125 | | */ |
126 | | inline rtl::OUString doubleToUString(double fValue, |
127 | | rtl_math_StringFormat eFormat, |
128 | | sal_Int32 nDecPlaces, |
129 | | sal_Unicode cDecSeparator, |
130 | | bool bEraseTrailingDecZeros = false) |
131 | 232k | { |
132 | 232k | rtl::OUString aResult; |
133 | 232k | rtl_math_doubleToUString(&aResult.pData, NULL, 0, fValue, eFormat, nDecPlaces, |
134 | 232k | cDecSeparator, NULL, 0, bEraseTrailingDecZeros); |
135 | 232k | return aResult; |
136 | 232k | } |
137 | | |
138 | | /** A wrapper around rtl_math_doubleToUString that appends to an |
139 | | rtl::OUStringBuffer. |
140 | | */ |
141 | | inline void doubleToUStringBuffer( rtl::OUStringBuffer& rBuffer, double fValue, |
142 | | rtl_math_StringFormat eFormat, |
143 | | sal_Int32 nDecPlaces, |
144 | | sal_Unicode cDecSeparator, |
145 | | sal_Int32 const * pGroups, |
146 | | sal_Unicode cGroupSeparator, |
147 | | bool bEraseTrailingDecZeros = false) |
148 | 0 | { |
149 | 0 | rtl_uString ** pData; |
150 | 0 | sal_Int32 * pCapacity; |
151 | 0 | rBuffer.accessInternals( &pData, &pCapacity ); |
152 | 0 | rtl_math_doubleToUString( pData, pCapacity, rBuffer.getLength(), fValue, |
153 | 0 | eFormat, nDecPlaces, cDecSeparator, pGroups, |
154 | 0 | cGroupSeparator, bEraseTrailingDecZeros); |
155 | 0 | } |
156 | | |
157 | | /** A wrapper around rtl_math_doubleToUString that appends to an |
158 | | rtl::OUStringBuffer, with no grouping. |
159 | | */ |
160 | | inline void doubleToUStringBuffer( rtl::OUStringBuffer& rBuffer, double fValue, |
161 | | rtl_math_StringFormat eFormat, |
162 | | sal_Int32 nDecPlaces, |
163 | | sal_Unicode cDecSeparator, |
164 | | bool bEraseTrailingDecZeros = false) |
165 | 218k | { |
166 | 218k | rtl_uString ** pData; |
167 | 218k | sal_Int32 * pCapacity; |
168 | 218k | rBuffer.accessInternals( &pData, &pCapacity ); |
169 | 218k | rtl_math_doubleToUString( pData, pCapacity, rBuffer.getLength(), fValue, |
170 | 218k | eFormat, nDecPlaces, cDecSeparator, NULL, 0, |
171 | 218k | bEraseTrailingDecZeros); |
172 | 218k | } |
173 | | |
174 | | /** A wrapper around rtl_math_stringToDouble. |
175 | | */ |
176 | | #ifdef LIBO_INTERNAL_ONLY |
177 | | inline double stringToDouble(std::string_view aString, |
178 | | char cDecSeparator, char cGroupSeparator, |
179 | | rtl_math_ConversionStatus * pStatus = NULL, |
180 | | sal_Int32 * pParsedEnd = NULL) |
181 | 0 | { |
182 | 0 | char const * pBegin = aString.data(); |
183 | 0 | char const * pEnd; |
184 | 0 | double fResult = rtl_math_stringToDouble(pBegin, |
185 | 0 | pBegin + aString.size(), |
186 | 0 | cDecSeparator, cGroupSeparator, |
187 | 0 | pStatus, &pEnd); |
188 | 0 | if (pParsedEnd != NULL) |
189 | 0 | *pParsedEnd = static_cast<sal_Int32>(pEnd - pBegin); |
190 | 0 | return fResult; |
191 | 0 | } |
192 | | #else |
193 | | inline double stringToDouble(rtl::OString const & rString, |
194 | | char cDecSeparator, char cGroupSeparator, |
195 | | rtl_math_ConversionStatus * pStatus = NULL, |
196 | | sal_Int32 * pParsedEnd = NULL) |
197 | | { |
198 | | char const * pBegin = rString.getStr(); |
199 | | char const * pEnd; |
200 | | double fResult = rtl_math_stringToDouble(pBegin, |
201 | | pBegin + rString.getLength(), |
202 | | cDecSeparator, cGroupSeparator, |
203 | | pStatus, &pEnd); |
204 | | if (pParsedEnd != NULL) |
205 | | *pParsedEnd = static_cast<sal_Int32>(pEnd - pBegin); |
206 | | return fResult; |
207 | | } |
208 | | #endif |
209 | | |
210 | | |
211 | | /** A wrapper around rtl_math_uStringToDouble. |
212 | | */ |
213 | | #ifdef LIBO_INTERNAL_ONLY |
214 | | inline double stringToDouble(std::u16string_view aString, |
215 | | sal_Unicode cDecSeparator, |
216 | | sal_Unicode cGroupSeparator, |
217 | | rtl_math_ConversionStatus * pStatus = NULL, |
218 | | sal_Int32 * pParsedEnd = NULL) |
219 | 428k | { |
220 | 428k | sal_Unicode const * pBegin = aString.data(); |
221 | 428k | sal_Unicode const * pEnd; |
222 | 428k | double fResult = rtl_math_uStringToDouble(pBegin, |
223 | 428k | pBegin + aString.size(), |
224 | 428k | cDecSeparator, cGroupSeparator, |
225 | 428k | pStatus, &pEnd); |
226 | 428k | if (pParsedEnd != NULL) |
227 | 317k | *pParsedEnd = static_cast<sal_Int32>(pEnd - pBegin); |
228 | 428k | return fResult; |
229 | 428k | } |
230 | | #else |
231 | | inline double stringToDouble(rtl::OUString const & rString, |
232 | | sal_Unicode cDecSeparator, |
233 | | sal_Unicode cGroupSeparator, |
234 | | rtl_math_ConversionStatus * pStatus = NULL, |
235 | | sal_Int32 * pParsedEnd = NULL) |
236 | | { |
237 | | sal_Unicode const * pBegin = rString.getStr(); |
238 | | sal_Unicode const * pEnd; |
239 | | double fResult = rtl_math_uStringToDouble(pBegin, |
240 | | pBegin + rString.getLength(), |
241 | | cDecSeparator, cGroupSeparator, |
242 | | pStatus, &pEnd); |
243 | | if (pParsedEnd != NULL) |
244 | | *pParsedEnd = static_cast<sal_Int32>(pEnd - pBegin); |
245 | | return fResult; |
246 | | } |
247 | | #endif |
248 | | |
249 | | /** A wrapper around rtl_math_round. |
250 | | */ |
251 | | inline double round( |
252 | | double fValue, int nDecPlaces = 0, |
253 | | rtl_math_RoundingMode eMode = rtl_math_RoundingMode_Corrected) |
254 | 581k | { |
255 | 581k | return rtl_math_round(fValue, nDecPlaces, eMode); |
256 | 581k | } |
257 | | |
258 | | /** A wrapper around rtl_math_pow10Exp. |
259 | | */ |
260 | | inline double pow10Exp(double fValue, int nExp) |
261 | 53 | { |
262 | 53 | return rtl_math_pow10Exp(fValue, nExp); |
263 | 53 | } |
264 | | |
265 | | /** A wrapper around rtl_math_approxValue. |
266 | | */ |
267 | | inline double approxValue(double fValue) |
268 | 7.10M | { |
269 | 7.10M | return rtl_math_approxValue(fValue); |
270 | 7.10M | } |
271 | | |
272 | | inline double approxDiff(double a, double b) |
273 | 0 | { |
274 | 0 | return rtl_math_approxDiff(a, b); |
275 | 0 | } |
276 | | |
277 | | /** A wrapper around rtl_math_expm1. |
278 | | */ |
279 | | inline double expm1(double fValue) |
280 | 0 | { |
281 | 0 | return rtl_math_expm1(fValue); |
282 | 0 | } |
283 | | |
284 | | /** A wrapper around rtl_math_log1p. |
285 | | */ |
286 | | inline double log1p(double fValue) |
287 | 0 | { |
288 | 0 | return rtl_math_log1p(fValue); |
289 | 0 | } |
290 | | |
291 | | /** A wrapper around rtl_math_atanh. |
292 | | */ |
293 | | inline double atanh(double fValue) |
294 | 0 | { |
295 | 0 | return rtl_math_atanh(fValue); |
296 | 0 | } |
297 | | |
298 | | /** A wrapper around rtl_math_erf. |
299 | | */ |
300 | | inline double erf(double fValue) |
301 | 0 | { |
302 | 0 | return rtl_math_erf(fValue); |
303 | 0 | } |
304 | | |
305 | | /** A wrapper around rtl_math_erfc. |
306 | | */ |
307 | | inline double erfc(double fValue) |
308 | 0 | { |
309 | 0 | return rtl_math_erfc(fValue); |
310 | 0 | } |
311 | | |
312 | | /** A wrapper around rtl_math_asinh. |
313 | | */ |
314 | | inline double asinh(double fValue) |
315 | 2 | { |
316 | 2 | return rtl_math_asinh(fValue); |
317 | 2 | } |
318 | | |
319 | | /** A wrapper around rtl_math_acosh. |
320 | | */ |
321 | | inline double acosh(double fValue) |
322 | 0 | { |
323 | 0 | return rtl_math_acosh(fValue); |
324 | 0 | } |
325 | | |
326 | | /** A wrapper around rtl_math_approxEqual. |
327 | | */ |
328 | | inline bool approxEqual(double a, double b) |
329 | 10.1M | { |
330 | 10.1M | return rtl_math_approxEqual( a, b ); |
331 | 10.1M | } |
332 | | |
333 | | /** Test equality of two values with an accuracy defined by nPrec |
334 | | |
335 | | @attention |
336 | | approxEqual( value!=0.0, 0.0 ) _never_ yields true. |
337 | | */ |
338 | | inline bool approxEqual(double a, double b, sal_Int16 nPrec) |
339 | 0 | { |
340 | 0 | if ( a == b ) |
341 | 0 | return true; |
342 | 0 | double x = a - b; |
343 | 0 | return (x < 0.0 ? -x : x) |
344 | 0 | < ((a < 0.0 ? -a : a) * (1.0 / (pow(2.0, nPrec)))); |
345 | 0 | } |
346 | | |
347 | | /** Add two values. |
348 | | |
349 | | If signs differ and the absolute values are equal according to approxEqual() |
350 | | the method returns 0.0 instead of calculating the sum. |
351 | | |
352 | | If you wanted to sum up multiple values it would be convenient not to call |
353 | | approxAdd() for each value but instead remember the first value not equal to |
354 | | 0.0, add all other values using normal + operator, and with the result and |
355 | | the remembered value call approxAdd(). |
356 | | */ |
357 | | inline double approxAdd(double a, double b) |
358 | 0 | { |
359 | 0 | if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0)) |
360 | 0 | && approxEqual( a, -b ) ) |
361 | 0 | return 0.0; |
362 | 0 | return a + b; |
363 | 0 | } |
364 | | |
365 | | /** Subtract two values (a-b). |
366 | | |
367 | | If signs are identical and the values are equal according to approxEqual() |
368 | | the method returns 0.0 instead of calculating the subtraction. |
369 | | */ |
370 | | inline double approxSub(double a, double b) |
371 | 56.3k | { |
372 | 56.3k | if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approxEqual( a, b ) ) |
373 | 700 | return 0.0; |
374 | 55.6k | return a - b; |
375 | 56.3k | } |
376 | | |
377 | | /** floor() method taking approxValue() into account. |
378 | | |
379 | | Use for expected integer values being calculated by double functions. |
380 | | */ |
381 | | inline double approxFloor(double a) |
382 | 3.80M | { |
383 | 3.80M | return floor( approxValue( a )); |
384 | 3.80M | } |
385 | | |
386 | | /** ceil() method taking approxValue() into account. |
387 | | |
388 | | Use for expected integer values being calculated by double functions. |
389 | | */ |
390 | | inline double approxCeil(double a) |
391 | 3.29M | { |
392 | 3.29M | return ceil( approxValue( a )); |
393 | 3.29M | } |
394 | | |
395 | | /** Tests whether a value is neither INF nor NAN. |
396 | | */ |
397 | | inline bool isFinite(double d) |
398 | 0 | { |
399 | 0 | return SAL_MATH_FINITE(d); |
400 | 0 | } |
401 | | |
402 | | /** If a value represents +INF or -INF. |
403 | | |
404 | | The sign bit may be queried with isSignBitSet(). |
405 | | |
406 | | If isFinite(d)==false and isInf(d)==false then NAN. |
407 | | */ |
408 | | inline bool isInf(double d) |
409 | 0 | { |
410 | 0 | // exponent==0x7ff fraction==0 |
411 | 0 | return !SAL_MATH_FINITE(d) && |
412 | 0 | (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi == 0) |
413 | 0 | && (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo |
414 | 0 | == 0); |
415 | 0 | } |
416 | | |
417 | | /** Test on any QNAN or SNAN. |
418 | | */ |
419 | | inline bool isNan(double d) |
420 | 0 | { |
421 | 0 | // exponent==0x7ff fraction!=0 |
422 | 0 | return !SAL_MATH_FINITE(d) && ( |
423 | 0 | (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi != 0) |
424 | 0 | || (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo |
425 | 0 | != 0) ); |
426 | 0 | } |
427 | | |
428 | | /** If the sign bit is set. |
429 | | */ |
430 | | inline bool isSignBitSet(double d) |
431 | 0 | { |
432 | 0 | return reinterpret_cast< sal_math_Double * >(&d)->inf_parts.sign != 0; |
433 | 0 | } |
434 | | |
435 | | /** Set to +INF if bNegative==false or -INF if bNegative==true. |
436 | | */ |
437 | | inline void setInf(double * pd, bool bNegative) |
438 | 0 | { |
439 | 0 | sal_math_Double& md = *reinterpret_cast<sal_math_Double*>(pd); |
440 | 0 | md.w32_parts.msw = bNegative ? 0xFFF00000 : 0x7FF00000; |
441 | 0 | md.w32_parts.lsw = 0; |
442 | 0 | } |
443 | | |
444 | | /** Set a QNAN. |
445 | | */ |
446 | | inline void setNan(double * pd) |
447 | 0 | { |
448 | 0 | sal_math_Double& md = *reinterpret_cast<sal_math_Double*>(pd); |
449 | 0 | md.w32_parts.msw = 0x7FFFFFFF; |
450 | 0 | md.w32_parts.lsw = 0xFFFFFFFF; |
451 | 0 | } |
452 | | |
453 | | /** If a value is a valid argument for sin(), cos(), tan(). |
454 | | |
455 | | IEEE 754 specifies that absolute values up to 2^64 (=1.844e19) for the |
456 | | radian must be supported by trigonometric functions. Unfortunately, at |
457 | | least on x86 architectures, the FPU doesn't generate an error pattern for |
458 | | values >2^64 but produces erroneous results instead and sets only the |
459 | | "invalid operation" (IM) flag in the status word :-( Thus the application |
460 | | has to handle it itself. |
461 | | */ |
462 | | inline bool isValidArcArg(double d) |
463 | 392 | { |
464 | 392 | return fabs(d) |
465 | 392 | <= (static_cast< double >(static_cast< unsigned long >(0x80000000)) |
466 | 392 | * static_cast< double >(static_cast< unsigned long >(0x80000000)) |
467 | 392 | * 4); |
468 | 392 | } |
469 | | |
470 | | /** Safe sin(), returns NAN if not valid. |
471 | | */ |
472 | | inline double sin(double d) |
473 | 171 | { |
474 | 171 | if ( isValidArcArg( d ) ) |
475 | 171 | return ::sin( d ); |
476 | 0 | setNan( &d ); |
477 | 0 | return d; |
478 | 171 | } |
479 | | |
480 | | /** Safe cos(), returns NAN if not valid. |
481 | | */ |
482 | | inline double cos(double d) |
483 | 173 | { |
484 | 173 | if ( isValidArcArg( d ) ) |
485 | 173 | return ::cos( d ); |
486 | 0 | setNan( &d ); |
487 | 0 | return d; |
488 | 173 | } |
489 | | |
490 | | /** Safe tan(), returns NAN if not valid. |
491 | | */ |
492 | | inline double tan(double d) |
493 | 8 | { |
494 | 8 | if ( isValidArcArg( d ) ) |
495 | 8 | return ::tan( d ); |
496 | 0 | setNan( &d ); |
497 | 0 | return d; |
498 | 8 | } |
499 | | |
500 | | } |
501 | | |
502 | | } |
503 | | |
504 | | #endif // INCLUDED_RTL_MATH_HXX |
505 | | |
506 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |