Skip to content

Commit bfcff49

Browse files
lemiredalle
authored andcommitted
16-bit float support
1 parent 31cc0d1 commit bfcff49

File tree

3 files changed

+215
-6
lines changed

3 files changed

+215
-6
lines changed

include/fast_float/float_common.h

Lines changed: 162 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,21 @@ fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() {
221221

222222
template <typename T>
223223
struct is_supported_float_type
224-
: std::integral_constant<bool, std::is_same<T, float>::value ||
225-
std::is_same<T, double>::value
224+
: std::integral_constant<
225+
bool, std::is_same<T, float>::value || std::is_same<T, double>::value
226226
#ifdef __STDCPP_FLOAT32_T__
227-
|| std::is_same<T, std::float32_t>::value
227+
|| std::is_same<T, std::float32_t>::value
228228
#endif
229229
#ifdef __STDCPP_FLOAT64_T__
230-
|| std::is_same<T, std::float64_t>::value
230+
|| std::is_same<T, std::float64_t>::value
231231
#endif
232-
> {
232+
#ifdef __STDCPP_FLOAT16_T__
233+
|| std::is_same<T, std::float16_t>::value
234+
#endif
235+
#ifdef __STDCPP_BFLOAT16_T__
236+
|| std::is_same<T, std::bfloat16_t>::value
237+
#endif
238+
> {
233239
};
234240

235241
template <typename T>
@@ -622,6 +628,157 @@ inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
622628
return uint64_t(2) << mantissa_explicit_bits();
623629
}
624630

631+
// credit: Jakub Jelínek
632+
#ifdef __STDCPP_FLOAT16_T__
633+
634+
template <typename U> struct binary_format_lookup_tables<std::float16_t, U> {
635+
static constexpr std::float16_t powers_of_ten[] = {};
636+
static constexpr uint64_t max_mantissa[] = {};
637+
};
638+
639+
template <typename U>
640+
constexpr std::float16_t
641+
binary_format_lookup_tables<std::float16_t, U>::powers_of_ten[];
642+
643+
template <typename U>
644+
constexpr uint64_t
645+
binary_format_lookup_tables<std::float16_t, U>::max_mantissa[];
646+
647+
template <>
648+
inline constexpr int binary_format<std::float16_t>::max_exponent_fast_path() {
649+
return 0;
650+
}
651+
652+
template <>
653+
inline constexpr uint64_t
654+
binary_format<std::float16_t>::max_mantissa_fast_path() {
655+
return 0;
656+
}
657+
658+
template <>
659+
inline constexpr int binary_format<std::float16_t>::min_exponent_fast_path() {
660+
return 0;
661+
}
662+
663+
template <>
664+
constexpr int binary_format<std::float16_t>::mantissa_explicit_bits() {
665+
return 10;
666+
}
667+
668+
template <>
669+
constexpr int binary_format<std::float16_t>::max_exponent_round_to_even() {
670+
return 5;
671+
}
672+
673+
template <>
674+
constexpr int binary_format<std::float16_t>::min_exponent_round_to_even() {
675+
return -22;
676+
}
677+
678+
template <> constexpr int binary_format<std::float16_t>::minimum_exponent() {
679+
return -15;
680+
}
681+
682+
template <> constexpr int binary_format<std::float16_t>::infinite_power() {
683+
return 0x1F;
684+
}
685+
686+
template <> constexpr int binary_format<std::float16_t>::sign_index() {
687+
return 15;
688+
}
689+
690+
template <>
691+
constexpr int binary_format<std::float16_t>::largest_power_of_ten() {
692+
return 4;
693+
}
694+
695+
template <>
696+
constexpr int binary_format<std::float16_t>::smallest_power_of_ten() {
697+
return -27;
698+
}
699+
700+
template <> constexpr size_t binary_format<std::float16_t>::max_digits() {
701+
return 22;
702+
}
703+
704+
#endif
705+
706+
// credit: Jakub Jelínek
707+
#ifdef __STDCPP_BFLOAT16_T__
708+
709+
template <typename U> struct binary_format_lookup_tables<std::bfloat16_t, U> {
710+
static constexpr std::bfloat16_t powers_of_ten[] = {};
711+
712+
static constexpr uint64_t max_mantissa[] = {};
713+
};
714+
715+
template <typename U>
716+
constexpr std::bfloat16_t
717+
binary_format_lookup_tables<std::bfloat16_t, U>::powers_of_ten[];
718+
719+
template <typename U>
720+
constexpr uint64_t
721+
binary_format_lookup_tables<std::bfloat16_t, U>::max_mantissa[];
722+
723+
template <>
724+
inline constexpr int binary_format<std::bfloat16_t>::max_exponent_fast_path() {
725+
return 0;
726+
}
727+
728+
template <>
729+
inline constexpr uint64_t
730+
binary_format<std::bfloat16_t>::max_mantissa_fast_path() {
731+
return 0;
732+
}
733+
734+
template <>
735+
inline constexpr int binary_format<std::bfloat16_t>::min_exponent_fast_path() {
736+
return 0;
737+
}
738+
739+
template <>
740+
constexpr int binary_format<std::bfloat16_t>::mantissa_explicit_bits() {
741+
return 7;
742+
}
743+
744+
template <>
745+
constexpr int binary_format<std::bfloat16_t>::max_exponent_round_to_even() {
746+
return 3;
747+
}
748+
749+
template <>
750+
constexpr int binary_format<std::bfloat16_t>::min_exponent_round_to_even() {
751+
return -24;
752+
}
753+
754+
template <> constexpr int binary_format<std::bfloat16_t>::minimum_exponent() {
755+
return -127;
756+
}
757+
758+
template <> constexpr int binary_format<std::bfloat16_t>::infinite_power() {
759+
return 0xFF;
760+
}
761+
762+
template <> constexpr int binary_format<std::bfloat16_t>::sign_index() {
763+
return 15;
764+
}
765+
766+
template <>
767+
constexpr int binary_format<std::bfloat16_t>::largest_power_of_ten() {
768+
return 38;
769+
}
770+
771+
template <>
772+
constexpr int binary_format<std::bfloat16_t>::smallest_power_of_ten() {
773+
return -60;
774+
}
775+
776+
template <> constexpr size_t binary_format<std::bfloat16_t>::max_digits() {
777+
return 98;
778+
}
779+
780+
#endif
781+
625782
template <>
626783
inline constexpr uint64_t
627784
binary_format<double>::max_mantissa_fast_path(int64_t power) {

tests/basictest.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,16 @@ bool check_file(std::string file_name) {
275275
std::string str;
276276
while (std::getline(newfile, str)) {
277277
if (str.size() > 0) {
278+
#ifdef __STDCPP_FLOAT16_T__
279+
// Read 16-bit hex
280+
uint16_t float16;
281+
auto r16 =
282+
std::from_chars(str.data(), str.data() + str.size(), float16, 16);
283+
if (r16.ec != std::errc()) {
284+
std::cerr << "16-bit parsing failure\n";
285+
return false;
286+
}
287+
#endif
278288
// Read 32-bit hex
279289
uint32_t float32;
280290
auto r32 = std::from_chars(str.data() + 5, str.data() + str.size(),
@@ -294,6 +304,17 @@ bool check_file(std::string file_name) {
294304
// The string to parse:
295305
char const *number_string = str.data() + 31;
296306
char const *end_of_string = str.data() + str.size();
307+
#ifdef __STDCPP_FLOAT16_T__
308+
// Parse as 16-bit float
309+
std::float16_t parsed_16{};
310+
// auto fast_float_r16 =
311+
fast_float::from_chars(number_string, end_of_string, parsed_16);
312+
// if (fast_float_r16.ec != std::errc() &&
313+
// fast_float_r16.ec != std::errc::result_out_of_range) {
314+
// std::cerr << "16-bit fast_float parsing failure for: " + str +
315+
// "\n"; return false;
316+
// }
317+
#endif
297318
// Parse as 32-bit float
298319
float parsed_32;
299320
auto fast_float_r32 =
@@ -313,11 +334,29 @@ bool check_file(std::string file_name) {
313334
return false;
314335
}
315336
// Convert the floats to unsigned ints.
337+
#ifdef __STDCPP_FLOAT16_T__
338+
uint16_t float16_parsed;
339+
#endif
316340
uint32_t float32_parsed;
317341
uint64_t float64_parsed;
342+
#ifdef __STDCPP_FLOAT16_T__
343+
::memcpy(&float16_parsed, &parsed_16, sizeof(parsed_16));
344+
345+
#endif
318346
::memcpy(&float32_parsed, &parsed_32, sizeof(parsed_32));
319347
::memcpy(&float64_parsed, &parsed_64, sizeof(parsed_64));
320348
// Compare with expected results
349+
#ifdef __STDCPP_FLOAT16_T__
350+
if (float16_parsed != float16) {
351+
std::cout << "bad 16 " << str << std::endl;
352+
std::cout << "parsed as " << iHexAndDec(parsed_16) << std::endl;
353+
std::cout << "as raw uint16_t, parsed = " << float16_parsed
354+
<< ", expected = " << float16 << std::endl;
355+
std::cout << "fesetround: " << round_name(d) << std::endl;
356+
fesetround(FE_TONEAREST);
357+
return false;
358+
}
359+
#endif
321360
if (float32_parsed != float32) {
322361
std::cout << "bad 32 " << str << std::endl;
323362
std::cout << "parsed as " << iHexAndDec(parsed_32) << std::endl;

tests/example_test.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ bool large() {
112112
}
113113

114114
int main() {
115-
std::string const input = "3.1416 xyz ";
115+
std::string input = "3.1416 xyz ";
116116
double result;
117117
auto answer =
118118
fast_float::from_chars(input.data(), input.data() + input.size(), result);
@@ -121,6 +121,19 @@ int main() {
121121
return EXIT_FAILURE;
122122
}
123123
std::cout << "parsed the number " << result << std::endl;
124+
#ifdef __STDCPP_FLOAT16_T__
125+
// Parse as 16-bit float
126+
std::float16_t parsed_16{};
127+
input = "10000e-1452";
128+
auto fast_float_r16 = fast_float::from_chars(
129+
input.data(), input.data() + input.size(), parsed_16);
130+
if (fast_float_r16.ec != std::errc() &&
131+
fast_float_r16.ec != std::errc::result_out_of_range) {
132+
std::cerr << "16-bit fast_float parsing failure for: " + input + "\n";
133+
return false;
134+
}
135+
std::cout << "parsed the 16-bit value " << float(parsed_16) << std::endl;
136+
#endif
124137
if (!small()) {
125138
printf("Bug\n");
126139
return EXIT_FAILURE;

0 commit comments

Comments
 (0)