Xpace
decimalfloat.h
Go to the documentation of this file.
1 
2 /**********************************************************//**
3  **
4  ** @file base/decimalfloat.h
5  **
6  ** Copyright (C) 2012 Xpace, LLC. All rights reserved
7  **
8  ** www.xpace.net
9  **
10  **************************************************************/
11 
12 #ifndef XPACE_DECIMAL_FLOAT_H
13 #define XPACE_DECIMAL_FLOAT_H
14 
15 #ifdef _WIN32
16 #undef min
17 #undef max
18 #endif
19 
20 #include <limits>
21 #include <cstdio>
22 #include <wchar.h>
23 #include <cstring>
24 
25 #include "base/types.h"
26 
27 namespace Xpace
28 {
29  // ================================ FLOAT ===================
30 
31  /// A floatimg-point number with explicit mantissa and decimals
32  /// TODO: normalize
34  {
35  public:
37  (const String8& str,
38  uint precision = ~0);
40  (const String16& str,
41  uint precision = ~0);
43  (const String& str,
44  uint precision = ~0);
45 
47  (int64 mantissa = 0,
48  int decimals = 0);
49 
51  (double val);
52 
53  operator double
54  ()
55  const;
56 
58  ()
59  const
60  {
61  return mantissa;
62  }
63 
64  int getDecimals
65  ()
66  const
67  {
68  return decimals;
69  }
70 
71  int compare
72  (const DecimalFloat& rhs)
73  const;
74  bool operator==
75  (const DecimalFloat& rhs)
76  const;
77  bool operator!=
78  (const DecimalFloat& rhs)
79  const;
80  bool operator<
81  (const DecimalFloat& rhs)
82  const
83  {
84  return compare(rhs) < 0;
85  }
86  bool operator<=
87  (const DecimalFloat& rhs)
88  const;
89  bool operator>
90  (const DecimalFloat& rhs)
91  const;
92  bool operator>=
93  (const DecimalFloat& rhs)
94  const;
95 
96  template <typename STR>
97  bool toRawString
98  (STR* str,
99  typename STR::charType decimalChar = '.')
100  const;
101 
103  (utf16_t decimalChar = '.')
104  const;
105 
106  private:
107  int64 mantissa;
108  int decimals;
109 
110  template <typename STR>
111  bool from_raw_string
112  (const STR& str,
113  uint precision = ~0);
114 
115  static
116  bool itoafn
117  (int64 val,
118  utf8_t* dest,
119  size_t size,
120  size_t* len = 0)
121  {
122  if (_i64toa_s(val, reinterpret_cast<char*>(dest), size, 10))
123  return false;
124  if (len)
125  *len = strlen(reinterpret_cast<char*>(dest));
126  return true;
127  }
128 
129  static
130  bool itoafn
131  (int64 val,
132  utf16_t* dest,
133  size_t size,
134  size_t* len = 0)
135  {
136  if (_i64tow_s(val, reinterpret_cast<wchar_t*>(dest), size, 10))
137  return false;
138  if (len)
139  *len = wcslen(reinterpret_cast<wchar_t*>(dest));
140  return true;
141  }
142  };
143 
144  /// =========================================================
145  /// =========================================================
146  /// =========================================================
147 
148  inline
150  (int64 m,
151  int e) :
152  mantissa(m),
153  decimals(e)
154  {
155  }
156 
157  inline
159  (const String8& str,
160  uint precision) :
161  mantissa(0),
162  decimals(0)
163  {
164  from_raw_string(str, precision);
165  }
166 
167  inline
169  (const String16& str,
170  uint precision) :
171  mantissa(0),
172  decimals(0)
173  {
174  from_raw_string(str, precision);
175  }
176 
177  inline
179  (const String& str,
180  uint precision)
181  {
182  String16 s16(const_cast<utf16_t*>(str.toUtf16()), str.getLength());
183  new (this) DecimalFloat(s16, precision);
184  }
185 
186  template <typename STR>
187  inline
189  (STR* str,
190  typename STR::charType decimalChar)
191  const
192  {
193  size_t len;
194 
195  if (decimals > 0)
196  {
197  if (!itoafn(mantissa, str->data + 1, str->length - 1, &len))
198  return false;
199  typename STR::charType* ch(str->data);
200  for (; ch < str->data + len - decimals; ++ch)
201  *ch = *(ch + 1);
202  *ch = decimalChar;
203  str->length = len + 1;
204  return true;
205  }
206 
207  if (decimals < 0)
208  {
209  if (!itoafn(mantissa, str->data, str->length + decimals, &len))
210  return false;
211  typename STR::charType* ch(str->data + len);
212  for (; ch < str->data + len - decimals; ++ch)
213  *ch = 0;
214  return true;
215  }
216 
217  if (!itoafn(mantissa, str->data, str->length, &len))
218  return false;
219 
220  str->length = len;
221 
222  return true;
223  }
224 
225  inline
227  (utf16_t decimalChar)
228  const
229  {
230  utf16_t buf[32];
231  String16 str(buf, 32);
232  return (toRawString(&str, decimalChar)) ? String(str.data, str.length) : String();
233  }
234 
235  template <typename STR>
236  inline
237  bool DecimalFloat::from_raw_string
238  (const STR& str,
239  uint precision)
240  {
241  typename STR::charType buf[256];
242  typename STR::charType* b(buf);
243  const typename STR::charType* d(str.data);
244  uint len(narrow_to<uint>(str.length));
245  bool minus(false);
246  for (uint i(0); i < len; ++i, ++d)
247  {
248  if (*d == '.')
249  {
250  if (INVALID(precision))
251  decimals = len - i - 1;
252  else
253  {
254  decimals = std::min(precision, len - i - 1);
255  len = std::min(len, i + precision + 1);
256  }
257  }
258  else if (*d == ',')
259  continue;
260  else if ((*d >= '0') && (*d <= '9'))
261  *b++ = *d;
262  else if (*d == '-')
263  minus = true;
264  else
265  return false;
266  }
267  *b = 0;
268 
269  while ((decimals > 0) && (b > buf) && (*--b == '0'))
270  {
271  --decimals;
272  *b = 0;
273  }
274 
275  mantissa = (sizeof(typename STR::charType) == 1) ? _atoi64(reinterpret_cast<const char*>(buf)) : _wtoi64(reinterpret_cast<const wchar_t*>(buf));
276 
277  if (mantissa == std::numeric_limits<int64>::max())
278  {
279  mantissa = 0;
280  return false;
281  }
282 
283  if (minus)
284  mantissa = -mantissa;
285 
286  if ((len < str.length) && (*d >= '5') && (*d <= '9'))
287  {
288  if (mantissa < 0)
289  --mantissa;
290  else
291  ++mantissa;
292  }
293  return true;
294  }
295 
296  inline
298  (double d)
299  {
300  // TODO: optimize this
301  byte buf[128];
302  int len(sprintf_s((char*)buf, sizeof(buf), "%f", d));
303  new (this) DecimalFloat(String8(buf, len));
304  }
305 
306  inline
307  DecimalFloat::operator double
308  ()
309  const
310  {
311  return double(mantissa) / pow10_64(decimals);
312  }
313 
314  inline
316  (const DecimalFloat& rhs)
317  const
318  {
319  if (decimals == rhs.decimals)
320  {
321  if (mantissa == rhs.mantissa)
322  return 0;
323  return (mantissa < rhs.mantissa) ? -1 : 1;
324  }
325 
326  if (decimals > rhs.decimals)
327  {
328  int64 rm(rhs.mantissa * pow10_64(decimals - rhs.decimals));
329  return (mantissa == rm) ? 0 : ((mantissa < rm) ? -1 : 1);
330  // TODO: worry about comparing 430 to 430.000
331  }
332 
333  int64 lm(mantissa * pow10_64(rhs.decimals - decimals));
334  return (lm == rhs.mantissa) ? 0 : ((lm < rhs.mantissa) ? -1 : 1);
335  }
336 
337  inline
338  bool DecimalFloat::operator==
339  (const DecimalFloat& rhs)
340  const
341  {
342  if (decimals == rhs.decimals)
343  return mantissa == rhs.mantissa;
344  if (decimals < rhs.decimals)
345  return int64(mantissa * pow10_64(rhs.decimals - decimals)) == rhs.mantissa;
346  return mantissa == int64(rhs.mantissa * pow10_64(decimals - rhs.decimals));
347  }
348 
349  inline
350  bool DecimalFloat::operator!=
351  (const DecimalFloat& rhs)
352  const
353  {
354  return !(*this == rhs);
355  }
356 }
357 
358 #endif
size_t getLength() const
String toString(utf16_t decimalChar= '.') const
Definition: decimalfloat.h:227
unsigned int uint
Definition: types.h:75
int64 getMantissa() const
Definition: decimalfloat.h:58
DecimalFloat(const String8 &str, uint precision=~0)
Definition: decimalfloat.h:159
int sprintf_s(char *, size_t, const char *,...)
bool INVALID(N n)
Definition: types.h:96
A string, Unicode UTF-16 and reference-counted.
Definition: types.h:269
uint const Xpace_Char8 size_t len
Definition: table_c.h:180
const utf16_t * toUtf16() const
unsigned short utf16_t
Definition: types.h:146
A floatimg-point number with explicit mantissa and decimals TODO: normalize.
Definition: decimalfloat.h:33
uint64 XPACE_EXPORT pow10_64(uint p)
int64 _wtoi64(const wchar_t *)
int64 _atoi64(const char *)
size_t length
Definition: types.h:207
errno_t _i64tow_s(int64, wchar_t *, size_t, int)
errno_t _i64toa_s(int64, char *, size_t, int)
int getDecimals() const
Definition: decimalfloat.h:65
RawString< utf8_t > String8
Definition: types.h:265
long long int64
Definition: types.h:86
unsigned char utf8_t
Definition: types.h:145
Xpace project main namespace
Definition: datetime.h:18
bool toRawString(STR *str, typename STR::charType decimalChar= '.') const
Definition: decimalfloat.h:189
uchar byte
Definition: types.h:74
int compare(const DecimalFloat &rhs) const
Definition: decimalfloat.h:316

current as of Wed Jun 10 2026 12:00:05