#ifndef RYU_COMMON_H
#define RYU_COMMON_H
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
#if defined(_M_IX86) || defined(_M_ARM)
#define RYU_32_BIT_PLATFORM
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));
//
// -DRYU_AVOID_UINT128 Avoid using uint128_t. Slower, depending on your compiler.
-#include "ryu/ryu.h"
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
#ifdef RYU_DEBUG
-#include <inttypes.h>
-#include <stdio.h>
#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
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
// 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;
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=");
// 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;
}
}
}
+ if (exp_out) {
+ *exp_out = exp;
+ }
result[index++] = 'e';
if (exp < 0) {
result[index++] = '-';
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;
-}
#ifndef RYU_D2FIXED_FULL_TABLE_H
#define RYU_D2FIXED_FULL_TABLE_H
-#include <stdint.h>
#define TABLE_SIZE 64
// 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 <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
#ifdef RYU_DEBUG
-#include <inttypes.h>
-#include <stdio.h>
#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
// 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) {
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++] = '-';
}
}
// 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;
// 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);
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.
++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;
}
#ifndef RYU_D2S_INTRINSICS_H
#define RYU_D2S_INTRINSICS_H
-#include <assert.h>
-#include <stdint.h>
// 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.
#if defined(HAS_64_BIT_INTRINSICS)
-#include <intrin.h>
static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
return _umul128(a, b, productHi);
// Runtime compiler options:
// -DRYU_DEBUG Generate verbose debugging output to stdout.
-#include "ryu/ryu.h"
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
#ifdef RYU_DEBUG
-#include <stdio.h>
#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
// 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) {
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++] = '-';
}
}
// 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);
// 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;
}
#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)
#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) {
#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;
}
// 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;