dtoa.h (rapidjson-1.0.2) | : | dtoa.h (rapidjson-1.1.0) | ||
---|---|---|---|---|
skipping to change at line 32 | skipping to change at line 32 | |||
#include "itoa.h" // GetDigitsLut() | #include "itoa.h" // GetDigitsLut() | |||
#include "diyfp.h" | #include "diyfp.h" | |||
#include "ieee754.h" | #include "ieee754.h" | |||
RAPIDJSON_NAMESPACE_BEGIN | RAPIDJSON_NAMESPACE_BEGIN | |||
namespace internal { | namespace internal { | |||
#ifdef __GNUC__ | #ifdef __GNUC__ | |||
RAPIDJSON_DIAG_PUSH | RAPIDJSON_DIAG_PUSH | |||
RAPIDJSON_DIAG_OFF(effc++) | RAPIDJSON_DIAG_OFF(effc++) | |||
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings ht tps://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 | ||||
#endif | #endif | |||
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin t64_t ten_kappa, uint64_t wp_w) { | inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin t64_t ten_kappa, uint64_t wp_w) { | |||
while (rest < wp_w && delta - rest >= ten_kappa && | while (rest < wp_w && delta - rest >= ten_kappa && | |||
(rest + ten_kappa < wp_w || /// closer | (rest + ten_kappa < wp_w || /// closer | |||
wp_w - rest > rest + ten_kappa - wp_w)) { | wp_w - rest > rest + ten_kappa - wp_w)) { | |||
buffer[len - 1]--; | buffer[len - 1]--; | |||
rest += ten_kappa; | rest += ten_kappa; | |||
} | } | |||
} | } | |||
skipping to change at line 65 | skipping to change at line 66 | |||
//return 10; | //return 10; | |||
return 9; | return 9; | |||
} | } | |||
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff er, int* len, int* K) { | inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff er, int* len, int* K) { | |||
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; | static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; | |||
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); | const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); | |||
const DiyFp wp_w = Mp - W; | const DiyFp wp_w = Mp - W; | |||
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); | uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); | |||
uint64_t p2 = Mp.f & (one.f - 1); | uint64_t p2 = Mp.f & (one.f - 1); | |||
int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] | unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] | |||
*len = 0; | *len = 0; | |||
while (kappa > 0) { | while (kappa > 0) { | |||
uint32_t d = 0; | uint32_t d = 0; | |||
switch (kappa) { | switch (kappa) { | |||
case 9: d = p1 / 100000000; p1 %= 100000000; break; | case 9: d = p1 / 100000000; p1 %= 100000000; break; | |||
case 8: d = p1 / 10000000; p1 %= 10000000; break; | case 8: d = p1 / 10000000; p1 %= 10000000; break; | |||
case 7: d = p1 / 1000000; p1 %= 1000000; break; | case 7: d = p1 / 1000000; p1 %= 1000000; break; | |||
case 6: d = p1 / 100000; p1 %= 100000; break; | case 6: d = p1 / 100000; p1 %= 100000; break; | |||
case 5: d = p1 / 10000; p1 %= 10000; break; | case 5: d = p1 / 10000; p1 %= 10000; break; | |||
skipping to change at line 104 | skipping to change at line 105 | |||
for (;;) { | for (;;) { | |||
p2 *= 10; | p2 *= 10; | |||
delta *= 10; | delta *= 10; | |||
char d = static_cast<char>(p2 >> -one.e); | char d = static_cast<char>(p2 >> -one.e); | |||
if (d || *len) | if (d || *len) | |||
buffer[(*len)++] = static_cast<char>('0' + d); | buffer[(*len)++] = static_cast<char>('0' + d); | |||
p2 &= one.f - 1; | p2 &= one.f - 1; | |||
kappa--; | kappa--; | |||
if (p2 < delta) { | if (p2 < delta) { | |||
*K += kappa; | *K += kappa; | |||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); | int index = -static_cast<int>(kappa); | |||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPo | ||||
w10[-static_cast<int>(kappa)] : 0)); | ||||
return; | return; | |||
} | } | |||
} | } | |||
} | } | |||
inline void Grisu2(double value, char* buffer, int* length, int* K) { | inline void Grisu2(double value, char* buffer, int* length, int* K) { | |||
const DiyFp v(value); | const DiyFp v(value); | |||
DiyFp w_m, w_p; | DiyFp w_m, w_p; | |||
v.NormalizedBoundaries(&w_m, &w_p); | v.NormalizedBoundaries(&w_m, &w_p); | |||
skipping to change at line 148 | skipping to change at line 150 | |||
const char* d = GetDigitsLut() + K * 2; | const char* d = GetDigitsLut() + K * 2; | |||
*buffer++ = d[0]; | *buffer++ = d[0]; | |||
*buffer++ = d[1]; | *buffer++ = d[1]; | |||
} | } | |||
else | else | |||
*buffer++ = static_cast<char>('0' + static_cast<char>(K)); | *buffer++ = static_cast<char>('0' + static_cast<char>(K)); | |||
return buffer; | return buffer; | |||
} | } | |||
inline char* Prettify(char* buffer, int length, int k) { | inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { | |||
const int kk = length + k; // 10^(kk-1) <= v < 10^kk | const int kk = length + k; // 10^(kk-1) <= v < 10^kk | |||
if (length <= kk && kk <= 21) { | if (0 <= k && kk <= 21) { | |||
// 1234e7 -> 12340000000 | // 1234e7 -> 12340000000 | |||
for (int i = length; i < kk; i++) | for (int i = length; i < kk; i++) | |||
buffer[i] = '0'; | buffer[i] = '0'; | |||
buffer[kk] = '.'; | buffer[kk] = '.'; | |||
buffer[kk + 1] = '0'; | buffer[kk + 1] = '0'; | |||
return &buffer[kk + 2]; | return &buffer[kk + 2]; | |||
} | } | |||
else if (0 < kk && kk <= 21) { | else if (0 < kk && kk <= 21) { | |||
// 1234e-2 -> 12.34 | // 1234e-2 -> 12.34 | |||
std::memmove(&buffer[kk + 1], &buffer[kk], length - kk); | std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk)); | |||
buffer[kk] = '.'; | buffer[kk] = '.'; | |||
return &buffer[length + 1]; | if (0 > k + maxDecimalPlaces) { | |||
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 | ||||
// Remove extra trailing zeros (at least one) after truncation. | ||||
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) | ||||
if (buffer[i] != '0') | ||||
return &buffer[i + 1]; | ||||
return &buffer[kk + 2]; // Reserve one zero | ||||
} | ||||
else | ||||
return &buffer[length + 1]; | ||||
} | } | |||
else if (-6 < kk && kk <= 0) { | else if (-6 < kk && kk <= 0) { | |||
// 1234e-6 -> 0.001234 | // 1234e-6 -> 0.001234 | |||
const int offset = 2 - kk; | const int offset = 2 - kk; | |||
std::memmove(&buffer[offset], &buffer[0], length); | std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length)); | |||
buffer[0] = '0'; | buffer[0] = '0'; | |||
buffer[1] = '.'; | buffer[1] = '.'; | |||
for (int i = 2; i < offset; i++) | for (int i = 2; i < offset; i++) | |||
buffer[i] = '0'; | buffer[i] = '0'; | |||
return &buffer[length + offset]; | if (length - kk > maxDecimalPlaces) { | |||
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 | ||||
// Remove extra trailing zeros (at least one) after truncation. | ||||
for (int i = maxDecimalPlaces + 1; i > 2; i--) | ||||
if (buffer[i] != '0') | ||||
return &buffer[i + 1]; | ||||
return &buffer[3]; // Reserve one zero | ||||
} | ||||
else | ||||
return &buffer[length + offset]; | ||||
} | ||||
else if (kk < -maxDecimalPlaces) { | ||||
// Truncate to zero | ||||
buffer[0] = '0'; | ||||
buffer[1] = '.'; | ||||
buffer[2] = '0'; | ||||
return &buffer[3]; | ||||
} | } | |||
else if (length == 1) { | else if (length == 1) { | |||
// 1e30 | // 1e30 | |||
buffer[1] = 'e'; | buffer[1] = 'e'; | |||
return WriteExponent(kk - 1, &buffer[2]); | return WriteExponent(kk - 1, &buffer[2]); | |||
} | } | |||
else { | else { | |||
// 1234e30 -> 1.234e33 | // 1234e30 -> 1.234e33 | |||
std::memmove(&buffer[2], &buffer[1], length - 1); | std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1)); | |||
buffer[1] = '.'; | buffer[1] = '.'; | |||
buffer[length + 1] = 'e'; | buffer[length + 1] = 'e'; | |||
return WriteExponent(kk - 1, &buffer[0 + length + 2]); | return WriteExponent(kk - 1, &buffer[0 + length + 2]); | |||
} | } | |||
} | } | |||
inline char* dtoa(double value, char* buffer) { | inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { | |||
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); | ||||
Double d(value); | Double d(value); | |||
if (d.IsZero()) { | if (d.IsZero()) { | |||
if (d.Sign()) | if (d.Sign()) | |||
*buffer++ = '-'; // -0.0, Issue #289 | *buffer++ = '-'; // -0.0, Issue #289 | |||
buffer[0] = '0'; | buffer[0] = '0'; | |||
buffer[1] = '.'; | buffer[1] = '.'; | |||
buffer[2] = '0'; | buffer[2] = '0'; | |||
return &buffer[3]; | return &buffer[3]; | |||
} | } | |||
else { | else { | |||
if (value < 0) { | if (value < 0) { | |||
*buffer++ = '-'; | *buffer++ = '-'; | |||
value = -value; | value = -value; | |||
} | } | |||
int length, K; | int length, K; | |||
Grisu2(value, buffer, &length, &K); | Grisu2(value, buffer, &length, &K); | |||
return Prettify(buffer, length, K); | return Prettify(buffer, length, K, maxDecimalPlaces); | |||
} | } | |||
} | } | |||
#ifdef __GNUC__ | #ifdef __GNUC__ | |||
RAPIDJSON_DIAG_POP | RAPIDJSON_DIAG_POP | |||
#endif | #endif | |||
} // namespace internal | } // namespace internal | |||
RAPIDJSON_NAMESPACE_END | RAPIDJSON_NAMESPACE_END | |||
End of changes. 12 change blocks. | ||||
11 lines changed or deleted | 40 lines changed or added |