1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/types.h>
21 #include <cppunit/TestAssert.h>
22 #include <cppunit/TestFixture.h>
23 #include <cppunit/extensions/HelperMacros.h>
24 #include <cppunit/plugin/TestPlugIn.h>
25 #include <rtl/math.hxx>
26 #include <rtl/ustring.h>
27 #include <rtl/ustring.hxx>
30 template<> inline std::string
CPPUNIT_NS::assertion_traits
<rtl_math_ConversionStatus
>::toString(
31 const rtl_math_ConversionStatus
& x
)
34 ost
<< static_cast<unsigned int>(x
);
40 class Test
: public CppUnit::TestFixture
{
42 void test_stringToDouble_good() {
43 rtl_math_ConversionStatus status
;
45 double res
= rtl::math::stringToDouble(
47 '.', ',', &status
, &end
);
48 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
49 CPPUNIT_ASSERT_EQUAL(RTL_CONSTASCII_LENGTH(" +1.E01"), end
);
50 CPPUNIT_ASSERT_EQUAL(10.0, res
);
52 res
= rtl::math::stringToDouble(
54 '.', ',', &status
, &end
);
55 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
56 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), end
);
57 CPPUNIT_ASSERT(std::isnan(res
));
59 res
= rtl::math::stringToDouble(
61 '.', ',', &status
, &end
);
62 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
63 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), end
);
64 CPPUNIT_ASSERT(std::isnan(res
));
66 res
= rtl::math::stringToDouble(
68 '.', ',', &status
, &end
);
69 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
70 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end
);
71 CPPUNIT_ASSERT_EQUAL(0.0, res
);
73 res
= rtl::math::stringToDouble(
75 '.', ',', &status
, &end
);
76 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
77 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end
);
78 CPPUNIT_ASSERT_EQUAL(0.0, res
);
80 res
= rtl::math::stringToDouble(
82 '.', ',', &status
, &end
);
83 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
84 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), end
);
85 CPPUNIT_ASSERT(std::isnan(res
));
86 CPPUNIT_ASSERT(!std::signbit(res
));
88 res
= rtl::math::stringToDouble(
90 '.', ',', &status
, &end
);
91 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
92 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), end
);
93 CPPUNIT_ASSERT(std::isnan(res
));
94 CPPUNIT_ASSERT(std::signbit(res
));
96 res
= rtl::math::stringToDouble(
98 '.', ',', &status
, &end
);
99 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_OutOfRange
, status
);
100 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), end
);
101 CPPUNIT_ASSERT(std::isinf(res
));
103 res
= rtl::math::stringToDouble(
105 '.', ',', &status
, &end
);
106 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_OutOfRange
, status
);
107 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), end
);
108 CPPUNIT_ASSERT(std::isinf(res
));
110 res
= rtl::math::stringToDouble(
112 '.', ',', &status
, &end
);
113 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
114 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end
);
115 CPPUNIT_ASSERT_EQUAL(0.5, res
);
117 res
= rtl::math::stringToDouble(
119 '.', ',', &status
, &end
);
120 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
121 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end
);
122 CPPUNIT_ASSERT_EQUAL(5.0, res
);
124 // Leading 0 and group separator.
125 res
= rtl::math::stringToDouble(
127 '.', ',', &status
, &end
);
128 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
129 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), end
);
130 CPPUNIT_ASSERT_EQUAL(123.0, res
);
132 // Leading 0 and two consecutive group separators are none.
133 res
= rtl::math::stringToDouble(
135 '.', ',', &status
, &end
);
136 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
137 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), end
);
138 CPPUNIT_ASSERT_EQUAL(0.0, res
);
140 // Leading 0 and group separator at end is none.
141 res
= rtl::math::stringToDouble(
143 '.', ',', &status
, &end
);
144 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
145 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), end
);
146 CPPUNIT_ASSERT_EQUAL(0.0, res
);
148 // Leading 0 and group separator before non-digit is none.
149 res
= rtl::math::stringToDouble(
151 '.', ',', &status
, &end
);
152 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
153 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), end
);
154 CPPUNIT_ASSERT_EQUAL(0.0, res
);
156 // Trailing group separator is none.
157 res
= rtl::math::stringToDouble(
159 '.', ',', &status
, &end
);
160 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
161 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), end
);
162 CPPUNIT_ASSERT_EQUAL(1234.0, res
);
164 // Group separator followed by non-digit is none.
165 res
= rtl::math::stringToDouble(
167 '.', ',', &status
, &end
);
168 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
169 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), end
);
170 CPPUNIT_ASSERT_EQUAL(1234.0, res
);
172 // Check that the value is the nearest double-precision representation of the decimal 0.0042
173 // (it was 0.0042000000000000006 instead of 0.0041999999999999997)
174 res
= rtl::math::stringToDouble("0,0042", ',', ' ', &status
, &end
);
175 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
176 CPPUNIT_ASSERT_EQUAL(0.0042, res
);
179 res
= rtl::math::stringToDouble("- 1", '.', ',', &status
, &end
);
180 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
181 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end
);
182 CPPUNIT_ASSERT_EQUAL(0.0, res
);
184 // "-1E+E" : no exponent
185 res
= rtl::math::stringToDouble("-1E+E", '.', ',', &status
, &end
);
186 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
187 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end
);
188 CPPUNIT_ASSERT_EQUAL(-1.0, res
);
190 // "-0" is negative zero
191 res
= rtl::math::stringToDouble("-0", '.', ',', &status
, &end
);
192 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
193 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end
);
194 CPPUNIT_ASSERT_EQUAL(0.0, res
);
195 CPPUNIT_ASSERT(std::signbit(res
));
197 // Compensating: "0.001E311" is 1E308, not overflow/inf
198 res
= rtl::math::stringToDouble("0.001E311", '.', ',', &status
, &end
);
199 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
200 CPPUNIT_ASSERT_EQUAL(sal_Int32(9), end
);
201 CPPUNIT_ASSERT_EQUAL(1E308
, res
);
203 res
= rtl::math::stringToDouble("1E8589934590", '.', ',', &status
, &end
);
204 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_OutOfRange
, status
);
205 CPPUNIT_ASSERT_EQUAL(sal_Int32(12), end
);
206 CPPUNIT_ASSERT_EQUAL(std::numeric_limits
<double>::infinity(), res
);
208 // DBL_MAX and 4 nextafters
209 double fValAfter
= DBL_MAX
;
210 res
= rtl::math::stringToDouble("1.7976931348623157e+308", '.', ',', &status
, &end
);
211 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
212 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end
);
213 CPPUNIT_ASSERT_EQUAL(fValAfter
, res
);
215 fValAfter
= std::nextafter( fValAfter
, 0);
216 res
= rtl::math::stringToDouble("1.7976931348623155e+308", '.', ',', &status
, &end
);
217 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
218 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end
);
219 CPPUNIT_ASSERT_EQUAL(fValAfter
, res
);
221 fValAfter
= std::nextafter( fValAfter
, 0);
222 res
= rtl::math::stringToDouble("1.7976931348623153e+308", '.', ',', &status
, &end
);
223 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
224 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end
);
225 CPPUNIT_ASSERT_EQUAL(fValAfter
, res
);
227 fValAfter
= std::nextafter( fValAfter
, 0);
228 res
= rtl::math::stringToDouble("1.7976931348623151e+308", '.', ',', &status
, &end
);
229 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
230 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end
);
231 CPPUNIT_ASSERT_EQUAL(fValAfter
, res
);
233 fValAfter
= std::nextafter( fValAfter
, 0);
234 res
= rtl::math::stringToDouble("1.7976931348623149e+308", '.', ',', &status
, &end
);
235 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
236 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end
);
237 CPPUNIT_ASSERT_EQUAL(fValAfter
, res
);
240 void test_stringToDouble_bad() {
241 rtl_math_ConversionStatus status
;
243 double res
= rtl::math::stringToDouble(
245 '.', ',', &status
, &end
);
246 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
247 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end
);
248 CPPUNIT_ASSERT_EQUAL(0.0, res
);
250 res
= rtl::math::stringToDouble(
252 '.', ',', &status
, &end
);
253 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
254 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end
);
255 CPPUNIT_ASSERT_EQUAL(0.0, res
);
257 res
= rtl::math::stringToDouble(
259 '.', ',', &status
, &end
);
260 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
261 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end
);
262 CPPUNIT_ASSERT_EQUAL(0.0, res
);
264 res
= rtl::math::stringToDouble(
266 '.', ',', &status
, &end
);
267 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
268 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end
);
269 CPPUNIT_ASSERT_EQUAL(0.0, res
);
271 // Leading group separator is none.
272 res
= rtl::math::stringToDouble(
274 '.', ',', &status
, &end
);
275 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
276 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end
);
277 CPPUNIT_ASSERT_EQUAL(0.0, res
);
280 void test_stringToDouble_exponent_without_digit() {
281 rtl_math_ConversionStatus status
;
283 double res
= rtl::math::stringToDouble(
285 '.', ',', &status
, &end
);
286 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
287 CPPUNIT_ASSERT_EQUAL(RTL_CONSTASCII_LENGTH("1"), end
);
288 CPPUNIT_ASSERT_EQUAL(1.0, res
);
289 res
= rtl::math::stringToDouble(
291 '.', ',', &status
, &end
);
292 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok
, status
);
293 CPPUNIT_ASSERT_EQUAL(RTL_CONSTASCII_LENGTH("1"), end
);
294 CPPUNIT_ASSERT_EQUAL(0.0, res
);
298 double fVal
= 5000000000000001.0;
299 CPPUNIT_ASSERT_EQUAL( 5000000000000001.0, rtl::math::round( fVal
, 9, rtl_math_RoundingMode_Corrected
));
301 fVal
= 8796093022188.0;
302 CPPUNIT_ASSERT_EQUAL( 6093022188.0 , rtl::math::round( fVal
, 9, rtl_math_RoundingMode_Corrected
) - 8790000000000);
304 fVal
= 4503599627370491.0;
305 CPPUNIT_ASSERT_EQUAL( 4503599627370000.0, rtl::math::round( fVal
, -3, rtl_math_RoundingMode_Corrected
));
308 void test_doubleToString() {
309 double fVal
= 999999999999999.0;
310 sal_Int32 aGroups
[3] = { 3, 2, 0 };
311 OUString
aRes( rtl::math::doubleToUString( fVal
,
312 rtl_math_StringFormat_Automatic
,
313 rtl_math_DecimalPlaces_Max
,
314 '.', aGroups
, ',', true));
315 CPPUNIT_ASSERT_EQUAL( OUString("99,99,99,99,99,99,999"), aRes
);
318 aRes
= rtl::math::doubleToUString( fVal
,
319 rtl_math_StringFormat_Automatic
,
320 -2, // round before decimals
321 '.', aGroups
, ',', true);
322 CPPUNIT_ASSERT_EQUAL( OUString("900"), aRes
);
325 aRes
= rtl::math::doubleToUString( fVal
,
326 rtl_math_StringFormat_Automatic
,
327 -2, // round before decimals
328 '.', aGroups
, ',', true);
329 CPPUNIT_ASSERT_EQUAL( OUString("1,000"), aRes
);
331 fVal
= 4503599627370495.0;
332 aRes
= rtl::math::doubleToUString( fVal
,
333 rtl_math_StringFormat_Automatic
,
334 rtl_math_DecimalPlaces_Max
, '.');
335 CPPUNIT_ASSERT_EQUAL( OUString("4503599627370495"), aRes
);
337 fVal
= 4503599627370496.0;
338 aRes
= rtl::math::doubleToUString( fVal
,
339 rtl_math_StringFormat_Automatic
,
341 CPPUNIT_ASSERT_EQUAL( OUString("4503599627370496.00"), aRes
);
343 fVal
= -4503599627370496.0;
344 aRes
= rtl::math::doubleToUString( fVal
,
345 rtl_math_StringFormat_Automatic
,
347 CPPUNIT_ASSERT_EQUAL( OUString("-4503599627370496.00"), aRes
);
349 fVal
= 9007199254740991.0; // (2^53)-1
350 aRes
= rtl::math::doubleToUString( fVal
,
351 rtl_math_StringFormat_Automatic
,
352 rtl_math_DecimalPlaces_Max
, '.', true);
353 CPPUNIT_ASSERT_EQUAL( OUString("9007199254740991"), aRes
);
355 fVal
= 9007199254740992.0; // (2^53), algorithm switch
356 aRes
= rtl::math::doubleToUString( fVal
,
357 rtl_math_StringFormat_Automatic
,
358 rtl_math_DecimalPlaces_Max
, '.', true);
359 CPPUNIT_ASSERT_EQUAL( OUString("9.00719925474099E+015"), aRes
);
361 fVal
= 9007199254740993.0; // (2^53)+1 would be but is 9007199254740992
362 aRes
= rtl::math::doubleToUString( fVal
,
363 rtl_math_StringFormat_Automatic
,
364 rtl_math_DecimalPlaces_Max
, '.', true);
365 CPPUNIT_ASSERT_EQUAL( OUString("9.00719925474099E+015"), aRes
);
367 // Test rtl_math_StringFormat_G
370 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_G
, 3, '.', true);
371 CPPUNIT_ASSERT_EQUAL( OUString("0.00123"), aRes
);
374 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_G
, 3, '.', true);
375 CPPUNIT_ASSERT_EQUAL( OUString("123"), aRes
);
378 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_G
, 4, '.', true);
379 CPPUNIT_ASSERT_EQUAL( OUString("123.5"), aRes
);
382 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_G
, 3, '.', true);
383 CPPUNIT_ASSERT_EQUAL( OUString("99.6"), aRes
);
385 // Expected could be 1E+03 (as 999.6 rounded to 3 significant digits
386 // results in 1000 with an exponent equal to significant digits).
387 // Currently we don't and output 1000 instead, negligible.
389 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_G
, 3, '.', true);
390 CPPUNIT_ASSERT_EQUAL( OUString("1000"), aRes
);
393 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_G
, 3, '.', true);
394 CPPUNIT_ASSERT_EQUAL( OUString("1E+004"), aRes
);
397 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_G
, -3, '.', true);
398 CPPUNIT_ASSERT_EQUAL( OUString("1.2E+004"), aRes
);
400 // DBL_MAX and 4 nextafters
402 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
,
403 rtl_math_DecimalPlaces_Max
, '.', true);
404 CPPUNIT_ASSERT_EQUAL( OUString("1.7976931348623157E+308"), aRes
);
406 fVal
= std::nextafter( fVal
, 0);
407 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
,
408 rtl_math_DecimalPlaces_Max
, '.', true);
409 CPPUNIT_ASSERT_EQUAL( OUString("1.7976931348623155E+308"), aRes
);
411 fVal
= std::nextafter( fVal
, 0);
412 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
,
413 rtl_math_DecimalPlaces_Max
, '.', true);
414 CPPUNIT_ASSERT_EQUAL( OUString("1.7976931348623153E+308"), aRes
);
416 fVal
= std::nextafter( fVal
, 0);
417 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
,
418 rtl_math_DecimalPlaces_Max
, '.', true);
419 CPPUNIT_ASSERT_EQUAL( OUString("1.7976931348623151E+308"), aRes
);
421 fVal
= std::nextafter( fVal
, 0);
422 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
,
423 rtl_math_DecimalPlaces_Max
, '.', true);
424 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862315E+308"), aRes
);
425 CPPUNIT_ASSERT_EQUAL(fVal
, rtl::math::stringToDouble(aRes
, '.', ',')); // Test roundtrip
427 // DBL_MAX and 4 nextafters rounded to 15 decimals
429 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
, 15, '.', true);
430 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862316E+308"), aRes
);
432 fVal
= std::nextafter( fVal
, 0);
433 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
, 15, '.', true);
434 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862316E+308"), aRes
);
436 fVal
= std::nextafter( fVal
, 0);
437 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
, 15, '.', true);
438 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862315E+308"), aRes
);
440 fVal
= std::nextafter( fVal
, 0);
441 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
, 15, '.', true);
442 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862315E+308"), aRes
);
444 fVal
= std::nextafter( fVal
, 0);
445 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
, 15, '.', true);
446 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862315E+308"), aRes
);
448 // DBL_MAX rounded to 14 decimals
450 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
, 14, '.', true);
451 CPPUNIT_ASSERT_EQUAL( OUString("1.79769313486232E+308"), aRes
);
453 // DBL_MAX rounded to 2 decimals
455 aRes
= rtl::math::doubleToUString( fVal
, rtl_math_StringFormat_Automatic
, 2, '.', true);
456 CPPUNIT_ASSERT_EQUAL( OUString("1.8E+308"), aRes
);
458 // Crashed after commit eae24a9488814e77254d175c11fc4a138c1dbd30
460 aRes
= rtl::math::doubleToUString(fVal
, rtl_math_StringFormat_E
, 2, '.', false);
461 CPPUNIT_ASSERT_EQUAL(OUString("1.23E+005"), aRes
);
463 fVal
= 9.9999999999999929;
464 aRes
= rtl::math::doubleToUString(fVal
, rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
, '.', true);
465 CPPUNIT_ASSERT_EQUAL(OUString("9.99999999999999"), aRes
);
467 fVal
= 0.99999999999999933;
468 aRes
= rtl::math::doubleToUString(fVal
, rtl_math_StringFormat_F
, rtl_math_DecimalPlaces_Max
, '.', true);
469 CPPUNIT_ASSERT_EQUAL(OUString("0.999999999999999"), aRes
);
473 // (2^53)-1 , (2^53)-3
474 CPPUNIT_ASSERT_EQUAL( false, rtl::math::approxEqual( 9007199254740991.0, 9007199254740989.0));
475 // (2^53)-1 , (2^53)-2
476 CPPUNIT_ASSERT_EQUAL( false, rtl::math::approxEqual( 9007199254740991.0, 9007199254740990.0));
477 // Note: the following are internally represented as 900719925474099.12
478 // and 900719925474098.88 and the difference is 0.25 ...
479 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 900719925474099.1, 900719925474098.9));
480 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 72.944444444444443, 72.9444444444444));
481 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 359650.27322404372, 359650.27322404401));
482 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 5.3590326375710063e+238, 5.3590326375710109e+238));
483 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 7.4124095894894475e+158, 7.4124095894894514e+158));
484 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 1.2905754687023132e+79, 1.2905754687023098e+79));
485 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 3.5612905090455637e+38, 3.5612905090455599e+38));
486 // 0.3 - 0.2 - 0.1 == 0.0
487 CPPUNIT_ASSERT_EQUAL( 0.0, rtl::math::approxSub( rtl::math::approxSub( 0.3, 0.2), 0.1));
488 // ((2^53)-1) - ((2^53)-2) == 1.0
489 CPPUNIT_ASSERT_EQUAL( 1.0, rtl::math::approxSub( 9007199254740991.0, 9007199254740990.0));
490 // (3^31) - ((3^31)-1) == 1.0
491 CPPUNIT_ASSERT_EQUAL( 1.0, rtl::math::approxSub( 617673396283947.0, 617673396283946.0));
497 res
= rtl::math::erf(x
);
498 CPPUNIT_ASSERT_EQUAL(0.0,res
);
499 rtl::math::setInf( &x
, false);
500 res
= rtl::math::erf(x
);
501 CPPUNIT_ASSERT_EQUAL(1.0,res
);
502 rtl::math::setInf( &x
, true);
503 res
= rtl::math::erf(x
);
504 CPPUNIT_ASSERT_EQUAL(-1.0,res
);
505 rtl::math::setNan( &x
);
506 res
= rtl::math::erf(x
);
507 CPPUNIT_ASSERT(std::isnan(res
));
509 res
= rtl::math::erf(-x
);
510 CPPUNIT_ASSERT_DOUBLES_EQUAL( -rtl::math::erf(x
), res
, 1E-12);
516 res
= rtl::math::erfc(x
);
517 CPPUNIT_ASSERT_EQUAL(1.0,res
);
518 rtl::math::setInf( &x
, false);
519 res
= rtl::math::erfc(x
);
520 CPPUNIT_ASSERT_EQUAL(0.0,res
);
521 rtl::math::setInf( &x
, true);
522 res
= rtl::math::erfc(x
);
523 CPPUNIT_ASSERT_EQUAL(2.0,res
);
524 rtl::math::setNan( &x
);
525 res
= rtl::math::erfc(x
);
526 CPPUNIT_ASSERT(std::isnan(res
));
528 res
= rtl::math::erfc(-x
);
529 CPPUNIT_ASSERT_DOUBLES_EQUAL( 2.0 - rtl::math::erfc(x
), res
, 1E-12);
535 res
= rtl::math::expm1(x
);
536 CPPUNIT_ASSERT_EQUAL(0.0,res
);
538 res
= rtl::math::expm1(x
);
539 CPPUNIT_ASSERT_EQUAL(-0.0,res
);
540 CPPUNIT_ASSERT(std::signbit(res
));
541 rtl::math::setInf( &x
, false);
542 res
= rtl::math::expm1(x
);
543 CPPUNIT_ASSERT_EQUAL(true, std::isinf(res
) && !std::signbit(res
));
544 rtl::math::setInf( &x
, true);
545 res
= rtl::math::expm1(x
);
546 CPPUNIT_ASSERT_EQUAL(-1.0,res
);
547 rtl::math::setNan( &x
);
548 res
= rtl::math::expm1(x
);
549 CPPUNIT_ASSERT(std::isnan(res
));
555 res
= rtl::math::log1p(x
);
556 CPPUNIT_ASSERT_EQUAL(0.0,res
);
558 res
= rtl::math::log1p(x
);
559 CPPUNIT_ASSERT_EQUAL(-0.0,res
);
560 CPPUNIT_ASSERT(std::signbit(res
));
561 rtl::math::setInf( &x
, false);
562 res
= rtl::math::log1p(x
);
563 CPPUNIT_ASSERT_EQUAL(true, std::isinf(res
) && !std::signbit(res
));
565 res
= rtl::math::log1p(x
);
566 CPPUNIT_ASSERT_EQUAL(true, std::isinf(res
) && std::signbit(res
));
568 res
= rtl::math::log1p(x
);
569 CPPUNIT_ASSERT(std::isnan(res
));
570 rtl::math::setInf( &x
, true);
571 res
= rtl::math::log1p(x
);
572 CPPUNIT_ASSERT(std::isnan(res
));
573 rtl::math::setNan( &x
);
574 res
= rtl::math::log1p(x
);
575 CPPUNIT_ASSERT(std::isnan(res
));
581 res
= rtl::math::acosh(-1.0); // NaN
582 CPPUNIT_ASSERT(std::isnan(res
));
584 res
= rtl::math::acosh(0.0); // NaN
585 CPPUNIT_ASSERT(std::isnan(res
));
587 res
= rtl::math::acosh(0.5); // NaN
588 CPPUNIT_ASSERT(std::isnan(res
));
590 CPPUNIT_ASSERT_EQUAL(0.0, rtl::math::acosh(1.0));
592 res
= rtl::math::acosh(std::numeric_limits
<double>::infinity()); // +Inf
593 CPPUNIT_ASSERT(!std::signbit(res
));
594 CPPUNIT_ASSERT(std::isinf(res
));
597 CPPUNIT_ASSERT_DOUBLES_EQUAL(692.56728736744176, rtl::math::acosh(3e+300), 1e-15);
598 CPPUNIT_ASSERT_DOUBLES_EQUAL(0.014142017775252324, rtl::math::acosh(1.0001), 1e-15);
604 res
= rtl::math::asinh(-std::numeric_limits
<double>::infinity()); // -Inf
605 CPPUNIT_ASSERT(std::signbit(res
));
606 CPPUNIT_ASSERT(std::isinf(res
));
608 CPPUNIT_ASSERT_EQUAL(0.0, rtl::math::asinh(0.0));
610 res
= rtl::math::asinh(std::numeric_limits
<double>::infinity()); // +Inf
611 CPPUNIT_ASSERT(!std::signbit(res
));
612 CPPUNIT_ASSERT(std::isinf(res
));
615 CPPUNIT_ASSERT_DOUBLES_EQUAL(691.67568924815798, rtl::math::asinh(1.23e+300), 1e-15);
616 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0350378961923076, rtl::math::asinh(1.23), 1e-16);
617 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23e-300, rtl::math::asinh(1.23e-300), 1e-303);
619 // asinh is an odd function
620 CPPUNIT_ASSERT_EQUAL(-rtl::math::asinh(1.23e+300), rtl::math::asinh(-1.23e+300));
621 CPPUNIT_ASSERT_EQUAL(-rtl::math::asinh(1.23), rtl::math::asinh(-1.23));
622 CPPUNIT_ASSERT_EQUAL(-rtl::math::asinh(1.23e-300), rtl::math::asinh(-1.23e-300));
628 res
= rtl::math::atanh(-2.0); // NaN
629 CPPUNIT_ASSERT(std::isnan(res
));
631 res
= rtl::math::atanh(-1.0); // -Inf
632 CPPUNIT_ASSERT(std::signbit(res
));
633 CPPUNIT_ASSERT(std::isinf(res
));
635 CPPUNIT_ASSERT_EQUAL(0.0, rtl::math::atanh(0.0));
637 res
= rtl::math::atanh(1.0); // +Inf
638 CPPUNIT_ASSERT(!std::signbit(res
));
639 CPPUNIT_ASSERT(std::isinf(res
));
641 res
= rtl::math::atanh(2.0); // NaN
642 CPPUNIT_ASSERT(std::isnan(res
));
645 void test_payloadNaN() {
646 // Test that a quiet NaN payload is propagated and behaves as we
647 // expect. Ideally that could be done with a constexpr in
648 // sal/rtl/math.cxx to fail already during compile time instead of make
651 // https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/nan-propagation.pdf
652 double fVal1
= std::numeric_limits
<double>::quiet_NaN();
653 reinterpret_cast<sal_math_Double
*>(&fVal1
)->nan_parts
.fraction_lo
= 0xbeef;
654 const double fVal2
= 0 + fVal1
;
655 CPPUNIT_ASSERT(std::isnan(fVal2
));
656 CPPUNIT_ASSERT_EQUAL_MESSAGE("Your platform does not support propagation of NaN payloads.",
657 static_cast<sal_uInt32
>(0xbeef),
658 static_cast<sal_uInt32
>(reinterpret_cast<const sal_math_Double
*>(&fVal2
)->nan_parts
.fraction_lo
));
659 reinterpret_cast<sal_math_Double
*>(&fVal1
)->nan_parts
.fraction_lo
= 0xdead;
660 const double fVal3
= fVal1
+ fVal2
;
661 // Result is one of the payloaded NaNs but the standard does not
663 CPPUNIT_ASSERT_MESSAGE("Your platform does not support propagation of two combined NaN payloads.",
664 0xbeef == reinterpret_cast<const sal_math_Double
*>(&fVal3
)->nan_parts
.fraction_lo
||
665 0xdead == reinterpret_cast<const sal_math_Double
*>(&fVal3
)->nan_parts
.fraction_lo
);
668 CPPUNIT_TEST_SUITE(Test
);
669 CPPUNIT_TEST(test_stringToDouble_good
);
670 CPPUNIT_TEST(test_stringToDouble_bad
);
671 CPPUNIT_TEST(test_stringToDouble_exponent_without_digit
);
672 CPPUNIT_TEST(test_round
);
673 CPPUNIT_TEST(test_doubleToString
);
674 CPPUNIT_TEST(test_erf
);
675 CPPUNIT_TEST(test_erfc
);
676 CPPUNIT_TEST(test_expm1
);
677 CPPUNIT_TEST(test_log1p
);
678 CPPUNIT_TEST(test_approx
);
679 CPPUNIT_TEST(test_acosh
);
680 CPPUNIT_TEST(test_asinh
);
681 CPPUNIT_TEST(test_atanh
);
682 CPPUNIT_TEST(test_payloadNaN
);
683 CPPUNIT_TEST_SUITE_END();
686 CPPUNIT_TEST_SUITE_REGISTRATION(Test
);
690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */