Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/rtl/math.hxx
Line
Count
Source
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
 */
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
0
{
51
0
    rtl::OString aResult;
52
0
    rtl_math_doubleToString(&aResult.pData, NULL, 0, fValue, eFormat, nDecPlaces,
53
0
                            cDecSeparator, pGroups, cGroupSeparator,
54
0
                            bEraseTrailingDecZeros);
55
0
    return aResult;
56
0
}
57
58
/** A wrapper around rtl_math_doubleToString, with no grouping.
59
 */
60
inline rtl::OString doubleToString(double fValue, rtl_math_StringFormat eFormat,
61
                                   sal_Int32 nDecPlaces,
62
                                   char cDecSeparator,
63
                                   bool bEraseTrailingDecZeros = false)
64
2.34k
{
65
2.34k
    rtl::OString aResult;
66
2.34k
    rtl_math_doubleToString(&aResult.pData, NULL, 0, fValue, eFormat, nDecPlaces,
67
2.34k
                            cDecSeparator, NULL, 0, bEraseTrailingDecZeros);
68
2.34k
    return aResult;
69
2.34k
}
70
71
/** A wrapper around rtl_math_doubleToString that appends to an
72
    rtl::OStringBuffer.
73
74
    @since LibreOffice 5.4
75
*/
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
0
{
81
0
    rtl_String ** pData;
82
0
    sal_Int32 * pCapacity;
83
0
    rBuffer.accessInternals(&pData, &pCapacity);
84
0
    rtl_math_doubleToString(
85
0
        pData, pCapacity, rBuffer.getLength(), fValue, eFormat, nDecPlaces,
86
0
        cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros);
87
0
}
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
*/
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
1.48M
{
99
1.48M
    rtl_String ** pData;
100
1.48M
    sal_Int32 * pCapacity;
101
1.48M
    rBuffer.accessInternals(&pData, &pCapacity);
102
1.48M
    rtl_math_doubleToString(
103
1.48M
        pData, pCapacity, rBuffer.getLength(), fValue, eFormat, nDecPlaces,
104
1.48M
        cDecSeparator, NULL, 0, bEraseTrailingDecZeros);
105
1.48M
}
106
107
/** A wrapper around rtl_math_doubleToUString.
108
 */
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
0
{
117
0
    rtl::OUString aResult;
118
0
    rtl_math_doubleToUString(&aResult.pData, NULL, 0, fValue, eFormat, nDecPlaces,
119
0
                             cDecSeparator, pGroups, cGroupSeparator,
120
0
                             bEraseTrailingDecZeros);
121
0
    return aResult;
122
0
}
123
124
/** A wrapper around rtl_math_doubleToUString, with no grouping.
125
 */
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
232k
{
132
232k
    rtl::OUString aResult;
133
232k
    rtl_math_doubleToUString(&aResult.pData, NULL, 0, fValue, eFormat, nDecPlaces,
134
232k
                             cDecSeparator, NULL, 0, bEraseTrailingDecZeros);
135
232k
    return aResult;
136
232k
}
137
138
/** A wrapper around rtl_math_doubleToUString that appends to an
139
    rtl::OUStringBuffer.
140
 */
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
0
{
149
0
    rtl_uString ** pData;
150
0
    sal_Int32 * pCapacity;
151
0
    rBuffer.accessInternals( &pData, &pCapacity );
152
0
    rtl_math_doubleToUString( pData, pCapacity, rBuffer.getLength(), fValue,
153
0
                              eFormat, nDecPlaces, cDecSeparator, pGroups,
154
0
                              cGroupSeparator, bEraseTrailingDecZeros);
155
0
}
156
157
/** A wrapper around rtl_math_doubleToUString that appends to an
158
    rtl::OUStringBuffer, with no grouping.
159
 */
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
218k
{
166
218k
    rtl_uString ** pData;
167
218k
    sal_Int32 * pCapacity;
168
218k
    rBuffer.accessInternals( &pData, &pCapacity );
169
218k
    rtl_math_doubleToUString( pData, pCapacity, rBuffer.getLength(), fValue,
170
218k
                              eFormat, nDecPlaces, cDecSeparator, NULL, 0,
171
218k
                              bEraseTrailingDecZeros);
172
218k
}
173
174
/** A wrapper around rtl_math_stringToDouble.
175
 */
176
#ifdef LIBO_INTERNAL_ONLY
177
inline double stringToDouble(std::string_view aString,
178
                             char cDecSeparator, char cGroupSeparator,
179
                             rtl_math_ConversionStatus * pStatus = NULL,
180
                             sal_Int32 * pParsedEnd = NULL)
181
0
{
182
0
    char const * pBegin = aString.data();
183
0
    char const * pEnd;
184
0
    double fResult = rtl_math_stringToDouble(pBegin,
185
0
                                             pBegin + aString.size(),
186
0
                                             cDecSeparator, cGroupSeparator,
187
0
                                             pStatus, &pEnd);
188
0
    if (pParsedEnd != NULL)
189
0
        *pParsedEnd = static_cast<sal_Int32>(pEnd - pBegin);
190
0
    return fResult;
191
0
}
192
#else
193
inline double stringToDouble(rtl::OString const & rString,
194
                             char cDecSeparator, char cGroupSeparator,
195
                             rtl_math_ConversionStatus * pStatus = NULL,
196
                             sal_Int32 * pParsedEnd = NULL)
197
{
198
    char const * pBegin = rString.getStr();
199
    char const * pEnd;
200
    double fResult = rtl_math_stringToDouble(pBegin,
201
                                             pBegin + rString.getLength(),
202
                                             cDecSeparator, cGroupSeparator,
203
                                             pStatus, &pEnd);
204
    if (pParsedEnd != NULL)
205
        *pParsedEnd = static_cast<sal_Int32>(pEnd - pBegin);
206
    return fResult;
207
}
208
#endif
209
210
211
/** A wrapper around rtl_math_uStringToDouble.
212
 */
213
#ifdef LIBO_INTERNAL_ONLY
214
inline double stringToDouble(std::u16string_view aString,
215
                             sal_Unicode cDecSeparator,
216
                             sal_Unicode cGroupSeparator,
217
                             rtl_math_ConversionStatus * pStatus = NULL,
218
                             sal_Int32 * pParsedEnd = NULL)
219
428k
{
220
428k
    sal_Unicode const * pBegin = aString.data();
221
428k
    sal_Unicode const * pEnd;
222
428k
    double fResult = rtl_math_uStringToDouble(pBegin,
223
428k
                                              pBegin + aString.size(),
224
428k
                                              cDecSeparator, cGroupSeparator,
225
428k
                                              pStatus, &pEnd);
226
428k
    if (pParsedEnd != NULL)
227
317k
        *pParsedEnd = static_cast<sal_Int32>(pEnd - pBegin);
228
428k
    return fResult;
229
428k
}
230
#else
231
inline double stringToDouble(rtl::OUString const & rString,
232
                             sal_Unicode cDecSeparator,
233
                             sal_Unicode cGroupSeparator,
234
                             rtl_math_ConversionStatus * pStatus = NULL,
235
                             sal_Int32 * pParsedEnd = NULL)
236
{
237
    sal_Unicode const * pBegin = rString.getStr();
238
    sal_Unicode const * pEnd;
239
    double fResult = rtl_math_uStringToDouble(pBegin,
240
                                              pBegin + rString.getLength(),
241
                                              cDecSeparator, cGroupSeparator,
242
                                              pStatus, &pEnd);
243
    if (pParsedEnd != NULL)
244
        *pParsedEnd = static_cast<sal_Int32>(pEnd - pBegin);
245
    return fResult;
246
}
247
#endif
248
249
/** A wrapper around rtl_math_round.
250
 */
251
inline double round(
252
    double fValue, int nDecPlaces = 0,
253
    rtl_math_RoundingMode eMode = rtl_math_RoundingMode_Corrected)
254
581k
{
255
581k
    return rtl_math_round(fValue, nDecPlaces, eMode);
256
581k
}
257
258
/** A wrapper around rtl_math_pow10Exp.
259
 */
260
inline double pow10Exp(double fValue, int nExp)
261
53
{
262
53
    return rtl_math_pow10Exp(fValue, nExp);
263
53
}
264
265
/** A wrapper around rtl_math_approxValue.
266
 */
267
inline double approxValue(double fValue)
268
7.10M
{
269
7.10M
    return rtl_math_approxValue(fValue);
270
7.10M
}
271
272
inline double approxDiff(double a, double b)
273
0
{
274
0
    return rtl_math_approxDiff(a, b);
275
0
}
276
277
/** A wrapper around rtl_math_expm1.
278
 */
279
inline double expm1(double fValue)
280
0
{
281
0
    return rtl_math_expm1(fValue);
282
0
}
283
284
/** A wrapper around rtl_math_log1p.
285
 */
286
inline double log1p(double fValue)
287
0
{
288
0
    return rtl_math_log1p(fValue);
289
0
}
290
291
/** A wrapper around rtl_math_atanh.
292
 */
293
inline double atanh(double fValue)
294
0
{
295
0
    return rtl_math_atanh(fValue);
296
0
}
297
298
/** A wrapper around rtl_math_erf.
299
 */
300
inline double erf(double fValue)
301
0
{
302
0
    return rtl_math_erf(fValue);
303
0
}
304
305
/** A wrapper around rtl_math_erfc.
306
 */
307
inline double erfc(double fValue)
308
0
{
309
0
    return rtl_math_erfc(fValue);
310
0
}
311
312
/** A wrapper around rtl_math_asinh.
313
 */
314
inline double asinh(double fValue)
315
2
{
316
2
    return rtl_math_asinh(fValue);
317
2
}
318
319
/** A wrapper around rtl_math_acosh.
320
 */
321
inline double acosh(double fValue)
322
0
{
323
0
    return rtl_math_acosh(fValue);
324
0
}
325
326
/** A wrapper around rtl_math_approxEqual.
327
 */
328
inline bool approxEqual(double a, double b)
329
10.1M
{
330
10.1M
    return rtl_math_approxEqual( a, b );
331
10.1M
}
332
333
/** Test equality of two values with an accuracy defined by nPrec
334
335
    @attention
336
    approxEqual( value!=0.0, 0.0 ) _never_ yields true.
337
 */
338
inline bool approxEqual(double a, double b, sal_Int16 nPrec)
339
0
{
340
0
    if ( a == b )
341
0
        return true;
342
0
    double x = a - b;
343
0
    return (x < 0.0 ? -x : x)
344
0
        < ((a < 0.0 ? -a : a) * (1.0 / (pow(2.0, nPrec))));
345
0
}
346
347
/** Add two values.
348
349
    If signs differ and the absolute values are equal according to approxEqual()
350
    the method returns 0.0 instead of calculating the sum.
351
352
    If you wanted to sum up multiple values it would be convenient not to call
353
    approxAdd() for each value but instead remember the first value not equal to
354
    0.0, add all other values using normal + operator, and with the result and
355
    the remembered value call approxAdd().
356
 */
357
inline double approxAdd(double a, double b)
358
0
{
359
0
    if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0))
360
0
         && approxEqual( a, -b ) )
361
0
        return 0.0;
362
0
    return a + b;
363
0
}
364
365
/** Subtract two values (a-b).
366
367
    If signs are identical and the values are equal according to approxEqual()
368
    the method returns 0.0 instead of calculating the subtraction.
369
 */
370
inline double approxSub(double a, double b)
371
56.3k
{
372
56.3k
    if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approxEqual( a, b ) )
373
700
        return 0.0;
374
55.6k
    return a - b;
375
56.3k
}
376
377
/** floor() method taking approxValue() into account.
378
379
    Use for expected integer values being calculated by double functions.
380
 */
381
inline double approxFloor(double a)
382
3.80M
{
383
3.80M
    return floor( approxValue( a ));
384
3.80M
}
385
386
/** ceil() method taking approxValue() into account.
387
388
    Use for expected integer values being calculated by double functions.
389
 */
390
inline double approxCeil(double a)
391
3.29M
{
392
3.29M
    return ceil( approxValue( a ));
393
3.29M
}
394
395
/** Tests whether a value is neither INF nor NAN.
396
 */
397
inline bool isFinite(double d)
398
0
{
399
0
    return SAL_MATH_FINITE(d);
400
0
}
401
402
/** If a value represents +INF or -INF.
403
404
    The sign bit may be queried with isSignBitSet().
405
406
    If isFinite(d)==false and isInf(d)==false then NAN.
407
 */
408
inline bool isInf(double d)
409
0
{
410
0
    // exponent==0x7ff fraction==0
411
0
    return !SAL_MATH_FINITE(d) &&
412
0
        (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi == 0)
413
0
        && (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo
414
0
            == 0);
415
0
}
416
417
/** Test on any QNAN or SNAN.
418
 */
419
inline bool isNan(double d)
420
0
{
421
0
    // exponent==0x7ff fraction!=0
422
0
    return !SAL_MATH_FINITE(d) && (
423
0
        (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi != 0)
424
0
        || (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo
425
0
            != 0) );
426
0
}
427
428
/** If the sign bit is set.
429
 */
430
inline bool isSignBitSet(double d)
431
0
{
432
0
    return reinterpret_cast< sal_math_Double * >(&d)->inf_parts.sign != 0;
433
0
}
434
435
/** Set to +INF if bNegative==false or -INF if bNegative==true.
436
 */
437
inline void setInf(double * pd, bool bNegative)
438
0
{
439
0
    sal_math_Double& md = *reinterpret_cast<sal_math_Double*>(pd);
440
0
    md.w32_parts.msw = bNegative ? 0xFFF00000 : 0x7FF00000;
441
0
    md.w32_parts.lsw = 0;
442
0
}
443
444
/** Set a QNAN.
445
 */
446
inline void setNan(double * pd)
447
0
{
448
0
    sal_math_Double& md = *reinterpret_cast<sal_math_Double*>(pd);
449
0
    md.w32_parts.msw = 0x7FFFFFFF;
450
0
    md.w32_parts.lsw = 0xFFFFFFFF;
451
0
}
452
453
/** If a value is a valid argument for sin(), cos(), tan().
454
455
    IEEE 754 specifies that absolute values up to 2^64 (=1.844e19) for the
456
    radian must be supported by trigonometric functions.  Unfortunately, at
457
    least on x86 architectures, the FPU doesn't generate an error pattern for
458
    values >2^64 but produces erroneous results instead and sets only the
459
    "invalid operation" (IM) flag in the status word :-(  Thus the application
460
    has to handle it itself.
461
 */
462
inline bool isValidArcArg(double d)
463
392
{
464
392
    return fabs(d)
465
392
        <= (static_cast< double >(static_cast< unsigned long >(0x80000000))
466
392
            * static_cast< double >(static_cast< unsigned long >(0x80000000))
467
392
            * 4);
468
392
}
469
470
/** Safe sin(), returns NAN if not valid.
471
 */
472
inline double sin(double d)
473
171
{
474
171
    if ( isValidArcArg( d ) )
475
171
        return ::sin( d );
476
0
    setNan( &d );
477
0
    return d;
478
171
}
479
480
/** Safe cos(), returns NAN if not valid.
481
 */
482
inline double cos(double d)
483
173
{
484
173
    if ( isValidArcArg( d ) )
485
173
        return ::cos( d );
486
0
    setNan( &d );
487
0
    return d;
488
173
}
489
490
/** Safe tan(), returns NAN if not valid.
491
 */
492
inline double tan(double d)
493
8
{
494
8
    if ( isValidArcArg( d ) )
495
8
        return ::tan( d );
496
0
    setNan( &d );
497
0
    return d;
498
8
}
499
500
}
501
502
}
503
504
#endif // INCLUDED_RTL_MATH_HXX
505
506
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */