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