sparrow 0.3.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#include <string_view>
7
8#if defined(__cpp_lib_format)
9# include <format>
10#endif
11
14
15namespace sparrow
16{
17 template <class T>
18 class decimal
19 {
20 public:
21
22 using integer_type = T;
23
25 requires(!is_int_placeholder_v<T>);
28 decimal(T value, int scale);
29
30 bool operator==(const decimal& other) const;
31 bool operator!=(const decimal& other) const;
32 explicit operator float() const
33 requires(!is_int_placeholder_v<T>);
34 explicit operator double() const
35 requires(!is_int_placeholder_v<T>);
36 explicit operator long double() const
37 requires(!is_int_placeholder_v<T>);
38
39 // convert to string
40 [[nodiscard]] explicit operator std::string() const
41 requires(!is_int_placeholder_v<T>);
42
43 [[nodiscard]] const T& storage() const;
44
45 [[nodiscard]] int scale() const;
46
47 private:
48
49 template <class FLOAT_TYPE>
50 [[nodiscard]] FLOAT_TYPE convert_to_floating_point() const
51 requires(!is_int_placeholder_v<T>);
52
53
54 T m_value;
55 int m_scale;
56 };
57
58 template <typename T>
59 constexpr bool is_decimal_v = mpl::is_type_instance_of_v<T, decimal>;
60
61 template <typename T>
63 requires(!is_int_placeholder_v<T>)
64 : m_value(0)
65 , m_scale()
66 {
67 }
68
69 template <typename T>
72 : m_value()
73 , m_scale()
74 {
75 }
76
77 template <typename T>
79 : m_value(value)
80 , m_scale(scale)
81 {
82 }
83
84 template <typename T>
85 bool decimal<T>::operator==(const decimal& other) const
86 {
87 return m_value == other.m_value && m_scale == other.m_scale;
88 }
89
90 template <typename T>
91 bool decimal<T>::operator!=(const decimal& other) const
92 {
93 return !(*this == other);
94 }
95
96 template <typename T>
98 requires(!is_int_placeholder_v<T>)
99 {
100 return convert_to_floating_point<float>();
101 }
102
103 template <typename 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 <typename 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 <typename 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 <typename T>
165 const T& decimal<T>::storage() const
166 {
167 return m_value;
168 }
169
170 template <typename T>
172 {
173 return m_scale;
174 }
175
176 template <typename 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
bool operator==(const decimal &other) const
Definition decimal.hpp:85
decimal(T value, int scale)
Definition decimal.hpp:78
const std::int32_t & storage() const
primesum::int128_t int128_t
Definition large_int.hpp:88
constexpr bool is_int_placeholder_v
Definition large_int.hpp:86
std::ostream & operator<<(std::ostream &stream, T n)
Definition large_int.hpp:93
constexpr bool is_decimal_v
Definition decimal.hpp:59