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