Line data Source code
1 : // Copyright (c) 2021-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : /** \file
21 : * \brief Verify the saturated_subtract() function.
22 : *
23 : * This file implements tests to verify that the saturated_subtract() function
24 : * will indeed saturate the result on an underflow.
25 : */
26 :
27 : // self
28 : //
29 : #include "catch_main.h"
30 :
31 :
32 :
33 : // snapdev
34 : //
35 : #include <snapdev/math.h>
36 : #include <snapdev/ostream_int128.h>
37 :
38 :
39 : // last include
40 : //
41 : #include <snapdev/poison.h>
42 :
43 :
44 : // __int128 is not ISO C++ yet
45 : #pragma GCC diagnostic ignored "-Wpedantic"
46 :
47 :
48 7 : CATCH_TEST_CASE("saturated_subtract_uint", "[math]")
49 : {
50 10 : CATCH_START_SECTION("saturated_subtract_uint8: test all possible cases with 8 bits")
51 : {
52 257 : for(std::uint32_t n(0); n < 256; ++n)
53 : {
54 65792 : for(std::uint32_t m(0); m < 256; ++m)
55 : {
56 65536 : std::int32_t expected(n - m);
57 65536 : if(expected < 0) // easy to test in this case
58 : {
59 32640 : expected = 0;
60 : }
61 65536 : std::int32_t const result(snapdev::saturated_subtract(
62 : static_cast<std::uint8_t>(n)
63 65536 : , static_cast<std::uint8_t>(m)));
64 65536 : CATCH_REQUIRE(result == expected);
65 : }
66 : }
67 : }
68 : CATCH_END_SECTION()
69 :
70 10 : CATCH_START_SECTION("saturated_subtract_uint16: test many possible cases with 16 bits")
71 : {
72 1312 : for(std::uint32_t n(0); n < 65536; n += rand() % 100)
73 : {
74 1737470 : for(std::uint32_t m(0); m < 65536; m += rand() % 100)
75 : {
76 1736159 : std::int32_t expected(n - m);
77 1736159 : if(expected < 0) // easy to test in this case
78 : {
79 871898 : expected = 0;
80 : }
81 1736159 : std::int32_t const result(snapdev::saturated_subtract(
82 : static_cast<std::uint16_t>(n)
83 1736159 : , static_cast<std::uint16_t>(m)));
84 1736159 : CATCH_REQUIRE(result == expected);
85 : }
86 : }
87 : }
88 : CATCH_END_SECTION()
89 :
90 10 : CATCH_START_SECTION("saturated_subtract: test a few possible cases with 32 bits")
91 : {
92 : // no underflow at all
93 : {
94 : std::uint32_t const result(snapdev::saturated_subtract(
95 : static_cast<std::uint32_t>(32'000)
96 1 : , static_cast<std::uint32_t>(1'000)));
97 1 : CATCH_REQUIRE(result == 31'000UL);
98 : }
99 :
100 : // no underflow, but close
101 : {
102 : std::uint32_t const result(snapdev::saturated_subtract(
103 : static_cast<std::uint32_t>(1'000)
104 1 : , static_cast<std::uint32_t>(1'000)));
105 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min());
106 : }
107 :
108 : // underflow by 1
109 : {
110 : std::uint32_t const result(snapdev::saturated_subtract(
111 : static_cast<std::uint32_t>(1'000)
112 1 : , static_cast<std::uint32_t>(1'001)));
113 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min());
114 : }
115 :
116 : // definitive underflow
117 : {
118 : std::uint32_t const result(snapdev::saturated_subtract(
119 : static_cast<std::uint32_t>(1'000)
120 1 : , static_cast<std::uint32_t>(3'501)));
121 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min());
122 : }
123 :
124 : // max. underflow
125 : {
126 1 : std::uint32_t const result(snapdev::saturated_subtract(
127 : std::numeric_limits<std::uint32_t>::min()
128 1 : , std::numeric_limits<std::uint32_t>::max()));
129 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min());
130 : }
131 : }
132 : CATCH_END_SECTION()
133 :
134 10 : CATCH_START_SECTION("saturated_subtract_uint64: test a few possible cases with 64 bits")
135 : {
136 : // no underflow at all
137 : {
138 : std::uint64_t const result(snapdev::saturated_subtract(
139 : static_cast<std::uint64_t>(32'000)
140 1 : , static_cast<std::uint64_t>(1'000)));
141 1 : CATCH_REQUIRE(result == 31'000UL);
142 : }
143 :
144 : // no underflow, but close
145 : {
146 : std::uint64_t const result(snapdev::saturated_subtract(
147 : static_cast<std::uint64_t>(1'000)
148 1 : , static_cast<std::uint64_t>(1'000)));
149 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min());
150 : }
151 :
152 : // underflow by 1
153 : {
154 : std::uint64_t const result(snapdev::saturated_subtract(
155 : static_cast<std::uint64_t>(1'000)
156 1 : , static_cast<std::uint64_t>(1'001)));
157 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min());
158 : }
159 :
160 : // definitive underflow
161 : {
162 : std::uint64_t const result(snapdev::saturated_subtract(
163 : static_cast<std::uint64_t>(1'000)
164 1 : , static_cast<std::uint64_t>(3'501)));
165 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min());
166 : }
167 :
168 : // max. underflow
169 : {
170 1 : std::uint64_t const result(snapdev::saturated_subtract(
171 : std::numeric_limits<std::uint64_t>::min()
172 1 : , std::numeric_limits<std::uint64_t>::max()));
173 1 : CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min());
174 : }
175 : }
176 : CATCH_END_SECTION()
177 :
178 10 : CATCH_START_SECTION("saturated_subtract_uint128: test a few possible cases with 128 bits")
179 : {
180 : #pragma GCC diagnostic push
181 : #pragma GCC diagnostic ignored "-Wpedantic"
182 : // no underflow at all
183 : {
184 1 : unsigned __int128 const result(snapdev::saturated_subtract(
185 : static_cast<unsigned __int128>(32'000)
186 1 : , static_cast<unsigned __int128>(1'000)));
187 1 : CATCH_REQUIRE(result == 31'000UL);
188 : }
189 :
190 : // no underflow, but close
191 : {
192 1 : unsigned __int128 const result(snapdev::saturated_subtract(
193 : static_cast<unsigned __int128>(1'000)
194 1 : , static_cast<unsigned __int128>(1'000)));
195 1 : CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min());
196 : }
197 :
198 : // underflow by 1
199 : {
200 1 : unsigned __int128 const result(snapdev::saturated_subtract(
201 : static_cast<unsigned __int128>(1'000)
202 1 : , static_cast<unsigned __int128>(1'001)));
203 1 : CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min());
204 : }
205 :
206 : // definitive underflow
207 : {
208 2 : unsigned __int128 const result(snapdev::saturated_subtract(
209 : static_cast<unsigned __int128>(3'501)
210 2 : , std::numeric_limits<unsigned __int128>::max() - 1'000));
211 1 : CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min());
212 : }
213 :
214 : // max. underflow
215 : {
216 1 : unsigned __int128 const result(snapdev::saturated_subtract(
217 : std::numeric_limits<unsigned __int128>::min()
218 1 : , std::numeric_limits<unsigned __int128>::max()));
219 1 : CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min());
220 : }
221 : #pragma GCC diagnostic pop
222 : }
223 : CATCH_END_SECTION()
224 11 : }
225 :
226 :
227 : // vim: ts=4 sw=4 et
|