1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2008 J. Erik Radmall
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 <ql/experimental/commodities/quantity.hpp>
21#include <ql/experimental/commodities/unitofmeasureconversionmanager.hpp>
22#include <ql/math/comparison.hpp>
23#include <ql/errors.hpp>
24
25namespace QuantLib {
26
27 Quantity::ConversionType Quantity::conversionType = Quantity::NoConversion;
28
29 UnitOfMeasure Quantity::baseUnitOfMeasure = UnitOfMeasure();
30
31 namespace {
32
33 void convertTo(Quantity& m, const UnitOfMeasure& target) {
34 if (m.unitOfMeasure() != target) {
35 UnitOfMeasureConversion rate =
36 UnitOfMeasureConversionManager::instance().lookup(
37 commodityType: m.commodityType(), m.unitOfMeasure(), target);
38 m = rate.convert(quantity: m).rounded();
39 }
40 }
41
42 void convertToBase(Quantity& m) {
43 QL_REQUIRE(!Quantity::baseUnitOfMeasure.empty(),
44 "no base unitOfMeasure set");
45 convertTo(m, target: Quantity::baseUnitOfMeasure);
46 }
47
48 }
49
50 Quantity& Quantity::operator+=(const Quantity& m) {
51 if (unitOfMeasure_ == m.unitOfMeasure_) {
52 amount_ += m.amount_;
53 } else if (conversionType == BaseUnitOfMeasureConversion) {
54 convertToBase(m&: *this);
55 Quantity tmp = m;
56 convertToBase(m&: tmp);
57 *this += tmp;
58 } else if (conversionType == AutomatedConversion) {
59 Quantity tmp = m;
60 convertTo(m&: tmp, target: unitOfMeasure_);
61 *this += tmp;
62 } else {
63 QL_FAIL("unitOfMeasure mismatch and no conversion specified");
64 }
65 return *this;
66 }
67
68 Quantity& Quantity::operator-=(const Quantity& m) {
69 if (unitOfMeasure_ == m.unitOfMeasure_) {
70 amount_ -= m.amount_;
71 } else if (conversionType == BaseUnitOfMeasureConversion) {
72 convertToBase(m&: *this);
73 Quantity tmp = m;
74 convertToBase(m&: tmp);
75 *this -= tmp;
76 } else if (conversionType == AutomatedConversion) {
77 Quantity tmp = m;
78 convertTo(m&: tmp, target: unitOfMeasure_);
79 *this -= tmp;
80 } else {
81 QL_FAIL("unitOfMeasure mismatch and no conversion specified");
82 }
83 return *this;
84 }
85
86 Real operator/(const Quantity& m1, const Quantity& m2) {
87 if (m1.unitOfMeasure() == m2.unitOfMeasure()) {
88 return m1.amount()/m2.amount();
89 } else if (Quantity::conversionType
90 == Quantity::BaseUnitOfMeasureConversion) {
91 Quantity tmp1 = m1;
92 convertToBase(m&: tmp1);
93 Quantity tmp2 = m2;
94 convertToBase(m&: tmp2);
95 return tmp1/tmp2;
96 } else if (Quantity::conversionType == Quantity::AutomatedConversion) {
97 Quantity tmp = m2;
98 convertTo(m&: tmp, target: m1.unitOfMeasure());
99 return m1/tmp;
100 } else {
101 QL_FAIL("unitOfMeasure mismatch and no conversion specified");
102 }
103 }
104
105 bool operator==(const Quantity& m1, const Quantity& m2) {
106 if (m1.unitOfMeasure() == m2.unitOfMeasure()) {
107 return m1.amount() == m2.amount();
108 } else if (Quantity::conversionType
109 == Quantity::BaseUnitOfMeasureConversion) {
110 Quantity tmp1 = m1;
111 convertToBase(m&: tmp1);
112 Quantity tmp2 = m2;
113 convertToBase(m&: tmp2);
114 return tmp1 == tmp2;
115 } else if (Quantity::conversionType
116 == Quantity::AutomatedConversion) {
117 Quantity tmp = m2;
118 convertTo(m&: tmp, target: m1.unitOfMeasure());
119 return m1 == tmp;
120 } else {
121 QL_FAIL("unitOfMeasure mismatch and no conversion specified");
122 }
123 }
124
125 bool operator<(const Quantity& m1, const Quantity& m2) {
126 if (m1.unitOfMeasure() == m2.unitOfMeasure()) {
127 return m1.amount() < m2.amount();
128 } else if (Quantity::conversionType
129 == Quantity::BaseUnitOfMeasureConversion) {
130 Quantity tmp1 = m1;
131 convertToBase(m&: tmp1);
132 Quantity tmp2 = m2;
133 convertToBase(m&: tmp2);
134 return tmp1 < tmp2;
135 } else if (Quantity::conversionType == Quantity::AutomatedConversion) {
136 Quantity tmp = m2;
137 convertTo(m&: tmp, target: m1.unitOfMeasure());
138 return m1 < tmp;
139 } else {
140 QL_FAIL("unitOfMeasure mismatch and no conversion specified");
141 }
142 }
143
144 bool operator<=(const Quantity& m1, const Quantity& m2) {
145 if (m1.unitOfMeasure() == m2.unitOfMeasure()) {
146 return m1.amount() <= m2.amount();
147 } else if (Quantity::conversionType
148 == Quantity::BaseUnitOfMeasureConversion) {
149 Quantity tmp1 = m1;
150 convertToBase(m&: tmp1);
151 Quantity tmp2 = m2;
152 convertToBase(m&: tmp2);
153 return tmp1 <= tmp2;
154 } else if (Quantity::conversionType == Quantity::AutomatedConversion) {
155 Quantity tmp = m2;
156 convertTo(m&: tmp, target: m1.unitOfMeasure());
157 return m1 <= tmp;
158 } else {
159 QL_FAIL("unitOfMeasure mismatch and no conversion specified");
160 }
161 }
162
163 bool close(const Quantity& m1, const Quantity& m2, Size n) {
164 if (m1.unitOfMeasure() == m2.unitOfMeasure()) {
165 return close(x: m1.amount(),y: m2.amount(),n);
166 } else if (Quantity::conversionType
167 == Quantity::BaseUnitOfMeasureConversion) {
168 Quantity tmp1 = m1;
169 convertToBase(m&: tmp1);
170 Quantity tmp2 = m2;
171 convertToBase(m&: tmp2);
172 return close(m1: tmp1,m2: tmp2,n);
173 } else if (Quantity::conversionType == Quantity::AutomatedConversion) {
174 Quantity tmp = m2;
175 convertTo(m&: tmp, target: m1.unitOfMeasure());
176 return close(m1,m2: tmp,n);
177 } else {
178 QL_FAIL("unitOfMeasure mismatch and no conversion specified");
179 }
180 }
181
182 bool close_enough(const Quantity& m1, const Quantity& m2, Size n) {
183 if (m1.unitOfMeasure() == m2.unitOfMeasure()) {
184 return close_enough(x: m1.amount(),y: m2.amount(),n);
185 } else if (Quantity::conversionType
186 == Quantity::BaseUnitOfMeasureConversion) {
187 Quantity tmp1 = m1;
188 convertToBase(m&: tmp1);
189 Quantity tmp2 = m2;
190 convertToBase(m&: tmp2);
191 return close_enough(m1: tmp1,m2: tmp2,n);
192 } else if (Quantity::conversionType == Quantity::AutomatedConversion) {
193 Quantity tmp = m2;
194 convertTo(m&: tmp, target: m1.unitOfMeasure());
195 return close_enough(m1,m2: tmp,n);
196 } else {
197 QL_FAIL("unitOfMeasure mismatch and no conversion specified");
198 }
199 }
200
201
202 std::ostream& operator<<(std::ostream& out, const Quantity& quantity) {
203 return out << quantity.commodityType_.code() << " "
204 << quantity.amount_ << " " << quantity.unitOfMeasure_.code();
205 }
206
207}
208
209

source code of quantlib/ql/experimental/commodities/quantity.cpp