xref: /trunk/main/sal/inc/rtl/math.hxx (revision cda7f8b3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #if !defined INCLUDED_RTL_MATH_HXX
25 #define INCLUDED_RTL_MATH_HXX
26 
27 #include "rtl/math.h"
28 #include "rtl/string.hxx"
29 #include "rtl/ustring.hxx"
30 #include "rtl/ustrbuf.hxx"
31 #include "sal/mathconf.h"
32 #include "sal/types.h"
33 
34 #include <math.h>
35 
36 namespace rtl {
37 
38 namespace math {
39 
40 /** A wrapper around rtl_math_doubleToString.
41  */
doubleToString(double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Char cDecSeparator,sal_Int32 const * pGroups,sal_Char cGroupSeparator,bool bEraseTrailingDecZeros=false)42 inline rtl::OString doubleToString(double fValue, rtl_math_StringFormat eFormat,
43                                    sal_Int32 nDecPlaces,
44                                    sal_Char cDecSeparator,
45                                    sal_Int32 const * pGroups,
46                                    sal_Char cGroupSeparator,
47                                    bool bEraseTrailingDecZeros = false)
48 {
49     rtl::OString aResult;
50     rtl_math_doubleToString(&aResult.pData, 0, 0, fValue, eFormat, nDecPlaces,
51                             cDecSeparator, pGroups, cGroupSeparator,
52                             bEraseTrailingDecZeros);
53     return aResult;
54 }
55 
56 /** A wrapper around rtl_math_doubleToString, with no grouping.
57  */
doubleToString(double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Char cDecSeparator,bool bEraseTrailingDecZeros=false)58 inline rtl::OString doubleToString(double fValue, rtl_math_StringFormat eFormat,
59                                    sal_Int32 nDecPlaces,
60                                    sal_Char cDecSeparator,
61                                    bool bEraseTrailingDecZeros = false)
62 {
63     rtl::OString aResult;
64     rtl_math_doubleToString(&aResult.pData, 0, 0, fValue, eFormat, nDecPlaces,
65                             cDecSeparator, 0, 0, bEraseTrailingDecZeros);
66     return aResult;
67 }
68 
69 /** A wrapper around rtl_math_doubleToUString.
70  */
doubleToUString(double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Unicode cDecSeparator,sal_Int32 const * pGroups,sal_Unicode cGroupSeparator,bool bEraseTrailingDecZeros=false)71 inline rtl::OUString doubleToUString(double fValue,
72                                      rtl_math_StringFormat eFormat,
73                                      sal_Int32 nDecPlaces,
74                                      sal_Unicode cDecSeparator,
75                                      sal_Int32 const * pGroups,
76                                      sal_Unicode cGroupSeparator,
77                                      bool bEraseTrailingDecZeros = false)
78 {
79     rtl::OUString aResult;
80     rtl_math_doubleToUString(&aResult.pData, 0, 0, fValue, eFormat, nDecPlaces,
81                              cDecSeparator, pGroups, cGroupSeparator,
82                              bEraseTrailingDecZeros);
83     return aResult;
84 }
85 
86 /** A wrapper around rtl_math_doubleToUString, with no grouping.
87  */
doubleToUString(double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Unicode cDecSeparator,bool bEraseTrailingDecZeros=false)88 inline rtl::OUString doubleToUString(double fValue,
89                                      rtl_math_StringFormat eFormat,
90                                      sal_Int32 nDecPlaces,
91                                      sal_Unicode cDecSeparator,
92                                      bool bEraseTrailingDecZeros = false)
93 {
94     rtl::OUString aResult;
95     rtl_math_doubleToUString(&aResult.pData, 0, 0, fValue, eFormat, nDecPlaces,
96                              cDecSeparator, 0, 0, bEraseTrailingDecZeros);
97     return aResult;
98 }
99 
100 /** A wrapper around rtl_math_doubleToUString that appends to an
101     rtl::OUStringBuffer.
102  */
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)103 inline void doubleToUStringBuffer( rtl::OUStringBuffer& rBuffer, double fValue,
104                                    rtl_math_StringFormat eFormat,
105                                    sal_Int32 nDecPlaces,
106                                    sal_Unicode cDecSeparator,
107                                    sal_Int32 const * pGroups,
108                                    sal_Unicode cGroupSeparator,
109                                    bool bEraseTrailingDecZeros = false)
110 {
111     rtl_uString ** pData;
112     sal_Int32 * pCapacity;
113     rBuffer.accessInternals( &pData, &pCapacity );
114     rtl_math_doubleToUString( pData, pCapacity, rBuffer.getLength(), fValue,
115                               eFormat, nDecPlaces, cDecSeparator, pGroups,
116                               cGroupSeparator, bEraseTrailingDecZeros);
117 }
118 
119 /** A wrapper around rtl_math_doubleToUString that appends to an
120     rtl::OUStringBuffer, with no grouping.
121  */
doubleToUStringBuffer(rtl::OUStringBuffer & rBuffer,double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Unicode cDecSeparator,bool bEraseTrailingDecZeros=false)122 inline void doubleToUStringBuffer( rtl::OUStringBuffer& rBuffer, double fValue,
123                                    rtl_math_StringFormat eFormat,
124                                    sal_Int32 nDecPlaces,
125                                    sal_Unicode cDecSeparator,
126                                    bool bEraseTrailingDecZeros = false)
127 {
128     rtl_uString ** pData;
129     sal_Int32 * pCapacity;
130     rBuffer.accessInternals( &pData, &pCapacity );
131     rtl_math_doubleToUString( pData, pCapacity, rBuffer.getLength(), fValue,
132                               eFormat, nDecPlaces, cDecSeparator, 0, 0,
133                               bEraseTrailingDecZeros);
134 }
135 
136 /** A wrapper around rtl_math_stringToDouble.
137  */
stringToDouble(rtl::OString const & rString,sal_Char cDecSeparator,sal_Char cGroupSeparator,rtl_math_ConversionStatus * pStatus,sal_Int32 * pParsedEnd)138 inline double stringToDouble(rtl::OString const & rString,
139                              sal_Char cDecSeparator, sal_Char cGroupSeparator,
140                              rtl_math_ConversionStatus * pStatus,
141                              sal_Int32 * pParsedEnd)
142 {
143     sal_Char const * pBegin = rString.getStr();
144     sal_Char const * pEnd;
145     double fResult = rtl_math_stringToDouble(pBegin,
146                                              pBegin + rString.getLength(),
147                                              cDecSeparator, cGroupSeparator,
148                                              pStatus, &pEnd);
149     if (pParsedEnd != 0)
150         *pParsedEnd = (sal_Int32)(pEnd - pBegin);
151     return fResult;
152 }
153 
154 /** A wrapper around rtl_math_uStringToDouble.
155  */
stringToDouble(rtl::OUString const & rString,sal_Unicode cDecSeparator,sal_Unicode cGroupSeparator,rtl_math_ConversionStatus * pStatus,sal_Int32 * pParsedEnd)156 inline double stringToDouble(rtl::OUString const & rString,
157                              sal_Unicode cDecSeparator,
158                              sal_Unicode cGroupSeparator,
159                              rtl_math_ConversionStatus * pStatus,
160                              sal_Int32 * pParsedEnd)
161 {
162     sal_Unicode const * pBegin = rString.getStr();
163     sal_Unicode const * pEnd;
164     double fResult = rtl_math_uStringToDouble(pBegin,
165                                               pBegin + rString.getLength(),
166                                               cDecSeparator, cGroupSeparator,
167                                               pStatus, &pEnd);
168     if (pParsedEnd != 0)
169         *pParsedEnd = (sal_Int32)(pEnd - pBegin);
170     return fResult;
171 }
172 
173 /** A wrapper around rtl_math_round.
174  */
round(double fValue,int nDecPlaces=0,rtl_math_RoundingMode eMode=rtl_math_RoundingMode_Corrected)175 inline double round(
176     double fValue, int nDecPlaces = 0,
177     rtl_math_RoundingMode eMode = rtl_math_RoundingMode_Corrected)
178 {
179     return rtl_math_round(fValue, nDecPlaces, eMode);
180 }
181 
182 /** A wrapper around rtl_math_pow10Exp.
183  */
pow10Exp(double fValue,int nExp)184 inline double pow10Exp(double fValue, int nExp)
185 {
186     return rtl_math_pow10Exp(fValue, nExp);
187 }
188 
189 /** A wrapper around rtl_math_powr.
190  */
powr(double fValue,double fExp)191 inline double powr(double fValue, double fExp)
192 {
193     return rtl_math_powr(fValue, fExp);
194 }
195 
196 /** A wrapper around rtl_math_approxValue.
197  */
approxValue(double fValue)198 inline double approxValue(double fValue)
199 {
200     return rtl_math_approxValue(fValue);
201 }
202 
203 /** A wrapper around rtl_math_expm1.
204  */
expm1(double fValue)205 inline double expm1(double fValue)
206 {
207     return rtl_math_expm1(fValue);
208 }
209 
210 /** A wrapper around rtl_math_log1p.
211  */
log1p(double fValue)212 inline double log1p(double fValue)
213 {
214     return rtl_math_log1p(fValue);
215 }
216 
217 /** A wrapper around rtl_math_atanh.
218  */
atanh(double fValue)219 inline double atanh(double fValue)
220 {
221     return rtl_math_atanh(fValue);
222 }
223 
224 /** A wrapper around rtl_math_erf.
225  */
erf(double fValue)226 inline double erf(double fValue)
227 {
228     return rtl_math_erf(fValue);
229 }
230 
231 /** A wrapper around rtl_math_erfc.
232  */
erfc(double fValue)233 inline double erfc(double fValue)
234 {
235     return rtl_math_erfc(fValue);
236 }
237 
238 /** A wrapper around rtl_math_asinh.
239  */
asinh(double fValue)240 inline double asinh(double fValue)
241 {
242     return rtl_math_asinh(fValue);
243 }
244 
245 /** A wrapper around rtl_math_acosh.
246  */
acosh(double fValue)247 inline double acosh(double fValue)
248 {
249     return rtl_math_acosh(fValue);
250 }
251 
252 
253 /** Test equality of two values with an accuracy of the magnitude of the
254     given values scaled by 2^-48 (4 bits roundoff stripped).
255 
256     @ATTENTION
257     approxEqual( value!=0.0, 0.0 ) _never_ yields true.
258  */
approxEqual(double a,double b)259 inline bool approxEqual(double a, double b)
260 {
261 	if ( a == b )
262 		return true;
263 	double x = a - b;
264 	return (x < 0.0 ? -x : x)
265         < ((a < 0.0 ? -a : a) * (1.0 / (16777216.0 * 16777216.0)));
266 }
267 
268 /** Add two values.
269 
270     If signs differ and the absolute values are equal according to approxEqual()
271     the method returns 0.0 instead of calculating the sum.
272 
273     If you wanted to sum up multiple values it would be convenient not to call
274     approxAdd() for each value but instead remember the first value not equal to
275     0.0, add all other values using normal + operator, and with the result and
276     the remembered value call approxAdd().
277  */
approxAdd(double a,double b)278 inline double approxAdd(double a, double b)
279 {
280 	if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0))
281          && approxEqual( a, -b ) )
282 		return 0.0;
283 	return a + b;
284 }
285 
286 /** Subtract two values (a-b).
287 
288     If signs are identical and the values are equal according to approxEqual()
289     the method returns 0.0 instead of calculating the subtraction.
290  */
approxSub(double a,double b)291 inline double approxSub(double a, double b)
292 {
293 	if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approxEqual( a, b ) )
294 		return 0.0;
295 	return a - b;
296 }
297 
298 /** floor() method taking approxValue() into account.
299 
300     Use for expected integer values being calculated by double functions.
301  */
approxFloor(double a)302 inline double approxFloor(double a)
303 {
304     return floor( approxValue( a ));
305 }
306 
307 /** ceil() method taking approxValue() into account.
308 
309     Use for expected integer values being calculated by double functions.
310  */
approxCeil(double a)311 inline double approxCeil(double a)
312 {
313     return ceil( approxValue( a ));
314 }
315 
316 /** Tests whether a value is neither INF nor NAN.
317  */
isFinite(double d)318 inline bool isFinite(double d)
319 {
320     return SAL_MATH_FINITE(d) != 0;
321 }
322 
323 /** If a value represents +INF or -INF.
324 
325     The sign bit may be queried with isSignBitSet().
326 
327     If isFinite(d)==false and isInf(d)==false then NAN.
328  */
isInf(double d)329 inline bool isInf(double d)
330 {
331 	// exponent==0x7ff fraction==0
332 	return (SAL_MATH_FINITE(d) == 0) &&
333         (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi == 0)
334         && (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo
335             == 0);
336 }
337 
338 /** Test on any QNAN or SNAN.
339  */
isNan(double d)340 inline bool isNan(double d)
341 {
342 	// exponent==0x7ff fraction!=0
343 	return (SAL_MATH_FINITE(d) == 0) && (
344         (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi != 0)
345         || (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo
346             != 0) );
347 }
348 
349 /** If the sign bit is set.
350  */
isSignBitSet(double d)351 inline bool isSignBitSet(double d)
352 {
353     return reinterpret_cast< sal_math_Double * >(&d)->inf_parts.sign != 0;
354 }
355 
356 /** Set to +INF if bNegative==false or -INF if bNegative==true.
357  */
setInf(double * pd,bool bNegative)358 inline void setInf(double * pd, bool bNegative)
359 {
360     union
361     {
362         double sd;
363         sal_math_Double md;
364     };
365     md.w32_parts.msw = bNegative ? 0xFFF00000 : 0x7FF00000;
366     md.w32_parts.lsw = 0;
367     *pd = sd;
368 }
369 
370 /** Set a QNAN.
371  */
setNan(double * pd)372 inline void setNan(double * pd)
373 {
374     union
375     {
376         double sd;
377         sal_math_Double md;
378     };
379     md.w32_parts.msw = 0x7FFFFFFF;
380     md.w32_parts.lsw = 0xFFFFFFFF;
381     *pd = sd;
382 }
383 
384 /** If a value is a valid argument for sin(), cos(), tan().
385 
386     IEEE 754 specifies that absolute values up to 2^64 (=1.844e19) for the
387     radian must be supported by trigonometric functions.  Unfortunately, at
388     least on x86 architectures, the FPU doesn't generate an error pattern for
389     values >2^64 but produces erroneous results instead and sets only the
390     "invalid operation" (IM) flag in the status word :-(  Thus the application
391     has to handle it itself.
392  */
isValidArcArg(double d)393 inline bool isValidArcArg(double d)
394 {
395     return fabs(d)
396         <= (static_cast< double >(static_cast< unsigned long >(0x80000000))
397             * static_cast< double >(static_cast< unsigned long >(0x80000000))
398             * 2);
399 }
400 
401 /** Safe sin(), returns NAN if not valid.
402  */
sin(double d)403 inline double sin(double d)
404 {
405     if ( isValidArcArg( d ) )
406         return ::sin( d );
407     setNan( &d );
408     return d;
409 }
410 
411 /** Safe cos(), returns NAN if not valid.
412  */
cos(double d)413 inline double cos(double d)
414 {
415     if ( isValidArcArg( d ) )
416         return ::cos( d );
417     setNan( &d );
418     return d;
419 }
420 
421 /** Safe tan(), returns NAN if not valid.
422  */
tan(double d)423 inline double tan(double d)
424 {
425     if ( isValidArcArg( d ) )
426         return ::tan( d );
427     setNan( &d );
428     return d;
429 }
430 
431 }
432 
433 }
434 
435 #endif // INCLUDED_RTL_MATH_HXX
436