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