Coverage Report

Created: 2026-02-03 07:02

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