| 1 | //===-- Unittests for str_to_float<long double> ---------------------------===// |
| 2 | // |
| 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 |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "src/__support/macros/config.h" |
| 10 | #include "str_to_fp_test.h" |
| 11 | |
| 12 | #include "src/__support/integer_literals.h" |
| 13 | |
| 14 | namespace LIBC_NAMESPACE_DECL { |
| 15 | |
| 16 | using LlvmLibcStrToLongDblTest = LlvmLibcStrToFloatTest<long double>; |
| 17 | using LIBC_NAMESPACE::operator""_u128 ; |
| 18 | |
| 19 | #if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) |
| 20 | |
| 21 | TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat64AsLongDouble) { |
| 22 | eisel_lemire_test(123, 0, 0x1EC00000000000, 1029); |
| 23 | } |
| 24 | |
| 25 | #elif defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) |
| 26 | |
| 27 | TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80Simple) { |
| 28 | eisel_lemire_test(123, 0, 0xf600000000000000, 16389); |
| 29 | eisel_lemire_test(12345678901234568192u, 0, 0xab54a98ceb1f0c00, 16446); |
| 30 | } |
| 31 | |
| 32 | TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80LongerMantissa) { |
| 33 | #if __SIZEOF_LONG_DOUBLE__ == 16 |
| 34 | eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, 0, |
| 35 | 0x91a2b3c091a2b3c1, 16507); |
| 36 | eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, 300, |
| 37 | 0xd97757de56adb65c, 17503); |
| 38 | eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, -300, |
| 39 | 0xc30feb9a7618457d, 15510); |
| 40 | #elif __SIZEOF_LONG_DOUBLE__ == 12 |
| 41 | eisel_lemire_test(0x12345678'12345678'12345678_u96, 0, 0x91a2b3c091a2b3c1, |
| 42 | 16475); |
| 43 | eisel_lemire_test(0x12345678'12345678'12345678_u96, 300, 0xd97757de56adb65c, |
| 44 | 17471); |
| 45 | eisel_lemire_test(0x12345678'12345678'12345678_u96, -300, 0xc30feb9a7618457d, |
| 46 | 15478); |
| 47 | #else |
| 48 | #error "unhandled long double type" |
| 49 | #endif |
| 50 | } |
| 51 | |
| 52 | // These tests check numbers at the edge of the DETAILED_POWERS_OF_TEN table. |
| 53 | // This doesn't reach very far into the range for long doubles, since it's sized |
| 54 | // for doubles and their 11 exponent bits, and not for long doubles and their |
| 55 | // 15 exponent bits. This is a known tradeoff, and was made because a proper |
| 56 | // long double table would be approximately 16 times longer (specifically the |
| 57 | // maximum exponent would need to be about 5000, leading to a 10,000 entry |
| 58 | // table). This would have significant memory and storage costs all the time to |
| 59 | // speed up a relatively uncommon path. |
| 60 | TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80TableLimits) { |
| 61 | eisel_lemire_test(1, 347, 0xd13eb46469447567, 17535); |
| 62 | eisel_lemire_test(1, -348, 0xfa8fd5a0081c0288, 15226); |
| 63 | } |
| 64 | |
| 65 | TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80Fallback) { |
| 66 | // This number is halfway between two possible results, and the algorithm |
| 67 | // can't determine which is correct. |
| 68 | ASSERT_FALSE(internal::eisel_lemire<long double>({12345678901234567890u, 1}) |
| 69 | .has_value()); |
| 70 | |
| 71 | // These numbers' exponents are out of range for the current powers of ten |
| 72 | // table. |
| 73 | ASSERT_FALSE(internal::eisel_lemire<long double>({1, 1000}).has_value()); |
| 74 | ASSERT_FALSE(internal::eisel_lemire<long double>({1, -1000}).has_value()); |
| 75 | } |
| 76 | |
| 77 | TEST_F(LlvmLibcStrToLongDblTest, ClingerFastPathFloat80Simple) { |
| 78 | clinger_fast_path_test(123, 0, 0xf600000000000000, 16389); |
| 79 | clinger_fast_path_test(1234567, 1, 0xbc61460000000000, 16406); |
| 80 | clinger_fast_path_test(12345, -5, 0xfcd35a858793dd98, 16379); |
| 81 | } |
| 82 | |
| 83 | #elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) |
| 84 | |
| 85 | TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat128Simple) { |
| 86 | eisel_lemire_test(123, 0, 0x1ec00'00000000'00000000'00000000_u128, 16389); |
| 87 | eisel_lemire_test(12345678901234568192u, 0, |
| 88 | 0x156a9'5319d63e'18000000'00000000_u128, 16446); |
| 89 | } |
| 90 | |
| 91 | TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat128LongerMantissa) { |
| 92 | eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, 0, |
| 93 | 0x12345'67812345'67812345'67812345_u128, 16507); |
| 94 | eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, 300, |
| 95 | 0x1b2ee'afbcad5b'6cb8b445'1dfcde19_u128, 17503); |
| 96 | eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, -300, |
| 97 | 0x1861f'd734ec30'8afa7189'f0f7595f_u128, 15510); |
| 98 | } |
| 99 | |
| 100 | TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat128Fallback) { |
| 101 | ASSERT_FALSE(internal::eisel_lemire<long double>( |
| 102 | {0x5ce0e9a5'6015fec5'aadfa328'ae39b333_u128, 1}) |
| 103 | .has_value()); |
| 104 | } |
| 105 | |
| 106 | TEST_F(LlvmLibcStrToLongDblTest, ClingerFastPathFloat128Simple) { |
| 107 | clinger_fast_path_test(123, 0, 0x1ec00'00000000'00000000'00000000_u128, |
| 108 | 16389); |
| 109 | clinger_fast_path_test(1234567, 1, 0x178c2'8c000000'00000000'00000000_u128, |
| 110 | 16406); |
| 111 | clinger_fast_path_test(12345, -5, 0x1f9a6'b50b0f27'bb2fec56'd5cfaace_u128, |
| 112 | 16379); |
| 113 | } |
| 114 | |
| 115 | #else |
| 116 | #error "Unknown long double type" |
| 117 | #endif |
| 118 | |
| 119 | } // namespace LIBC_NAMESPACE_DECL |
| 120 | |