1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2004 StatPro Italia srl
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include "rounding.hpp"
21#include "utilities.hpp"
22#include <ql/math/rounding.hpp>
23#include <ql/math/comparison.hpp>
24
25using namespace QuantLib;
26using namespace boost::unit_test_framework;
27
28namespace rounding_test {
29
30 struct TestCase {
31 Decimal x;
32 Integer precision;
33 Decimal closest;
34 Decimal up;
35 Decimal down;
36 Decimal floor;
37 Decimal ceiling;
38 };
39
40 TestCase testData[] = {
41 { .x: 0.86313513, .precision: 5, .closest: 0.86314, .up: 0.86314, .down: 0.86313, .floor: 0.86314, .ceiling: 0.86313 },
42 { .x: 0.86313, .precision: 5, .closest: 0.86313, .up: 0.86313, .down: 0.86313, .floor: 0.86313, .ceiling: 0.86313 },
43 { .x: -7.64555346, .precision: 1, .closest: -7.6, .up: -7.7, .down: -7.6, .floor: -7.6, .ceiling: -7.6 },
44 { .x: 0.13961605, .precision: 2, .closest: 0.14, .up: 0.14, .down: 0.13, .floor: 0.14, .ceiling: 0.13 },
45 { .x: 0.14344179, .precision: 4, .closest: 0.1434, .up: 0.1435, .down: 0.1434, .floor: 0.1434, .ceiling: 0.1434 },
46 { .x: -4.74315016, .precision: 2, .closest: -4.74, .up: -4.75, .down: -4.74, .floor: -4.74, .ceiling: -4.74 },
47 { .x: -7.82772074, .precision: 5, .closest: -7.82772, .up: -7.82773, .down: -7.82772, .floor: -7.82772, .ceiling: -7.82772 },
48 { .x: 2.74137947, .precision: 3, .closest: 2.741, .up: 2.742, .down: 2.741, .floor: 2.741, .ceiling: 2.741 },
49 { .x: 2.13056714, .precision: 1, .closest: 2.1, .up: 2.2, .down: 2.1, .floor: 2.1, .ceiling: 2.1 },
50 { .x: -1.06228670, .precision: 1, .closest: -1.1, .up: -1.1, .down: -1.0, .floor: -1.0, .ceiling: -1.1 },
51 { .x: 8.29234094, .precision: 4, .closest: 8.2923, .up: 8.2924, .down: 8.2923, .floor: 8.2923, .ceiling: 8.2923 },
52 { .x: 7.90185598, .precision: 2, .closest: 7.90, .up: 7.91, .down: 7.90, .floor: 7.90, .ceiling: 7.90 },
53 { .x: -0.26738058, .precision: 1, .closest: -0.3, .up: -0.3, .down: -0.2, .floor: -0.2, .ceiling: -0.3 },
54 { .x: 1.78128713, .precision: 1, .closest: 1.8, .up: 1.8, .down: 1.7, .floor: 1.8, .ceiling: 1.7 },
55 { .x: 4.23537260, .precision: 1, .closest: 4.2, .up: 4.3, .down: 4.2, .floor: 4.2, .ceiling: 4.2 },
56 { .x: 3.64369953, .precision: 4, .closest: 3.6437, .up: 3.6437, .down: 3.6436, .floor: 3.6437, .ceiling: 3.6436 },
57 { .x: 6.34542470, .precision: 2, .closest: 6.35, .up: 6.35, .down: 6.34, .floor: 6.35, .ceiling: 6.34 },
58 { .x: -0.84754962, .precision: 4, .closest: -0.8475, .up: -0.8476, .down: -0.8475, .floor: -0.8475, .ceiling: -0.8475 },
59 { .x: 4.60998652, .precision: 1, .closest: 4.6, .up: 4.7, .down: 4.6, .floor: 4.6, .ceiling: 4.6 },
60 { .x: 6.28794223, .precision: 3, .closest: 6.288, .up: 6.288, .down: 6.287, .floor: 6.288, .ceiling: 6.287 },
61 { .x: 7.89428221, .precision: 2, .closest: 7.89, .up: 7.90, .down: 7.89, .floor: 7.89, .ceiling: 7.89 }
62 };
63
64}
65
66
67void RoundingTest::testClosest() {
68
69 BOOST_TEST_MESSAGE("Testing closest decimal rounding...");
70
71 using namespace rounding_test;
72
73 for (auto& i : testData) {
74 Integer digits = i.precision;
75 ClosestRounding closest(digits);
76 Real calculated = closest(i.x);
77 Real expected = i.closest;
78 if (!close(x: calculated,y: expected,n: 1))
79 BOOST_ERROR(std::fixed << std::setprecision(8) << "Original number: " << i.x << "\n"
80 << std::setprecision(digits) << "Expected: " << expected
81 << "\n"
82 << "Calculated: " << calculated);
83 }
84}
85
86void RoundingTest::testUp() {
87
88 BOOST_TEST_MESSAGE("Testing upward decimal rounding...");
89
90 using namespace rounding_test;
91
92 for (auto& i : testData) {
93 Integer digits = i.precision;
94 UpRounding up(digits);
95 Real calculated = up(i.x);
96 Real expected = i.up;
97 if (!close(x: calculated,y: expected,n: 1))
98 BOOST_ERROR(std::fixed << std::setprecision(8) << "Original number: " << i.x << "\n"
99 << std::setprecision(digits) << "Expected: " << expected
100 << "\n"
101 << "Calculated: " << calculated);
102 }
103}
104
105void RoundingTest::testDown() {
106
107 BOOST_TEST_MESSAGE("Testing downward decimal rounding...");
108
109 using namespace rounding_test;
110
111 for (auto& i : testData) {
112 Integer digits = i.precision;
113 DownRounding down(digits);
114 Real calculated = down(i.x);
115 Real expected = i.down;
116 if (!close(x: calculated,y: expected,n: 1))
117 BOOST_ERROR(std::fixed << std::setprecision(8) << "Original number: " << i.x << "\n"
118 << std::setprecision(digits) << "Expected: " << expected
119 << "\n"
120 << "Calculated: " << calculated);
121 }
122}
123
124void RoundingTest::testFloor() {
125
126 BOOST_TEST_MESSAGE("Testing floor decimal rounding...");
127
128 using namespace rounding_test;
129
130 for (auto& i : testData) {
131 Integer digits = i.precision;
132 FloorTruncation floor(digits);
133 Real calculated = floor(i.x);
134 Real expected = i.floor;
135 if (!close(x: calculated,y: expected,n: 1))
136 BOOST_ERROR(std::fixed << std::setprecision(8) << "Original number: " << i.x << "\n"
137 << std::setprecision(digits) << "Expected: " << expected
138 << "\n"
139 << "Calculated: " << calculated);
140 }
141}
142
143void RoundingTest::testCeiling() {
144
145 BOOST_TEST_MESSAGE("Testing ceiling decimal rounding...");
146
147 using namespace rounding_test;
148
149 for (auto& i : testData) {
150 Integer digits = i.precision;
151 CeilingTruncation ceiling(digits);
152 Real calculated = ceiling(i.x);
153 Real expected = i.ceiling;
154 if (!close(x: calculated,y: expected,n: 1))
155 BOOST_ERROR(std::fixed << std::setprecision(8) << "Original number: " << i.x << "\n"
156 << std::setprecision(digits) << "Expected: " << expected
157 << "\n"
158 << "Calculated: " << calculated);
159 }
160}
161
162
163test_suite* RoundingTest::suite() {
164 auto* suite = BOOST_TEST_SUITE("Rounding tests");
165 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testClosest));
166 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testUp));
167 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testDown));
168 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testFloor));
169 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testCeiling));
170 return suite;
171}
172
173

source code of quantlib/test-suite/rounding.cpp