mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-07 01:06:48 +08:00
16-bit float support
This commit is contained in:
parent
00f25932b0
commit
ab7f0a0283
@ -10,6 +10,7 @@
|
|||||||
#ifdef __has_include
|
#ifdef __has_include
|
||||||
#if __has_include(<stdfloat>) && (__cplusplus > 202002L || _MSVC_LANG > 202002L)
|
#if __has_include(<stdfloat>) && (__cplusplus > 202002L || _MSVC_LANG > 202002L)
|
||||||
#include <stdfloat>
|
#include <stdfloat>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#include "constexpr_feature_detect.h"
|
#include "constexpr_feature_detect.h"
|
||||||
@ -202,6 +203,12 @@ fastfloat_really_inline constexpr bool is_supported_float_type() {
|
|||||||
#if __STDCPP_FLOAT64_T__
|
#if __STDCPP_FLOAT64_T__
|
||||||
|| std::is_same<T, std::float64_t>::value
|
|| std::is_same<T, std::float64_t>::value
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __STDCPP_FLOAT16_T__
|
||||||
|
|| std::is_same<T, std::float16_t>::value
|
||||||
|
#endif // __STDCPP_FLOAT16_T__
|
||||||
|
#ifdef _STDCPP_BFLOAT16
|
||||||
|
|| std::is_same<T, std::bfloat16_t>::value
|
||||||
|
#endif // _STDCPP_BFLOAT16
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,6 +563,157 @@ template <>
|
|||||||
inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
|
inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
|
||||||
return uint64_t(2) << mantissa_explicit_bits();
|
return uint64_t(2) << mantissa_explicit_bits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// credit: Jakub Jelínek
|
||||||
|
#ifdef __STDCPP_FLOAT16_T__
|
||||||
|
|
||||||
|
template <typename U> struct binary_format_lookup_tables<std::float16_t, U> {
|
||||||
|
static constexpr std::float16_t powers_of_ten[] = {};
|
||||||
|
static constexpr uint64_t max_mantissa[] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr std::float16_t
|
||||||
|
binary_format_lookup_tables<std::float16_t, U>::powers_of_ten[];
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr uint64_t
|
||||||
|
binary_format_lookup_tables<std::float16_t, U>::max_mantissa[];
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline constexpr int binary_format<std::float16_t>::max_exponent_fast_path() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline constexpr uint64_t
|
||||||
|
binary_format<std::float16_t>::max_mantissa_fast_path() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline constexpr int binary_format<std::float16_t>::min_exponent_fast_path() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::float16_t>::mantissa_explicit_bits() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::float16_t>::max_exponent_round_to_even() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::float16_t>::min_exponent_round_to_even() {
|
||||||
|
return -22;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> constexpr int binary_format<std::float16_t>::minimum_exponent() {
|
||||||
|
return -15;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> constexpr int binary_format<std::float16_t>::infinite_power() {
|
||||||
|
return 0x1F;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> constexpr int binary_format<std::float16_t>::sign_index() {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::float16_t>::largest_power_of_ten() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::float16_t>::smallest_power_of_ten() {
|
||||||
|
return -27;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> constexpr size_t binary_format<std::float16_t>::max_digits() {
|
||||||
|
return 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// credit: Jakub Jelínek
|
||||||
|
#ifdef __STDCPP_BFLOAT16_T__
|
||||||
|
|
||||||
|
template <typename U> struct binary_format_lookup_tables<std::bfloat16_t, U> {
|
||||||
|
static constexpr std::bfloat16_t powers_of_ten[] = {};
|
||||||
|
|
||||||
|
static constexpr uint64_t max_mantissa[] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr std::bfloat16_t
|
||||||
|
binary_format_lookup_tables<std::bfloat16_t, U>::powers_of_ten[];
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr uint64_t
|
||||||
|
binary_format_lookup_tables<std::bfloat16_t, U>::max_mantissa[];
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline constexpr int binary_format<std::bfloat16_t>::max_exponent_fast_path() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline constexpr uint64_t
|
||||||
|
binary_format<std::bfloat16_t>::max_mantissa_fast_path() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline constexpr int binary_format<std::bfloat16_t>::min_exponent_fast_path() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::bfloat16_t>::mantissa_explicit_bits() {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::bfloat16_t>::max_exponent_round_to_even() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::bfloat16_t>::min_exponent_round_to_even() {
|
||||||
|
return -24;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> constexpr int binary_format<std::bfloat16_t>::minimum_exponent() {
|
||||||
|
return -127;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> constexpr int binary_format<std::bfloat16_t>::infinite_power() {
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> constexpr int binary_format<std::bfloat16_t>::sign_index() {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::bfloat16_t>::largest_power_of_ten() {
|
||||||
|
return 38;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr int binary_format<std::bfloat16_t>::smallest_power_of_ten() {
|
||||||
|
return -60;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> constexpr size_t binary_format<std::bfloat16_t>::max_digits() {
|
||||||
|
return 98;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline constexpr uint64_t
|
inline constexpr uint64_t
|
||||||
binary_format<double>::max_mantissa_fast_path(int64_t power) {
|
binary_format<double>::max_mantissa_fast_path(int64_t power) {
|
||||||
|
|||||||
@ -182,7 +182,6 @@ template <> struct from_chars_caller<std::float64_t> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T, typename UC, typename>
|
template <typename T, typename UC, typename>
|
||||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||||
from_chars(UC const *first, UC const *last, T &value,
|
from_chars(UC const *first, UC const *last, T &value,
|
||||||
@ -199,12 +198,10 @@ from_chars(UC const *first, UC const *last, T &value,
|
|||||||
template <typename T, typename UC>
|
template <typename T, typename UC>
|
||||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||||
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
||||||
|
|
||||||
static_assert(is_supported_float_type<T>(),
|
static_assert(is_supported_float_type<T>(),
|
||||||
"only some floating-point types are supported");
|
"only some floating-point types are supported");
|
||||||
static_assert(is_supported_char_type<UC>(),
|
static_assert(is_supported_char_type<UC>(),
|
||||||
"only char, wchar_t, char16_t and char32_t are supported");
|
"only char, wchar_t, char16_t and char32_t are supported");
|
||||||
|
|
||||||
from_chars_result_t<UC> answer;
|
from_chars_result_t<UC> answer;
|
||||||
|
|
||||||
answer.ec = std::errc(); // be optimistic
|
answer.ec = std::errc(); // be optimistic
|
||||||
|
|||||||
@ -275,6 +275,16 @@ bool check_file(std::string file_name) {
|
|||||||
std::string str;
|
std::string str;
|
||||||
while (std::getline(newfile, str)) {
|
while (std::getline(newfile, str)) {
|
||||||
if (str.size() > 0) {
|
if (str.size() > 0) {
|
||||||
|
#ifdef __STDCPP_FLOAT16_T__
|
||||||
|
// Read 16-bit hex
|
||||||
|
uint16_t float16;
|
||||||
|
auto r16 = std::from_chars(str.data(), str.data() + str.size(),
|
||||||
|
float16, 16);
|
||||||
|
if (r16.ec != std::errc()) {
|
||||||
|
std::cerr << "16-bit parsing failure\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Read 32-bit hex
|
// Read 32-bit hex
|
||||||
uint32_t float32;
|
uint32_t float32;
|
||||||
auto r32 = std::from_chars(str.data() + 5, str.data() + str.size(),
|
auto r32 = std::from_chars(str.data() + 5, str.data() + str.size(),
|
||||||
@ -294,6 +304,17 @@ bool check_file(std::string file_name) {
|
|||||||
// The string to parse:
|
// The string to parse:
|
||||||
const char *number_string = str.data() + 31;
|
const char *number_string = str.data() + 31;
|
||||||
const char *end_of_string = str.data() + str.size();
|
const char *end_of_string = str.data() + str.size();
|
||||||
|
#ifdef __STDCPP_FLOAT16_T__
|
||||||
|
// Parse as 16-bit float
|
||||||
|
std::float16_t parsed_16{};
|
||||||
|
//auto fast_float_r16 =
|
||||||
|
fast_float::from_chars(number_string, end_of_string, parsed_16);
|
||||||
|
//if (fast_float_r16.ec != std::errc() &&
|
||||||
|
// fast_float_r16.ec != std::errc::result_out_of_range) {
|
||||||
|
//std::cerr << "16-bit fast_float parsing failure for: " + str + "\n";
|
||||||
|
//return false;
|
||||||
|
// }
|
||||||
|
#endif
|
||||||
// Parse as 32-bit float
|
// Parse as 32-bit float
|
||||||
float parsed_32;
|
float parsed_32;
|
||||||
auto fast_float_r32 =
|
auto fast_float_r32 =
|
||||||
@ -313,11 +334,29 @@ bool check_file(std::string file_name) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Convert the floats to unsigned ints.
|
// Convert the floats to unsigned ints.
|
||||||
|
#ifdef __STDCPP_FLOAT16_T__
|
||||||
|
uint16_t float16_parsed;
|
||||||
|
#endif
|
||||||
uint32_t float32_parsed;
|
uint32_t float32_parsed;
|
||||||
uint64_t float64_parsed;
|
uint64_t float64_parsed;
|
||||||
|
#ifdef __STDCPP_FLOAT16_T__
|
||||||
|
::memcpy(&float16_parsed, &parsed_16, sizeof(parsed_16));
|
||||||
|
|
||||||
|
#endif
|
||||||
::memcpy(&float32_parsed, &parsed_32, sizeof(parsed_32));
|
::memcpy(&float32_parsed, &parsed_32, sizeof(parsed_32));
|
||||||
::memcpy(&float64_parsed, &parsed_64, sizeof(parsed_64));
|
::memcpy(&float64_parsed, &parsed_64, sizeof(parsed_64));
|
||||||
// Compare with expected results
|
// Compare with expected results
|
||||||
|
#ifdef __STDCPP_FLOAT16_T__
|
||||||
|
if (float16_parsed != float16) {
|
||||||
|
std::cout << "bad 16 " << str << std::endl;
|
||||||
|
std::cout << "parsed as " << iHexAndDec(parsed_16) << std::endl;
|
||||||
|
std::cout << "as raw uint16_t, parsed = " << float16_parsed
|
||||||
|
<< ", expected = " << float16 << std::endl;
|
||||||
|
std::cout << "fesetround: " << round_name(d) << std::endl;
|
||||||
|
fesetround(FE_TONEAREST);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (float32_parsed != float32) {
|
if (float32_parsed != float32) {
|
||||||
std::cout << "bad 32 " << str << std::endl;
|
std::cout << "bad 32 " << str << std::endl;
|
||||||
std::cout << "parsed as " << iHexAndDec(parsed_32) << std::endl;
|
std::cout << "parsed as " << iHexAndDec(parsed_32) << std::endl;
|
||||||
|
|||||||
@ -81,9 +81,15 @@ bool small() {
|
|||||||
double result = -1;
|
double result = -1;
|
||||||
std::string str = "3e-1000";
|
std::string str = "3e-1000";
|
||||||
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
|
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
|
||||||
if(r.ec != std::errc::result_out_of_range) { return false; }
|
if (r.ec != std::errc::result_out_of_range) {
|
||||||
if(r.ptr != str.data() + 7) { return false; }
|
return false;
|
||||||
if(result != 0) { return false; }
|
}
|
||||||
|
if (r.ptr != str.data() + 7) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (result != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
printf("small values go to zero\n");
|
printf("small values go to zero\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -92,15 +98,21 @@ bool large() {
|
|||||||
double result = -1;
|
double result = -1;
|
||||||
std::string str = "3e1000";
|
std::string str = "3e1000";
|
||||||
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
|
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
|
||||||
if(r.ec != std::errc::result_out_of_range) { return false; }
|
if (r.ec != std::errc::result_out_of_range) {
|
||||||
if(r.ptr != str.data() + 6) { return false; }
|
return false;
|
||||||
if(result != std::numeric_limits<double>::infinity()) { return false; }
|
}
|
||||||
|
if (r.ptr != str.data() + 6) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (result != std::numeric_limits<double>::infinity()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
printf("large values go to infinity\n");
|
printf("large values go to infinity\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
const std::string input = "3.1416 xyz ";
|
std::string input = "3.1416 xyz ";
|
||||||
double result;
|
double result;
|
||||||
auto answer =
|
auto answer =
|
||||||
fast_float::from_chars(input.data(), input.data() + input.size(), result);
|
fast_float::from_chars(input.data(), input.data() + input.size(), result);
|
||||||
@ -109,6 +121,19 @@ int main() {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
std::cout << "parsed the number " << result << std::endl;
|
std::cout << "parsed the number " << result << std::endl;
|
||||||
|
#ifdef __STDCPP_FLOAT16_T__
|
||||||
|
// Parse as 16-bit float
|
||||||
|
std::float16_t parsed_16{};
|
||||||
|
input = "10000e-1452";
|
||||||
|
auto fast_float_r16 =
|
||||||
|
fast_float::from_chars(input.data(), input.data() + input.size(), parsed_16);
|
||||||
|
if (fast_float_r16.ec != std::errc() &&
|
||||||
|
fast_float_r16.ec != std::errc::result_out_of_range) {
|
||||||
|
std::cerr << "16-bit fast_float parsing failure for: " + input + "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::cout << "parsed the 16-bit value " << float(parsed_16) << std::endl;
|
||||||
|
#endif
|
||||||
if (!small()) {
|
if (!small()) {
|
||||||
printf("Bug\n");
|
printf("Bug\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user