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