From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id 8E65B388C03B; Fri, 17 Jul 2020 04:27:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8E65B388C03B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1594960059; bh=JX90rPPlGwH5MQiNG5kQuOGAR2w62RbllOK/6C68MPQ=; h=From:To:Subject:Date:From; b=TRI4fh53HbM2pemrXVp45aH5Y7UUHi5woXLX1tirkj7YD+tMll+4fb/LE9wQHA3+l GyCbKW3MOkrPG+bPaAszYy+QOPdCCfNEpWPG+05ysMTPprG4AvCBr3gRUmB+zQlgOJ bhRj0Rk5XCXDG1n1bMmevqpt49EUQwof78z13Slg= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Patrick Palka To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc(refs/users/ppalka/heads/libstdcxx-floating-to_chars)] libstdc++: Apply modifications to our local copy of Ryu X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/users/ppalka/heads/libstdcxx-floating-to_chars X-Git-Oldrev: aab058ef1f29f85153179cc5ea87d75b83807e6b X-Git-Newrev: 85cc1de2bfa72d301e682be3b69059eeccfef89b Message-Id: <20200717042739.8E65B388C03B@sourceware.org> Date: Fri, 17 Jul 2020 04:27:39 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Jul 2020 04:27:39 -0000 https://gcc.gnu.org/g:85cc1de2bfa72d301e682be3b69059eeccfef89b commit 85cc1de2bfa72d301e682be3b69059eeccfef89b Author: Patrick Palka Date: Fri Jul 10 12:33:01 2020 -0400 libstdc++: Apply modifications to our local copy of Ryu This performs the following modifications to our local copy of Ryu in order to make it more easily usable for our std::to_chars implementation: * Remove all #includes * Remove copy_special_str routines * Adjust the exponent formatting to match printf * Remove some functions we're not going to use * Add an out-parameter to d2exp_buffered_n for the scientific exponent * Store the sign bit inside struct floating_decimal_[32|64] * Rename [df]2s_buffered_n and change their return type * Make generic_binary_to_decimal take the bit representation in parts libstdc++-v3/ChangeLog: * src/c++17/ryu/common.h, src/c++17/ryu/d2fixed.c, src/c++17/ryu/d2fixed_full_table.h, src/c++17/ryu/d2s.c, src/c++17/ryu/d2s_intrinsics.h, src/c++17/ryu/f2s.c, src/c++17/ryu/f2s_intrinsics.h: Apply local modifications. Diff: --- libstdc++-v3/src/c++17/ryu/common.h | 19 ----- libstdc++-v3/src/c++17/ryu/d2fixed.c | 98 ++----------------------- libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h | 1 - libstdc++-v3/src/c++17/ryu/d2s.c | 56 ++++---------- libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h | 4 - libstdc++-v3/src/c++17/ryu/f2s.c | 52 ++++--------- libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h | 4 - libstdc++-v3/src/c++17/ryu/generic_128.c | 47 ++---------- 8 files changed, 45 insertions(+), 236 deletions(-) diff --git a/libstdc++-v3/src/c++17/ryu/common.h b/libstdc++-v3/src/c++17/ryu/common.h index 7dc130947ac..f8ee147db04 100644 --- a/libstdc++-v3/src/c++17/ryu/common.h +++ b/libstdc++-v3/src/c++17/ryu/common.h @@ -17,9 +17,6 @@ #ifndef RYU_COMMON_H #define RYU_COMMON_H -#include -#include -#include #if defined(_M_IX86) || defined(_M_ARM) #define RYU_32_BIT_PLATFORM @@ -83,22 +80,6 @@ static inline uint32_t log10Pow5(const int32_t e) { return (((uint32_t) e) * 732923) >> 20; } -static inline int copy_special_str(char * const result, const bool sign, const bool exponent, const bool mantissa) { - if (mantissa) { - memcpy(result, "NaN", 3); - return 3; - } - if (sign) { - result[0] = '-'; - } - if (exponent) { - memcpy(result + sign, "Infinity", 8); - return sign + 8; - } - memcpy(result + sign, "0E0", 3); - return sign + 3; -} - static inline uint32_t float_to_bits(const float f) { uint32_t bits = 0; memcpy(&bits, &f, sizeof(float)); diff --git a/libstdc++-v3/src/c++17/ryu/d2fixed.c b/libstdc++-v3/src/c++17/ryu/d2fixed.c index 5f479abb91b..642a29d3010 100644 --- a/libstdc++-v3/src/c++17/ryu/d2fixed.c +++ b/libstdc++-v3/src/c++17/ryu/d2fixed.c @@ -23,23 +23,11 @@ // // -DRYU_AVOID_UINT128 Avoid using uint128_t. Slower, depending on your compiler. -#include "ryu/ryu.h" -#include -#include -#include -#include -#include #ifdef RYU_DEBUG -#include -#include #endif -#include "ryu/common.h" -#include "ryu/digit_table.h" -#include "ryu/d2fixed_full_table.h" -#include "ryu/d2s_intrinsics.h" #define DOUBLE_MANTISSA_BITS 52 #define DOUBLE_EXPONENT_BITS 11 @@ -328,33 +316,6 @@ static inline uint32_t lengthForIndex(const uint32_t idx) { return (log10Pow2(16 * (int32_t) idx) + 1 + 16 + 8) / 9; } -static inline int copy_special_str_printf(char* const result, const bool sign, const uint64_t mantissa) { -#if defined(_MSC_VER) - // TODO: Check that -nan is expected output on Windows. - if (sign) { - result[0] = '-'; - } - if (mantissa) { - if (mantissa < (1ull << (DOUBLE_MANTISSA_BITS - 1))) { - memcpy(result + sign, "nan(snan)", 9); - return sign + 9; - } - memcpy(result + sign, "nan", 3); - return sign + 3; - } -#else - if (mantissa) { - memcpy(result, "nan", 3); - return 3; - } - if (sign) { - result[0] = '-'; - } -#endif - memcpy(result + sign, "Infinity", 8); - return sign + 8; -} - int d2fixed_buffered_n(double d, uint32_t precision, char* result) { const uint64_t bits = double_to_bits(d); #ifdef RYU_DEBUG @@ -372,20 +333,10 @@ int d2fixed_buffered_n(double d, uint32_t precision, char* result) { // Case distinction; exit early for the easy cases. if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u)) { - return copy_special_str_printf(result, ieeeSign, ieeeMantissa); + __builtin_abort(); } if (ieeeExponent == 0 && ieeeMantissa == 0) { - int index = 0; - if (ieeeSign) { - result[index++] = '-'; - } - result[index++] = '0'; - if (precision > 0) { - result[index++] = '.'; - memset(result + index, '0', precision); - index += precision; - } - return index; + __builtin_abort(); } int32_t e2; @@ -549,21 +500,9 @@ int d2fixed_buffered_n(double d, uint32_t precision, char* result) { return index; } -void d2fixed_buffered(double d, uint32_t precision, char* result) { - const int len = d2fixed_buffered_n(d, precision, result); - result[len] = '\0'; -} - -char* d2fixed(double d, uint32_t precision) { - char* const buffer = (char*)malloc(2000); - const int index = d2fixed_buffered_n(d, precision, buffer); - buffer[index] = '\0'; - return buffer; -} - -int d2exp_buffered_n(double d, uint32_t precision, char* result) { +int d2exp_buffered_n(double d, uint32_t precision, char* result, int* exp_out) { const uint64_t bits = double_to_bits(d); #ifdef RYU_DEBUG printf("IN="); @@ -580,22 +519,10 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) { // Case distinction; exit early for the easy cases. if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u)) { - return copy_special_str_printf(result, ieeeSign, ieeeMantissa); + __builtin_abort(); } if (ieeeExponent == 0 && ieeeMantissa == 0) { - int index = 0; - if (ieeeSign) { - result[index++] = '-'; - } - result[index++] = '0'; - if (precision > 0) { - result[index++] = '.'; - memset(result + index, '0', precision); - index += precision; - } - memcpy(result + index, "e+00", 4); - index += 4; - return index; + __builtin_abort(); } int32_t e2; @@ -785,6 +712,9 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) { } } } + if (exp_out) { + *exp_out = exp; + } result[index++] = 'e'; if (exp < 0) { result[index++] = '-'; @@ -805,15 +735,3 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) { return index; } - -void d2exp_buffered(double d, uint32_t precision, char* result) { - const int len = d2exp_buffered_n(d, precision, result); - result[len] = '\0'; -} - -char* d2exp(double d, uint32_t precision) { - char* const buffer = (char*)malloc(2000); - const int index = d2exp_buffered_n(d, precision, buffer); - buffer[index] = '\0'; - return buffer; -} diff --git a/libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h b/libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h index 70857652161..1fa252959e6 100644 --- a/libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h +++ b/libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h @@ -17,7 +17,6 @@ #ifndef RYU_D2FIXED_FULL_TABLE_H #define RYU_D2FIXED_FULL_TABLE_H -#include #define TABLE_SIZE 64 diff --git a/libstdc++-v3/src/c++17/ryu/d2s.c b/libstdc++-v3/src/c++17/ryu/d2s.c index aa0da52da71..3225808c463 100644 --- a/libstdc++-v3/src/c++17/ryu/d2s.c +++ b/libstdc++-v3/src/c++17/ryu/d2s.c @@ -27,28 +27,15 @@ // size by about 10x (only one case, and only double) at the cost of some // performance. Currently requires MSVC intrinsics. -#include "ryu/ryu.h" -#include -#include -#include -#include -#include #ifdef RYU_DEBUG -#include -#include #endif -#include "ryu/common.h" -#include "ryu/digit_table.h" -#include "ryu/d2s_intrinsics.h" // Include either the small or the full lookup tables depending on the mode. #if defined(RYU_OPTIMIZE_SIZE) -#include "ryu/d2s_small_table.h" #else -#include "ryu/d2s_full_table.h" #endif #define DOUBLE_MANTISSA_BITS 52 @@ -86,9 +73,10 @@ typedef struct floating_decimal_64 { // Decimal exponent's range is -324 to 308 // inclusive, and can fit in a short if needed. int32_t exponent; + bool sign; } floating_decimal_64; -static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_t ieeeExponent) { +static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign) { int32_t e2; uint64_t m2; if (ieeeExponent == 0) { @@ -308,13 +296,14 @@ static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_ floating_decimal_64 fd; fd.exponent = exp; fd.mantissa = output; + fd.sign = ieeeSign; return fd; } -static inline int to_chars(const floating_decimal_64 v, const bool sign, char* const result) { +static inline int to_chars(const floating_decimal_64 v, char* const result) { // Step 5: Print the decimal representation. int index = 0; - if (sign) { + if (v.sign) { result[index++] = '-'; } @@ -397,29 +386,28 @@ static inline int to_chars(const floating_decimal_64 v, const bool sign, char* c } // Print the exponent. - result[index++] = 'E'; + result[index++] = 'e'; int32_t exp = v.exponent + (int32_t) olength - 1; if (exp < 0) { result[index++] = '-'; exp = -exp; - } + } else + result[index++] = '+'; if (exp >= 100) { const int32_t c = exp % 10; memcpy(result + index, DIGIT_TABLE + 2 * (exp / 10), 2); result[index + 2] = (char) ('0' + c); index += 3; - } else if (exp >= 10) { + } else { memcpy(result + index, DIGIT_TABLE + 2 * exp, 2); index += 2; - } else { - result[index++] = (char) ('0' + exp); } return index; } -static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent, +static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign, floating_decimal_64* const v) { const uint64_t m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa; const int32_t e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS; @@ -448,10 +436,11 @@ static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t iee // Note: since 2^53 < 10^16, there is no need to adjust decimalLength17(). v->mantissa = m2 >> -e2; v->exponent = 0; + v->sign = ieeeSign; return true; } -int d2s_buffered_n(double f, char* result) { +floating_decimal_64 floating_to_fd64(double f) { // Step 1: Decode the floating-point number, and unify normalized and subnormal cases. const uint64_t bits = double_to_bits(f); @@ -469,11 +458,11 @@ int d2s_buffered_n(double f, char* result) { const uint32_t ieeeExponent = (uint32_t) ((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1)); // Case distinction; exit early for the easy cases. if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) { - return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa); + __builtin_abort(); } floating_decimal_64 v; - const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, &v); + const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, ieeeSign, &v); if (isSmallInt) { // For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros. // For scientific notation we need to move these zeros into the exponent. @@ -489,21 +478,8 @@ int d2s_buffered_n(double f, char* result) { ++v.exponent; } } else { - v = d2d(ieeeMantissa, ieeeExponent); + v = d2d(ieeeMantissa, ieeeExponent, ieeeSign); } - return to_chars(v, ieeeSign, result); -} - -void d2s_buffered(double f, char* result) { - const int index = d2s_buffered_n(f, result); - - // Terminate the string. - result[index] = '\0'; -} - -char* d2s(double f) { - char* const result = (char*) malloc(25); - d2s_buffered(f, result); - return result; + return v; } diff --git a/libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h b/libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h index ea590a60d25..fa993e6fad6 100644 --- a/libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h +++ b/libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h @@ -17,11 +17,8 @@ #ifndef RYU_D2S_INTRINSICS_H #define RYU_D2S_INTRINSICS_H -#include -#include // Defines RYU_32_BIT_PLATFORM if applicable. -#include "ryu/common.h" // ABSL avoids uint128_t on Win32 even if __SIZEOF_INT128__ is defined. // Let's do the same for now. @@ -37,7 +34,6 @@ typedef __uint128_t uint128_t; #if defined(HAS_64_BIT_INTRINSICS) -#include static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) { return _umul128(a, b, productHi); diff --git a/libstdc++-v3/src/c++17/ryu/f2s.c b/libstdc++-v3/src/c++17/ryu/f2s.c index 255ecbe599c..5e635958aa1 100644 --- a/libstdc++-v3/src/c++17/ryu/f2s.c +++ b/libstdc++-v3/src/c++17/ryu/f2s.c @@ -18,22 +18,11 @@ // Runtime compiler options: // -DRYU_DEBUG Generate verbose debugging output to stdout. -#include "ryu/ryu.h" -#include -#include -#include -#include -#include -#include #ifdef RYU_DEBUG -#include #endif -#include "ryu/common.h" -#include "ryu/f2s_intrinsics.h" -#include "ryu/digit_table.h" #define FLOAT_MANTISSA_BITS 23 #define FLOAT_EXPONENT_BITS 8 @@ -45,9 +34,10 @@ typedef struct floating_decimal_32 { // Decimal exponent's range is -45 to 38 // inclusive, and can fit in a short if needed. int32_t exponent; + bool sign; } floating_decimal_32; -static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_t ieeeExponent) { +static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign) { int32_t e2; uint32_t m2; if (ieeeExponent == 0) { @@ -224,13 +214,14 @@ static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_ floating_decimal_32 fd; fd.exponent = exp; fd.mantissa = output; + fd.sign = ieeeSign; return fd; } -static inline int to_chars(const floating_decimal_32 v, const bool sign, char* const result) { +static inline int to_chars(const floating_decimal_32 v, char* const result) { // Step 5: Print the decimal representation. int index = 0; - if (sign) { + if (v.sign) { result[index++] = '-'; } @@ -288,24 +279,22 @@ static inline int to_chars(const floating_decimal_32 v, const bool sign, char* c } // Print the exponent. - result[index++] = 'E'; + result[index++] = 'e'; int32_t exp = v.exponent + (int32_t) olength - 1; if (exp < 0) { result[index++] = '-'; exp = -exp; - } - - if (exp >= 10) { - memcpy(result + index, DIGIT_TABLE + 2 * exp, 2); - index += 2; } else { - result[index++] = (char) ('0' + exp); + result[index++] = '+'; } + memcpy(result + index, DIGIT_TABLE + 2 * exp, 2); + index += 2; + return index; } -int f2s_buffered_n(float f, char* result) { +floating_decimal_32 floating_to_fd32(float f) { // Step 1: Decode the floating-point number, and unify normalized and subnormal cases. const uint32_t bits = float_to_bits(f); @@ -324,22 +313,9 @@ int f2s_buffered_n(float f, char* result) { // Case distinction; exit early for the easy cases. if (ieeeExponent == ((1u << FLOAT_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) { - return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa); + __builtin_abort(); } - const floating_decimal_32 v = f2d(ieeeMantissa, ieeeExponent); - return to_chars(v, ieeeSign, result); -} - -void f2s_buffered(float f, char* result) { - const int index = f2s_buffered_n(f, result); - - // Terminate the string. - result[index] = '\0'; -} - -char* f2s(float f) { - char* const result = (char*) malloc(16); - f2s_buffered(f, result); - return result; + const floating_decimal_32 v = f2d(ieeeMantissa, ieeeExponent, ieeeSign); + return v; } diff --git a/libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h b/libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h index bb822c9a0c0..db751a41329 100644 --- a/libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h +++ b/libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h @@ -18,18 +18,14 @@ #define RYU_F2S_INTRINSICS_H // Defines RYU_32_BIT_PLATFORM if applicable. -#include "ryu/common.h" #if defined(RYU_FLOAT_FULL_TABLE) -#include "ryu/f2s_full_table.h" #else #if defined(RYU_OPTIMIZE_SIZE) -#include "ryu/d2s_small_table.h" #else -#include "ryu/d2s_full_table.h" #endif #define FLOAT_POW5_INV_BITCOUNT (DOUBLE_POW5_INV_BITCOUNT - 64) #define FLOAT_POW5_BITCOUNT (DOUBLE_POW5_BITCOUNT - 64) diff --git a/libstdc++-v3/src/c++17/ryu/generic_128.c b/libstdc++-v3/src/c++17/ryu/generic_128.c index 2eb8da8aba8..17c1567a6a1 100644 --- a/libstdc++-v3/src/c++17/ryu/generic_128.c +++ b/libstdc++-v3/src/c++17/ryu/generic_128.c @@ -37,42 +37,9 @@ static char* s(uint128_t v) { #define ONE ((uint128_t) 1) -#define FLOAT_MANTISSA_BITS 23 -#define FLOAT_EXPONENT_BITS 8 - -struct floating_decimal_128 float_to_fd128(float f) { - uint32_t bits = 0; - memcpy(&bits, &f, sizeof(float)); - return generic_binary_to_decimal(bits, FLOAT_MANTISSA_BITS, FLOAT_EXPONENT_BITS, false); -} - -#define DOUBLE_MANTISSA_BITS 52 -#define DOUBLE_EXPONENT_BITS 11 - -struct floating_decimal_128 double_to_fd128(double d) { - uint64_t bits = 0; - memcpy(&bits, &d, sizeof(double)); - return generic_binary_to_decimal(bits, DOUBLE_MANTISSA_BITS, DOUBLE_EXPONENT_BITS, false); -} - -#define LONG_DOUBLE_MANTISSA_BITS 64 -#define LONG_DOUBLE_EXPONENT_BITS 15 - -struct floating_decimal_128 long_double_to_fd128(long double d) { - uint128_t bits = 0; - memcpy(&bits, &d, sizeof(long double)); -#ifdef RYU_DEBUG - // For some odd reason, this ends up with noise in the top 48 bits. We can - // clear out those bits with the following line; this is not required, the - // conversion routine should ignore those bits, but the debug output can be - // confusing if they aren't 0s. - bits &= (ONE << 80) - 1; -#endif - return generic_binary_to_decimal(bits, LONG_DOUBLE_MANTISSA_BITS, LONG_DOUBLE_EXPONENT_BITS, true); -} - struct floating_decimal_128 generic_binary_to_decimal( - const uint128_t bits, const uint32_t mantissaBits, const uint32_t exponentBits, const bool explicitLeadingBit) { + const uint128_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign, + const uint32_t mantissaBits, const uint32_t exponentBits, const bool explicitLeadingBit) { #ifdef RYU_DEBUG printf("IN="); for (int32_t bit = 127; bit >= 0; --bit) { @@ -82,9 +49,6 @@ struct floating_decimal_128 generic_binary_to_decimal( #endif const uint32_t bias = (1u << (exponentBits - 1)) - 1; - const bool ieeeSign = ((bits >> (mantissaBits + exponentBits)) & 1) != 0; - const uint128_t ieeeMantissa = bits & ((ONE << mantissaBits) - 1); - const uint32_t ieeeExponent = (uint32_t) ((bits >> mantissaBits) & ((ONE << exponentBits) - 1u)); if (ieeeExponent == 0 && ieeeMantissa == 0) { struct floating_decimal_128 fd; @@ -320,14 +284,17 @@ int generic_to_chars(const struct floating_decimal_128 v, char* const result) { } // Print the exponent. - result[index++] = 'E'; + result[index++] = 'e'; int32_t exp = v.exponent + olength - 1; if (exp < 0) { result[index++] = '-'; exp = -exp; - } + } else + result[index++] = '+'; uint32_t elength = decimalLength(exp); + if (elength == 1) + ++elength; for (uint32_t i = 0; i < elength; ++i) { const uint32_t c = exp % 10; exp /= 10;