1 //===-- strtofloatingpoint comparison test --------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // #include "src/__support/str_float_conv_utils.h"
11 #include <stdlib.h> // For string to float functions
13 // #include "src/__support/FPUtil/FPBits.h"
20 // The intent of this test is to read in files in the format used in this test
21 // dataset: https://github.com/nigeltao/parse-number-fxx-test-data
22 // The format is as follows:
23 // Hexadecimal representations of IEEE754 floats in 16 bits, 32 bits, and 64
24 // bits, then the string that matches to them.
26 // 3C00 3F800000 3FF0000000000000 1.0
28 // By default, float_comp_in.txt is used as the test set, but once built this
29 // file can be run against the larger test set. To do that, clone the repository
30 // with the dataset, then navigate to the compiled binary of this file (it
31 // should be in llvm_project/build/bin). Run the following command:
32 // ./libc_str_to_float_comparison_test <path/to/dataset/repo>/data/*
33 // It will take a few seconds to run.
35 static inline uint32_t hexCharToU32(char in
) {
36 return in
> '9' ? in
+ 10 - 'A' : in
- '0';
39 // Fast because it assumes inStr points to exactly 8 uppercase hex chars
40 static inline uint32_t fastHexToU32(const char *inStr
) {
42 result
= (hexCharToU32(inStr
[0]) << 28) + (hexCharToU32(inStr
[1]) << 24) +
43 (hexCharToU32(inStr
[2]) << 20) + (hexCharToU32(inStr
[3]) << 16) +
44 (hexCharToU32(inStr
[4]) << 12) + (hexCharToU32(inStr
[5]) << 8) +
45 (hexCharToU32(inStr
[6]) << 4) + hexCharToU32(inStr
[7]);
49 // Fast because it assumes inStr points to exactly 8 uppercase hex chars
50 static inline uint64_t fastHexToU64(const char *inStr
) {
52 result
= (static_cast<uint64_t>(fastHexToU32(inStr
)) << 32) +
53 fastHexToU32(inStr
+ 8);
57 int checkFile(char *inputFileName
, int *totalFails
, int *totalBitDiffs
,
58 int *detailedBitDiffs
, int *total
) {
59 int32_t curFails
= 0; // Only counts actual failures, not bitdiffs.
60 int32_t curBitDiffs
= 0; // A bitdiff is when the expected result and actual
61 // result are off by +/- 1 bit.
65 std::ifstream
fileStream(inputFileName
, std::ifstream::in
);
67 if (!fileStream
.is_open()) {
68 std::cout
<< "file '" << inputFileName
<< "' failed to open. Exiting.\n";
71 while (getline(fileStream
, line
)) {
76 uint32_t expectedFloatRaw
;
77 uint64_t expectedDoubleRaw
;
79 expectedFloatRaw
= fastHexToU32(line
.c_str() + 5);
80 expectedDoubleRaw
= fastHexToU64(line
.c_str() + 14);
81 num
= line
.substr(31);
83 float floatResult
= strtof(num
.c_str(), nullptr);
85 double doubleResult
= strtod(num
.c_str(), nullptr);
87 uint32_t floatRaw
= *(uint32_t *)(&floatResult
);
89 uint64_t doubleRaw
= *(uint64_t *)(&doubleResult
);
91 if (!(expectedFloatRaw
== floatRaw
)) {
92 if (expectedFloatRaw
== floatRaw
+ 1 ||
93 expectedFloatRaw
== floatRaw
- 1) {
95 if (expectedFloatRaw
== floatRaw
+ 1) {
96 detailedBitDiffs
[0] = detailedBitDiffs
[0] + 1; // float low
98 detailedBitDiffs
[1] = detailedBitDiffs
[1] + 1; // float high
103 if (curFails
+ curBitDiffs
< 10) {
104 std::cout
<< "Float fail for '" << num
<< "'. Expected " << std::hex
105 << expectedFloatRaw
<< " but got " << floatRaw
<< "\n"
110 if (!(expectedDoubleRaw
== doubleRaw
)) {
111 if (expectedDoubleRaw
== doubleRaw
+ 1 ||
112 expectedDoubleRaw
== doubleRaw
- 1) {
114 if (expectedDoubleRaw
== doubleRaw
+ 1) {
115 detailedBitDiffs
[2] = detailedBitDiffs
[2] + 1; // double low
117 detailedBitDiffs
[3] = detailedBitDiffs
[3] + 1; // double high
122 if (curFails
+ curBitDiffs
< 10) {
123 std::cout
<< "Double fail for '" << num
<< "'. Expected " << std::hex
124 << expectedDoubleRaw
<< " but got " << doubleRaw
<< "\n"
132 *totalBitDiffs
+= curBitDiffs
;
133 *totalFails
+= curFails
;
135 if (curFails
> 1 || curBitDiffs
> 1) {
141 int main(int argc
, char *argv
[]) {
145 // Bitdiffs are cases where the expected result and actual result only differ
146 // by +/- the least significant bit. They are tracked separately from larger
147 // failures since a bitdiff is most likely the result of a rounding error, and
148 // splitting them off makes them easier to track down.
150 int detailedBitDiffs
[4] = {0, 0, 0, 0};
153 for (int i
= 1; i
< argc
; i
++) {
154 std::cout
<< "Starting file " << argv
[i
] << "\n";
156 checkFile(argv
[i
], &fails
, &bitdiffs
, detailedBitDiffs
, &total
);
157 if (curResult
== 1) {
160 } else if (curResult
== 2) {
164 std::cout
<< "Results:\n"
165 << "Total significant failed conversions: " << fails
<< "\n"
166 << "Total conversions off by +/- 1 bit: " << bitdiffs
<< "\n"
167 << "\t" << detailedBitDiffs
[0] << "\tfloat low\n"
168 << "\t" << detailedBitDiffs
[1] << "\tfloat high\n"
169 << "\t" << detailedBitDiffs
[2] << "\tdouble low\n"
170 << "\t" << detailedBitDiffs
[3] << "\tdouble high\n"
171 << "Total lines: " << total
<< "\n";