hex_float_test.cpp 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. // Copyright (c) 2015-2016 The Khronos Group Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <cfloat>
  15. #include <cmath>
  16. #include <cstdio>
  17. #include <limits>
  18. #include <sstream>
  19. #include <string>
  20. #include <tuple>
  21. #include <utility>
  22. #include <vector>
  23. #include "gmock/gmock.h"
  24. #include "source/util/hex_float.h"
  25. #include "test/unit_spirv.h"
  26. namespace spvtools {
  27. namespace utils {
  28. namespace {
  29. using ::testing::Eq;
  30. // In this file "encode" means converting a number into a string,
  31. // and "decode" means converting a string into a number.
  32. using HexFloatTest =
  33. ::testing::TestWithParam<std::pair<FloatProxy<float>, std::string>>;
  34. using DecodeHexFloatTest =
  35. ::testing::TestWithParam<std::pair<std::string, FloatProxy<float>>>;
  36. using HexDoubleTest =
  37. ::testing::TestWithParam<std::pair<FloatProxy<double>, std::string>>;
  38. using DecodeHexDoubleTest =
  39. ::testing::TestWithParam<std::pair<std::string, FloatProxy<double>>>;
  40. using RoundTripFloatTest = ::testing::TestWithParam<float>;
  41. using RoundTripDoubleTest = ::testing::TestWithParam<double>;
  42. // Hex-encodes a float value.
  43. template <typename T>
  44. std::string EncodeViaHexFloat(const T& value) {
  45. std::stringstream ss;
  46. ss << HexFloat<T>(value);
  47. return ss.str();
  48. }
  49. // The following two tests can't be DRY because they take different parameter
  50. // types.
  51. TEST_P(HexFloatTest, EncodeCorrectly) {
  52. EXPECT_THAT(EncodeViaHexFloat(GetParam().first), Eq(GetParam().second));
  53. }
  54. TEST_P(HexDoubleTest, EncodeCorrectly) {
  55. EXPECT_THAT(EncodeViaHexFloat(GetParam().first), Eq(GetParam().second));
  56. }
  57. // Decodes a hex-float string.
  58. template <typename T>
  59. FloatProxy<T> Decode(const std::string& str) {
  60. HexFloat<FloatProxy<T>> decoded(0.f);
  61. EXPECT_TRUE((std::stringstream(str) >> decoded).eof());
  62. return decoded.value();
  63. }
  64. TEST_P(HexFloatTest, DecodeCorrectly) {
  65. EXPECT_THAT(Decode<float>(GetParam().second), Eq(GetParam().first));
  66. }
  67. TEST_P(HexDoubleTest, DecodeCorrectly) {
  68. EXPECT_THAT(Decode<double>(GetParam().second), Eq(GetParam().first));
  69. }
  70. INSTANTIATE_TEST_SUITE_P(
  71. Float32Tests, HexFloatTest,
  72. ::testing::ValuesIn(std::vector<std::pair<FloatProxy<float>, std::string>>({
  73. {0.f, "0x0p+0"},
  74. {1.f, "0x1p+0"},
  75. {2.f, "0x1p+1"},
  76. {3.f, "0x1.8p+1"},
  77. {0.5f, "0x1p-1"},
  78. {0.25f, "0x1p-2"},
  79. {0.75f, "0x1.8p-1"},
  80. {-0.f, "-0x0p+0"},
  81. {-1.f, "-0x1p+0"},
  82. {-0.5f, "-0x1p-1"},
  83. {-0.25f, "-0x1p-2"},
  84. {-0.75f, "-0x1.8p-1"},
  85. // Larger numbers
  86. {512.f, "0x1p+9"},
  87. {-512.f, "-0x1p+9"},
  88. {1024.f, "0x1p+10"},
  89. {-1024.f, "-0x1p+10"},
  90. {1024.f + 8.f, "0x1.02p+10"},
  91. {-1024.f - 8.f, "-0x1.02p+10"},
  92. // Small numbers
  93. {1.0f / 512.f, "0x1p-9"},
  94. {1.0f / -512.f, "-0x1p-9"},
  95. {1.0f / 1024.f, "0x1p-10"},
  96. {1.0f / -1024.f, "-0x1p-10"},
  97. {1.0f / 1024.f + 1.0f / 8.f, "0x1.02p-3"},
  98. {1.0f / -1024.f - 1.0f / 8.f, "-0x1.02p-3"},
  99. // lowest non-denorm
  100. {float(ldexp(1.0f, -126)), "0x1p-126"},
  101. {float(ldexp(-1.0f, -126)), "-0x1p-126"},
  102. // Denormalized values
  103. {float(ldexp(1.0f, -127)), "0x1p-127"},
  104. {float(ldexp(1.0f, -127) / 2.0f), "0x1p-128"},
  105. {float(ldexp(1.0f, -127) / 4.0f), "0x1p-129"},
  106. {float(ldexp(1.0f, -127) / 8.0f), "0x1p-130"},
  107. {float(ldexp(-1.0f, -127)), "-0x1p-127"},
  108. {float(ldexp(-1.0f, -127) / 2.0f), "-0x1p-128"},
  109. {float(ldexp(-1.0f, -127) / 4.0f), "-0x1p-129"},
  110. {float(ldexp(-1.0f, -127) / 8.0f), "-0x1p-130"},
  111. {float(ldexp(1.0, -127) + (ldexp(1.0, -127) / 2.0f)), "0x1.8p-127"},
  112. {float(ldexp(1.0, -127) / 2.0 + (ldexp(1.0, -127) / 4.0f)),
  113. "0x1.8p-128"},
  114. })));
  115. INSTANTIATE_TEST_SUITE_P(
  116. Float32NanTests, HexFloatTest,
  117. ::testing::ValuesIn(std::vector<std::pair<FloatProxy<float>, std::string>>({
  118. // Various NAN and INF cases
  119. {uint32_t(0xFF800000), "-0x1p+128"}, // -inf
  120. {uint32_t(0x7F800000), "0x1p+128"}, // inf
  121. {uint32_t(0xFFC00000), "-0x1.8p+128"}, // -nan
  122. {uint32_t(0xFF800100), "-0x1.0002p+128"}, // -nan
  123. {uint32_t(0xFF800c00), "-0x1.0018p+128"}, // -nan
  124. {uint32_t(0xFF80F000), "-0x1.01ep+128"}, // -nan
  125. {uint32_t(0xFFFFFFFF), "-0x1.fffffep+128"}, // -nan
  126. {uint32_t(0x7FC00000), "0x1.8p+128"}, // +nan
  127. {uint32_t(0x7F800100), "0x1.0002p+128"}, // +nan
  128. {uint32_t(0x7f800c00), "0x1.0018p+128"}, // +nan
  129. {uint32_t(0x7F80F000), "0x1.01ep+128"}, // +nan
  130. {uint32_t(0x7FFFFFFF), "0x1.fffffep+128"}, // +nan
  131. })));
  132. INSTANTIATE_TEST_SUITE_P(
  133. Float64Tests, HexDoubleTest,
  134. ::testing::ValuesIn(
  135. std::vector<std::pair<FloatProxy<double>, std::string>>({
  136. {0., "0x0p+0"},
  137. {1., "0x1p+0"},
  138. {2., "0x1p+1"},
  139. {3., "0x1.8p+1"},
  140. {0.5, "0x1p-1"},
  141. {0.25, "0x1p-2"},
  142. {0.75, "0x1.8p-1"},
  143. {-0., "-0x0p+0"},
  144. {-1., "-0x1p+0"},
  145. {-0.5, "-0x1p-1"},
  146. {-0.25, "-0x1p-2"},
  147. {-0.75, "-0x1.8p-1"},
  148. // Larger numbers
  149. {512., "0x1p+9"},
  150. {-512., "-0x1p+9"},
  151. {1024., "0x1p+10"},
  152. {-1024., "-0x1p+10"},
  153. {1024. + 8., "0x1.02p+10"},
  154. {-1024. - 8., "-0x1.02p+10"},
  155. // Large outside the range of normal floats
  156. {ldexp(1.0, 128), "0x1p+128"},
  157. {ldexp(1.0, 129), "0x1p+129"},
  158. {ldexp(-1.0, 128), "-0x1p+128"},
  159. {ldexp(-1.0, 129), "-0x1p+129"},
  160. {ldexp(1.0, 128) + ldexp(1.0, 90), "0x1.0000000004p+128"},
  161. {ldexp(1.0, 129) + ldexp(1.0, 120), "0x1.008p+129"},
  162. {ldexp(-1.0, 128) + ldexp(1.0, 90), "-0x1.fffffffff8p+127"},
  163. {ldexp(-1.0, 129) + ldexp(1.0, 120), "-0x1.ffp+128"},
  164. // Small numbers
  165. {1.0 / 512., "0x1p-9"},
  166. {1.0 / -512., "-0x1p-9"},
  167. {1.0 / 1024., "0x1p-10"},
  168. {1.0 / -1024., "-0x1p-10"},
  169. {1.0 / 1024. + 1.0 / 8., "0x1.02p-3"},
  170. {1.0 / -1024. - 1.0 / 8., "-0x1.02p-3"},
  171. // Small outside the range of normal floats
  172. {ldexp(1.0, -128), "0x1p-128"},
  173. {ldexp(1.0, -129), "0x1p-129"},
  174. {ldexp(-1.0, -128), "-0x1p-128"},
  175. {ldexp(-1.0, -129), "-0x1p-129"},
  176. {ldexp(1.0, -128) + ldexp(1.0, -90), "0x1.0000000004p-90"},
  177. {ldexp(1.0, -129) + ldexp(1.0, -120), "0x1.008p-120"},
  178. {ldexp(-1.0, -128) + ldexp(1.0, -90), "0x1.fffffffff8p-91"},
  179. {ldexp(-1.0, -129) + ldexp(1.0, -120), "0x1.ffp-121"},
  180. // lowest non-denorm
  181. {ldexp(1.0, -1022), "0x1p-1022"},
  182. {ldexp(-1.0, -1022), "-0x1p-1022"},
  183. // Denormalized values
  184. {ldexp(1.0, -1023), "0x1p-1023"},
  185. {ldexp(1.0, -1023) / 2.0, "0x1p-1024"},
  186. {ldexp(1.0, -1023) / 4.0, "0x1p-1025"},
  187. {ldexp(1.0, -1023) / 8.0, "0x1p-1026"},
  188. {ldexp(-1.0, -1024), "-0x1p-1024"},
  189. {ldexp(-1.0, -1024) / 2.0, "-0x1p-1025"},
  190. {ldexp(-1.0, -1024) / 4.0, "-0x1p-1026"},
  191. {ldexp(-1.0, -1024) / 8.0, "-0x1p-1027"},
  192. {ldexp(1.0, -1023) + (ldexp(1.0, -1023) / 2.0), "0x1.8p-1023"},
  193. {ldexp(1.0, -1023) / 2.0 + (ldexp(1.0, -1023) / 4.0),
  194. "0x1.8p-1024"},
  195. })));
  196. INSTANTIATE_TEST_SUITE_P(
  197. Float64NanTests, HexDoubleTest,
  198. ::testing::ValuesIn(std::vector<
  199. std::pair<FloatProxy<double>, std::string>>({
  200. // Various NAN and INF cases
  201. {uint64_t(0xFFF0000000000000LL), "-0x1p+1024"}, // -inf
  202. {uint64_t(0x7FF0000000000000LL), "0x1p+1024"}, // +inf
  203. {uint64_t(0xFFF8000000000000LL), "-0x1.8p+1024"}, // -nan
  204. {uint64_t(0xFFF0F00000000000LL), "-0x1.0fp+1024"}, // -nan
  205. {uint64_t(0xFFF0000000000001LL), "-0x1.0000000000001p+1024"}, // -nan
  206. {uint64_t(0xFFF0000300000000LL), "-0x1.00003p+1024"}, // -nan
  207. {uint64_t(0xFFFFFFFFFFFFFFFFLL), "-0x1.fffffffffffffp+1024"}, // -nan
  208. {uint64_t(0x7FF8000000000000LL), "0x1.8p+1024"}, // +nan
  209. {uint64_t(0x7FF0F00000000000LL), "0x1.0fp+1024"}, // +nan
  210. {uint64_t(0x7FF0000000000001LL), "0x1.0000000000001p+1024"}, // -nan
  211. {uint64_t(0x7FF0000300000000LL), "0x1.00003p+1024"}, // -nan
  212. {uint64_t(0x7FFFFFFFFFFFFFFFLL), "0x1.fffffffffffffp+1024"}, // -nan
  213. })));
  214. // Tests that encoding a value and decoding it again restores
  215. // the same value.
  216. TEST_P(RoundTripFloatTest, CanStoreAccurately) {
  217. std::stringstream ss;
  218. ss << FloatProxy<float>(GetParam());
  219. ss.seekg(0);
  220. FloatProxy<float> res;
  221. ss >> res;
  222. EXPECT_THAT(GetParam(), Eq(res.getAsFloat()));
  223. }
  224. TEST_P(RoundTripDoubleTest, CanStoreAccurately) {
  225. std::stringstream ss;
  226. ss << FloatProxy<double>(GetParam());
  227. ss.seekg(0);
  228. FloatProxy<double> res;
  229. ss >> res;
  230. EXPECT_THAT(GetParam(), Eq(res.getAsFloat()));
  231. }
  232. INSTANTIATE_TEST_SUITE_P(
  233. Float32StoreTests, RoundTripFloatTest,
  234. ::testing::ValuesIn(std::vector<float>(
  235. {// Value requiring more than 6 digits of precision to be
  236. // represented accurately.
  237. 3.0000002f})));
  238. INSTANTIATE_TEST_SUITE_P(
  239. Float64StoreTests, RoundTripDoubleTest,
  240. ::testing::ValuesIn(std::vector<double>(
  241. {// Value requiring more than 15 digits of precision to be
  242. // represented accurately.
  243. 1.5000000000000002})));
  244. TEST(HexFloatStreamTest, OperatorLeftShiftPreservesFloatAndFill) {
  245. std::stringstream s;
  246. s << std::setw(4) << std::oct << std::setfill('x') << 8 << " "
  247. << FloatProxy<float>(uint32_t(0xFF800100)) << " " << std::setw(4) << 9;
  248. EXPECT_THAT(s.str(), Eq(std::string("xx10 -0x1.0002p+128 xx11")));
  249. }
  250. TEST(HexDoubleStreamTest, OperatorLeftShiftPreservesFloatAndFill) {
  251. std::stringstream s;
  252. s << std::setw(4) << std::oct << std::setfill('x') << 8 << " "
  253. << FloatProxy<double>(uint64_t(0x7FF0F00000000000LL)) << " " << std::setw(4)
  254. << 9;
  255. EXPECT_THAT(s.str(), Eq(std::string("xx10 0x1.0fp+1024 xx11")));
  256. }
  257. TEST_P(DecodeHexFloatTest, DecodeCorrectly) {
  258. EXPECT_THAT(Decode<float>(GetParam().first), Eq(GetParam().second));
  259. }
  260. TEST_P(DecodeHexDoubleTest, DecodeCorrectly) {
  261. EXPECT_THAT(Decode<double>(GetParam().first), Eq(GetParam().second));
  262. }
  263. INSTANTIATE_TEST_SUITE_P(
  264. Float32DecodeTests, DecodeHexFloatTest,
  265. ::testing::ValuesIn(std::vector<std::pair<std::string, FloatProxy<float>>>({
  266. {"0x0p+000", 0.f},
  267. {"0x0p0", 0.f},
  268. {"0x0p-0", 0.f},
  269. // flush to zero cases
  270. {"0x1p-500", 0.f}, // Exponent underflows.
  271. {"-0x1p-500", -0.f},
  272. {"0x0.00000000001p-126", 0.f}, // Fraction causes underflow.
  273. {"-0x0.0000000001p-127", -0.f},
  274. {"-0x0.01p-142", -0.f}, // Fraction causes additional underflow.
  275. {"0x0.01p-142", 0.f},
  276. // Some floats that do not encode the same way as they decode.
  277. {"0x2p+0", 2.f},
  278. {"0xFFp+0", 255.f},
  279. {"0x0.8p+0", 0.5f},
  280. {"0x0.4p+0", 0.25f},
  281. })));
  282. INSTANTIATE_TEST_SUITE_P(
  283. Float32DecodeInfTests, DecodeHexFloatTest,
  284. ::testing::ValuesIn(std::vector<std::pair<std::string, FloatProxy<float>>>({
  285. // inf cases
  286. {"-0x1p+128", uint32_t(0xFF800000)}, // -inf
  287. {"0x32p+127", uint32_t(0x7F800000)}, // inf
  288. {"0x32p+500", uint32_t(0x7F800000)}, // inf
  289. {"-0x32p+127", uint32_t(0xFF800000)}, // -inf
  290. })));
  291. INSTANTIATE_TEST_SUITE_P(
  292. Float64DecodeTests, DecodeHexDoubleTest,
  293. ::testing::ValuesIn(
  294. std::vector<std::pair<std::string, FloatProxy<double>>>({
  295. {"0x0p+000", 0.},
  296. {"0x0p0", 0.},
  297. {"0x0p-0", 0.},
  298. // flush to zero cases
  299. {"0x1p-5000", 0.}, // Exponent underflows.
  300. {"-0x1p-5000", -0.},
  301. {"0x0.0000000000000001p-1023", 0.}, // Fraction causes underflow.
  302. {"-0x0.000000000000001p-1024", -0.},
  303. {"-0x0.01p-1090", -0.f}, // Fraction causes additional underflow.
  304. {"0x0.01p-1090", 0.},
  305. // Some floats that do not encode the same way as they decode.
  306. {"0x2p+0", 2.},
  307. {"0xFFp+0", 255.},
  308. {"0x0.8p+0", 0.5},
  309. {"0x0.4p+0", 0.25},
  310. })));
  311. INSTANTIATE_TEST_SUITE_P(
  312. Float64DecodeInfTests, DecodeHexDoubleTest,
  313. ::testing::ValuesIn(
  314. std::vector<std::pair<std::string, FloatProxy<double>>>({
  315. // inf cases
  316. {"-0x1p+1024", uint64_t(0xFFF0000000000000)}, // -inf
  317. {"0x32p+1023", uint64_t(0x7FF0000000000000)}, // inf
  318. {"0x32p+5000", uint64_t(0x7FF0000000000000)}, // inf
  319. {"-0x32p+1023", uint64_t(0xFFF0000000000000)}, // -inf
  320. })));
  321. TEST(FloatProxy, ValidConversion) {
  322. EXPECT_THAT(FloatProxy<float>(1.f).getAsFloat(), Eq(1.0f));
  323. EXPECT_THAT(FloatProxy<float>(32.f).getAsFloat(), Eq(32.0f));
  324. EXPECT_THAT(FloatProxy<float>(-1.f).getAsFloat(), Eq(-1.0f));
  325. EXPECT_THAT(FloatProxy<float>(0.f).getAsFloat(), Eq(0.0f));
  326. EXPECT_THAT(FloatProxy<float>(-0.f).getAsFloat(), Eq(-0.0f));
  327. EXPECT_THAT(FloatProxy<float>(1.2e32f).getAsFloat(), Eq(1.2e32f));
  328. EXPECT_TRUE(std::isinf(FloatProxy<float>(uint32_t(0xFF800000)).getAsFloat()));
  329. EXPECT_TRUE(std::isinf(FloatProxy<float>(uint32_t(0x7F800000)).getAsFloat()));
  330. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0xFFC00000)).getAsFloat()));
  331. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0xFF800100)).getAsFloat()));
  332. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0xFF800c00)).getAsFloat()));
  333. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0xFF80F000)).getAsFloat()));
  334. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0xFFFFFFFF)).getAsFloat()));
  335. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0x7FC00000)).getAsFloat()));
  336. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0x7F800100)).getAsFloat()));
  337. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0x7f800c00)).getAsFloat()));
  338. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0x7F80F000)).getAsFloat()));
  339. EXPECT_TRUE(std::isnan(FloatProxy<float>(uint32_t(0x7FFFFFFF)).getAsFloat()));
  340. EXPECT_THAT(FloatProxy<float>(uint32_t(0xFF800000)).data(), Eq(0xFF800000u));
  341. EXPECT_THAT(FloatProxy<float>(uint32_t(0x7F800000)).data(), Eq(0x7F800000u));
  342. EXPECT_THAT(FloatProxy<float>(uint32_t(0xFFC00000)).data(), Eq(0xFFC00000u));
  343. EXPECT_THAT(FloatProxy<float>(uint32_t(0xFF800100)).data(), Eq(0xFF800100u));
  344. EXPECT_THAT(FloatProxy<float>(uint32_t(0xFF800c00)).data(), Eq(0xFF800c00u));
  345. EXPECT_THAT(FloatProxy<float>(uint32_t(0xFF80F000)).data(), Eq(0xFF80F000u));
  346. EXPECT_THAT(FloatProxy<float>(uint32_t(0xFFFFFFFF)).data(), Eq(0xFFFFFFFFu));
  347. EXPECT_THAT(FloatProxy<float>(uint32_t(0x7FC00000)).data(), Eq(0x7FC00000u));
  348. EXPECT_THAT(FloatProxy<float>(uint32_t(0x7F800100)).data(), Eq(0x7F800100u));
  349. EXPECT_THAT(FloatProxy<float>(uint32_t(0x7f800c00)).data(), Eq(0x7f800c00u));
  350. EXPECT_THAT(FloatProxy<float>(uint32_t(0x7F80F000)).data(), Eq(0x7F80F000u));
  351. EXPECT_THAT(FloatProxy<float>(uint32_t(0x7FFFFFFF)).data(), Eq(0x7FFFFFFFu));
  352. }
  353. TEST(FloatProxy, Nan) {
  354. EXPECT_TRUE(FloatProxy<float>(uint32_t(0xFFC00000)).isNan());
  355. EXPECT_TRUE(FloatProxy<float>(uint32_t(0xFF800100)).isNan());
  356. EXPECT_TRUE(FloatProxy<float>(uint32_t(0xFF800c00)).isNan());
  357. EXPECT_TRUE(FloatProxy<float>(uint32_t(0xFF80F000)).isNan());
  358. EXPECT_TRUE(FloatProxy<float>(uint32_t(0xFFFFFFFF)).isNan());
  359. EXPECT_TRUE(FloatProxy<float>(uint32_t(0x7FC00000)).isNan());
  360. EXPECT_TRUE(FloatProxy<float>(uint32_t(0x7F800100)).isNan());
  361. EXPECT_TRUE(FloatProxy<float>(uint32_t(0x7f800c00)).isNan());
  362. EXPECT_TRUE(FloatProxy<float>(uint32_t(0x7F80F000)).isNan());
  363. EXPECT_TRUE(FloatProxy<float>(uint32_t(0x7FFFFFFF)).isNan());
  364. }
  365. TEST(FloatProxy, Negation) {
  366. EXPECT_THAT((-FloatProxy<float>(1.f)).getAsFloat(), Eq(-1.0f));
  367. EXPECT_THAT((-FloatProxy<float>(0.f)).getAsFloat(), Eq(-0.0f));
  368. EXPECT_THAT((-FloatProxy<float>(-1.f)).getAsFloat(), Eq(1.0f));
  369. EXPECT_THAT((-FloatProxy<float>(-0.f)).getAsFloat(), Eq(0.0f));
  370. EXPECT_THAT((-FloatProxy<float>(32.f)).getAsFloat(), Eq(-32.0f));
  371. EXPECT_THAT((-FloatProxy<float>(-32.f)).getAsFloat(), Eq(32.0f));
  372. EXPECT_THAT((-FloatProxy<float>(1.2e32f)).getAsFloat(), Eq(-1.2e32f));
  373. EXPECT_THAT((-FloatProxy<float>(-1.2e32f)).getAsFloat(), Eq(1.2e32f));
  374. EXPECT_THAT(
  375. (-FloatProxy<float>(std::numeric_limits<float>::infinity())).getAsFloat(),
  376. Eq(-std::numeric_limits<float>::infinity()));
  377. EXPECT_THAT((-FloatProxy<float>(-std::numeric_limits<float>::infinity()))
  378. .getAsFloat(),
  379. Eq(std::numeric_limits<float>::infinity()));
  380. }
  381. // Test conversion of FloatProxy values to strings.
  382. //
  383. // In previous cases, we always wrapped the FloatProxy value in a HexFloat
  384. // before conversion to a string. In the following cases, the FloatProxy
  385. // decides for itself whether to print as a regular number or as a hex float.
  386. using FloatProxyFloatTest =
  387. ::testing::TestWithParam<std::pair<FloatProxy<float>, std::string>>;
  388. using FloatProxyDoubleTest =
  389. ::testing::TestWithParam<std::pair<FloatProxy<double>, std::string>>;
  390. // Converts a float value to a string via a FloatProxy.
  391. template <typename T>
  392. std::string EncodeViaFloatProxy(const T& value) {
  393. std::stringstream ss;
  394. ss << value;
  395. return ss.str();
  396. }
  397. // Converts a floating point string so that the exponent prefix
  398. // is 'e', and the exponent value does not have leading zeros.
  399. // The Microsoft runtime library likes to write things like "2.5E+010".
  400. // Convert that to "2.5e+10".
  401. // We don't care what happens to strings that are not floating point
  402. // strings.
  403. std::string NormalizeExponentInFloatString(std::string in) {
  404. std::string result;
  405. // Reserve one spot for the terminating null, even when the sscanf fails.
  406. std::vector<char> prefix(in.size() + 1);
  407. char e;
  408. char plus_or_minus;
  409. int exponent; // in base 10
  410. if ((4 == std::sscanf(in.c_str(), "%[-+.0123456789]%c%c%d", prefix.data(), &e,
  411. &plus_or_minus, &exponent)) &&
  412. (e == 'e' || e == 'E') &&
  413. (plus_or_minus == '-' || plus_or_minus == '+')) {
  414. // It looks like a floating point value with exponent.
  415. std::stringstream out;
  416. out << prefix.data() << 'e' << plus_or_minus << exponent;
  417. result = out.str();
  418. } else {
  419. result = in;
  420. }
  421. return result;
  422. }
  423. TEST(NormalizeFloat, Sample) {
  424. EXPECT_THAT(NormalizeExponentInFloatString(""), Eq(""));
  425. EXPECT_THAT(NormalizeExponentInFloatString("1e-12"), Eq("1e-12"));
  426. EXPECT_THAT(NormalizeExponentInFloatString("1E+14"), Eq("1e+14"));
  427. EXPECT_THAT(NormalizeExponentInFloatString("1e-0012"), Eq("1e-12"));
  428. EXPECT_THAT(NormalizeExponentInFloatString("1.263E+014"), Eq("1.263e+14"));
  429. }
  430. // The following two tests can't be DRY because they take different parameter
  431. // types.
  432. TEST_P(FloatProxyFloatTest, EncodeCorrectly) {
  433. EXPECT_THAT(
  434. NormalizeExponentInFloatString(EncodeViaFloatProxy(GetParam().first)),
  435. Eq(GetParam().second));
  436. }
  437. TEST_P(FloatProxyDoubleTest, EncodeCorrectly) {
  438. EXPECT_THAT(
  439. NormalizeExponentInFloatString(EncodeViaFloatProxy(GetParam().first)),
  440. Eq(GetParam().second));
  441. }
  442. INSTANTIATE_TEST_SUITE_P(
  443. Float32Tests, FloatProxyFloatTest,
  444. ::testing::ValuesIn(std::vector<std::pair<FloatProxy<float>, std::string>>({
  445. // Zero
  446. {0.f, "0"},
  447. // Normal numbers
  448. {1.f, "1"},
  449. {-0.25f, "-0.25"},
  450. {1000.0f, "1000"},
  451. // Still normal numbers, but with large magnitude exponents.
  452. {float(ldexp(1.f, 126)), "8.50705917e+37"},
  453. {float(ldexp(-1.f, -126)), "-1.17549435e-38"},
  454. // denormalized values are printed as hex floats.
  455. {float(ldexp(1.0f, -127)), "0x1p-127"},
  456. {float(ldexp(1.5f, -128)), "0x1.8p-128"},
  457. {float(ldexp(1.25, -129)), "0x1.4p-129"},
  458. {float(ldexp(1.125, -130)), "0x1.2p-130"},
  459. {float(ldexp(-1.0f, -127)), "-0x1p-127"},
  460. {float(ldexp(-1.0f, -128)), "-0x1p-128"},
  461. {float(ldexp(-1.0f, -129)), "-0x1p-129"},
  462. {float(ldexp(-1.5f, -130)), "-0x1.8p-130"},
  463. // NaNs
  464. {FloatProxy<float>(uint32_t(0xFFC00000)), "-0x1.8p+128"},
  465. {FloatProxy<float>(uint32_t(0xFF800100)), "-0x1.0002p+128"},
  466. {std::numeric_limits<float>::infinity(), "0x1p+128"},
  467. {-std::numeric_limits<float>::infinity(), "-0x1p+128"},
  468. })));
  469. INSTANTIATE_TEST_SUITE_P(
  470. Float64Tests, FloatProxyDoubleTest,
  471. ::testing::ValuesIn(
  472. std::vector<std::pair<FloatProxy<double>, std::string>>({
  473. {0., "0"},
  474. {1., "1"},
  475. {-0.25, "-0.25"},
  476. {1000.0, "1000"},
  477. // Large outside the range of normal floats
  478. {ldexp(1.0, 128), "3.4028236692093846e+38"},
  479. {ldexp(1.5, 129), "1.0208471007628154e+39"},
  480. {ldexp(-1.0, 128), "-3.4028236692093846e+38"},
  481. {ldexp(-1.5, 129), "-1.0208471007628154e+39"},
  482. // Small outside the range of normal floats
  483. {ldexp(1.5, -129), "2.2040519077917891e-39"},
  484. {ldexp(-1.5, -129), "-2.2040519077917891e-39"},
  485. // lowest non-denorm
  486. {ldexp(1.0, -1022), "2.2250738585072014e-308"},
  487. {ldexp(-1.0, -1022), "-2.2250738585072014e-308"},
  488. // Denormalized values
  489. {ldexp(1.125, -1023), "0x1.2p-1023"},
  490. {ldexp(-1.375, -1024), "-0x1.6p-1024"},
  491. // NaNs
  492. {uint64_t(0x7FF8000000000000LL), "0x1.8p+1024"},
  493. {uint64_t(0xFFF0F00000000000LL), "-0x1.0fp+1024"},
  494. // Infinity
  495. {std::numeric_limits<double>::infinity(), "0x1p+1024"},
  496. {-std::numeric_limits<double>::infinity(), "-0x1p+1024"},
  497. })));
  498. // double is used so that unbiased_exponent can be used with the output
  499. // of ldexp directly.
  500. int32_t unbiased_exponent(double f) {
  501. return HexFloat<FloatProxy<float>>(static_cast<float>(f))
  502. .getUnbiasedNormalizedExponent();
  503. }
  504. int16_t unbiased_half_exponent(uint16_t f) {
  505. return HexFloat<FloatProxy<Float16>>(f).getUnbiasedNormalizedExponent();
  506. }
  507. TEST(HexFloatOperationTest, UnbiasedExponent) {
  508. // Float cases
  509. EXPECT_EQ(0, unbiased_exponent(ldexp(1.0f, 0)));
  510. EXPECT_EQ(-32, unbiased_exponent(ldexp(1.0f, -32)));
  511. EXPECT_EQ(42, unbiased_exponent(ldexp(1.0f, 42)));
  512. EXPECT_EQ(125, unbiased_exponent(ldexp(1.0f, 125)));
  513. EXPECT_EQ(128,
  514. HexFloat<FloatProxy<float>>(std::numeric_limits<float>::infinity())
  515. .getUnbiasedNormalizedExponent());
  516. EXPECT_EQ(-100, unbiased_exponent(ldexp(1.0f, -100)));
  517. EXPECT_EQ(-127, unbiased_exponent(ldexp(1.0f, -127))); // First denorm
  518. EXPECT_EQ(-128, unbiased_exponent(ldexp(1.0f, -128)));
  519. EXPECT_EQ(-129, unbiased_exponent(ldexp(1.0f, -129)));
  520. EXPECT_EQ(-140, unbiased_exponent(ldexp(1.0f, -140)));
  521. // Smallest representable number
  522. EXPECT_EQ(-126 - 23, unbiased_exponent(ldexp(1.0f, -126 - 23)));
  523. // Should get rounded to 0 first.
  524. EXPECT_EQ(0, unbiased_exponent(ldexp(1.0f, -127 - 23)));
  525. // Float16 cases
  526. // The exponent is represented in the bits 0x7C00
  527. // The offset is -15
  528. EXPECT_EQ(0, unbiased_half_exponent(0x3C00));
  529. EXPECT_EQ(3, unbiased_half_exponent(0x4800));
  530. EXPECT_EQ(-1, unbiased_half_exponent(0x3800));
  531. EXPECT_EQ(-14, unbiased_half_exponent(0x0400));
  532. EXPECT_EQ(16, unbiased_half_exponent(0x7C00));
  533. EXPECT_EQ(10, unbiased_half_exponent(0x6400));
  534. // Smallest representable number
  535. EXPECT_EQ(-24, unbiased_half_exponent(0x0001));
  536. }
  537. // Creates a float that is the sum of 1/(2 ^ fractions[i]) for i in factions
  538. float float_fractions(const std::vector<uint32_t>& fractions) {
  539. float f = 0;
  540. for (int32_t i : fractions) {
  541. f += std::ldexp(1.0f, -i);
  542. }
  543. return f;
  544. }
  545. // Returns the normalized significand of a HexFloat<FloatProxy<float>>
  546. // that was created by calling float_fractions with the input fractions,
  547. // raised to the power of exp.
  548. uint32_t normalized_significand(const std::vector<uint32_t>& fractions,
  549. uint32_t exp) {
  550. return HexFloat<FloatProxy<float>>(
  551. static_cast<float>(ldexp(float_fractions(fractions), exp)))
  552. .getNormalizedSignificand();
  553. }
  554. // Sets the bits from MSB to LSB of the significand part of a float.
  555. // For example 0 would set the bit 23 (counting from LSB to MSB),
  556. // and 1 would set the 22nd bit.
  557. uint32_t bits_set(const std::vector<uint32_t>& bits) {
  558. const uint32_t top_bit = 1u << 22u;
  559. uint32_t val = 0;
  560. for (uint32_t i : bits) {
  561. val |= top_bit >> i;
  562. }
  563. return val;
  564. }
  565. // The same as bits_set but for a Float16 value instead of 32-bit floating
  566. // point.
  567. uint16_t half_bits_set(const std::vector<uint32_t>& bits) {
  568. const uint32_t top_bit = 1u << 9u;
  569. uint32_t val = 0;
  570. for (uint32_t i : bits) {
  571. val |= top_bit >> i;
  572. }
  573. return static_cast<uint16_t>(val);
  574. }
  575. TEST(HexFloatOperationTest, NormalizedSignificand) {
  576. // For normalized numbers (the following) it should be a simple matter
  577. // of getting rid of the top implicit bit
  578. EXPECT_EQ(bits_set({}), normalized_significand({0}, 0));
  579. EXPECT_EQ(bits_set({0}), normalized_significand({0, 1}, 0));
  580. EXPECT_EQ(bits_set({0, 1}), normalized_significand({0, 1, 2}, 0));
  581. EXPECT_EQ(bits_set({1}), normalized_significand({0, 2}, 0));
  582. EXPECT_EQ(bits_set({1}), normalized_significand({0, 2}, 32));
  583. EXPECT_EQ(bits_set({1}), normalized_significand({0, 2}, 126));
  584. // For denormalized numbers we expect the normalized significand to
  585. // shift as if it were normalized. This means, in practice that the
  586. // top_most set bit will be cut off. Looks very similar to above (on purpose)
  587. EXPECT_EQ(bits_set({}),
  588. normalized_significand({0}, static_cast<uint32_t>(-127)));
  589. EXPECT_EQ(bits_set({3}),
  590. normalized_significand({0, 4}, static_cast<uint32_t>(-128)));
  591. EXPECT_EQ(bits_set({3}),
  592. normalized_significand({0, 4}, static_cast<uint32_t>(-127)));
  593. EXPECT_EQ(bits_set({}),
  594. normalized_significand({22}, static_cast<uint32_t>(-127)));
  595. EXPECT_EQ(bits_set({0}),
  596. normalized_significand({21, 22}, static_cast<uint32_t>(-127)));
  597. }
  598. // Returns the 32-bit floating point value created by
  599. // calling setFromSignUnbiasedExponentAndNormalizedSignificand
  600. // on a HexFloat<FloatProxy<float>>
  601. float set_from_sign(bool negative, int32_t unbiased_exponent,
  602. uint32_t significand, bool round_denorm_up) {
  603. HexFloat<FloatProxy<float>> f(0.f);
  604. f.setFromSignUnbiasedExponentAndNormalizedSignificand(
  605. negative, unbiased_exponent, significand, round_denorm_up);
  606. return f.value().getAsFloat();
  607. }
  608. TEST(HexFloatOperationTests,
  609. SetFromSignUnbiasedExponentAndNormalizedSignificand) {
  610. EXPECT_EQ(1.f, set_from_sign(false, 0, 0, false));
  611. // Tests insertion of various denormalized numbers with and without round up.
  612. EXPECT_EQ(static_cast<float>(ldexp(1.f, -149)),
  613. set_from_sign(false, -149, 0, false));
  614. EXPECT_EQ(static_cast<float>(ldexp(1.f, -149)),
  615. set_from_sign(false, -149, 0, true));
  616. EXPECT_EQ(0.f, set_from_sign(false, -150, 1, false));
  617. EXPECT_EQ(static_cast<float>(ldexp(1.f, -149)),
  618. set_from_sign(false, -150, 1, true));
  619. EXPECT_EQ(ldexp(1.0f, -127), set_from_sign(false, -127, 0, false));
  620. EXPECT_EQ(ldexp(1.0f, -128), set_from_sign(false, -128, 0, false));
  621. EXPECT_EQ(float_fractions({0, 1, 2, 5}),
  622. set_from_sign(false, 0, bits_set({0, 1, 4}), false));
  623. EXPECT_EQ(ldexp(float_fractions({0, 1, 2, 5}), -32),
  624. set_from_sign(false, -32, bits_set({0, 1, 4}), false));
  625. EXPECT_EQ(ldexp(float_fractions({0, 1, 2, 5}), -128),
  626. set_from_sign(false, -128, bits_set({0, 1, 4}), false));
  627. // The negative cases from above.
  628. EXPECT_EQ(-1.f, set_from_sign(true, 0, 0, false));
  629. EXPECT_EQ(-ldexp(1.0, -127), set_from_sign(true, -127, 0, false));
  630. EXPECT_EQ(-ldexp(1.0, -128), set_from_sign(true, -128, 0, false));
  631. EXPECT_EQ(-float_fractions({0, 1, 2, 5}),
  632. set_from_sign(true, 0, bits_set({0, 1, 4}), false));
  633. EXPECT_EQ(-ldexp(float_fractions({0, 1, 2, 5}), -32),
  634. set_from_sign(true, -32, bits_set({0, 1, 4}), false));
  635. EXPECT_EQ(-ldexp(float_fractions({0, 1, 2, 5}), -128),
  636. set_from_sign(true, -128, bits_set({0, 1, 4}), false));
  637. }
  638. TEST(HexFloatOperationTests, NonRounding) {
  639. // Rounding from 32-bit hex-float to 32-bit hex-float should be trivial,
  640. // except in the denorm case which is a bit more complex.
  641. using HF = HexFloat<FloatProxy<float>>;
  642. bool carry_bit = false;
  643. round_direction rounding[] = {round_direction::kToZero,
  644. round_direction::kToNearestEven,
  645. round_direction::kToPositiveInfinity,
  646. round_direction::kToNegativeInfinity};
  647. // Everything fits, so this should be straight-forward
  648. for (round_direction round : rounding) {
  649. EXPECT_EQ(bits_set({}),
  650. HF(0.f).getRoundedNormalizedSignificand<HF>(round, &carry_bit));
  651. EXPECT_FALSE(carry_bit);
  652. EXPECT_EQ(bits_set({0}),
  653. HF(float_fractions({0, 1}))
  654. .getRoundedNormalizedSignificand<HF>(round, &carry_bit));
  655. EXPECT_FALSE(carry_bit);
  656. EXPECT_EQ(bits_set({1, 3}),
  657. HF(float_fractions({0, 2, 4}))
  658. .getRoundedNormalizedSignificand<HF>(round, &carry_bit));
  659. EXPECT_FALSE(carry_bit);
  660. EXPECT_EQ(
  661. bits_set({0, 1, 4}),
  662. HF(static_cast<float>(-ldexp(float_fractions({0, 1, 2, 5}), -128)))
  663. .getRoundedNormalizedSignificand<HF>(round, &carry_bit));
  664. EXPECT_FALSE(carry_bit);
  665. EXPECT_EQ(bits_set({0, 1, 4, 22}),
  666. HF(static_cast<float>(float_fractions({0, 1, 2, 5, 23})))
  667. .getRoundedNormalizedSignificand<HF>(round, &carry_bit));
  668. EXPECT_FALSE(carry_bit);
  669. }
  670. }
  671. using RD = round_direction;
  672. struct RoundSignificandCase {
  673. float source_float;
  674. std::pair<int16_t, bool> expected_results;
  675. round_direction round;
  676. };
  677. using HexFloatRoundTest = ::testing::TestWithParam<RoundSignificandCase>;
  678. TEST_P(HexFloatRoundTest, RoundDownToFP16) {
  679. using HF = HexFloat<FloatProxy<float>>;
  680. using HF16 = HexFloat<FloatProxy<Float16>>;
  681. HF input_value(GetParam().source_float);
  682. bool carry_bit = false;
  683. EXPECT_EQ(GetParam().expected_results.first,
  684. input_value.getRoundedNormalizedSignificand<HF16>(GetParam().round,
  685. &carry_bit));
  686. EXPECT_EQ(carry_bit, GetParam().expected_results.second);
  687. }
  688. // clang-format off
  689. INSTANTIATE_TEST_SUITE_P(F32ToF16, HexFloatRoundTest,
  690. ::testing::ValuesIn(std::vector<RoundSignificandCase>(
  691. {
  692. {float_fractions({0}), std::make_pair(half_bits_set({}), false), RD::kToZero},
  693. {float_fractions({0}), std::make_pair(half_bits_set({}), false), RD::kToNearestEven},
  694. {float_fractions({0}), std::make_pair(half_bits_set({}), false), RD::kToPositiveInfinity},
  695. {float_fractions({0}), std::make_pair(half_bits_set({}), false), RD::kToNegativeInfinity},
  696. {float_fractions({0, 1}), std::make_pair(half_bits_set({0}), false), RD::kToZero},
  697. {float_fractions({0, 1, 11}), std::make_pair(half_bits_set({0}), false), RD::kToZero},
  698. {float_fractions({0, 1, 11}), std::make_pair(half_bits_set({0, 9}), false), RD::kToPositiveInfinity},
  699. {float_fractions({0, 1, 11}), std::make_pair(half_bits_set({0}), false), RD::kToNegativeInfinity},
  700. {float_fractions({0, 1, 11}), std::make_pair(half_bits_set({0}), false), RD::kToNearestEven},
  701. {float_fractions({0, 1, 10, 11}), std::make_pair(half_bits_set({0, 9}), false), RD::kToZero},
  702. {float_fractions({0, 1, 10, 11}), std::make_pair(half_bits_set({0, 8}), false), RD::kToPositiveInfinity},
  703. {float_fractions({0, 1, 10, 11}), std::make_pair(half_bits_set({0, 9}), false), RD::kToNegativeInfinity},
  704. {float_fractions({0, 1, 10, 11}), std::make_pair(half_bits_set({0, 8}), false), RD::kToNearestEven},
  705. {float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0}), false), RD::kToZero},
  706. {float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0, 9}), false), RD::kToPositiveInfinity},
  707. {float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0}), false), RD::kToNegativeInfinity},
  708. {float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0, 9}), false), RD::kToNearestEven},
  709. {-float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0}), false), RD::kToZero},
  710. {-float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0}), false), RD::kToPositiveInfinity},
  711. {-float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0, 9}), false), RD::kToNegativeInfinity},
  712. {-float_fractions({0, 1, 11, 12}), std::make_pair(half_bits_set({0, 9}), false), RD::kToNearestEven},
  713. {float_fractions({0, 1, 11, 22}), std::make_pair(half_bits_set({0}), false), RD::kToZero},
  714. {float_fractions({0, 1, 11, 22}), std::make_pair(half_bits_set({0, 9}), false), RD::kToPositiveInfinity},
  715. {float_fractions({0, 1, 11, 22}), std::make_pair(half_bits_set({0}), false), RD::kToNegativeInfinity},
  716. {float_fractions({0, 1, 11, 22}), std::make_pair(half_bits_set({0, 9}), false), RD::kToNearestEven},
  717. // Carries
  718. {float_fractions({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), std::make_pair(half_bits_set({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), false), RD::kToZero},
  719. {float_fractions({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), std::make_pair(half_bits_set({}), true), RD::kToPositiveInfinity},
  720. {float_fractions({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), std::make_pair(half_bits_set({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), false), RD::kToNegativeInfinity},
  721. {float_fractions({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), std::make_pair(half_bits_set({}), true), RD::kToNearestEven},
  722. // Cases where original number was denorm. Note: this should have no effect
  723. // the number is pre-normalized.
  724. {static_cast<float>(ldexp(float_fractions({0, 1, 11, 13}), -128)), std::make_pair(half_bits_set({0}), false), RD::kToZero},
  725. {static_cast<float>(ldexp(float_fractions({0, 1, 11, 13}), -129)), std::make_pair(half_bits_set({0, 9}), false), RD::kToPositiveInfinity},
  726. {static_cast<float>(ldexp(float_fractions({0, 1, 11, 13}), -131)), std::make_pair(half_bits_set({0}), false), RD::kToNegativeInfinity},
  727. {static_cast<float>(ldexp(float_fractions({0, 1, 11, 13}), -130)), std::make_pair(half_bits_set({0, 9}), false), RD::kToNearestEven},
  728. })));
  729. // clang-format on
  730. struct UpCastSignificandCase {
  731. uint16_t source_half;
  732. uint32_t expected_result;
  733. };
  734. using HexFloatRoundUpSignificandTest =
  735. ::testing::TestWithParam<UpCastSignificandCase>;
  736. TEST_P(HexFloatRoundUpSignificandTest, Widening) {
  737. using HF = HexFloat<FloatProxy<float>>;
  738. using HF16 = HexFloat<FloatProxy<Float16>>;
  739. bool carry_bit = false;
  740. round_direction rounding[] = {round_direction::kToZero,
  741. round_direction::kToNearestEven,
  742. round_direction::kToPositiveInfinity,
  743. round_direction::kToNegativeInfinity};
  744. // Everything fits, so everything should just be bit-shifts.
  745. for (round_direction round : rounding) {
  746. carry_bit = false;
  747. HF16 input_value(GetParam().source_half);
  748. EXPECT_EQ(
  749. GetParam().expected_result,
  750. input_value.getRoundedNormalizedSignificand<HF>(round, &carry_bit))
  751. << std::hex << "0x"
  752. << input_value.getRoundedNormalizedSignificand<HF>(round, &carry_bit)
  753. << " 0x" << GetParam().expected_result;
  754. EXPECT_FALSE(carry_bit);
  755. }
  756. }
  757. INSTANTIATE_TEST_SUITE_P(
  758. F16toF32, HexFloatRoundUpSignificandTest,
  759. // 0xFC00 of the source 16-bit hex value cover the sign and the exponent.
  760. // They are ignored for this test.
  761. ::testing::ValuesIn(std::vector<UpCastSignificandCase>({
  762. {0x3F00, 0x600000},
  763. {0x0F00, 0x600000},
  764. {0x0F01, 0x602000},
  765. {0x0FFF, 0x7FE000},
  766. })));
  767. struct DownCastTest {
  768. float source_float;
  769. uint16_t expected_half;
  770. std::vector<round_direction> directions;
  771. };
  772. std::string get_round_text(round_direction direction) {
  773. #define CASE(round_direction) \
  774. case round_direction: \
  775. return #round_direction
  776. switch (direction) {
  777. CASE(round_direction::kToZero);
  778. CASE(round_direction::kToPositiveInfinity);
  779. CASE(round_direction::kToNegativeInfinity);
  780. CASE(round_direction::kToNearestEven);
  781. }
  782. #undef CASE
  783. return "";
  784. }
  785. using HexFloatFP32To16Tests = ::testing::TestWithParam<DownCastTest>;
  786. TEST_P(HexFloatFP32To16Tests, NarrowingCasts) {
  787. using HF = HexFloat<FloatProxy<float>>;
  788. using HF16 = HexFloat<FloatProxy<Float16>>;
  789. HF f(GetParam().source_float);
  790. for (auto round : GetParam().directions) {
  791. HF16 half(0);
  792. f.castTo(half, round);
  793. EXPECT_EQ(GetParam().expected_half, half.value().getAsFloat().get_value())
  794. << get_round_text(round) << " " << std::hex
  795. << BitwiseCast<uint32_t>(GetParam().source_float)
  796. << " cast to: " << half.value().getAsFloat().get_value();
  797. }
  798. }
  799. const uint16_t positive_infinity = 0x7C00;
  800. const uint16_t negative_infinity = 0xFC00;
  801. INSTANTIATE_TEST_SUITE_P(
  802. F32ToF16, HexFloatFP32To16Tests,
  803. ::testing::ValuesIn(std::vector<DownCastTest>({
  804. // Exactly representable as half.
  805. {0.f,
  806. 0x0,
  807. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  808. RD::kToNearestEven}},
  809. {-0.f,
  810. 0x8000,
  811. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  812. RD::kToNearestEven}},
  813. {1.0f,
  814. 0x3C00,
  815. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  816. RD::kToNearestEven}},
  817. {-1.0f,
  818. 0xBC00,
  819. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  820. RD::kToNearestEven}},
  821. {float_fractions({0, 1, 10}),
  822. 0x3E01,
  823. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  824. RD::kToNearestEven}},
  825. {-float_fractions({0, 1, 10}),
  826. 0xBE01,
  827. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  828. RD::kToNearestEven}},
  829. {static_cast<float>(ldexp(float_fractions({0, 1, 10}), 3)),
  830. 0x4A01,
  831. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  832. RD::kToNearestEven}},
  833. {static_cast<float>(-ldexp(float_fractions({0, 1, 10}), 3)),
  834. 0xCA01,
  835. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  836. RD::kToNearestEven}},
  837. // Underflow
  838. {static_cast<float>(ldexp(1.0f, -25)),
  839. 0x0,
  840. {RD::kToZero, RD::kToNegativeInfinity, RD::kToNearestEven}},
  841. {static_cast<float>(ldexp(1.0f, -25)), 0x1, {RD::kToPositiveInfinity}},
  842. {static_cast<float>(-ldexp(1.0f, -25)),
  843. 0x8000,
  844. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNearestEven}},
  845. {static_cast<float>(-ldexp(1.0f, -25)),
  846. 0x8001,
  847. {RD::kToNegativeInfinity}},
  848. {static_cast<float>(ldexp(1.0f, -24)),
  849. 0x1,
  850. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  851. RD::kToNearestEven}},
  852. // Overflow
  853. {static_cast<float>(ldexp(1.0f, 16)),
  854. positive_infinity,
  855. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  856. RD::kToNearestEven}},
  857. {static_cast<float>(ldexp(1.0f, 18)),
  858. positive_infinity,
  859. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  860. RD::kToNearestEven}},
  861. {static_cast<float>(ldexp(1.3f, 16)),
  862. positive_infinity,
  863. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  864. RD::kToNearestEven}},
  865. {static_cast<float>(-ldexp(1.0f, 16)),
  866. negative_infinity,
  867. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  868. RD::kToNearestEven}},
  869. {static_cast<float>(-ldexp(1.0f, 18)),
  870. negative_infinity,
  871. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  872. RD::kToNearestEven}},
  873. {static_cast<float>(-ldexp(1.3f, 16)),
  874. negative_infinity,
  875. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  876. RD::kToNearestEven}},
  877. // Transfer of Infinities
  878. {std::numeric_limits<float>::infinity(),
  879. positive_infinity,
  880. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  881. RD::kToNearestEven}},
  882. {-std::numeric_limits<float>::infinity(),
  883. negative_infinity,
  884. {RD::kToZero, RD::kToPositiveInfinity, RD::kToNegativeInfinity,
  885. RD::kToNearestEven}},
  886. // Nans are below because we cannot test for equality.
  887. })));
  888. struct UpCastCase {
  889. uint16_t source_half;
  890. float expected_float;
  891. };
  892. using HexFloatFP16To32Tests = ::testing::TestWithParam<UpCastCase>;
  893. TEST_P(HexFloatFP16To32Tests, WideningCasts) {
  894. using HF = HexFloat<FloatProxy<float>>;
  895. using HF16 = HexFloat<FloatProxy<Float16>>;
  896. HF16 f(GetParam().source_half);
  897. round_direction rounding[] = {round_direction::kToZero,
  898. round_direction::kToNearestEven,
  899. round_direction::kToPositiveInfinity,
  900. round_direction::kToNegativeInfinity};
  901. // Everything fits, so everything should just be bit-shifts.
  902. for (round_direction round : rounding) {
  903. HF flt(0.f);
  904. f.castTo(flt, round);
  905. EXPECT_EQ(GetParam().expected_float, flt.value().getAsFloat())
  906. << get_round_text(round) << " " << std::hex
  907. << BitwiseCast<uint16_t>(GetParam().source_half)
  908. << " cast to: " << flt.value().getAsFloat();
  909. }
  910. }
  911. INSTANTIATE_TEST_SUITE_P(
  912. F16ToF32, HexFloatFP16To32Tests,
  913. ::testing::ValuesIn(std::vector<UpCastCase>({
  914. {0x0000, 0.f},
  915. {0x8000, -0.f},
  916. {0x3C00, 1.0f},
  917. {0xBC00, -1.0f},
  918. {0x3F00, float_fractions({0, 1, 2})},
  919. {0xBF00, -float_fractions({0, 1, 2})},
  920. {0x3F01, float_fractions({0, 1, 2, 10})},
  921. {0xBF01, -float_fractions({0, 1, 2, 10})},
  922. // denorm
  923. {0x0001, static_cast<float>(ldexp(1.0, -24))},
  924. {0x0002, static_cast<float>(ldexp(1.0, -23))},
  925. {0x8001, static_cast<float>(-ldexp(1.0, -24))},
  926. {0x8011, static_cast<float>(-ldexp(1.0, -20) + -ldexp(1.0, -24))},
  927. // inf
  928. {0x7C00, std::numeric_limits<float>::infinity()},
  929. {0xFC00, -std::numeric_limits<float>::infinity()},
  930. })));
  931. TEST(HexFloatOperationTests, NanTests) {
  932. using HF = HexFloat<FloatProxy<float>>;
  933. using HF16 = HexFloat<FloatProxy<Float16>>;
  934. round_direction rounding[] = {round_direction::kToZero,
  935. round_direction::kToNearestEven,
  936. round_direction::kToPositiveInfinity,
  937. round_direction::kToNegativeInfinity};
  938. // Everything fits, so everything should just be bit-shifts.
  939. for (round_direction round : rounding) {
  940. HF16 f16(0);
  941. HF f(0.f);
  942. HF(std::numeric_limits<float>::quiet_NaN()).castTo(f16, round);
  943. EXPECT_TRUE(f16.value().isNan());
  944. HF(std::numeric_limits<float>::signaling_NaN()).castTo(f16, round);
  945. EXPECT_TRUE(f16.value().isNan());
  946. HF16(0x7C01).castTo(f, round);
  947. EXPECT_TRUE(f.value().isNan());
  948. HF16(0x7C11).castTo(f, round);
  949. EXPECT_TRUE(f.value().isNan());
  950. HF16(0xFC01).castTo(f, round);
  951. EXPECT_TRUE(f.value().isNan());
  952. HF16(0x7C10).castTo(f, round);
  953. EXPECT_TRUE(f.value().isNan());
  954. HF16(0xFF00).castTo(f, round);
  955. EXPECT_TRUE(f.value().isNan());
  956. }
  957. }
  958. // A test case for parsing good and bad HexFloat<FloatProxy<T>> literals.
  959. template <typename T>
  960. struct FloatParseCase {
  961. std::string literal;
  962. bool negate_value;
  963. bool expect_success;
  964. HexFloat<FloatProxy<T>> expected_value;
  965. };
  966. using ParseNormalFloatTest = ::testing::TestWithParam<FloatParseCase<float>>;
  967. TEST_P(ParseNormalFloatTest, Samples) {
  968. std::stringstream input(GetParam().literal);
  969. HexFloat<FloatProxy<float>> parsed_value(0.0f);
  970. ParseNormalFloat(input, GetParam().negate_value, parsed_value);
  971. EXPECT_NE(GetParam().expect_success, input.fail())
  972. << " literal: " << GetParam().literal
  973. << " negate: " << GetParam().negate_value;
  974. if (GetParam().expect_success) {
  975. EXPECT_THAT(parsed_value.value(), Eq(GetParam().expected_value.value()))
  976. << " literal: " << GetParam().literal
  977. << " negate: " << GetParam().negate_value;
  978. }
  979. }
  980. // Returns a FloatParseCase with expected failure.
  981. template <typename T>
  982. FloatParseCase<T> BadFloatParseCase(std::string literal, bool negate_value,
  983. T expected_value) {
  984. HexFloat<FloatProxy<T>> proxy_expected_value(expected_value);
  985. return FloatParseCase<T>{literal, negate_value, false, proxy_expected_value};
  986. }
  987. // Returns a FloatParseCase that should successfully parse to a given value.
  988. template <typename T>
  989. FloatParseCase<T> GoodFloatParseCase(std::string literal, bool negate_value,
  990. T expected_value) {
  991. HexFloat<FloatProxy<T>> proxy_expected_value(expected_value);
  992. return FloatParseCase<T>{literal, negate_value, true, proxy_expected_value};
  993. }
  994. INSTANTIATE_TEST_SUITE_P(
  995. FloatParse, ParseNormalFloatTest,
  996. ::testing::ValuesIn(std::vector<FloatParseCase<float>>{
  997. // Failing cases due to trivially incorrect syntax.
  998. BadFloatParseCase("abc", false, 0.0f),
  999. BadFloatParseCase("abc", true, 0.0f),
  1000. // Valid cases.
  1001. GoodFloatParseCase("0", false, 0.0f),
  1002. GoodFloatParseCase("0.0", false, 0.0f),
  1003. GoodFloatParseCase("-0.0", false, -0.0f),
  1004. GoodFloatParseCase("2.0", false, 2.0f),
  1005. GoodFloatParseCase("-2.0", false, -2.0f),
  1006. GoodFloatParseCase("+2.0", false, 2.0f),
  1007. // Cases with negate_value being true.
  1008. GoodFloatParseCase("0.0", true, -0.0f),
  1009. GoodFloatParseCase("2.0", true, -2.0f),
  1010. // When negate_value is true, we should not accept a
  1011. // leading minus or plus.
  1012. BadFloatParseCase("-0.0", true, 0.0f),
  1013. BadFloatParseCase("-2.0", true, 0.0f),
  1014. BadFloatParseCase("+0.0", true, 0.0f),
  1015. BadFloatParseCase("+2.0", true, 0.0f),
  1016. // Overflow is an error for 32-bit float parsing.
  1017. BadFloatParseCase("1e40", false, FLT_MAX),
  1018. BadFloatParseCase("1e40", true, -FLT_MAX),
  1019. BadFloatParseCase("-1e40", false, -FLT_MAX),
  1020. // We can't have -1e40 and negate_value == true since
  1021. // that represents an original case of "--1e40" which
  1022. // is invalid.
  1023. }));
  1024. using ParseNormalFloat16Test =
  1025. ::testing::TestWithParam<FloatParseCase<Float16>>;
  1026. TEST_P(ParseNormalFloat16Test, Samples) {
  1027. std::stringstream input(GetParam().literal);
  1028. HexFloat<FloatProxy<Float16>> parsed_value(0);
  1029. ParseNormalFloat(input, GetParam().negate_value, parsed_value);
  1030. EXPECT_NE(GetParam().expect_success, input.fail())
  1031. << " literal: " << GetParam().literal
  1032. << " negate: " << GetParam().negate_value;
  1033. if (GetParam().expect_success) {
  1034. EXPECT_THAT(parsed_value.value(), Eq(GetParam().expected_value.value()))
  1035. << " literal: " << GetParam().literal
  1036. << " negate: " << GetParam().negate_value;
  1037. }
  1038. }
  1039. INSTANTIATE_TEST_SUITE_P(
  1040. Float16Parse, ParseNormalFloat16Test,
  1041. ::testing::ValuesIn(std::vector<FloatParseCase<Float16>>{
  1042. // Failing cases due to trivially incorrect syntax.
  1043. BadFloatParseCase<Float16>("abc", false, uint16_t{0}),
  1044. BadFloatParseCase<Float16>("abc", true, uint16_t{0}),
  1045. // Valid cases.
  1046. GoodFloatParseCase<Float16>("0", false, uint16_t{0}),
  1047. GoodFloatParseCase<Float16>("0.0", false, uint16_t{0}),
  1048. GoodFloatParseCase<Float16>("-0.0", false, uint16_t{0x8000}),
  1049. GoodFloatParseCase<Float16>("2.0", false, uint16_t{0x4000}),
  1050. GoodFloatParseCase<Float16>("-2.0", false, uint16_t{0xc000}),
  1051. GoodFloatParseCase<Float16>("+2.0", false, uint16_t{0x4000}),
  1052. // Cases with negate_value being true.
  1053. GoodFloatParseCase<Float16>("0.0", true, uint16_t{0x8000}),
  1054. GoodFloatParseCase<Float16>("2.0", true, uint16_t{0xc000}),
  1055. // When negate_value is true, we should not accept a leading minus or
  1056. // plus.
  1057. BadFloatParseCase<Float16>("-0.0", true, uint16_t{0}),
  1058. BadFloatParseCase<Float16>("-2.0", true, uint16_t{0}),
  1059. BadFloatParseCase<Float16>("+0.0", true, uint16_t{0}),
  1060. BadFloatParseCase<Float16>("+2.0", true, uint16_t{0}),
  1061. }));
  1062. // A test case for detecting infinities.
  1063. template <typename T>
  1064. struct OverflowParseCase {
  1065. std::string input;
  1066. bool expect_success;
  1067. T expected_value;
  1068. };
  1069. using FloatProxyParseOverflowFloatTest =
  1070. ::testing::TestWithParam<OverflowParseCase<float>>;
  1071. TEST_P(FloatProxyParseOverflowFloatTest, Sample) {
  1072. std::istringstream input(GetParam().input);
  1073. HexFloat<FloatProxy<float>> value(0.0f);
  1074. input >> value;
  1075. EXPECT_NE(GetParam().expect_success, input.fail());
  1076. if (GetParam().expect_success) {
  1077. EXPECT_THAT(value.value().getAsFloat(), GetParam().expected_value);
  1078. }
  1079. }
  1080. INSTANTIATE_TEST_SUITE_P(
  1081. FloatOverflow, FloatProxyParseOverflowFloatTest,
  1082. ::testing::ValuesIn(std::vector<OverflowParseCase<float>>({
  1083. {"0", true, 0.0f},
  1084. {"0.0", true, 0.0f},
  1085. {"1.0", true, 1.0f},
  1086. {"1e38", true, 1e38f},
  1087. {"-1e38", true, -1e38f},
  1088. {"1e40", false, FLT_MAX},
  1089. {"-1e40", false, -FLT_MAX},
  1090. {"1e400", false, FLT_MAX},
  1091. {"-1e400", false, -FLT_MAX},
  1092. })));
  1093. using FloatProxyParseOverflowDoubleTest =
  1094. ::testing::TestWithParam<OverflowParseCase<double>>;
  1095. TEST_P(FloatProxyParseOverflowDoubleTest, Sample) {
  1096. std::istringstream input(GetParam().input);
  1097. HexFloat<FloatProxy<double>> value(0.0);
  1098. input >> value;
  1099. EXPECT_NE(GetParam().expect_success, input.fail());
  1100. if (GetParam().expect_success) {
  1101. EXPECT_THAT(value.value().getAsFloat(), Eq(GetParam().expected_value));
  1102. }
  1103. }
  1104. INSTANTIATE_TEST_SUITE_P(
  1105. DoubleOverflow, FloatProxyParseOverflowDoubleTest,
  1106. ::testing::ValuesIn(std::vector<OverflowParseCase<double>>({
  1107. {"0", true, 0.0},
  1108. {"0.0", true, 0.0},
  1109. {"1.0", true, 1.0},
  1110. {"1e38", true, 1e38},
  1111. {"-1e38", true, -1e38},
  1112. {"1e40", true, 1e40},
  1113. {"-1e40", true, -1e40},
  1114. {"1e400", false, DBL_MAX},
  1115. {"-1e400", false, -DBL_MAX},
  1116. })));
  1117. using FloatProxyParseOverflowFloat16Test =
  1118. ::testing::TestWithParam<OverflowParseCase<uint16_t>>;
  1119. TEST_P(FloatProxyParseOverflowFloat16Test, Sample) {
  1120. std::istringstream input(GetParam().input);
  1121. HexFloat<FloatProxy<Float16>> value(0);
  1122. input >> value;
  1123. EXPECT_NE(GetParam().expect_success, input.fail())
  1124. << " literal: " << GetParam().input;
  1125. if (GetParam().expect_success) {
  1126. EXPECT_THAT(value.value().data(), Eq(GetParam().expected_value))
  1127. << " literal: " << GetParam().input;
  1128. }
  1129. }
  1130. INSTANTIATE_TEST_SUITE_P(
  1131. Float16Overflow, FloatProxyParseOverflowFloat16Test,
  1132. ::testing::ValuesIn(std::vector<OverflowParseCase<uint16_t>>({
  1133. {"0", true, uint16_t{0}},
  1134. {"0.0", true, uint16_t{0}},
  1135. {"1.0", true, uint16_t{0x3c00}},
  1136. // Overflow for 16-bit float is an error, and returns max or
  1137. // lowest value.
  1138. {"1e38", false, uint16_t{0x7bff}},
  1139. {"1e40", false, uint16_t{0x7bff}},
  1140. {"1e400", false, uint16_t{0x7bff}},
  1141. {"-1e38", false, uint16_t{0xfbff}},
  1142. {"-1e40", false, uint16_t{0xfbff}},
  1143. {"-1e400", false, uint16_t{0xfbff}},
  1144. })));
  1145. TEST(FloatProxy, Max) {
  1146. EXPECT_THAT(FloatProxy<Float16>::max().getAsFloat().get_value(),
  1147. Eq(uint16_t{0x7bff}));
  1148. EXPECT_THAT(FloatProxy<float>::max().getAsFloat(),
  1149. Eq(std::numeric_limits<float>::max()));
  1150. EXPECT_THAT(FloatProxy<double>::max().getAsFloat(),
  1151. Eq(std::numeric_limits<double>::max()));
  1152. }
  1153. TEST(FloatProxy, Lowest) {
  1154. EXPECT_THAT(FloatProxy<Float16>::lowest().getAsFloat().get_value(),
  1155. Eq(uint16_t{0xfbff}));
  1156. EXPECT_THAT(FloatProxy<float>::lowest().getAsFloat(),
  1157. Eq(std::numeric_limits<float>::lowest()));
  1158. EXPECT_THAT(FloatProxy<double>::lowest().getAsFloat(),
  1159. Eq(std::numeric_limits<double>::lowest()));
  1160. }
  1161. // TODO(awoloszyn): Add fp16 tests and HexFloatTraits.
  1162. } // namespace
  1163. } // namespace utils
  1164. } // namespace spvtools