29 | | template <class Char, class FloatType> |
30 | | void FloatToString(FloatType f, Char* sz) |
31 | | { |
32 | | Char* buffer = sz + 1; |
33 | | static const int digitCount = 6; |
34 | | int decimal, sign; |
35 | | |
36 | | // ecvt rounds the string for us: http://www.datafocus.com/docs/man3/ecvt.3.asp |
37 | | char* end = ecvt(f, digitCount, &decimal, &sign); |
38 | | |
39 | | if (sign != 0) (*buffer++) = '-'; |
40 | | int count = digitCount; |
41 | | if (decimal > digitCount) |
42 | | { |
43 | | // We use the scientific notation: P.MeX |
44 | | (*buffer++) = (*end++); // P is one character. |
45 | | (*buffer++) = '.'; |
46 | | |
47 | | // Mantissa (cleaned for zeroes) |
48 | | for (--count; count > 0; --count) if (end[count - 1] != '0') break; |
49 | | for (int i = 0; i < count; ++i) (*buffer++) = (*end++); |
50 | | if (buffer[-1] == '.') --buffer; |
51 | | |
52 | | // Exponent |
53 | | (*buffer++) = 'e'; |
54 | | uint32 exponent = decimal - 1; // X |
55 | | if (exponent >= 10) (*buffer++) = (Char) ('0' + (exponent / 10)); |
56 | | (*buffer++) = (Char) ('0' + (exponent % 10)); |
57 | | (*buffer) = 0; |
58 | | return; |
59 | | } |
60 | | else if (decimal > 0) |
61 | | { |
62 | | // Simple number: A.B |
63 | | for (int i = 0; i < decimal; ++i) (*buffer++) = (*end++); |
64 | | if (decimal < digitCount) (*buffer++) = '.'; |
65 | | count = digitCount - decimal; |
66 | | } |
67 | | else if (decimal < -digitCount) |
68 | | { |
69 | | // What case is this? |
70 | | decimal = count = 0; |
71 | | } |
72 | | else if (decimal < 0 || (decimal == 0 && *end != '0')) |
73 | | { |
74 | | // Tiny number: 0.Me-X |
75 | | (*buffer++) = '0'; (*buffer++) = '.'; |
76 | | for (int i = 0; i < -decimal; ++i) (*buffer++) = '0'; |
77 | | count = digitCount + decimal; |
78 | | } |
79 | | for (; count > 0; --count) if (end[count - 1] != '0') break; |
80 | | for (int i = 0; i < count; ++i) (*buffer++) = (*end++); |
81 | | if (decimal == 0 && count == 0) (*buffer++) = '0'; |
82 | | if (buffer[-1] == '.') --buffer; |
83 | | (*buffer) = 0; |
84 | | } |
85 | | |
237 | | #ifdef WIN32 |
238 | | // use <float.h> _isnan method to detect the 1.#IND00 NaN. |
239 | | if (f != std::numeric_limits<float>::infinity() && f != -std::numeric_limits<float>::infinity() && f != std::numeric_limits<float>::quiet_NaN() && f != std::numeric_limits<float>::signaling_NaN() && !_isnan((double)f)) |
240 | | #else |
241 | | if (f != std::numeric_limits<float>::infinity() && f != -std::numeric_limits<float>::infinity() && f != std::numeric_limits<float>::quiet_NaN() && f != std::numeric_limits<float>::signaling_NaN()) |
242 | | #endif |
243 | | { |
244 | | if (IsEquivalent(f, 0.0f, std::numeric_limits<float>::epsilon())) append((Char)'0'); |
245 | | else |
246 | | { |
247 | | Char sz[128]; |
248 | | FloatToString(f, sz); |
249 | | append(sz + 1); |
250 | | } |
251 | | } |
252 | | else if (f == std::numeric_limits<float>::infinity()) |
253 | | { append((Char)'I'); append((Char)'N'); append((Char)'F'); } |
254 | | else if (f == -std::numeric_limits<float>::infinity()) |
255 | | { append((Char)'-'); append((Char)'I'); append((Char)'N'); append((Char)'F'); } |
256 | | else |
257 | | { append((Char)'N'); append((Char)'a'); append((Char)'N'); } |
| 180 | append((double)f); |
263 | | #ifdef WIN32 |
264 | | // use <float.h> _isnan method to detect the .#IND00 NaN. |
265 | | if (f != std::numeric_limits<float>::infinity() && f != -std::numeric_limits<float>::infinity() && f != std::numeric_limits<float>::quiet_NaN() && f != std::numeric_limits<float>::signaling_NaN() && !_isnan(f)) |
266 | | #else |
267 | | if (f != std::numeric_limits<float>::infinity() && f != -std::numeric_limits<float>::infinity() && f != std::numeric_limits<float>::quiet_NaN() && f != std::numeric_limits<float>::signaling_NaN()) |
268 | | #endif |
269 | | { |
270 | | if (IsEquivalent(f, 0.0, std::numeric_limits<double>::epsilon())) append((Char)'0'); |
271 | | else |
272 | | { |
273 | | Char sz[128]; |
274 | | FloatToString(f, sz); |
275 | | append(sz + 1); |
276 | | } |
| 186 | if (f == -std::numeric_limits<double>::infinity()) { |
| 187 | append("-INF"); |
| 188 | return; |
| 189 | } else if (f == std::numeric_limits<double>::infinity()) { |
| 190 | append("INF"); |
| 191 | return; |
| 192 | } else if (f != f) { |
| 193 | append("NaN"); |
| 194 | return; |
| 195 | } else if (-std::numeric_limits<double>::epsilon() < f && f < std::numeric_limits<double>::epsilon()) { |
| 196 | append("0.0E0"); |
| 197 | return; |
| 198 | } |
| 199 | |
| 200 | if (f < 0.0) { |
| 201 | f = -f; |
| 202 | append('-'); |