├── .github
└── workflows
│ └── action.yml
├── CMakeLists.txt
├── README.md
├── build
└── cb_win
│ └── decimal
│ ├── decimal.cbp
│ └── readme.txt
├── doc
└── license.txt
├── include
└── decimal.h
└── tests
├── decimalTest.cpp
├── decimalTestAbout.cpp
├── decimalTestArithmetic.cpp
├── decimalTestDiv.cpp
├── decimalTestEdgeCases.cpp
├── decimalTestModulo.cpp
├── decimalTestMult.cpp
├── decimalTestMultDiv.cpp
├── decimalTestRoundOth.cpp
├── decimalTestRounding.cpp
├── decimalTestString.cpp
├── decimalTestTypeLevel.cpp
├── decimalTestUtils.cpp
├── decimalTestUtils.h
├── decimalTestWithExponent.cpp
└── runner.cpp
/.github/workflows/action.yml:
--------------------------------------------------------------------------------
1 | name: decimal_for_cpp
2 |
3 | on: [push]
4 |
5 | jobs:
6 | linux:
7 | runs-on: ${{ matrix.os }}
8 |
9 | strategy:
10 | matrix:
11 | os: [ubuntu-latest, ubuntu-20.04]
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 |
16 | - name: Install dependencies
17 | run: |
18 | sudo apt update
19 | sudo apt install -y libboost-all-dev
20 |
21 | - name: Build c++11
22 | run: |
23 | cd ${{ github.workspace }}
24 | rm -rf b
25 | mkdir -p b
26 | cd b
27 | cmake -DCMAKE_CXX_STANDARD=11 ../
28 | make VERBOSE=1 && ./test_runner
29 |
30 | - name: Build c++14
31 | run: |
32 | cd ${{ github.workspace }}
33 | rm -rf b
34 | mkdir -p b
35 | cd b
36 | cmake -DCMAKE_CXX_STANDARD=14 ../
37 | make VERBOSE=1 && ./test_runner
38 |
39 | - name: Build c++17
40 | run: |
41 | cd ${{ github.workspace }}
42 | rm -rf b
43 | mkdir -p b
44 | cd b
45 | cmake -DCMAKE_CXX_STANDARD=17 ../
46 | make VERBOSE=1 && ./test_runner
47 |
48 | macos:
49 | runs-on: ${{ matrix.os }}
50 |
51 | strategy:
52 | matrix:
53 | os: [macos-latest]
54 |
55 | steps:
56 | - uses: actions/checkout@v2
57 |
58 | - name: Install dependencies
59 | run: |
60 | brew install boost
61 |
62 | - name: Update dependencies
63 | run: |
64 | brew upgrade boost cmake
65 |
66 | - name: Build c++11
67 | run: |
68 | cd ${{ github.workspace }}
69 | rm -rf b
70 | mkdir -p b
71 | cd b
72 | cmake -DCMAKE_CXX_STANDARD=11 ../
73 | make VERBOSE=1 && ./test_runner
74 |
75 | - name: Build c++14
76 | run: |
77 | cd ${{ github.workspace }}
78 | rm -rf b
79 | mkdir -p b
80 | cd b
81 | cmake -DCMAKE_CXX_STANDARD=14 ../
82 | make VERBOSE=1 && ./test_runner
83 |
84 | - name: Build c++17
85 | run: |
86 | cd ${{ github.workspace }}
87 | rm -rf b
88 | mkdir -p b
89 | cd b
90 | cmake -DCMAKE_CXX_STANDARD=17 ../
91 | make VERBOSE=1 && ./test_runner
92 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.12)
2 | project(decimal_for_cpp)
3 | include(CTest)
4 |
5 | set(Boost_USE_STATIC_LIBS OFF)
6 | set(Boost_USE_MULTITHREADED ON)
7 | set(Boost_USE_STATIC_RUNTIME OFF)
8 |
9 | set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard version to use (default is 11)")
10 | #set(CMAKE_CXX_STANDARD 98)
11 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
12 |
13 | if(BUILD_TESTING)
14 | find_package(Boost COMPONENTS unit_test_framework REQUIRED)
15 |
16 | if(Boost_FOUND)
17 | include_directories(${Boost_INCLUDE_DIRS} include)
18 | add_executable(test_runner include/decimal.h
19 | tests/runner.cpp
20 | tests/decimalTest.cpp
21 | tests/decimalTestAbout.cpp
22 | tests/decimalTestArithmetic.cpp
23 | tests/decimalTestDiv.cpp
24 | tests/decimalTestEdgeCases.cpp
25 | tests/decimalTestModulo.cpp
26 | tests/decimalTestMult.cpp
27 | tests/decimalTestMultDiv.cpp
28 | tests/decimalTestRounding.cpp
29 | tests/decimalTestRoundOth.cpp
30 | tests/decimalTestString.cpp
31 | tests/decimalTestTypeLevel.cpp
32 | tests/decimalTestUtils.cpp
33 | tests/decimalTestWithExponent.cpp
34 | tests/decimalTestUtils.h)
35 | target_include_directories(test_runner PRIVATE ${BOOST_INCLUDE_DIRS})
36 | endif()
37 |
38 | enable_testing()
39 | add_test(test_runner test_runner)
40 | endif()
41 |
42 | install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # About
2 | Decimal data type support, for COBOL-like fixed-point operations on currency/money values.
3 |
4 | 
5 |
6 | Author: Piotr Likus
7 |
8 | Created: 03/01/2011
9 |
10 | Modified: 18/09/2024
11 |
12 | Licence: BSD
13 |
14 | Version: 1.21
15 |
16 |
17 | This data type is designed to perform calculation with on-fly roundings
18 | & to support correct compare function (floating-point compare is
19 | unreliable).
20 |
21 | Values are stored internally using 64-bit integer, so maximum number of
22 | digits is 18.
23 |
24 | Precision is user-defined, so you can use this data type for currency
25 | rates.
26 |
27 | To store decimal in file you can use "unbiased" functions or use stream i/o.
28 |
29 | # Examples
30 |
31 | Example usage:
32 | ```c++
33 | #include "decimal.h"
34 |
35 | using namespace dec;
36 | using namespace std;
37 |
38 | // the following declares currency variable with 2 decimal points
39 | // initialized with integer value (can be also floating-point)
40 | decimal<2> value(143125);
41 |
42 | // displays: Value #1 is: 143125.00
43 | cout << "Value #1 is: " << value << endl;
44 |
45 | // declare precise value with digits after decimal point
46 | decimal<2> b("0.11");
47 |
48 | // perform calculations as with any other numeric type
49 | value += b;
50 |
51 | // displays: Value #2 is: 143125.11
52 | cout << "Value #2 is: " << value << endl;
53 |
54 | // automatic rounding performed here
55 | value /= 1000;
56 |
57 | // displays: Value #3 is: 143.13
58 | cout << "Value #3 is: " << value << endl;
59 |
60 | // integer multiplication and division can be used directly in expression
61 | // when integer is on right side
62 | // displays: Value: 143.13 * 2 is: 286.26
63 | cout << "Value: " << value << " * 2 is: " << (value * 2) << endl;
64 |
65 | // to use integer on left side you need to cast it
66 | // displays: Value: 2 * 143.13 is: 286.26
67 | cout << "Value: 2 * " << value << " is: " << (decimal_cast<2>(2) * value) << endl;
68 |
69 | // to use non-integer constants in expressions you need to use decimal_cast
70 | value = value * decimal_cast<2>("3.33") / decimal_cast<2>(333.0);
71 |
72 | // displays: Value #4 is: 1.43
73 | cout << "Value #4 is: " << value << endl;
74 |
75 | // to mix decimals with different precision use decimal_cast
76 | // it will round result automatically
77 | decimal<6> exchangeRate(12.1234);
78 | value = decimal_cast<2>(decimal_cast<6>(value) * exchangeRate);
79 |
80 | // displays: Value #5 is: 17.34
81 | cout << "Value #5 is: " << value << endl;
82 |
83 | // supports optional strong typing, e.g.
84 | // depending on configuration mixing precision can be forbidden
85 | // or handled automatically
86 | decimal<2> d2("12.03");
87 | decimal<4> d4("123.0103");
88 |
89 | // compiles always
90 | d2 += d2;
91 | d2 += decimal_cast<2>(d4);
92 | d4 += decimal_cast<4>(d2);
93 |
94 | #if DEC_TYPE_LEVEL >= 2
95 | // potential precision loss
96 | // this will fail to compile if you define DEC_TYPE_LEVEL = 0 or 1
97 | d2 += d4;
98 | #endif
99 |
100 | #if DEC_TYPE_LEVEL >= 1
101 | // (possibly unintentional) mixed precision without type casting
102 | // this will fail to compile if you define DEC_TYPE_LEVEL = 0
103 | d4 += d2;
104 | #endif
105 |
106 | // for default setup displays: mixed d2 = 417.15
107 | cout << "mixed d2 = " << d2 << endl;
108 | // for default setup displays: mixed d4 = 687.2303
109 | cout << "mixed d4 = " << d4 << endl;
110 |
111 | // supports decimal and thousand separator localization
112 | dec::decimal_format format(',', '.');
113 |
114 | std::string srcText = "315499999999999.98";
115 | std::string formatted = "315.499.999.999.999,98";
116 | dec::decimal<2> srcDecimal(srcText);
117 |
118 | BOOST_CHECK_EQUAL(dec::toString(srcDecimal, format), formatted);
119 |
120 | ```
121 |
122 | # Supported rounding modes:
123 |
124 | * def_round_policy: default rounding (arithmetic)
125 | * null_round_policy: round towards zero = truncate
126 | * half_down_round_policy: round half towards negative infinity
127 | * half_up_round_policy: round half towards positive infinity
128 | * half_even_round_policy: bankers' rounding, convergent rounding, statistician's rounding, Dutch rounding, Gaussian rounding
129 | * ceiling_round_policy: round towards positive infinity
130 | * floor_round_policy: round towards negative infinity
131 | * round_down_round_policy: round towards zero = truncate
132 | * round_up_round_policy: round away from zero
133 |
134 | In order to use one of these rounding modes you need to declare your decimal variable like this:
135 |
136 | dec::decimal<2, half_even_round_policy> a;
137 |
138 | and it will perform required rounding automatically - for example during assignment or arithmetic operations.
139 |
140 | # Testing
141 |
142 | In order to test the library:
143 |
144 | cd ~/tmp
145 | git clone https://github.com/vpiotr/decimal_for_cpp.git
146 | cd decimal_for_cpp
147 | mkdir _build
148 | cd _build
149 |
150 | # to create makefile with test support
151 | cmake ..
152 | # or
153 | cmake -DBUILD_TESTING=ON ..
154 |
155 | # to create makefile without test support (and to avoid Boost unit testing)
156 | cmake -DBUILD_TESTING=OFF ..
157 |
158 | # to build or install library (only required for testing)
159 | make all
160 |
161 | # to execute all test runners
162 | make test
163 |
164 | # to execute specific runner
165 | ./test_runner
166 |
167 | # to list all test cases during runner execution
168 | ./test_runner --log_level=test_suite
169 |
170 | # to execute tests via ctest
171 | ctest -v
172 |
173 | # Other information
174 | For more examples please see \test directory.
175 |
176 | Directory structure:
177 | ```
178 | \doc - documentation (licence etc.)
179 | \include - headers
180 | \test - unit tests, Boost-based
181 | ```
182 |
183 | Code documentation can be generated using Doxygen:
184 | http://www.doxygen.org/
185 |
186 | Tested compilers:
187 |
188 | - VS2019 Community (MSVC++ 14.2)
189 | - gcc 11.4.0
190 |
191 | Uses C++11 by default, define DEC_NO_CPP11 symbol if your compiler does not support this standard.
192 | To use custom namespace, define DEC_NAMESPACE symbol which should contain your target namespace for decimal type.
193 | For full list of configuration options see "Config section" in decimal.h file.
194 |
195 | For list of project contributors, currently open issues or latest version see project site:
196 | https://github.com/vpiotr/decimal_for_cpp
197 |
198 |
199 |
--------------------------------------------------------------------------------
/build/cb_win/decimal/decimal.cbp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/build/cb_win/decimal/readme.txt:
--------------------------------------------------------------------------------
1 | Project files for unit tests for Code::Blocks + MinGW compiler on Windows.
--------------------------------------------------------------------------------
/doc/license.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010-2014, Piotr Likus
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice,
8 | this list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of Piotr Likus nor the names of his
15 | contributors may be used to endorse or promote products derived from this
16 | software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/include/decimal.h:
--------------------------------------------------------------------------------
1 | /////////////////////////////////////////////////////////////////////////////
2 | // Name: decimal.h
3 | // Purpose: Decimal data type support, for COBOL-like fixed-point
4 | // operations on currency values.
5 | // Author: Piotr Likus
6 | // Created: 03/01/2011
7 | // Last change: 18/04/2021
8 | // Version: 1.18
9 | // Licence: BSD
10 | /////////////////////////////////////////////////////////////////////////////
11 |
12 | #ifndef _DECIMAL_H__
13 | #define _DECIMAL_H__
14 |
15 | // ----------------------------------------------------------------------------
16 | // Description
17 | // ----------------------------------------------------------------------------
18 | /// \file decimal.h
19 | ///
20 | /// Decimal value type. Use for capital calculations.
21 | /// Note: maximum handled value is: +9,223,372,036,854,775,807 (divided by prec)
22 | ///
23 | /// Sample usage:
24 | /// using namespace dec;
25 | /// decimal<2> value(143125);
26 | /// value = value / decimal_cast<2>(333);
27 | /// cout << "Result is: " << value << endl;
28 |
29 | // ----------------------------------------------------------------------------
30 | // Config section
31 | // ----------------------------------------------------------------------------
32 | // - define DEC_EXTERNAL_INT64 if you do not want internal definition of "int64" data type
33 | // in this case define "DEC_INT64" somewhere
34 | // - define DEC_EXTERNAL_ROUND if you do not want internal "round()" function
35 | // - define DEC_CROSS_DOUBLE if you want to use double (instead of xdouble) for cross-conversions
36 | // - define DEC_EXTERNAL_LIMITS to define by yourself DEC_MAX_INT32
37 | // - define DEC_NO_CPP11 if your compiler does not support C++11
38 | // - define DEC_ALLOW_SPACESHIP_OPER as 1 if your compiler supports spaceship operator
39 | // - define DEC_TRIVIAL_DEFAULT_CONSTRUCTIBLE as 1 if you want to make default constructor trivial
40 | // use with caution because default constructor will not initialize the object
41 | // - define DEC_TYPE_LEVEL as 0 for strong typing (same precision required for both arguments),
42 | // as 1 for allowing to mix lower or equal precision types
43 | // as 2 for automatic rounding when different precision is mixed
44 |
45 | #include
46 | #include
47 | #include
48 | #include
49 | #include
50 |
51 | #ifndef DEC_TYPE_LEVEL
52 | #define DEC_TYPE_LEVEL 2
53 | #endif
54 |
55 | // --> include headers for limits and int64_t
56 |
57 | #ifndef DEC_NO_CPP11
58 | #include
59 | #include
60 |
61 | #else
62 |
63 | #ifndef __STDC_LIMIT_MACROS
64 | #define __STDC_LIMIT_MACROS
65 | #endif
66 |
67 | #if defined(__GXX_EXPERIMENTAL_CXX0X) || (__cplusplus >= 201103L)
68 | #include
69 | #else
70 | #include
71 | #endif // defined
72 |
73 | #endif // DEC_NO_CPP11
74 |
75 | #ifdef DEC_NO_CPP11
76 | #define DEC_OVERRIDE
77 | #else
78 | #define DEC_OVERRIDE override
79 | #endif
80 |
81 | #ifdef DEC_NO_CPP11
82 | #define DEC_CONSTEXPR const
83 | #else
84 | #define DEC_CONSTEXPR constexpr
85 | #endif
86 |
87 | #ifdef DEC_NO_CPP11
88 | #define DEC_MOVE(x) (x)
89 | #else
90 | #include
91 | #define DEC_MOVE(x) std::move(x)
92 | #endif
93 |
94 | #if (DEC_ALLOW_SPACESHIP_OPER == 1) && (__cplusplus > 201703L)
95 | #define DEC_USE_SPACESHIP_OPER 1
96 | #else
97 | #undef DEC_USE_SPACESHIP_OPER
98 | #define DEC_USE_SPACESHIP_OPER 0
99 | #endif
100 |
101 | // <--
102 |
103 | // --> define DEC_MAX_INTxx, DEC_MIN_INTxx if required
104 |
105 | #ifndef DEC_NAMESPACE
106 | #define DEC_NAMESPACE dec
107 | #endif // DEC_NAMESPACE
108 |
109 | #ifndef DEC_EXTERNAL_LIMITS
110 | #ifndef DEC_NO_CPP11
111 | //#define DEC_MAX_INT32 ((std::numeric_limits::max)())
112 | #define DEC_MAX_INT64 ((std::numeric_limits::max)())
113 | #define DEC_MIN_INT64 ((std::numeric_limits::min)())
114 | #else
115 | //#define DEC_MAX_INT32 INT32_MAX
116 | #define DEC_MAX_INT64 INT64_MAX
117 | #define DEC_MIN_INT64 INT64_MIN
118 | #endif // DEC_NO_CPP11
119 | #endif // DEC_EXTERNAL_LIMITS
120 |
121 | // <--
122 |
123 | namespace DEC_NAMESPACE {
124 |
125 | #ifdef DEC_NO_CPP11
126 | template
127 | struct enable_if_type {
128 | typedef T type;
129 | };
130 |
131 | template
132 | struct enable_if_type {
133 | };
134 |
135 | template
136 | struct enable_if: public enable_if_type {
137 | };
138 |
139 | #define ENABLE_IF dec::enable_if
140 | #else
141 | #define ENABLE_IF std::enable_if
142 | #endif
143 |
144 |
145 | // ----------------------------------------------------------------------------
146 | // Simple type definitions
147 | // ----------------------------------------------------------------------------
148 |
149 | // --> define DEC_INT64 if required
150 | #ifndef DEC_EXTERNAL_INT64
151 | #ifndef DEC_NO_CPP11
152 | typedef int64_t DEC_INT64;
153 | #else
154 | #if defined(_MSC_VER) || defined(__BORLANDC__)
155 | typedef signed __int64 DEC_INT64;
156 | #else
157 | typedef signed long long DEC_INT64;
158 | #endif
159 | #endif
160 | #endif // DEC_EXTERNAL_INT64
161 | // <--
162 |
163 | // --> define DEC_HANDLE_LONG if const long meets ambiguous conversion.
164 | #ifndef DEC_HANDLE_LONG
165 | #if defined(__APPLE__) || defined(__MACH__)
166 | #define DEC_HANDLE_LONG
167 | #endif
168 | #endif // DEC_HANDLE_LONG
169 | // <--
170 |
171 | #ifdef DEC_NO_CPP11
172 | #define static_assert(a,b)
173 | #endif
174 |
175 | typedef DEC_INT64 int64;
176 | // type for storing currency value internally
177 | typedef int64 dec_storage_t;
178 | typedef unsigned int uint;
179 | // xdouble is an "extended double" - can be long double, __float128, _Quad - as you wish
180 | typedef long double xdouble;
181 |
182 | #ifdef DEC_CROSS_DOUBLE
183 | typedef double cross_float;
184 | #else
185 | typedef xdouble cross_float;
186 | #endif
187 |
188 | // ----------------------------------------------------------------------------
189 | // Forward class definitions
190 | // ----------------------------------------------------------------------------
191 | class basic_decimal_format;
192 |
193 | // ----------------------------------------------------------------------------
194 | // Constants
195 | // ----------------------------------------------------------------------------
196 | enum {
197 | max_decimal_points = 18
198 | };
199 |
200 | // ----------------------------------------------------------------------------
201 | // Class definitions
202 | // ----------------------------------------------------------------------------
203 | template struct DecimalFactor {
204 | static DEC_CONSTEXPR int64 value = 10 * DecimalFactor::value;
205 | };
206 |
207 | template<> struct DecimalFactor<0> {
208 | static DEC_CONSTEXPR int64 value = 1;
209 | };
210 |
211 | template<> struct DecimalFactor<1> {
212 | static DEC_CONSTEXPR int64 value = 10;
213 | };
214 |
215 | template struct DecimalFactorDiff_impl {
216 | static DEC_CONSTEXPR int64 value = DecimalFactor::value;
217 | };
218 |
219 | template struct DecimalFactorDiff_impl {
220 | static DEC_CONSTEXPR int64 value = INT64_MIN;
221 | };
222 |
223 | template struct DecimalFactorDiff {
224 | static DEC_CONSTEXPR int64 value = DecimalFactorDiff_impl= 0>::value;
225 | };
226 |
227 | #ifndef DEC_EXTERNAL_ROUND
228 |
229 | // round floating point value and convert to int64
230 | template
231 | inline int64 round(T value) {
232 | T val1;
233 |
234 | if (value < 0.0) {
235 | val1 = value - 0.5;
236 | } else {
237 | val1 = value + 0.5;
238 | }
239 | int64 intPart = static_cast(val1);
240 |
241 | return intPart;
242 | }
243 |
244 | // calculate output = round(a / b), where output, a, b are int64
245 | inline bool div_rounded(int64 &output, int64 a, int64 b) {
246 | int64 divisorCorr = std::abs(b) / 2;
247 | if (a >= 0) {
248 | if (DEC_MAX_INT64 - a >= divisorCorr) {
249 | output = (a + divisorCorr) / b;
250 | return true;
251 | } else {
252 | const int64 i = a / b;
253 | const int64 r = a - i * b;
254 | if (r < divisorCorr) {
255 | output = i;
256 | return true;
257 | }
258 | }
259 | } else {
260 | if (-(DEC_MIN_INT64 - a) >= divisorCorr) {
261 | output = (a - divisorCorr) / b;
262 | return true;
263 | } else {
264 | const int64 i = a / b;
265 | const int64 r = a - i * b;
266 | if (r < divisorCorr) {
267 | output = i;
268 | return true;
269 | }
270 | }
271 | }
272 |
273 | output = 0;
274 | return false;
275 | }
276 |
277 | #endif // DEC_EXTERNAL_ROUND
278 |
279 | template
280 | class dec_utils {
281 | public:
282 | // result = (value1 * value2) / divisor
283 | inline static int64 multDiv(const int64 value1, const int64 value2,
284 | int64 divisor) {
285 |
286 | if (value1 == 0 || value2 == 0) {
287 | return 0;
288 | }
289 |
290 | if (divisor == 1) {
291 | return value1 * value2;
292 | }
293 |
294 | if (value1 == 1) {
295 | int64 result;
296 | if (RoundPolicy::div_rounded(result, value2, divisor)) {
297 | return result;
298 | }
299 | }
300 |
301 | if (value2 == 1) {
302 | int64 result;
303 | if (RoundPolicy::div_rounded(result, value1, divisor)) {
304 | return result;
305 | }
306 | }
307 |
308 | // we don't check for division by zero, the caller should - the next line will throw.
309 | const int64 value1int = value1 / divisor;
310 | int64 value1dec = value1 % divisor;
311 | const int64 value2int = value2 / divisor;
312 | int64 value2dec = value2 % divisor;
313 |
314 | int64 result = value1 * value2int + value1int * value2dec;
315 |
316 | if (value1dec == 0 || value2dec == 0) {
317 | return result;
318 | }
319 |
320 | if (!isMultOverflow(value1dec, value2dec)) { // no overflow
321 | int64 resDecPart = value1dec * value2dec;
322 | if (!RoundPolicy::div_rounded(resDecPart, resDecPart, divisor))
323 | resDecPart = 0;
324 | result += resDecPart;
325 | return result;
326 | }
327 |
328 | // minimize value1 & divisor
329 | {
330 | int64 c = gcd(value1dec, divisor);
331 | if (c != 1) {
332 | value1dec /= c;
333 | divisor /= c;
334 | }
335 |
336 | // minimize value2 & divisor
337 | c = gcd(value2dec, divisor);
338 | if (c != 1) {
339 | value2dec /= c;
340 | divisor /= c;
341 | }
342 | }
343 |
344 | if (!isMultOverflow(value1dec, value2dec)) { // no overflow
345 | int64 resDecPart = value1dec * value2dec;
346 | if (RoundPolicy::div_rounded(resDecPart, resDecPart, divisor)) {
347 | result += resDecPart;
348 | return result;
349 | }
350 | }
351 |
352 | // overflow can occur - use less precise version
353 | result += RoundPolicy::round(
354 | static_cast(value1dec)
355 | * static_cast(value2dec)
356 | / static_cast(divisor));
357 | return result;
358 | }
359 |
360 | static bool isMultOverflow(const int64 value1, const int64 value2) {
361 | if (value1 == 0 || value2 == 0) {
362 | return false;
363 | }
364 |
365 | if ((value1 < 0) != (value2 < 0)) { // different sign
366 | if (value1 == DEC_MIN_INT64) {
367 | return value2 > 1;
368 | } else if (value2 == DEC_MIN_INT64) {
369 | return value1 > 1;
370 | }
371 | if (value1 < 0) {
372 | return isMultOverflow(-value1, value2);
373 | }
374 | if (value2 < 0) {
375 | return isMultOverflow(value1, -value2);
376 | }
377 | } else if (value1 < 0 && value2 < 0) {
378 | if (value1 == DEC_MIN_INT64) {
379 | return value2 < -1;
380 | } else if (value2 == DEC_MIN_INT64) {
381 | return value1 < -1;
382 | }
383 | return isMultOverflow(-value1, -value2);
384 | }
385 |
386 | return (value1 > DEC_MAX_INT64 / value2);
387 | }
388 |
389 | static int64 pow10(int n) {
390 | static const int64 decimalFactorTable[] = { 1, 10, 100, 1000, 10000,
391 | 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000,
392 | 100000000000, 1000000000000, 10000000000000, 100000000000000,
393 | 1000000000000000, 10000000000000000, 100000000000000000,
394 | 1000000000000000000 };
395 |
396 | if (n >= 0 && n <= max_decimal_points) {
397 | return decimalFactorTable[n];
398 | } else {
399 | return 0;
400 | }
401 | }
402 |
403 | template
404 | static int64 trunc(T value) {
405 | return static_cast(value);
406 | }
407 |
408 | private:
409 | // calculate greatest common divisor
410 | static int64 gcd(int64 a, int64 b) {
411 | int64 c;
412 | while (a != 0) {
413 | c = a;
414 | a = b % a;
415 | b = c;
416 | }
417 | return b;
418 | }
419 |
420 | };
421 |
422 | // no-rounding policy (decimal places stripped)
423 | class null_round_policy {
424 | public:
425 | template
426 | static int64 round(T value) {
427 | return static_cast(value);
428 | }
429 |
430 | static bool div_rounded(int64 &output, int64 a, int64 b) {
431 | output = a / b;
432 | return true;
433 | }
434 | };
435 |
436 | // default rounding policy - arithmetic, to nearest integer
437 | class def_round_policy {
438 | public:
439 | template
440 | static int64 round(T value) {
441 | return DEC_NAMESPACE::round(value);
442 | }
443 |
444 | static bool div_rounded(int64 &output, int64 a, int64 b) {
445 | return DEC_NAMESPACE::div_rounded(output, a, b);
446 | }
447 | };
448 |
449 | class half_down_round_policy {
450 | public:
451 | template
452 | static int64 round(T value) {
453 | T val1;
454 | T decimals;
455 |
456 | if (value >= 0.0) {
457 | decimals = value - floor(value);
458 | if (decimals > 0.5) {
459 | val1 = ceil(value);
460 | } else {
461 | val1 = value;
462 | }
463 | } else {
464 | decimals = std::abs(value + floor(std::abs(value)));
465 | if (decimals < 0.5) {
466 | val1 = ceil(value);
467 | } else {
468 | val1 = value;
469 | }
470 | }
471 |
472 | return static_cast(floor(val1));
473 | }
474 |
475 | static bool div_rounded(int64 &output, int64 a, int64 b) {
476 | int64 divisorCorr = std::abs(b) / 2;
477 | int64 remainder = std::abs(a) % std::abs(b);
478 |
479 | if (a >= 0) {
480 | if (DEC_MAX_INT64 - a >= divisorCorr) {
481 | if (remainder > divisorCorr) {
482 | output = (a + divisorCorr) / b;
483 | } else {
484 | output = a / b;
485 | }
486 | return true;
487 | }
488 | } else {
489 | if (-(DEC_MIN_INT64 - a) >= divisorCorr) {
490 | output = (a - divisorCorr) / b;
491 | return true;
492 | }
493 | }
494 |
495 | output = 0;
496 | return false;
497 | }
498 | };
499 |
500 | class half_up_round_policy {
501 | public:
502 | template
503 | static int64 round(T value) {
504 | T val1;
505 | T decimals;
506 |
507 | if (value >= 0.0) {
508 | decimals = value - floor(value);
509 | if (decimals >= 0.5) {
510 | val1 = ceil(value);
511 | } else {
512 | val1 = value;
513 | }
514 | } else {
515 | decimals = std::abs(value + floor(std::abs(value)));
516 | if (decimals <= 0.5) {
517 | val1 = ceil(value);
518 | } else {
519 | val1 = value;
520 | }
521 | }
522 |
523 | return static_cast(floor(val1));
524 | }
525 |
526 | static bool div_rounded(int64 &output, int64 a, int64 b) {
527 | int64 divisorCorr = std::abs(b) / 2;
528 | int64 remainder = std::abs(a) % std::abs(b);
529 |
530 | if (a >= 0) {
531 | if (DEC_MAX_INT64 - a >= divisorCorr) {
532 | if (remainder >= divisorCorr) {
533 | output = (a + divisorCorr) / b;
534 | } else {
535 | output = a / b;
536 | }
537 | return true;
538 | }
539 | } else {
540 | if (-(DEC_MIN_INT64 - a) >= divisorCorr) {
541 | if (remainder < divisorCorr) {
542 | output = (a - remainder) / b;
543 | } else if (remainder == divisorCorr) {
544 | output = (a + divisorCorr) / b;
545 | } else {
546 | output = (a + remainder - std::abs(b)) / b;
547 | }
548 | return true;
549 | }
550 | }
551 |
552 | output = 0;
553 | return false;
554 | }
555 | };
556 |
557 | // bankers' rounding
558 | class half_even_round_policy {
559 | public:
560 | template
561 | static int64 round(T value) {
562 | T val1;
563 | T decimals;
564 |
565 | if (value >= 0.0) {
566 | decimals = value - floor(value);
567 | if (decimals > 0.5) {
568 | val1 = ceil(value);
569 | } else if (decimals < 0.5) {
570 | val1 = floor(value);
571 | } else {
572 | bool is_even = (static_cast(value - decimals) % 2 == 0);
573 | if (is_even) {
574 | val1 = floor(value);
575 | } else {
576 | val1 = ceil(value);
577 | }
578 | }
579 | } else {
580 | decimals = std::abs(value + floor(std::abs(value)));
581 | if (decimals > 0.5) {
582 | val1 = floor(value);
583 | } else if (decimals < 0.5) {
584 | val1 = ceil(value);
585 | } else {
586 | bool is_even = (static_cast(value + decimals) % 2 == 0);
587 | if (is_even) {
588 | val1 = ceil(value);
589 | } else {
590 | val1 = floor(value);
591 | }
592 | }
593 | }
594 |
595 | return static_cast(val1);
596 | }
597 |
598 | static bool div_rounded(int64 &output, int64 a, int64 b) {
599 | int64 divisorDiv2 = std::abs(b) / 2;
600 | int64 remainder = std::abs(a) % std::abs(b);
601 |
602 | if (remainder == 0) {
603 | output = a / b;
604 | } else {
605 | if (a >= 0) {
606 |
607 | if (remainder > divisorDiv2) {
608 | output = (a - remainder + std::abs(b)) / b;
609 | } else if (remainder < divisorDiv2) {
610 | output = (a - remainder) / b;
611 | } else {
612 | bool is_even = std::abs(a / b) % 2 == 0;
613 | if (is_even) {
614 | output = a / b;
615 | } else {
616 | output = (a - remainder + std::abs(b)) / b;
617 | }
618 | }
619 | } else {
620 | // negative value
621 | if (remainder > divisorDiv2) {
622 | output = (a + remainder - std::abs(b)) / b;
623 | } else if (remainder < divisorDiv2) {
624 | output = (a + remainder) / b;
625 | } else {
626 | bool is_even = std::abs(a / b) % 2 == 0;
627 | if (is_even) {
628 | output = a / b;
629 | } else {
630 | output = (a + remainder - std::abs(b)) / b;
631 | }
632 | }
633 | }
634 | }
635 |
636 | return true;
637 | }
638 | };
639 |
640 | // round towards +infinity
641 | class ceiling_round_policy {
642 | public:
643 | template
644 | static int64 round(T value) {
645 | return static_cast(ceil(value));
646 | }
647 |
648 | static bool div_rounded(int64 &output, int64 a, int64 b) {
649 | int64 remainder = std::abs(a) % std::abs(b);
650 | if (remainder == 0) {
651 | output = a / b;
652 | } else {
653 | if (a >= 0) {
654 | output = (a + std::abs(b)) / b;
655 | } else {
656 | output = a / b;
657 | }
658 | }
659 | return true;
660 | }
661 | };
662 |
663 | // round towards -infinity
664 | class floor_round_policy {
665 | public:
666 | template
667 | static int64 round(T value) {
668 | return static_cast(floor(value));
669 | }
670 |
671 | static bool div_rounded(int64 &output, int64 a, int64 b) {
672 | int64 remainder = std::abs(a) % std::abs(b);
673 | if (remainder == 0) {
674 | output = a / b;
675 | } else {
676 | if (a >= 0) {
677 | output = (a - remainder) / b;
678 | } else {
679 | output = (a + remainder - std::abs(b)) / b;
680 | }
681 | }
682 | return true;
683 | }
684 | };
685 |
686 | // round towards zero = truncate
687 | class round_down_round_policy: public null_round_policy {
688 | };
689 |
690 | // round away from zero
691 | class round_up_round_policy {
692 | public:
693 | template
694 | static int64 round(T value) {
695 | if (value >= 0.0) {
696 | return static_cast(ceil(value));
697 | } else {
698 | return static_cast(floor(value));
699 | }
700 | }
701 |
702 | static bool div_rounded(int64 &output, int64 a, int64 b) {
703 | int64 remainder = std::abs(a) % std::abs(b);
704 | if (remainder == 0) {
705 | output = a / b;
706 | } else {
707 | if (a >= 0) {
708 | output = (a + std::abs(b)) / b;
709 | } else {
710 | output = (a - std::abs(b)) / b;
711 | }
712 | }
713 | return true;
714 | }
715 | };
716 |
717 | template
718 | class decimal {
719 | public:
720 | typedef dec_storage_t raw_data_t;
721 | enum {
722 | decimal_points = Prec
723 | };
724 |
725 | #ifdef DEC_NO_CPP11
726 | #ifdef DEC_TRIVIAL_DEFAULT_CONSTRUCTIBLE
727 | decimal() {
728 | }
729 | #else
730 | decimal() {
731 | init(0);
732 | }
733 | #endif
734 | decimal(const decimal &src) {
735 | init(src);
736 | }
737 | #else
738 | #ifdef DEC_TRIVIAL_DEFAULT_CONSTRUCTIBLE
739 | decimal() noexcept = default;
740 | #else
741 | decimal() noexcept : m_value(0) {}
742 | #endif
743 | decimal(const decimal &src) = default;
744 | #endif
745 | explicit decimal(uint value) {
746 | init(value);
747 | }
748 | explicit decimal(int value) {
749 | init(value);
750 | }
751 | #ifdef DEC_HANDLE_LONG
752 | explicit decimal(long int value) {
753 | init(value);
754 | }
755 | #endif
756 | explicit decimal(int64 value) {
757 | init(value);
758 | }
759 | explicit decimal(xdouble value) {
760 | init(value);
761 | }
762 | explicit decimal(double value) {
763 | init(value);
764 | }
765 | explicit decimal(float value) {
766 | init(value);
767 | }
768 | explicit decimal(int64 value, int64 precFactor) {
769 | initWithPrec(value, precFactor);
770 | }
771 | explicit decimal(const std::string &value) {
772 | fromString(value, *this);
773 | }
774 |
775 | explicit decimal(const std::string &value, const basic_decimal_format &format) {
776 | fromString(value, format, *this);
777 | }
778 |
779 | #ifdef DEC_NO_CPP11
780 | ~decimal() {
781 | }
782 | #else
783 | ~decimal() = default;
784 | #endif
785 |
786 | static int64 getPrecFactor() {
787 | return DecimalFactor::value;
788 | }
789 | static int getDecimalPoints() {
790 | return Prec;
791 | }
792 |
793 | #ifdef DEC_NO_CPP11
794 | decimal & operator=(const decimal &rhs) {
795 | if (&rhs != this)
796 | m_value = rhs.m_value;
797 | return *this;
798 | }
799 | #else
800 | decimal & operator=(const decimal &rhs) = default;
801 | #endif
802 |
803 | #if DEC_TYPE_LEVEL == 1
804 | template
805 | typename ENABLE_IF= Prec2, decimal>::type
806 | & operator=(const decimal &rhs) {
807 | m_value = rhs.getUnbiased() * DecimalFactorDiff::value;
808 | return *this;
809 | }
810 | #elif DEC_TYPE_LEVEL > 1
811 | template
812 | decimal & operator=(const decimal &rhs) {
813 | if (Prec2 > Prec) {
814 | RoundPolicy::div_rounded(m_value, rhs.getUnbiased(),
815 | DecimalFactorDiff::value);
816 | } else {
817 | m_value = rhs.getUnbiased()
818 | * DecimalFactorDiff::value;
819 | }
820 | return *this;
821 | }
822 | #endif
823 |
824 | decimal & operator=(int64 rhs) {
825 | m_value = DecimalFactor::value * rhs;
826 | return *this;
827 | }
828 |
829 | decimal & operator=(int rhs) {
830 | m_value = DecimalFactor::value * rhs;
831 | return *this;
832 | }
833 |
834 | decimal & operator=(double rhs) {
835 | m_value = fpToStorage(rhs);
836 | return *this;
837 | }
838 |
839 | decimal & operator=(xdouble rhs) {
840 | m_value = fpToStorage(rhs);
841 | return *this;
842 | }
843 |
844 | template
845 | bool operator==(const T &rhs) const {
846 | return (*this == static_cast(rhs));
847 | }
848 |
849 | template
850 | bool operator!=(const T &rhs) const {
851 | return !(*this == rhs);
852 | }
853 |
854 | #if DEC_USE_SPACESHIP_OPER
855 | template
856 | auto operator<=>(const T &rhs) const {
857 | return (*this <=> static_cast(rhs));
858 | }
859 | #else
860 | template
861 | bool operator<(const T &rhs) const {
862 | return (*this < static_cast(rhs));
863 | }
864 |
865 | template
866 | bool operator<=(const T &rhs) const {
867 | return (*this <= static_cast(rhs));
868 | }
869 |
870 | template
871 | bool operator>(const T &rhs) const {
872 | return (*this > static_cast(rhs));
873 | }
874 |
875 | template
876 | bool operator>=(const T &rhs) const {
877 | return (*this >= static_cast(rhs));
878 | }
879 | #endif
880 |
881 | bool operator==(const decimal &rhs) const {
882 | return (m_value == rhs.m_value);
883 | }
884 |
885 | bool operator!=(const decimal &rhs) const {
886 | return !(*this == rhs);
887 | }
888 |
889 | #if DEC_USE_SPACESHIP_OPER
890 | auto operator<=>(const decimal &rhs) const {
891 | return m_value <=> rhs.m_value;
892 | }
893 | #else
894 |
895 | bool operator<(const decimal &rhs) const {
896 | return (m_value < rhs.m_value);
897 | }
898 |
899 | bool operator<=(const decimal &rhs) const {
900 | return (m_value <= rhs.m_value);
901 | }
902 |
903 | bool operator>(const decimal &rhs) const {
904 | return (m_value > rhs.m_value);
905 | }
906 |
907 | bool operator>=(const decimal &rhs) const {
908 | return (m_value >= rhs.m_value);
909 | }
910 | #endif
911 |
912 | template
913 | const decimal operator+(const T &rhs) const {
914 | return *this + static_cast(rhs);
915 | }
916 |
917 | const decimal operator+(const decimal &rhs) const {
918 | decimal result = *this;
919 | result.m_value += rhs.m_value;
920 | return result;
921 | }
922 |
923 | #if DEC_TYPE_LEVEL == 1
924 | template
925 | const typename ENABLE_IF= Prec2, decimal>::type
926 | operator+(const decimal &rhs) const {
927 | decimal result = *this;
928 | result.m_value += rhs.getUnbiased() * DecimalFactorDiff::value;
929 | return result;
930 | }
931 | #elif DEC_TYPE_LEVEL > 1
932 | template
933 | const decimal operator+(const decimal &rhs) const {
934 | decimal result = *this;
935 | if (Prec2 > Prec) {
936 | int64 val;
937 | RoundPolicy::div_rounded(val, rhs.getUnbiased(),
938 | DecimalFactorDiff::value);
939 | result.m_value += val;
940 | } else {
941 | result.m_value += rhs.getUnbiased()
942 | * DecimalFactorDiff::value;
943 | }
944 |
945 | return result;
946 | }
947 | #endif
948 |
949 | template
950 | decimal & operator+=(const T &rhs) {
951 | *this += static_cast(rhs);
952 | return *this;
953 | }
954 |
955 | decimal & operator+=(const decimal &rhs) {
956 | m_value += rhs.m_value;
957 | return *this;
958 | }
959 |
960 | #if DEC_TYPE_LEVEL == 1
961 | template
962 | typename ENABLE_IF= Prec2, decimal>::type
963 | & operator+=(const decimal &rhs) {
964 | m_value += rhs.getUnbiased() * DecimalFactorDiff::value;
965 | return *this;
966 | }
967 | #elif DEC_TYPE_LEVEL > 1
968 | template
969 | decimal & operator+=(const decimal &rhs) {
970 | if (Prec2 > Prec) {
971 | int64 val;
972 | RoundPolicy::div_rounded(val, rhs.getUnbiased(),
973 | DecimalFactorDiff::value);
974 | m_value += val;
975 | } else {
976 | m_value += rhs.getUnbiased()
977 | * DecimalFactorDiff::value;
978 | }
979 |
980 | return *this;
981 | }
982 | #endif
983 |
984 | const decimal operator+() const {
985 | return *this;
986 | }
987 |
988 | const decimal operator-() const {
989 | decimal result = *this;
990 | result.m_value = -result.m_value;
991 | return result;
992 | }
993 |
994 | template
995 | const decimal operator-(const T &rhs) const {
996 | return *this - static_cast(rhs);
997 | }
998 |
999 | const decimal operator-(const decimal &rhs) const {
1000 | decimal result = *this;
1001 | result.m_value -= rhs.m_value;
1002 | return result;
1003 | }
1004 |
1005 | #if DEC_TYPE_LEVEL == 1
1006 | template
1007 | const typename ENABLE_IF= Prec2, decimal>::type
1008 | operator-(const decimal &rhs) const {
1009 | decimal result = *this;
1010 | result.m_value -= rhs.getUnbiased() * DecimalFactorDiff::value;
1011 | return result;
1012 | }
1013 | #elif DEC_TYPE_LEVEL > 1
1014 | template
1015 | const decimal operator-(const decimal &rhs) const {
1016 | decimal result = *this;
1017 | if (Prec2 > Prec) {
1018 | int64 val;
1019 | RoundPolicy::div_rounded(val, rhs.getUnbiased(),
1020 | DecimalFactorDiff::value);
1021 | result.m_value -= val;
1022 | } else {
1023 | result.m_value -= rhs.getUnbiased()
1024 | * DecimalFactorDiff::value;
1025 | }
1026 |
1027 | return result;
1028 | }
1029 | #endif
1030 |
1031 | template
1032 | decimal & operator-=(const T &rhs) {
1033 | *this -= static_cast(rhs);
1034 | return *this;
1035 | }
1036 |
1037 | decimal & operator-=(const decimal &rhs) {
1038 | m_value -= rhs.m_value;
1039 | return *this;
1040 | }
1041 |
1042 | #if DEC_TYPE_LEVEL == 1
1043 | template
1044 | typename ENABLE_IF= Prec2, decimal>::type
1045 | & operator-=(const decimal &rhs) {
1046 | m_value -= rhs.getUnbiased() * DecimalFactorDiff::value;
1047 | return *this;
1048 | }
1049 | #elif DEC_TYPE_LEVEL > 1
1050 | template
1051 | decimal & operator-=(const decimal &rhs) {
1052 | if (Prec2 > Prec) {
1053 | int64 val;
1054 | RoundPolicy::div_rounded(val, rhs.getUnbiased(),
1055 | DecimalFactorDiff::value);
1056 | m_value -= val;
1057 | } else {
1058 | m_value -= rhs.getUnbiased()
1059 | * DecimalFactorDiff::value;
1060 | }
1061 |
1062 | return *this;
1063 | }
1064 | #endif
1065 |
1066 | template
1067 | const decimal operator*(const T &rhs) const {
1068 | return *this * static_cast(rhs);
1069 | }
1070 |
1071 | const decimal operator*(const decimal &rhs) const {
1072 | decimal result = *this;
1073 | result.m_value = dec_utils::multDiv(result.m_value,
1074 | rhs.m_value, DecimalFactor::value);
1075 | return result;
1076 | }
1077 |
1078 | #if DEC_TYPE_LEVEL == 1
1079 | template
1080 | const typename ENABLE_IF= Prec2, decimal>::type
1081 | operator*(const decimal& rhs) const {
1082 | decimal result = *this;
1083 | result.m_value = dec_utils::multDiv(result.m_value,
1084 | rhs.getUnbiased(), DecimalFactor::value);
1085 | return result;
1086 | }
1087 | #elif DEC_TYPE_LEVEL > 1
1088 | template
1089 | const decimal operator*(const decimal& rhs) const {
1090 | decimal result = *this;
1091 | result.m_value = dec_utils::multDiv(result.m_value,
1092 | rhs.getUnbiased(), DecimalFactor::value);
1093 | return result;
1094 | }
1095 | #endif
1096 |
1097 | template
1098 | decimal & operator*=(const T &rhs) {
1099 | *this *= static_cast(rhs);
1100 | return *this;
1101 | }
1102 |
1103 | decimal & operator*=(const decimal &rhs) {
1104 | m_value = dec_utils::multDiv(m_value, rhs.m_value,
1105 | DecimalFactor::value);
1106 | return *this;
1107 | }
1108 |
1109 | #if DEC_TYPE_LEVEL == 1
1110 | template
1111 | typename ENABLE_IF= Prec2, decimal>::type
1112 | & operator*=(const decimal& rhs) {
1113 | m_value = dec_utils::multDiv(m_value, rhs.getUnbiased(),
1114 | DecimalFactor::value);
1115 | return *this;
1116 | }
1117 | #elif DEC_TYPE_LEVEL > 1
1118 | template
1119 | decimal & operator*=(const decimal& rhs) {
1120 | m_value = dec_utils::multDiv(m_value, rhs.getUnbiased(),
1121 | DecimalFactor::value);
1122 | return *this;
1123 | }
1124 | #endif
1125 |
1126 | template
1127 | const decimal operator/(const T &rhs) const {
1128 | return *this / static_cast(rhs);
1129 | }
1130 |
1131 | const decimal operator/(const decimal &rhs) const {
1132 | decimal result = *this;
1133 | //result.m_value = (result.m_value * DecimalFactor::value) / rhs.m_value;
1134 | result.m_value = dec_utils::multDiv(result.m_value,
1135 | DecimalFactor::value, rhs.m_value);
1136 |
1137 | return result;
1138 | }
1139 |
1140 | #if DEC_TYPE_LEVEL == 1
1141 | template
1142 | const typename ENABLE_IF= Prec2, decimal>::type
1143 | operator/(const decimal& rhs) const {
1144 | decimal result = *this;
1145 | result.m_value = dec_utils::multDiv(result.m_value,
1146 | DecimalFactor::value, rhs.getUnbiased());
1147 | return result;
1148 | }
1149 | #elif DEC_TYPE_LEVEL > 1
1150 | template
1151 | const decimal operator/(const decimal& rhs) const {
1152 | decimal result = *this;
1153 | result.m_value = dec_utils::multDiv(result.m_value,
1154 | DecimalFactor::value, rhs.getUnbiased());
1155 | return result;
1156 | }
1157 | #endif
1158 |
1159 | template
1160 | decimal & operator/=(const T &rhs) {
1161 | *this /= static_cast(rhs);
1162 | return *this;
1163 | }
1164 |
1165 | decimal & operator/=(const decimal &rhs) {
1166 | //m_value = (m_value * DecimalFactor::value) / rhs.m_value;
1167 | m_value = dec_utils::multDiv(m_value,
1168 | DecimalFactor::value, rhs.m_value);
1169 |
1170 | return *this;
1171 | }
1172 |
1173 | #if DEC_TYPE_LEVEL == 1
1174 | template
1175 | typename ENABLE_IF= Prec2, decimal>::type
1176 | & operator/=(const decimal &rhs) {
1177 | m_value = dec_utils::multDiv(m_value,
1178 | DecimalFactor::value, rhs.getUnbiased());
1179 |
1180 | return *this;
1181 | }
1182 | #elif DEC_TYPE_LEVEL > 1
1183 | template
1184 | decimal & operator/=(const decimal &rhs) {
1185 | m_value = dec_utils::multDiv(m_value,
1186 | DecimalFactor::value, rhs.getUnbiased());
1187 |
1188 | return *this;
1189 | }
1190 | #endif
1191 |
1192 | template
1193 | const decimal operator%(T n) const {
1194 | return *this % static_cast(n);
1195 | }
1196 |
1197 | template
1198 | decimal & operator%=(T rhs) {
1199 | *this %= static_cast(rhs);
1200 | return *this;
1201 | }
1202 |
1203 | const decimal operator%(const decimal &rhs) const {
1204 | int64 resultPayload;
1205 | resultPayload = this->m_value;
1206 | resultPayload %= rhs.m_value;
1207 | decimal result;
1208 | result.m_value = resultPayload;
1209 | return result;
1210 | }
1211 |
1212 | decimal & operator%=(const decimal &rhs) {
1213 | int64 resultPayload;
1214 | resultPayload = this->m_value;
1215 | resultPayload %= rhs.m_value;
1216 | this->m_value = resultPayload;
1217 | return *this;
1218 | }
1219 |
1220 | #if DEC_TYPE_LEVEL >= 1
1221 | template
1222 | typename ENABLE_IF= Prec2, decimal>::type
1223 | operator%(const decimal &rhs) const {
1224 | int64 rhsInThisPrec = rhs.getUnbiased() * DecimalFactorDiff::value;
1225 | int64 resultPayload = this->m_value;
1226 | resultPayload %= rhsInThisPrec;
1227 | decimal result;
1228 | result.m_value = resultPayload;
1229 | return result;
1230 | }
1231 |
1232 | template
1233 | typename ENABLE_IF= Prec2, decimal &>::type
1234 | operator%=(const decimal &rhs) {
1235 | int64 rhsInThisPrec = rhs.getUnbiased() * DecimalFactorDiff::value;
1236 | int64 resultPayload = this->m_value;
1237 | resultPayload %= rhsInThisPrec;
1238 | this->m_value = resultPayload;
1239 | return *this;
1240 | }
1241 | #endif
1242 |
1243 | #if DEC_TYPE_LEVEL > 1
1244 | template
1245 | typename ENABLE_IF::type
1246 | operator%(const decimal &rhs) const {
1247 | int64 thisInRhsPrec = m_value * DecimalFactorDiff::value;
1248 | int64 resultPayload = thisInRhsPrec % rhs.getUnbiased();
1249 | resultPayload /= DecimalFactorDiff::value;
1250 | decimal result;
1251 | result.m_value = resultPayload;
1252 | return result;
1253 | }
1254 |
1255 | template
1256 | typename ENABLE_IF::type
1257 | operator%=(const decimal &rhs) {
1258 | int64 thisInRhsPrec = m_value * DecimalFactorDiff::value;
1259 | int64 resultPayload = thisInRhsPrec % rhs.getUnbiased();
1260 | resultPayload /= DecimalFactorDiff::value;
1261 | this->m_value = resultPayload;
1262 | return *this;
1263 | }
1264 | #endif
1265 |
1266 | /// Returns integer indicating sign of value
1267 | /// -1 if value is < 0
1268 | /// +1 if value is > 0
1269 | /// 0 if value is 0
1270 | int sign() const {
1271 | return (m_value > 0) ? 1 : ((m_value < 0) ? -1 : 0);
1272 | }
1273 |
1274 | double getAsDouble() const {
1275 | return static_cast(m_value) / getPrecFactorDouble();
1276 | }
1277 |
1278 | void setAsDouble(double value) {
1279 | m_value = fpToStorage(value);
1280 | }
1281 |
1282 | xdouble getAsXDouble() const {
1283 | return static_cast(m_value) / getPrecFactorXDouble();
1284 | }
1285 |
1286 | void setAsXDouble(xdouble value) {
1287 | m_value = fpToStorage(value);
1288 | }
1289 |
1290 | // returns integer value = real_value * (10 ^ precision)
1291 | // use to load/store decimal value in external memory
1292 | int64 getUnbiased() const {
1293 | return m_value;
1294 | }
1295 | void setUnbiased(int64 value) {
1296 | m_value = value;
1297 | }
1298 |
1299 | decimal abs() const {
1300 | if (m_value >= 0)
1301 | return *this;
1302 | else
1303 | return (decimal(0) - *this);
1304 | }
1305 |
1306 | decimal trunc() const {
1307 | int64 beforeValue, afterValue;
1308 | afterValue = m_value % DecimalFactor::value;
1309 | beforeValue = (m_value - afterValue);
1310 | decimal result;
1311 | result.m_value = beforeValue;
1312 | return result;
1313 | }
1314 |
1315 | decimal floor() const {
1316 | int64 beforeValue, afterValue;
1317 | afterValue = m_value % DecimalFactor::value;
1318 | beforeValue = (m_value - afterValue);
1319 |
1320 | if (afterValue < 0) beforeValue -= DecimalFactor::value;
1321 |
1322 | decimal result;
1323 | result.m_value = beforeValue;
1324 | return result;
1325 | }
1326 |
1327 | decimal ceil() const {
1328 | int64 beforeValue, afterValue;
1329 | afterValue = m_value % DecimalFactor::value;
1330 | beforeValue = (m_value - afterValue);
1331 |
1332 | if (afterValue > 0) beforeValue += DecimalFactor::value;
1333 | decimal result;
1334 | result.m_value = beforeValue;
1335 | return result;
1336 | }
1337 |
1338 | decimal round() const {
1339 | int64 resultPayload;
1340 | RoundPolicy::div_rounded(resultPayload, this->m_value, DecimalFactor::value);
1341 | decimal result(resultPayload);
1342 | return result;
1343 | }
1344 |
1345 | /// returns value rounded to integer using active rounding policy
1346 | int64 getAsInteger() const {
1347 | int64 result;
1348 | RoundPolicy::div_rounded(result, m_value, DecimalFactor::value);
1349 | return result;
1350 | }
1351 |
1352 | /// overwrites internal value with integer
1353 | void setAsInteger(int64 value) {
1354 | m_value = DecimalFactor::value * value;
1355 | }
1356 |
1357 | /// Returns two parts: before and after decimal point
1358 | /// For negative values both numbers are negative or zero.
1359 | void unpack(int64 &beforeValue, int64 &afterValue) const {
1360 | afterValue = m_value % DecimalFactor::value;
1361 | beforeValue = (m_value - afterValue) / DecimalFactor::value;
1362 | }
1363 |
1364 | /// Combines two parts (before and after decimal point) into decimal value.
1365 | /// Both input values have to have the same sign for correct results.
1366 | /// Does not perform any rounding or input validation - afterValue must be less than 10^prec.
1367 | /// \param[in] beforeValue value before decimal point
1368 | /// \param[in] afterValue value after decimal point multiplied by 10^prec
1369 | /// \result Returns *this
1370 | decimal &pack(int64 beforeValue, int64 afterValue) {
1371 | if (Prec > 0) {
1372 | m_value = beforeValue * DecimalFactor::value;
1373 | m_value += (afterValue % DecimalFactor::value);
1374 | } else
1375 | m_value = beforeValue * DecimalFactor::value;
1376 | return *this;
1377 | }
1378 |
1379 | /// Version of pack() with rounding, sourcePrec specifies precision of source values.
1380 | /// See also @pack.
1381 | template
1382 | decimal &pack_rounded(int64 beforeValue, int64 afterValue) {
1383 | decimal temp;
1384 | temp.pack(beforeValue, afterValue);
1385 | decimal result(temp.getUnbiased(), temp.getPrecFactor());
1386 |
1387 | *this = result;
1388 | return *this;
1389 | }
1390 |
1391 | static decimal buildWithExponent(int64 mantissa, int exponent) {
1392 | decimal result;
1393 | result.setWithExponent(mantissa, exponent);
1394 | return result;
1395 | }
1396 |
1397 | static decimal &buildWithExponent(decimal &output, int64 mantissa,
1398 | int exponent) {
1399 | output.setWithExponent(mantissa, exponent);
1400 | return output;
1401 | }
1402 |
1403 | void setWithExponent(int64 mantissa, int exponent) {
1404 |
1405 | int exponentForPack = exponent + Prec;
1406 |
1407 | if (exponentForPack < 0) {
1408 | int64 newValue;
1409 |
1410 | if (!RoundPolicy::div_rounded(newValue, mantissa,
1411 | dec_utils::pow10(-exponentForPack))) {
1412 | newValue = 0;
1413 | }
1414 |
1415 | m_value = newValue;
1416 | } else {
1417 | m_value = mantissa * dec_utils::pow10(exponentForPack);
1418 | }
1419 | }
1420 |
1421 | void getWithExponent(int64 &mantissa, int &exponent) const {
1422 | int64 value = m_value;
1423 | int exp = -Prec;
1424 |
1425 | if (value != 0) {
1426 | // normalize
1427 | while (value % 10 == 0) {
1428 | value /= 10;
1429 | exp++;
1430 | }
1431 | }
1432 |
1433 | mantissa = value;
1434 | exponent = exp;
1435 | }
1436 |
1437 | protected:
1438 | inline xdouble getPrecFactorXDouble() const {
1439 | return static_cast(DecimalFactor::value);
1440 | }
1441 |
1442 | inline double getPrecFactorDouble() const {
1443 | return static_cast(DecimalFactor::value);
1444 | }
1445 |
1446 | void init(const decimal &src) {
1447 | m_value = src.m_value;
1448 | }
1449 |
1450 | void init(uint value) {
1451 | m_value = DecimalFactor::value * value;
1452 | }
1453 |
1454 | void init(int value) {
1455 | m_value = DecimalFactor::value * value;
1456 | }
1457 |
1458 | #ifdef DEC_HANDLE_LONG
1459 | void init(long int value) {
1460 | m_value = DecimalFactor::value * value;
1461 | }
1462 | #endif
1463 |
1464 | void init(int64 value) {
1465 | m_value = DecimalFactor::value * value;
1466 | }
1467 |
1468 | void init(xdouble value) {
1469 | m_value = fpToStorage(value);
1470 | }
1471 |
1472 | void init(double value) {
1473 | m_value = fpToStorage(value);
1474 | }
1475 |
1476 | void init(float value) {
1477 | m_value = fpToStorage(static_cast(value));
1478 | }
1479 |
1480 | void initWithPrec(int64 value, int64 precFactor) {
1481 | int64 ownFactor = DecimalFactor::value;
1482 |
1483 | if (ownFactor == precFactor) {
1484 | // no conversion required
1485 | m_value = value;
1486 | }
1487 | else if (ownFactor > precFactor) {
1488 | m_value = value * (ownFactor / precFactor);
1489 | }
1490 | else {
1491 | // conversion
1492 | RoundPolicy::div_rounded(m_value, value, precFactor / ownFactor);
1493 | }
1494 | }
1495 |
1496 | template
1497 | static dec_storage_t fpToStorage(T value) {
1498 | dec_storage_t intPart = dec_utils::trunc(value);
1499 | T fracPart = value - intPart;
1500 | return RoundPolicy::round(
1501 | static_cast(DecimalFactor::value) * fracPart) +
1502 | DecimalFactor::value * intPart;
1503 | }
1504 |
1505 | template
1506 | static T abs(T value) {
1507 | if (value < 0)
1508 | return -value;
1509 | else
1510 | return value;
1511 | }
1512 |
1513 | static int sign(int64 value) {
1514 | return (value > 0) ? 1 : ((value < 0) ? -1 : 0);
1515 | }
1516 | protected:
1517 | dec_storage_t m_value;
1518 | };
1519 |
1520 | // ----------------------------------------------------------------------------
1521 | // Pre-defined types
1522 | // ----------------------------------------------------------------------------
1523 | typedef decimal<2> decimal2;
1524 | typedef decimal<4> decimal4;
1525 | typedef decimal<6> decimal6;
1526 |
1527 | // ----------------------------------------------------------------------------
1528 | // global functions
1529 | // ----------------------------------------------------------------------------
1530 | template
1531 | decimal decimal_cast(const T &arg) {
1532 | return decimal(arg.getUnbiased(), arg.getPrecFactor());
1533 | }
1534 |
1535 | // Example of use:
1536 | // c = dec::decimal_cast<6>(a * b);
1537 | template
1538 | decimal decimal_cast(uint arg) {
1539 | decimal result(arg);
1540 | return result;
1541 | }
1542 |
1543 | template
1544 | decimal decimal_cast(int arg) {
1545 | decimal result(arg);
1546 | return result;
1547 | }
1548 |
1549 | template
1550 | decimal