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