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