Bump version to 24.04.3.4
[LibreOffice.git] / sal / qa / rtl / math / test-rtl-math.cxx
blobbab2774a414ce9b6d5db03fb1ea5451bdf17110c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <rtl/math.hxx>
25 #include <rtl/ustring.hxx>
26 #include <limits>
28 template<> inline std::string CPPUNIT_NS::assertion_traits<rtl_math_ConversionStatus>::toString(
29 const rtl_math_ConversionStatus& x )
31 OStringStream ost;
32 ost << static_cast<unsigned int>(x);
33 return ost.str();
36 namespace {
38 class Test: public CppUnit::TestFixture {
39 public:
40 void test_stringToDouble_good() {
41 rtl_math_ConversionStatus status;
42 sal_Int32 end;
43 double res = rtl::math::stringToDouble(
44 " +1.E01foo",
45 '.', ',', &status, &end);
46 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
47 CPPUNIT_ASSERT_EQUAL(RTL_CONSTASCII_LENGTH(" +1.E01"), end);
48 CPPUNIT_ASSERT_EQUAL(10.0, res);
50 res = rtl::math::stringToDouble(
51 "NaN",
52 '.', ',', &status, &end);
53 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
54 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), end);
55 CPPUNIT_ASSERT(std::isnan(res));
57 res = rtl::math::stringToDouble(
58 "NaN1.23",
59 '.', ',', &status, &end);
60 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
61 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), end);
62 CPPUNIT_ASSERT(std::isnan(res));
64 res = rtl::math::stringToDouble(
65 "+NaN",
66 '.', ',', &status, &end);
67 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
68 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
69 CPPUNIT_ASSERT_EQUAL(0.0, res);
71 res = rtl::math::stringToDouble(
72 "-NaN",
73 '.', ',', &status, &end);
74 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
75 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
76 CPPUNIT_ASSERT_EQUAL(0.0, res);
78 res = rtl::math::stringToDouble(
79 "+1.#NAN",
80 '.', ',', &status, &end);
81 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
82 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), end);
83 CPPUNIT_ASSERT(std::isnan(res));
84 CPPUNIT_ASSERT(!std::signbit(res));
86 res = rtl::math::stringToDouble(
87 "-1.#NAN",
88 '.', ',', &status, &end);
89 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
90 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), end);
91 CPPUNIT_ASSERT(std::isnan(res));
92 CPPUNIT_ASSERT(std::signbit(res));
94 res = rtl::math::stringToDouble(
95 "INF",
96 '.', ',', &status, &end);
97 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_OutOfRange, status);
98 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), end);
99 CPPUNIT_ASSERT(std::isinf(res));
101 res = rtl::math::stringToDouble(
102 "INF1.23",
103 '.', ',', &status, &end);
104 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_OutOfRange, status);
105 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), end);
106 CPPUNIT_ASSERT(std::isinf(res));
108 res = rtl::math::stringToDouble(
109 ".5",
110 '.', ',', &status, &end);
111 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
112 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end);
113 CPPUNIT_ASSERT_EQUAL(0.5, res);
115 res = rtl::math::stringToDouble(
116 "5.",
117 '.', ',', &status, &end);
118 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
119 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end);
120 CPPUNIT_ASSERT_EQUAL(5.0, res);
122 // Leading 0 and group separator.
123 res = rtl::math::stringToDouble(
124 "0,123",
125 '.', ',', &status, &end);
126 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
127 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), end);
128 CPPUNIT_ASSERT_EQUAL(123.0, res);
130 // Leading 0 and two consecutive group separators are none.
131 res = rtl::math::stringToDouble(
132 "0,,1",
133 '.', ',', &status, &end);
134 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
135 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), end);
136 CPPUNIT_ASSERT_EQUAL(0.0, res);
138 // Leading 0 and group separator at end is none.
139 res = rtl::math::stringToDouble(
140 "0,",
141 '.', ',', &status, &end);
142 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
143 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), end);
144 CPPUNIT_ASSERT_EQUAL(0.0, res);
146 // Leading 0 and group separator before non-digit is none.
147 res = rtl::math::stringToDouble(
148 "0,x",
149 '.', ',', &status, &end);
150 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
151 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), end);
152 CPPUNIT_ASSERT_EQUAL(0.0, res);
154 // Trailing group separator is none.
155 res = rtl::math::stringToDouble(
156 "1,234,",
157 '.', ',', &status, &end);
158 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
159 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), end);
160 CPPUNIT_ASSERT_EQUAL(1234.0, res);
162 // Group separator followed by non-digit is none.
163 res = rtl::math::stringToDouble(
164 "1,234,x",
165 '.', ',', &status, &end);
166 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
167 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), end);
168 CPPUNIT_ASSERT_EQUAL(1234.0, res);
170 // Check that the value is the nearest double-precision representation of the decimal 0.0042
171 // (it was 0.0042000000000000006 instead of 0.0041999999999999997)
172 res = rtl::math::stringToDouble("0,0042", ',', ' ', &status, &end);
173 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
174 CPPUNIT_ASSERT_EQUAL(0.0042, res);
176 // "- 1" is nothing
177 res = rtl::math::stringToDouble("- 1", '.', ',', &status, &end);
178 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
179 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
180 CPPUNIT_ASSERT_EQUAL(0.0, res);
182 // "-1E+E" : no exponent
183 res = rtl::math::stringToDouble("-1E+E", '.', ',', &status, &end);
184 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
185 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end);
186 CPPUNIT_ASSERT_EQUAL(-1.0, res);
188 // "-0" is negative zero
189 res = rtl::math::stringToDouble("-0", '.', ',', &status, &end);
190 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
191 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), end);
192 CPPUNIT_ASSERT_EQUAL(0.0, res);
193 CPPUNIT_ASSERT(std::signbit(res));
195 // Compensating: "0.001E311" is 1E308, not overflow/inf
196 res = rtl::math::stringToDouble("0.001E311", '.', ',', &status, &end);
197 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
198 CPPUNIT_ASSERT_EQUAL(sal_Int32(9), end);
199 CPPUNIT_ASSERT_EQUAL(1E308, res);
201 res = rtl::math::stringToDouble("1E8589934590", '.', ',', &status, &end);
202 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_OutOfRange, status);
203 CPPUNIT_ASSERT_EQUAL(sal_Int32(12), end);
204 CPPUNIT_ASSERT_EQUAL(std::numeric_limits<double>::infinity(), res);
206 // DBL_MAX and 4 nextafters
207 double fValAfter = DBL_MAX;
208 res = rtl::math::stringToDouble("1.7976931348623157e+308", '.', ',', &status, &end);
209 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
210 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end);
211 CPPUNIT_ASSERT_EQUAL(fValAfter, res);
213 fValAfter = std::nextafter( fValAfter, 0);
214 res = rtl::math::stringToDouble("1.7976931348623155e+308", '.', ',', &status, &end);
215 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
216 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end);
217 CPPUNIT_ASSERT_EQUAL(fValAfter, res);
219 fValAfter = std::nextafter( fValAfter, 0);
220 res = rtl::math::stringToDouble("1.7976931348623153e+308", '.', ',', &status, &end);
221 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
222 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end);
223 CPPUNIT_ASSERT_EQUAL(fValAfter, res);
225 fValAfter = std::nextafter( fValAfter, 0);
226 res = rtl::math::stringToDouble("1.7976931348623151e+308", '.', ',', &status, &end);
227 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
228 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end);
229 CPPUNIT_ASSERT_EQUAL(fValAfter, res);
231 fValAfter = std::nextafter( fValAfter, 0);
232 res = rtl::math::stringToDouble("1.7976931348623149e+308", '.', ',', &status, &end);
233 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
234 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end);
235 CPPUNIT_ASSERT_EQUAL(fValAfter, res);
238 void test_stringToDouble_bad() {
239 rtl_math_ConversionStatus status;
240 sal_Int32 end;
241 double res = rtl::math::stringToDouble(
242 " +Efoo",
243 '.', ',', &status, &end);
244 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
245 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
246 CPPUNIT_ASSERT_EQUAL(0.0, res);
248 res = rtl::math::stringToDouble(
249 ".",
250 '.', ',', &status, &end);
251 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
252 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
253 CPPUNIT_ASSERT_EQUAL(0.0, res);
255 res = rtl::math::stringToDouble(
256 " +.Efoo",
257 '.', ',', &status, &end);
258 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
259 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
260 CPPUNIT_ASSERT_EQUAL(0.0, res);
262 res = rtl::math::stringToDouble(
263 " +,.Efoo",
264 '.', ',', &status, &end);
265 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
266 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
267 CPPUNIT_ASSERT_EQUAL(0.0, res);
269 // Leading group separator is none.
270 res = rtl::math::stringToDouble(
271 ",1234",
272 '.', ',', &status, &end);
273 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
274 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), end);
275 CPPUNIT_ASSERT_EQUAL(0.0, res);
278 void test_stringToDouble_exponent_without_digit() {
279 rtl_math_ConversionStatus status;
280 sal_Int32 end;
281 double res = rtl::math::stringToDouble(
282 "1e",
283 '.', ',', &status, &end);
284 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
285 CPPUNIT_ASSERT_EQUAL(RTL_CONSTASCII_LENGTH("1"), end);
286 CPPUNIT_ASSERT_EQUAL(1.0, res);
287 res = rtl::math::stringToDouble(
288 "0e",
289 '.', ',', &status, &end);
290 CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
291 CPPUNIT_ASSERT_EQUAL(RTL_CONSTASCII_LENGTH("1"), end);
292 CPPUNIT_ASSERT_EQUAL(0.0, res);
295 void test_round() {
296 double fVal = 5000000000000001.0;
297 CPPUNIT_ASSERT_EQUAL( 5000000000000001.0, rtl::math::round( fVal, 9, rtl_math_RoundingMode_Corrected));
299 fVal = 8796093022188.0;
300 CPPUNIT_ASSERT_EQUAL( 6093022188.0 , rtl::math::round( fVal, 9, rtl_math_RoundingMode_Corrected) - 8790000000000);
302 fVal = 4503599627370491.0;
303 CPPUNIT_ASSERT_EQUAL( 4503599627370000.0, rtl::math::round( fVal, -3, rtl_math_RoundingMode_Corrected));
306 void test_doubleToString() {
307 double fVal = 999999999999999.0;
308 sal_Int32 aGroups[3] = { 3, 2, 0 };
309 OUString aRes( rtl::math::doubleToUString( fVal,
310 rtl_math_StringFormat_Automatic,
311 rtl_math_DecimalPlaces_Max,
312 '.', aGroups, ',', true));
313 CPPUNIT_ASSERT_EQUAL( OUString("99,99,99,99,99,99,999"), aRes);
315 fVal = 949.0;
316 aRes = rtl::math::doubleToUString( fVal,
317 rtl_math_StringFormat_Automatic,
318 -2, // round before decimals
319 '.', aGroups, ',', true);
320 CPPUNIT_ASSERT_EQUAL( OUString("900"), aRes);
322 fVal = 950.0;
323 aRes = rtl::math::doubleToUString( fVal,
324 rtl_math_StringFormat_Automatic,
325 -2, // round before decimals
326 '.', aGroups, ',', true);
327 CPPUNIT_ASSERT_EQUAL( OUString("1,000"), aRes);
329 // Check non-ASCII separators: Arabic decimal separator U+066B, thousand separator U+066C
330 fVal = 123456.78;
331 aRes = rtl::math::doubleToUString( fVal,
332 rtl_math_StringFormat_Automatic,
334 u'Ù«', aGroups, u'Ù¬', true);
335 CPPUNIT_ASSERT_EQUAL( u"1Ù¬23Ù¬456Ù«78"_ustr, aRes);
337 fVal = 4503599627370495.0;
338 aRes = rtl::math::doubleToUString( fVal,
339 rtl_math_StringFormat_Automatic,
340 rtl_math_DecimalPlaces_Max, '.');
341 CPPUNIT_ASSERT_EQUAL( OUString("4503599627370495"), aRes);
343 fVal = 4503599627370496.0;
344 aRes = rtl::math::doubleToUString( fVal,
345 rtl_math_StringFormat_Automatic,
346 2, '.');
347 CPPUNIT_ASSERT_EQUAL( OUString("4503599627370496.00"), aRes);
349 fVal = -4503599627370496.0;
350 aRes = rtl::math::doubleToUString( fVal,
351 rtl_math_StringFormat_Automatic,
352 2, '.');
353 CPPUNIT_ASSERT_EQUAL( OUString("-4503599627370496.00"), aRes);
355 fVal = 9007199254740991.0; // (2^53)-1
356 aRes = rtl::math::doubleToUString( fVal,
357 rtl_math_StringFormat_Automatic,
358 rtl_math_DecimalPlaces_Max, '.', true);
359 CPPUNIT_ASSERT_EQUAL( OUString("9007199254740991"), aRes);
361 fVal = 9007199254740992.0; // (2^53), algorithm switch
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 fVal = 9007199254740993.0; // (2^53)+1 would be but is 9007199254740992
368 aRes = rtl::math::doubleToUString( fVal,
369 rtl_math_StringFormat_Automatic,
370 rtl_math_DecimalPlaces_Max, '.', true);
371 CPPUNIT_ASSERT_EQUAL( OUString("9.00719925474099E+015"), aRes);
373 // Test rtl_math_StringFormat_G
375 fVal = 0.001234567;
376 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_G, 3, '.', true);
377 CPPUNIT_ASSERT_EQUAL( OUString("0.00123"), aRes);
379 fVal = 123.4567;
380 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_G, 3, '.', true);
381 CPPUNIT_ASSERT_EQUAL( OUString("123"), aRes);
383 fVal = 123.4567;
384 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_G, 4, '.', true);
385 CPPUNIT_ASSERT_EQUAL( OUString("123.5"), aRes);
387 fVal = 99.6;
388 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_G, 3, '.', true);
389 CPPUNIT_ASSERT_EQUAL( OUString("99.6"), aRes);
391 // Expected could be 1E+03 (as 999.6 rounded to 3 significant digits
392 // results in 1000 with an exponent equal to significant digits).
393 // Currently we don't and output 1000 instead, negligible.
394 fVal = 999.6;
395 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_G, 3, '.', true);
396 CPPUNIT_ASSERT_EQUAL( OUString("1000"), aRes);
398 fVal = 9999.6;
399 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_G, 3, '.', true);
400 CPPUNIT_ASSERT_EQUAL( OUString("1E+004"), aRes);
402 fVal = 12345.6789;
403 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_G, -3, '.', true);
404 CPPUNIT_ASSERT_EQUAL( OUString("1.2E+004"), aRes);
406 // DBL_MAX and 4 nextafters
407 fVal = DBL_MAX;
408 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic,
409 rtl_math_DecimalPlaces_Max, '.', true);
410 CPPUNIT_ASSERT_EQUAL( OUString("1.7976931348623157E+308"), aRes);
412 fVal = std::nextafter( fVal, 0);
413 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic,
414 rtl_math_DecimalPlaces_Max, '.', true);
415 CPPUNIT_ASSERT_EQUAL( OUString("1.7976931348623155E+308"), aRes);
417 fVal = std::nextafter( fVal, 0);
418 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic,
419 rtl_math_DecimalPlaces_Max, '.', true);
420 CPPUNIT_ASSERT_EQUAL( OUString("1.7976931348623153E+308"), aRes);
422 fVal = std::nextafter( fVal, 0);
423 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic,
424 rtl_math_DecimalPlaces_Max, '.', true);
425 CPPUNIT_ASSERT_EQUAL( OUString("1.7976931348623151E+308"), aRes);
427 fVal = std::nextafter( fVal, 0);
428 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic,
429 rtl_math_DecimalPlaces_Max, '.', true);
430 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862315E+308"), aRes);
431 CPPUNIT_ASSERT_EQUAL(fVal, rtl::math::stringToDouble(aRes, '.', ',')); // Test roundtrip
433 // DBL_MAX and 4 nextafters rounded to 15 decimals
434 fVal = DBL_MAX;
435 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic, 15, '.', true);
436 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862316E+308"), aRes);
438 fVal = std::nextafter( fVal, 0);
439 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic, 15, '.', true);
440 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862316E+308"), aRes);
442 fVal = std::nextafter( fVal, 0);
443 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic, 15, '.', true);
444 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862315E+308"), aRes);
446 fVal = std::nextafter( fVal, 0);
447 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic, 15, '.', true);
448 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862315E+308"), aRes);
450 fVal = std::nextafter( fVal, 0);
451 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic, 15, '.', true);
452 CPPUNIT_ASSERT_EQUAL( OUString("1.797693134862315E+308"), aRes);
454 // DBL_MAX rounded to 14 decimals
455 fVal = DBL_MAX;
456 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic, 14, '.', true);
457 CPPUNIT_ASSERT_EQUAL( OUString("1.79769313486232E+308"), aRes);
459 // DBL_MAX rounded to 2 decimals
460 fVal = DBL_MAX;
461 aRes = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic, 2, '.', true);
462 CPPUNIT_ASSERT_EQUAL( OUString("1.8E+308"), aRes);
464 // Crashed after commit eae24a9488814e77254d175c11fc4a138c1dbd30
465 fVal = 123456.789;
466 aRes = rtl::math::doubleToUString(fVal, rtl_math_StringFormat_E, 2, '.', false);
467 CPPUNIT_ASSERT_EQUAL(OUString("1.23E+005"), aRes);
469 fVal = 9.9999999999999929;
470 aRes = rtl::math::doubleToUString(fVal, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
471 CPPUNIT_ASSERT_EQUAL(OUString("9.99999999999999"), aRes);
473 fVal = 0.99999999999999933;
474 aRes = rtl::math::doubleToUString(fVal, rtl_math_StringFormat_F, rtl_math_DecimalPlaces_Max, '.', true);
475 CPPUNIT_ASSERT_EQUAL(OUString("0.999999999999999"), aRes);
478 void test_approx() {
479 // (2^53)-1 , (2^53)-3
480 CPPUNIT_ASSERT_EQUAL( false, rtl::math::approxEqual( 9007199254740991.0, 9007199254740989.0));
481 // (2^53)-1 , (2^53)-2
482 CPPUNIT_ASSERT_EQUAL( false, rtl::math::approxEqual( 9007199254740991.0, 9007199254740990.0));
483 // Note: the following are internally represented as 900719925474099.12
484 // and 900719925474098.88 and the difference is 0.25 ...
485 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 900719925474099.1, 900719925474098.9));
486 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 72.944444444444443, 72.9444444444444));
487 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 359650.27322404372, 359650.27322404401));
488 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 5.3590326375710063e+238, 5.3590326375710109e+238));
489 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 7.4124095894894475e+158, 7.4124095894894514e+158));
490 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 1.2905754687023132e+79, 1.2905754687023098e+79));
491 CPPUNIT_ASSERT_EQUAL( true, rtl::math::approxEqual( 3.5612905090455637e+38, 3.5612905090455599e+38));
492 // 0.3 - 0.2 - 0.1 == 0.0
493 CPPUNIT_ASSERT_EQUAL( 0.0, rtl::math::approxSub( rtl::math::approxSub( 0.3, 0.2), 0.1));
494 // ((2^53)-1) - ((2^53)-2) == 1.0
495 CPPUNIT_ASSERT_EQUAL( 1.0, rtl::math::approxSub( 9007199254740991.0, 9007199254740990.0));
496 // (3^31) - ((3^31)-1) == 1.0
497 CPPUNIT_ASSERT_EQUAL( 1.0, rtl::math::approxSub( 617673396283947.0, 617673396283946.0));
500 void test_erf() {
501 double x, res;
502 x = 0.0;
503 res = rtl::math::erf(x);
504 CPPUNIT_ASSERT_EQUAL(0.0,res);
505 rtl::math::setInf( &x, false);
506 res = rtl::math::erf(x);
507 CPPUNIT_ASSERT_EQUAL(1.0,res);
508 rtl::math::setInf( &x, true);
509 res = rtl::math::erf(x);
510 CPPUNIT_ASSERT_EQUAL(-1.0,res);
511 rtl::math::setNan( &x);
512 res = rtl::math::erf(x);
513 CPPUNIT_ASSERT(std::isnan(res));
514 x = 3.0;
515 res = rtl::math::erf(-x);
516 CPPUNIT_ASSERT_DOUBLES_EQUAL( -rtl::math::erf(x), res, 1E-12);
519 void test_erfc() {
520 double x, res;
521 x = 0.0;
522 res = rtl::math::erfc(x);
523 CPPUNIT_ASSERT_EQUAL(1.0,res);
524 rtl::math::setInf( &x, false);
525 res = rtl::math::erfc(x);
526 CPPUNIT_ASSERT_EQUAL(0.0,res);
527 rtl::math::setInf( &x, true);
528 res = rtl::math::erfc(x);
529 CPPUNIT_ASSERT_EQUAL(2.0,res);
530 rtl::math::setNan( &x);
531 res = rtl::math::erfc(x);
532 CPPUNIT_ASSERT(std::isnan(res));
533 x = 3.0;
534 res = rtl::math::erfc(-x);
535 CPPUNIT_ASSERT_DOUBLES_EQUAL( 2.0 - rtl::math::erfc(x), res, 1E-12);
538 void test_expm1() {
539 double x, res;
540 x = 0.0;
541 res = rtl::math::expm1(x);
542 CPPUNIT_ASSERT_EQUAL(0.0,res);
543 x = -0.0;
544 res = rtl::math::expm1(x);
545 CPPUNIT_ASSERT_EQUAL(-0.0,res);
546 CPPUNIT_ASSERT(std::signbit(res));
547 rtl::math::setInf( &x, false);
548 res = rtl::math::expm1(x);
549 CPPUNIT_ASSERT_EQUAL(true, std::isinf(res) && !std::signbit(res));
550 rtl::math::setInf( &x, true);
551 res = rtl::math::expm1(x);
552 CPPUNIT_ASSERT_EQUAL(-1.0,res);
553 rtl::math::setNan( &x);
554 res = rtl::math::expm1(x);
555 CPPUNIT_ASSERT(std::isnan(res));
558 void test_log1p() {
559 double x, res;
560 x = 0.0;
561 res = rtl::math::log1p(x);
562 CPPUNIT_ASSERT_EQUAL(0.0,res);
563 x = -0.0;
564 res = rtl::math::log1p(x);
565 CPPUNIT_ASSERT_EQUAL(-0.0,res);
566 CPPUNIT_ASSERT(std::signbit(res));
567 rtl::math::setInf( &x, false);
568 res = rtl::math::log1p(x);
569 CPPUNIT_ASSERT_EQUAL(true, std::isinf(res) && !std::signbit(res));
570 x = -1.0;
571 res = rtl::math::log1p(x);
572 CPPUNIT_ASSERT_EQUAL(true, std::isinf(res) && std::signbit(res));
573 x = -1.1;
574 res = rtl::math::log1p(x);
575 CPPUNIT_ASSERT(std::isnan(res));
576 rtl::math::setInf( &x, true);
577 res = rtl::math::log1p(x);
578 CPPUNIT_ASSERT(std::isnan(res));
579 rtl::math::setNan( &x);
580 res = rtl::math::log1p(x);
581 CPPUNIT_ASSERT(std::isnan(res));
584 void test_acosh() {
585 double res;
587 res = rtl::math::acosh(-1.0); // NaN
588 CPPUNIT_ASSERT(std::isnan(res));
590 res = rtl::math::acosh(0.0); // NaN
591 CPPUNIT_ASSERT(std::isnan(res));
593 res = rtl::math::acosh(0.5); // NaN
594 CPPUNIT_ASSERT(std::isnan(res));
596 CPPUNIT_ASSERT_EQUAL(0.0, rtl::math::acosh(1.0));
598 res = rtl::math::acosh(std::numeric_limits<double>::infinity()); // +Inf
599 CPPUNIT_ASSERT(!std::signbit(res));
600 CPPUNIT_ASSERT(std::isinf(res));
602 // #i97605
603 CPPUNIT_ASSERT_DOUBLES_EQUAL(692.56728736744176, rtl::math::acosh(3e+300), 1e-15);
604 CPPUNIT_ASSERT_DOUBLES_EQUAL(0.014142017775252324, rtl::math::acosh(1.0001), 1e-15);
607 void test_asinh() {
608 double res;
610 res = rtl::math::asinh(-std::numeric_limits<double>::infinity()); // -Inf
611 CPPUNIT_ASSERT(std::signbit(res));
612 CPPUNIT_ASSERT(std::isinf(res));
614 CPPUNIT_ASSERT_EQUAL(0.0, rtl::math::asinh(0.0));
616 res = rtl::math::asinh(std::numeric_limits<double>::infinity()); // +Inf
617 CPPUNIT_ASSERT(!std::signbit(res));
618 CPPUNIT_ASSERT(std::isinf(res));
620 // #i97605
621 CPPUNIT_ASSERT_DOUBLES_EQUAL(691.67568924815798, rtl::math::asinh(1.23e+300), 1e-15);
622 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0350378961923076, rtl::math::asinh(1.23), 1e-16);
623 CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23e-300, rtl::math::asinh(1.23e-300), 1e-303);
625 // asinh is an odd function
626 CPPUNIT_ASSERT_EQUAL(-rtl::math::asinh(1.23e+300), rtl::math::asinh(-1.23e+300));
627 CPPUNIT_ASSERT_EQUAL(-rtl::math::asinh(1.23), rtl::math::asinh(-1.23));
628 CPPUNIT_ASSERT_EQUAL(-rtl::math::asinh(1.23e-300), rtl::math::asinh(-1.23e-300));
631 void test_atanh() {
632 double res;
634 res = rtl::math::atanh(-2.0); // NaN
635 CPPUNIT_ASSERT(std::isnan(res));
637 res = rtl::math::atanh(-1.0); // -Inf
638 CPPUNIT_ASSERT(std::signbit(res));
639 CPPUNIT_ASSERT(std::isinf(res));
641 CPPUNIT_ASSERT_EQUAL(0.0, rtl::math::atanh(0.0));
643 res = rtl::math::atanh(1.0); // +Inf
644 CPPUNIT_ASSERT(!std::signbit(res));
645 CPPUNIT_ASSERT(std::isinf(res));
647 res = rtl::math::atanh(2.0); // NaN
648 CPPUNIT_ASSERT(std::isnan(res));
651 void test_payloadNaN() {
652 // Test that a quiet NaN payload is propagated and behaves as we
653 // expect. Ideally that could be done with a constexpr in
654 // sal/rtl/math.cxx to fail already during compile time instead of make
655 // check, but..
656 // See
657 // https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/nan-propagation.pdf
658 double fVal1 = std::numeric_limits<double>::quiet_NaN();
659 reinterpret_cast<sal_math_Double*>(&fVal1)->nan_parts.fraction_lo = 0xbeef;
660 const double fVal2 = 0 + fVal1;
661 CPPUNIT_ASSERT(std::isnan(fVal2));
662 CPPUNIT_ASSERT_EQUAL_MESSAGE("Your platform does not support propagation of NaN payloads.",
663 static_cast<sal_uInt32>(0xbeef),
664 static_cast<sal_uInt32>(reinterpret_cast<const sal_math_Double*>(&fVal2)->nan_parts.fraction_lo));
665 reinterpret_cast<sal_math_Double*>(&fVal1)->nan_parts.fraction_lo = 0xdead;
666 const double fVal3 = fVal1 + fVal2;
667 // Result is one of the payloaded NaNs but the standard does not
668 // specify which.
669 CPPUNIT_ASSERT_MESSAGE("Your platform does not support propagation of two combined NaN payloads.",
670 0xbeef == reinterpret_cast<const sal_math_Double*>(&fVal3)->nan_parts.fraction_lo ||
671 0xdead == reinterpret_cast<const sal_math_Double*>(&fVal3)->nan_parts.fraction_lo);
674 CPPUNIT_TEST_SUITE(Test);
675 CPPUNIT_TEST(test_stringToDouble_good);
676 CPPUNIT_TEST(test_stringToDouble_bad);
677 CPPUNIT_TEST(test_stringToDouble_exponent_without_digit);
678 CPPUNIT_TEST(test_round);
679 CPPUNIT_TEST(test_doubleToString);
680 CPPUNIT_TEST(test_erf);
681 CPPUNIT_TEST(test_erfc);
682 CPPUNIT_TEST(test_expm1);
683 CPPUNIT_TEST(test_log1p);
684 CPPUNIT_TEST(test_approx);
685 CPPUNIT_TEST(test_acosh);
686 CPPUNIT_TEST(test_asinh);
687 CPPUNIT_TEST(test_atanh);
688 CPPUNIT_TEST(test_payloadNaN);
689 CPPUNIT_TEST_SUITE_END();
692 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
696 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */