1 | //===----------------------------------------------------------------------===// |
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 | // __clamp_to_integral<IntT>(RealT) |
10 | |
11 | // Test the conversion function that truncates floating point types to the |
12 | // closest representable value for the specified integer type, or |
13 | // numeric_limits<IntT>::max()/min() if the value isn't representable. |
14 | |
15 | #include <cassert> |
16 | #include <cmath> |
17 | #include <limits> |
18 | #include <random> // for __clamp_to_integral |
19 | |
20 | template <class IntT> |
21 | void test() { |
22 | typedef std::numeric_limits<IntT> Lim; |
23 | const bool MaxIsRepresentable = sizeof(IntT) < 8; |
24 | const bool IsSigned = std::is_signed<IntT>::value; |
25 | struct TestCase { |
26 | double Input; |
27 | IntT Expect; |
28 | bool IsRepresentable; |
29 | } TestCases[] = { |
30 | {0, 0, true}, |
31 | {1, 1, true}, |
32 | {IsSigned ? static_cast<IntT>(-1) : 0, |
33 | IsSigned ? static_cast<IntT>(-1) : 0, true}, |
34 | {Lim::lowest(), Lim::lowest(), true}, |
35 | {static_cast<double>(Lim::max()), Lim::max(), MaxIsRepresentable}, |
36 | {static_cast<double>(Lim::max()) + 1, Lim::max(), false}, |
37 | {static_cast<double>(Lim::max()) + 1024, Lim::max(), false}, |
38 | {nextafter(x: static_cast<double>(Lim::max()), INFINITY), Lim::max(), false}, |
39 | }; |
40 | for (TestCase TC : TestCases) { |
41 | auto res = std::__clamp_to_integral<IntT>(TC.Input); |
42 | assert(res == TC.Expect); |
43 | if (TC.IsRepresentable) { |
44 | auto other = static_cast<IntT>(std::trunc(TC.Input)); |
45 | assert(res == other); |
46 | } else |
47 | assert(res == Lim::min() || res == Lim::max()); |
48 | } |
49 | } |
50 | |
51 | template <class IntT> |
52 | void test_float() { |
53 | typedef std::numeric_limits<IntT> Lim; |
54 | const bool MaxIsRepresentable = sizeof(IntT) < 4; |
55 | ((void)MaxIsRepresentable); |
56 | const bool IsSigned = std::is_signed<IntT>::value; |
57 | struct TestCase { |
58 | float Input; |
59 | IntT Expect; |
60 | bool IsRepresentable; |
61 | } TestCases[] = { |
62 | {0, 0, true}, |
63 | {1, 1, true}, |
64 | {IsSigned ? static_cast<IntT>(-1) : 0, |
65 | IsSigned ? static_cast<IntT>(-1) : 0, true}, |
66 | {Lim::lowest(), Lim::lowest(), true}, |
67 | {static_cast<float>(Lim::max()), Lim::max(), MaxIsRepresentable }, |
68 | {nextafter(x: static_cast<float>(Lim::max()), INFINITY), Lim::max(), false}, |
69 | }; |
70 | for (TestCase TC : TestCases) { |
71 | auto res = std::__clamp_to_integral<IntT>(TC.Input); |
72 | assert(res == TC.Expect); |
73 | if (TC.IsRepresentable) { |
74 | auto other = static_cast<IntT>(std::trunc(TC.Input)); |
75 | assert(res == other); |
76 | } else |
77 | assert(res == Lim::min() || res == Lim::max()); |
78 | } |
79 | } |
80 | |
81 | int main(int, char**) { |
82 | test<short>(); |
83 | test<unsigned short>(); |
84 | test<int>(); |
85 | test<unsigned>(); |
86 | test<long long>(); |
87 | test<unsigned long long>(); |
88 | test_float<short>(); |
89 | test_float<int>(); |
90 | test_float<long long>(); |
91 | return 0; |
92 | } |
93 | |