Mstdlib-1.24.0
m_decimal.h
1/* The MIT License (MIT)
2 *
3 * Copyright (c) 2015 Monetra Technologies, LLC.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#ifndef __M_DECIMAL_H__
25#define __M_DECIMAL_H__
26
27/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28
29#include <mstdlib/base/m_defs.h>
30#include <mstdlib/base/m_types.h>
31
32/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
33
34__BEGIN_DECLS
35
36/*! \addtogroup m_decimal Decimal
37 * \ingroup mstdlib_base
38 *
39 * Floating point number type. Used instead of double or float to elimiate rounding errors.
40 *
41 * Example:
42 *
43 * \code{.c}
44 * const char *s1 = "1.01";
45 * const char *s2 = "0.001";
46 * M_decimal_t d1;
47 * M_decimal_t d2;
48 * char out[16];
49 *
50 * M_mem_set(out, 0, sizeof(out));
51 *
52 * M_decimal_from_str(s1, M_str_len(s1), &d1, NULL);
53 * M_decimal_from_str(s2, M_str_len(s2), &d2, NULL);
54 * M_decimal_add(&d1, &d1, &d2);
55 * M_decimal_reduce(&d1);
56 *
57 * if (M_decimal_to_str(&d1, out, sizeof(out)) != M_DECIMAL_SUCCESS) {
58 * M_printf("failure\n");
59 * } else {
60 * M_printf("out='%s'\n", out);
61 * }
62 * \endcode
63 *
64 * Example output:
65 *
66 * \code
67 * out='1.011'
68 * \endcode
69 *
70 * @{
71 */
72
73
74/*! Structure defining storage for decimal numbers.
75 *
76 * This structure should never be touched directly. It is only made public to reduce the overhead of using this
77 * datatype (no malloc needed). */
78typedef struct {
79 M_int64 num; /*!< Number represented. */
80 M_uint8 num_dec; /*!< How many implied decimal places. */
82
83
84/*! Result/Error codes for M_decimal functions. */
86 M_DECIMAL_SUCCESS = 0, /*!< Operation successful. */
87 M_DECIMAL_OVERFLOW = 1, /*!< An overflow occurred in the operation. */
88 M_DECIMAL_TRUNCATION = 2, /*!< The result was truncated/rounded in order
89 to approximate the best result. This is
90 true on most divide operations. */
91 M_DECIMAL_INVALID = 3 /*!< Invalid data. */
92};
93
94/*! Rounding formula */
95typedef enum {
96 M_DECIMAL_ROUND_NONE = 0, /*!< Truncate */
97 M_DECIMAL_ROUND_TRADITIONAL = 1, /*!< Traditional, aka Round Half away from Zero. */
98 M_DECIMAL_ROUND_BANKERS = 2, /*!< Bankers, aka Round Half to Even */
100
101/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
102
103/*! Create new zero'd out decimal number.
104 *
105 * \param[out] dec New decimal output.
106 */
108
109
110/*! Convert to a decimal representation from an integer
111 *
112 * \param[out] dec New decimal output.
113 * \param[in] integer Integer to convert to decimal.
114 * \param[in] implied_dec Number of implied decimals in integer input.
115 */
116M_API void M_decimal_from_int(M_decimal_t *dec, M_int64 integer, M_uint8 implied_dec);
117
118
119/*! Convert from a decimal representation to an integer with implied decimal places.
120 * If the conversion causes truncation, the number will be rounded.
121 * For example a decimal of 123.456, with implied decimals 2, will return
122 * 12346.
123 *
124 * \param[in] dec Decimal type
125 * \param[in] implied_dec Number of implied decimal positions.
126 *
127 * \return Rounded integer representation of number.
128 */
129M_API M_int64 M_decimal_to_int(const M_decimal_t *dec, M_uint8 implied_dec);
130
131
132/*! Convert to a decimal representation from a string.
133 *
134 * \param[in] string Buffer with decimal representation.
135 * \param[in] len Length of bytes to evaluate from string.
136 * \param[out] val New decimal output.
137 * \param[out] endptr Pointer to end of evaluated decimal.
138 *
139 * \return One of the enum M_DECIMAL_RETVAL values.
140 */
141M_API enum M_DECIMAL_RETVAL M_decimal_from_str(const char *string, size_t len, M_decimal_t *val, const char **endptr);
142
143
144/*! Convert from a decimal representation to a string.
145 *
146 * \param[in] dec Decimal type.
147 * \param[out] buf Buffer to output string representation.
148 * \param[in] buf_len Length of output buffer.
149 *
150 * \return One of the enum M_DECIMAL_RETVAL values.
151 */
152M_API enum M_DECIMAL_RETVAL M_decimal_to_str(const M_decimal_t *dec, char *buf, size_t buf_len);
153
154
155/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
156
157/*! Compare 2 decimals.
158 *
159 * \param[in] dec1 Decimal 1.
160 * \param[in] dec2 Decimal 2.
161 *
162 * \return -1 if dec1 < dec2, 0 if dec1 == dec2, 1 if dec1 > dec2.
163 */
164M_API M_int8 M_decimal_cmp(const M_decimal_t *dec1, const M_decimal_t *dec2);
165
166
167/*! Transform decimal number representation to have the specified number
168 * of decimal places (rounding if needed).
169 *
170 * \param[in,out] dec Decimal type.
171 * \param[in] num_dec Number of decimal places number should be transformed to.
172 * \param[in] round Round method to use when rounding.
173 *
174 * \return One of the enum M_DECIMAL_RETVAL values.
175 */
176M_API enum M_DECIMAL_RETVAL M_decimal_transform(M_decimal_t *dec, M_uint8 num_dec, M_decimal_round_t round);
177
178
179/*! Reduce the decimal representation to the smallest number of decimal places
180 * possible without reducing precision (remove trailing zeros).
181 *
182 * \param[in,out] dec Decimal type.
183 */
185
186
187/*! Number of decimal places present in the M_decimal_t representation.
188 *
189 * \param[in] dec Decimal type.
190 *
191 * \return Number of decimals currently represented by type.
192 */
193M_API M_uint8 M_decimal_num_decimals(const M_decimal_t *dec);
194
195
196/*! Copy the decimal object from the source into the destination
197 *
198 * \param[out] dest New decimal duplicated from src.
199 * \param[in] src Decimal type to copy.
200 */
201M_API void M_decimal_duplicate(M_decimal_t *dest, const M_decimal_t *src);
202
203
204/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
205
206/*! Multiply the two decimals together putting the result in dest.
207 *
208 * The destination and one of the sources may be the same. The number of resulting decimal places will be the same as
209 * the largest input.
210 *
211 * \param[out] dest New decimal with result.
212 * \param[in] dec1 First decimal to multiply.
213 * \param[in] dec2 Second decimal to multiply.
214 *
215 * \return One of the enum M_DECIMAL_RETVAL values.
216 */
217M_API enum M_DECIMAL_RETVAL M_decimal_multiply(M_decimal_t *dest, const M_decimal_t *dec1, const M_decimal_t *dec2);
218
219
220/*! Divide the two decimals, putting the result in dest.
221 *
222 * The destination and one of the sources may be the same. The maximum number of decimal places able to be represented
223 * will be.
224 *
225 * \param[out] dest New decimal with result.
226 * \param[in] dec1 First decimal (numerator).
227 * \param[in] dec2 Second decimal (denominator).
228 * \param[in] round The result may not be able to be represented fully, select the rounding method if truncated.
229 *
230 * \return One of the enum M_DECIMAL_RETVAL values.
231 */
233
234
235/*! Subtract two decimals, putting the result in dest.
236 *
237 * The destination and one of the sources may be the same. The number of resulting decimal places will be the same as
238 * the largest input.
239 *
240 * \param[out] dest New decimal with result.
241 * \param[in] dec1 First decimal.
242 * \param[in] dec2 Second decimal.
243 *
244 * \return One of the enum M_DECIMAL_RETVAL values.
245 */
246M_API enum M_DECIMAL_RETVAL M_decimal_subtract(M_decimal_t *dest, const M_decimal_t *dec1, const M_decimal_t *dec2);
247
248
249/*! Add two decimals, putting the result in dest.
250 *
251 * The destination and one of the sources may be the same. The number of resulting decimal places will be the same as
252 * the largest input.
253 *
254 * \param[out] dest New decimal with result.
255 * \param[in] dec1 First decimal.
256 * \param[in] dec2 Second decimal.
257 *
258 * \return One of the enum M_DECIMAL_RETVAL values
259 */
260M_API enum M_DECIMAL_RETVAL M_decimal_add(M_decimal_t *dest, const M_decimal_t *dec1, const M_decimal_t *dec2);
261
262/*! @} */
263
264__END_DECLS
265
266#endif /* __M_DECIMAL_H__ */
M_int64 num
Definition: m_decimal.h:79
M_uint8 num_dec
Definition: m_decimal.h:80
M_int8 M_decimal_cmp(const M_decimal_t *dec1, const M_decimal_t *dec2)
void M_decimal_create(M_decimal_t *dec)
enum M_DECIMAL_RETVAL M_decimal_add(M_decimal_t *dest, const M_decimal_t *dec1, const M_decimal_t *dec2)
M_int64 M_decimal_to_int(const M_decimal_t *dec, M_uint8 implied_dec)
enum M_DECIMAL_RETVAL M_decimal_divide(M_decimal_t *dest, const M_decimal_t *dec1, const M_decimal_t *dec2, M_decimal_round_t round)
void M_decimal_duplicate(M_decimal_t *dest, const M_decimal_t *src)
M_DECIMAL_RETVAL
Definition: m_decimal.h:85
enum M_DECIMAL_RETVAL M_decimal_from_str(const char *string, size_t len, M_decimal_t *val, const char **endptr)
M_uint8 M_decimal_num_decimals(const M_decimal_t *dec)
void M_decimal_from_int(M_decimal_t *dec, M_int64 integer, M_uint8 implied_dec)
enum M_DECIMAL_RETVAL M_decimal_to_str(const M_decimal_t *dec, char *buf, size_t buf_len)
enum M_DECIMAL_RETVAL M_decimal_transform(M_decimal_t *dec, M_uint8 num_dec, M_decimal_round_t round)
enum M_DECIMAL_RETVAL M_decimal_subtract(M_decimal_t *dest, const M_decimal_t *dec1, const M_decimal_t *dec2)
M_decimal_round_t
Definition: m_decimal.h:95
enum M_DECIMAL_RETVAL M_decimal_multiply(M_decimal_t *dest, const M_decimal_t *dec1, const M_decimal_t *dec2)
void M_decimal_reduce(M_decimal_t *dec)
@ M_DECIMAL_OVERFLOW
Definition: m_decimal.h:87
@ M_DECIMAL_TRUNCATION
Definition: m_decimal.h:88
@ M_DECIMAL_INVALID
Definition: m_decimal.h:91
@ M_DECIMAL_SUCCESS
Definition: m_decimal.h:86
@ M_DECIMAL_ROUND_TRADITIONAL
Definition: m_decimal.h:97
@ M_DECIMAL_ROUND_BANKERS
Definition: m_decimal.h:98
@ M_DECIMAL_ROUND_NONE
Definition: m_decimal.h:96
Definition: m_decimal.h:78