sparrow 0.9.0
Loading...
Searching...
No Matches
decimal.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <iostream>
5#include <sstream>
6
7#if defined(__cpp_lib_format)
8# include <format>
9#endif
10
13
14namespace sparrow
15{
16 template <typename T>
17 concept decimal_integer_type = std::is_same_v<T, std::int32_t> || std::is_same_v<T, std::int64_t>
18 || std::is_same_v<T, int128_t> || std::is_same_v<T, int256_t>;
19
20 template <decimal_integer_type T>
21 class decimal
22 {
23 public:
24
25 using integer_type = T;
26
28 requires(!is_int_placeholder_v<T>);
31 decimal(T value, int scale);
32
33 bool operator==(const decimal& other) const;
34
35 explicit operator float() const
36 requires(!is_int_placeholder_v<T>);
37 explicit operator double() const
38 requires(!is_int_placeholder_v<T>);
39 explicit operator long double() const
40 requires(!is_int_placeholder_v<T>);
41
42 // convert to string
43 [[nodiscard]] explicit operator std::string() const
44 requires(!is_int_placeholder_v<T>);
45
46 [[nodiscard]] T storage() const;
47
48 [[nodiscard]] int scale() const;
49
50 private:
51
52 template <class FLOAT_TYPE>
53 [[nodiscard]] FLOAT_TYPE convert_to_floating_point() const
54 requires(!is_int_placeholder_v<T>);
55
56
57 T m_value;
58 int m_scale;
59 };
60
61 template <typename T>
62 constexpr bool is_decimal_v = mpl::is_type_instance_of_v<T, decimal>;
63
64 template <typename T>
66
67 template <decimal_integer_type T>
69 requires(!is_int_placeholder_v<T>)
70 : m_value(0)
71 , m_scale()
72 {
73 }
74
75 template <decimal_integer_type T>
78 : m_value()
79 , m_scale()
80 {
81 }
82
83 template <decimal_integer_type T>
85 : m_value(value)
86 , m_scale(scale)
87 {
88 }
89
90 template <decimal_integer_type T>
91 bool decimal<T>::operator==(const decimal& other) const
92 {
93 return m_value == other.m_value && m_scale == other.m_scale;
94 }
95
96 template <decimal_integer_type T>
98 requires(!is_int_placeholder_v<T>)
99 {
100 return convert_to_floating_point<float>();
101 }
102
103 template <decimal_integer_type T>
104 decimal<T>::operator double() const
105 requires(!is_int_placeholder_v<T>)
106 {
107 return convert_to_floating_point<double>();
108 }
109
110 template <decimal_integer_type T>
111 decimal<T>::operator long double() const
112 requires(!is_int_placeholder_v<T>)
113 {
114 return convert_to_floating_point<long double>();
115 }
116
117 template <decimal_integer_type T>
118 decimal<T>::operator std::string() const
119 requires(!is_int_placeholder_v<T>)
120 {
121 std::stringstream ss;
122 ss << m_value;
123 std::string result = ss.str();
124 if (m_scale == 0)
125 {
126 return result;
127 }
128 if (result[0] == '0')
129 {
130 return "0";
131 }
132 // remove - (we handle it later)
133 if (result[0] == '-')
134 {
135 result = result.substr(1);
136 }
137
138 if (m_scale > 0)
139 {
140 if (result.length() <= static_cast<std::size_t>(m_scale))
141 {
142 result.insert(
143 0,
144 std::string(static_cast<std::size_t>(m_scale) + 1 - result.length(), '0')
145 ); // Pad with leading zeros
146 }
147 std::size_t int_part_len = result.length() - static_cast<std::size_t>(m_scale);
148 std::string int_part = result.substr(0, int_part_len);
149 std::string frac_part = result.substr(int_part_len);
150 result = int_part + "." + frac_part;
151 }
152 else
153 {
154 result += std::string(static_cast<std::size_t>(-m_scale), '0'); // Append zeros
155 }
156 // handle negative values
157 if (m_value < 0)
158 {
159 result.insert(0, 1, '-');
160 }
161 return result;
162 }
163
164 template <decimal_integer_type T>
166 {
167 return m_value;
168 }
169
170 template <decimal_integer_type T>
172 {
173 return m_scale;
174 }
175
176 template <decimal_integer_type T>
177 template <class FLOAT_TYPE>
178 FLOAT_TYPE decimal<T>::convert_to_floating_point() const
179 requires(!is_int_placeholder_v<T>)
180 {
181 using to_type = FLOAT_TYPE;
182 if constexpr (std::is_same_v<T, int256_t>)
183 {
184 // danger zone
185 auto val = static_cast<int128_t>(m_value);
186 return static_cast<to_type>(val) / static_cast<to_type>(std::pow(10, m_scale));
187 }
188 else
189 {
190 return static_cast<to_type>(m_value) / static_cast<to_type>(std::pow(10, m_scale));
191 }
192 }
193
194} // namespace sparrow
195
196#if defined(__cpp_lib_format)
197
198template <typename T>
199struct std::formatter<sparrow::decimal<T>>
200{
201 constexpr auto parse(std::format_parse_context& ctx)
202 {
203 return ctx.begin();
204 }
205
206 auto format(const sparrow::decimal<T>& d, std::format_context& ctx) const
207 {
208 return std::format_to(ctx.out(), "Decimal({}, {})", d.storage(), d.scale());
209 }
210};
211
212template <typename T>
213std::ostream& operator<<(std::ostream& os, const sparrow::decimal<T>& value)
214{
215 os << std::format("{}", value);
216 return os;
217}
218
219#endif
bool operator==(const decimal &other) const
Definition decimal.hpp:91
decimal(T value, int scale)
Definition decimal.hpp:84
primesum::int128_t int128_t
Definition large_int.hpp:84
constexpr bool is_int_placeholder_v
Definition large_int.hpp:82
constexpr bool is_decimal_v
Definition decimal.hpp:62
std::ostream & operator<<(std::ostream &os, const sparrow::nullval_t &)
Definition nullable.hpp:933