1 // Copyright (C) 2016-2020 Jonathan Müller <jonathanmueller.dev@gmail.com>
2 // This file is subject to the license terms in the LICENSE file
3 // found in the top-level directory of this distribution.
4 
5 #include <type_safe/floating_point.hpp>
6 
7 #include <catch.hpp>
8 
9 #include <sstream>
10 
11 using namespace type_safe;
12 
13 #ifndef TYPE_SAFE_TEST_NO_STATIC_ASSERT
14 static_assert(std::is_trivially_copyable<floating_point<float>>::value, "");
15 static_assert(std::is_standard_layout<floating_point<float>>::value, "");
16 // conversion checks
17 static_assert(std::is_constructible<floating_point<float>, float>::value, "");
18 static_assert(!std::is_constructible<floating_point<float>, double>::value, "");
19 static_assert(std::is_constructible<floating_point<double>, double>::value, "");
20 static_assert(std::is_constructible<floating_point<double>, double>::value, "");
21 static_assert(!std::is_constructible<floating_point<double>, long double>::value, "");
22 static_assert(std::is_assignable<floating_point<float>, float>::value, "");
23 static_assert(!std::is_assignable<floating_point<float>, double>::value, "");
24 static_assert(std::is_assignable<floating_point<double>, double>::value, "");
25 static_assert(std::is_assignable<floating_point<double>, double>::value, "");
26 static_assert(!std::is_assignable<floating_point<double>, long double>::value, "");
27 #endif
28 
29 TEST_CASE("floating_point")
30 {
31     using float_t = floating_point<double>;
32 
33     SECTION("constructor")
34     {
35         float_t a(0.);
36         REQUIRE(static_cast<double>(a) == 0.);
37         float_t b(3.14);
38         REQUIRE(static_cast<double>(b) == 3.14);
39         float_t c(-42.5);
40         REQUIRE(static_cast<double>(c) == -42.5);
41     }
42     SECTION("assignment")
43     {
44         float_t a(0.);
45         a = 3.14;
46         REQUIRE(static_cast<double>(a) == 3.14);
47         a = -42.5;
48         REQUIRE(static_cast<double>(a) == -42.5);
49     }
50     SECTION("unary")
51     {
52         float_t a(13.255);
53         REQUIRE(static_cast<double>(+a) == static_cast<double>(a));
54         REQUIRE(static_cast<double>(-a) == -static_cast<double>(a));
55     }
56     SECTION("addition")
57     {
58         float_t wrapper(0.);
59         double  normal(0.);
60         REQUIRE(static_cast<double>(wrapper) == normal);
61 
62         wrapper += 4.5;
63         normal += 4.5;
64         REQUIRE(static_cast<double>(wrapper) == normal);
65 
66         wrapper = wrapper + (-2.3);
67         normal  = normal + (-2.3);
68         REQUIRE(static_cast<double>(wrapper) == normal);
69 
70         wrapper = 1.1 + wrapper;
71         normal  = 1.1 + normal;
72         REQUIRE(static_cast<double>(wrapper) == normal);
73 
74         wrapper = float_t(-11.0) + wrapper;
75         normal  = -11.0 + normal;
76         REQUIRE(static_cast<double>(wrapper) == normal);
77     }
78     SECTION("subtraction")
79     {
80         float_t wrapper(0.);
81         double  normal(0.);
82         REQUIRE(static_cast<double>(wrapper) == normal);
83 
84         wrapper -= 4.5;
85         normal -= 4.5;
86         REQUIRE(static_cast<double>(wrapper) == normal);
87 
88         wrapper = wrapper - (-2.3);
89         normal  = normal - (-2.3);
90         REQUIRE(static_cast<double>(wrapper) == normal);
91 
92         wrapper = 1.1 - wrapper;
93         normal  = 1.1 - normal;
94         REQUIRE(static_cast<double>(wrapper) == normal);
95 
96         wrapper = float_t(-11.0) - wrapper;
97         normal  = -11.0 - normal;
98         REQUIRE(static_cast<double>(wrapper) == normal);
99     }
100     SECTION("multiplication")
101     {
102         float_t wrapper(1.);
103         double  normal(1.);
104         REQUIRE(static_cast<double>(wrapper) == normal);
105 
106         wrapper *= 4.5;
107         normal *= 4.5;
108         REQUIRE(static_cast<double>(wrapper) == normal);
109 
110         wrapper = wrapper * (-2.3);
111         normal  = normal * (-2.3);
112         REQUIRE(static_cast<double>(wrapper) == normal);
113 
114         wrapper = 1.1 * wrapper;
115         normal  = 1.1 * normal;
116         REQUIRE(static_cast<double>(wrapper) == normal);
117 
118         wrapper = float_t(-11.0) * wrapper;
119         normal  = -11.0 * normal;
120         REQUIRE(static_cast<double>(wrapper) == normal);
121     }
122     SECTION("division")
123     {
124         float_t wrapper(10.);
125         double  normal(10.);
126         REQUIRE(static_cast<double>(wrapper) == normal);
127 
128         wrapper /= 4.5;
129         normal /= 4.5;
130         REQUIRE(static_cast<double>(wrapper) == normal);
131 
132         wrapper = wrapper / (-2.3);
133         normal  = normal / (-2.3);
134         REQUIRE(static_cast<double>(wrapper) == normal);
135 
136         wrapper = 1.1 / wrapper;
137         normal  = 1.1 / normal;
138         REQUIRE(static_cast<double>(wrapper) == normal);
139 
140         wrapper = float_t(-11.0) / wrapper;
141         normal  = -11.0 / normal;
142         REQUIRE(static_cast<double>(wrapper) == normal);
143     }
144     SECTION("comparison")
145     {
146         // <
147         REQUIRE(bool(float_t(4.) < float_t(5.)));
148         REQUIRE(!(float_t(5.) < float_t(4.)));
149         REQUIRE(!(float_t(4.) < float_t(4.)));
150 
151         REQUIRE(bool(4. < float_t(5.)));
152         REQUIRE(!(5. < float_t(4.)));
153         REQUIRE(!(4. < float_t(4.)));
154 
155         REQUIRE(bool(float_t(4.) < 5.));
156         REQUIRE(!(float_t(5.) < 4.));
157         REQUIRE(!(float_t(4.) < 4.));
158 
159         // <=
160         REQUIRE(bool(float_t(4.) <= float_t(5.)));
161         REQUIRE(!(float_t(5.) <= float_t(4.)));
162         REQUIRE(bool(float_t(4.) <= float_t(4.)));
163 
164         REQUIRE(bool(4. <= float_t(5.)));
165         REQUIRE(!(5. <= float_t(4.)));
166         REQUIRE(bool(4. <= float_t(4.)));
167 
168         REQUIRE(bool(float_t(4.) <= 5.));
169         REQUIRE(!(float_t(5.) <= 4.));
170         REQUIRE(bool(float_t(4.) <= 4.));
171 
172         // >
173         REQUIRE(bool(float_t(5.) > float_t(4.)));
174         REQUIRE(!(float_t(4.) > float_t(5.)));
175         REQUIRE(!(float_t(5.) > float_t(5.)));
176 
177         REQUIRE(bool(5. > float_t(4.)));
178         REQUIRE(!(4. > float_t(5.)));
179         REQUIRE(!(5. > float_t(5.)));
180 
181         REQUIRE(bool(float_t(5.) > 4.));
182         REQUIRE(!(float_t(4.) > 5.));
183         REQUIRE(!(float_t(5.) > 5.));
184 
185         // >=
186         REQUIRE(bool(float_t(5.) >= float_t(4.)));
187         REQUIRE(!(float_t(4.) >= float_t(5.)));
188         REQUIRE(bool(float_t(5.) >= float_t(5.)));
189 
190         REQUIRE(bool(5. >= float_t(4.)));
191         REQUIRE(!(4. >= float_t(5.)));
192         REQUIRE(bool(5. >= float_t(5.)));
193 
194         REQUIRE(bool(float_t(5.) >= 4.));
195         REQUIRE(!(float_t(4.) >= 5.));
196         REQUIRE(bool(float_t(5.) >= 5.));
197     }
198     SECTION("i/o")
199     {
200         std::ostringstream out;
201         std::istringstream in("1.0");
202 
203         float_t f(0.0);
204         out << f;
205         REQUIRE(out.str() == "0");
206 
207         in >> f;
208         REQUIRE(static_cast<double>(f) == 1.0);
209     }
210 }
211