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
25 using namespace QuantLib;
26 using namespace boost::unit_test_framework;
27
28 namespace 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 { 0.86313513, 5, 0.86314, 0.86314, 0.86313, 0.86314, 0.86313 },
42 { 0.86313, 5, 0.86313, 0.86313, 0.86313, 0.86313, 0.86313 },
43 { -7.64555346, 1, -7.6, -7.7, -7.6, -7.6, -7.6 },
44 { 0.13961605, 2, 0.14, 0.14, 0.13, 0.14, 0.13 },
45 { 0.14344179, 4, 0.1434, 0.1435, 0.1434, 0.1434, 0.1434 },
46 { -4.74315016, 2, -4.74, -4.75, -4.74, -4.74, -4.74 },
47 { -7.82772074, 5, -7.82772, -7.82773, -7.82772, -7.82772, -7.82772 },
48 { 2.74137947, 3, 2.741, 2.742, 2.741, 2.741, 2.741 },
49 { 2.13056714, 1, 2.1, 2.2, 2.1, 2.1, 2.1 },
50 { -1.06228670, 1, -1.1, -1.1, -1.0, -1.0, -1.1 },
51 { 8.29234094, 4, 8.2923, 8.2924, 8.2923, 8.2923, 8.2923 },
52 { 7.90185598, 2, 7.90, 7.91, 7.90, 7.90, 7.90 },
53 { -0.26738058, 1, -0.3, -0.3, -0.2, -0.2, -0.3 },
54 { 1.78128713, 1, 1.8, 1.8, 1.7, 1.8, 1.7 },
55 { 4.23537260, 1, 4.2, 4.3, 4.2, 4.2, 4.2 },
56 { 3.64369953, 4, 3.6437, 3.6437, 3.6436, 3.6437, 3.6436 },
57 { 6.34542470, 2, 6.35, 6.35, 6.34, 6.35, 6.34 },
58 { -0.84754962, 4, -0.8475, -0.8476, -0.8475, -0.8475, -0.8475 },
59 { 4.60998652, 1, 4.6, 4.7, 4.6, 4.6, 4.6 },
60 { 6.28794223, 3, 6.288, 6.288, 6.287, 6.288, 6.287 },
61 { 7.89428221, 2, 7.89, 7.90, 7.89, 7.89, 7.89 }
62 };
63
64 }
65
66
testClosest()67 void RoundingTest::testClosest() {
68
69 BOOST_TEST_MESSAGE("Testing closest decimal rounding...");
70
71 using namespace rounding_test;
72
73 for (Size i=0; i<LENGTH(testData); i++) {
74 Integer digits = testData[i].precision;
75 ClosestRounding closest(digits);
76 Real calculated = closest(testData[i].x);
77 Real expected = testData[i].closest;
78 if (!close(calculated,expected,1))
79 BOOST_ERROR(std::fixed << std::setprecision(8)
80 << "Original number: " << testData[i].x << "\n"
81 << std::setprecision(digits)
82 << "Expected: " << expected << "\n"
83 << "Calculated: " << calculated);
84 }
85 }
86
testUp()87 void RoundingTest::testUp() {
88
89 BOOST_TEST_MESSAGE("Testing upward decimal rounding...");
90
91 using namespace rounding_test;
92
93 for (Size i=0; i<LENGTH(testData); i++) {
94 Integer digits = testData[i].precision;
95 UpRounding up(digits);
96 Real calculated = up(testData[i].x);
97 Real expected = testData[i].up;
98 if (!close(calculated,expected,1))
99 BOOST_ERROR(std::fixed << std::setprecision(8)
100 << "Original number: " << testData[i].x << "\n"
101 << std::setprecision(digits)
102 << "Expected: " << expected << "\n"
103 << "Calculated: " << calculated);
104 }
105 }
106
testDown()107 void RoundingTest::testDown() {
108
109 BOOST_TEST_MESSAGE("Testing downward decimal rounding...");
110
111 using namespace rounding_test;
112
113 for (Size i=0; i<LENGTH(testData); i++) {
114 Integer digits = testData[i].precision;
115 DownRounding down(digits);
116 Real calculated = down(testData[i].x);
117 Real expected = testData[i].down;
118 if (!close(calculated,expected,1))
119 BOOST_ERROR(std::fixed << std::setprecision(8)
120 << "Original number: " << testData[i].x << "\n"
121 << std::setprecision(digits)
122 << "Expected: " << expected << "\n"
123 << "Calculated: " << calculated);
124 }
125 }
126
testFloor()127 void RoundingTest::testFloor() {
128
129 BOOST_TEST_MESSAGE("Testing floor decimal rounding...");
130
131 using namespace rounding_test;
132
133 for (Size i=0; i<LENGTH(testData); i++) {
134 Integer digits = testData[i].precision;
135 FloorTruncation floor(digits);
136 Real calculated = floor(testData[i].x);
137 Real expected = testData[i].floor;
138 if (!close(calculated,expected,1))
139 BOOST_ERROR(std::fixed << std::setprecision(8)
140 << "Original number: " << testData[i].x << "\n"
141 << std::setprecision(digits)
142 << "Expected: " << expected << "\n"
143 << "Calculated: " << calculated);
144 }
145 }
146
testCeiling()147 void RoundingTest::testCeiling() {
148
149 BOOST_TEST_MESSAGE("Testing ceiling decimal rounding...");
150
151 using namespace rounding_test;
152
153 for (Size i=0; i<LENGTH(testData); i++) {
154 Integer digits = testData[i].precision;
155 CeilingTruncation ceiling(digits);
156 Real calculated = ceiling(testData[i].x);
157 Real expected = testData[i].ceiling;
158 if (!close(calculated,expected,1))
159 BOOST_ERROR(std::fixed << std::setprecision(8)
160 << "Original number: " << testData[i].x << "\n"
161 << std::setprecision(digits)
162 << "Expected: " << expected << "\n"
163 << "Calculated: " << calculated);
164 }
165 }
166
167
suite()168 test_suite* RoundingTest::suite() {
169 test_suite* suite = BOOST_TEST_SUITE("Rounding tests");
170 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testClosest));
171 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testUp));
172 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testDown));
173 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testFloor));
174 suite->add(QUANTLIB_TEST_CASE(&RoundingTest::testCeiling));
175 return suite;
176 }
177
178