Skip to content

Commit e90b61b

Browse files
committed
Transform float_utils unit test to use CATCH and enable it
It now tests both the approximating and non-approximating version of float_utilst.
1 parent 8b2bd7b commit e90b61b

File tree

5 files changed

+224
-135
lines changed

5 files changed

+224
-135
lines changed

unit/CMakeLists.txt

-2
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@ list(REMOVE_ITEM sources
77
${CMAKE_CURRENT_SOURCE_DIR}/miniBDD.cpp
88

99
# Don't build
10-
${CMAKE_CURRENT_SOURCE_DIR}/sharing_map.cpp
1110
${CMAKE_CURRENT_SOURCE_DIR}/elf_reader.cpp
1211
${CMAKE_CURRENT_SOURCE_DIR}/smt2_parser.cpp
1312
${CMAKE_CURRENT_SOURCE_DIR}/json.cpp
1413
${CMAKE_CURRENT_SOURCE_DIR}/cpp_parser.cpp
1514
${CMAKE_CURRENT_SOURCE_DIR}/osx_fat_reader.cpp
1615
${CMAKE_CURRENT_SOURCE_DIR}/wp.cpp
1716
${CMAKE_CURRENT_SOURCE_DIR}/cpp_scanner.cpp
18-
${CMAKE_CURRENT_SOURCE_DIR}/float_utils.cpp
1917
${CMAKE_CURRENT_SOURCE_DIR}/ieee_float.cpp
2018

2119
# Will be built into a separate library and linked

unit/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SRC += unit_tests.cpp \
1717
analyses/does_remove_const/is_type_at_least_as_const_as.cpp \
1818
goto-programs/goto_trace_output.cpp \
1919
path_strategies.cpp \
20+
solvers/floatbv/float_utils.cpp \
2021
solvers/refinement/array_pool/array_pool.cpp \
2122
solvers/refinement/string_constraint_generator_valueof/calculate_max_string_length.cpp \
2223
solvers/refinement/string_constraint_generator_valueof/get_numeric_value_from_character.cpp \

unit/float_utils.cpp

-133
This file was deleted.

unit/solvers/floatbv/float_utils.cpp

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for float utils and approximation
4+
5+
Author: Daniel Kroening
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/catch.hpp>
10+
11+
// for debug output in case of failure
12+
#include <iostream>
13+
#include <limits>
14+
#include <random>
15+
16+
#include <solvers/floatbv/float_approximation.h>
17+
#include <solvers/floatbv/float_utils.h>
18+
#include <solvers/sat/satcheck.h>
19+
20+
typedef std::uniform_int_distribution<unsigned> distt;
21+
22+
static float random_float(distt &dist, std::mt19937 &gen)
23+
{
24+
union
25+
{
26+
float f;
27+
unsigned int i;
28+
} u;
29+
30+
u.i = dist(gen);
31+
u.i = (u.i << 16) ^ dist(gen);
32+
33+
return u.f;
34+
}
35+
36+
static bool eq(const ieee_floatt &a, const ieee_floatt &b)
37+
{
38+
return (a.is_NaN() && b.is_NaN()) ||
39+
(a.is_infinity() && b.is_infinity() && a.get_sign() == b.get_sign()) ||
40+
a == b;
41+
}
42+
43+
#if 0
44+
static std::string to_str(const bvt &bv)
45+
{
46+
std::string result;
47+
for(unsigned i=0; i<bv.size(); i++)
48+
{
49+
char ch;
50+
if(bv[i]==const_literal(true))
51+
ch='1';
52+
else if(bv[i]==const_literal(false))
53+
ch='0';
54+
else
55+
ch='?';
56+
result=ch+result;
57+
}
58+
return result;
59+
}
60+
#endif
61+
62+
typedef enum { PLUS=0, MINUS=1, MULT=2, DIV=3 } binopt;
63+
const char *binopsyms[]={ " + ", " - ", " * ", " / " };
64+
65+
static float set_values(
66+
distt &dist,
67+
std::mt19937 &gen,
68+
float_utilst &float_utils,
69+
float &f1,
70+
float &f2,
71+
ieee_floatt &i1,
72+
ieee_floatt &i2)
73+
{
74+
f1 = random_float(dist, gen);
75+
f2 = random_float(dist, gen);
76+
i1.from_float(f1);
77+
i2.from_float(f2);
78+
float_utils.spec = i1.spec;
79+
80+
return f1;
81+
}
82+
83+
static bvt compute(
84+
unsigned i,
85+
float_utilst &float_utils,
86+
const float &f2,
87+
float &f3,
88+
const ieee_floatt &i1,
89+
const ieee_floatt &i2)
90+
{
91+
const bvt b1 = float_utils.build_constant(i1);
92+
const bvt b2 = float_utils.build_constant(i2);
93+
94+
const auto op = i % 3;
95+
96+
switch(op)
97+
{
98+
case PLUS:
99+
f3 += f2;
100+
return float_utils.add(b1, b2);
101+
102+
case MINUS:
103+
f3 -= f2;
104+
return float_utils.sub(b1, b2);
105+
106+
case MULT:
107+
f3 *= f2;
108+
return float_utils.mul(b1, b2);
109+
110+
case DIV:
111+
f3 /= f2;
112+
return float_utils.div(b1, b2);
113+
}
114+
115+
return bvt();
116+
}
117+
118+
static void print(
119+
unsigned i,
120+
const ieee_floatt &i1,
121+
const ieee_floatt &i2,
122+
const ieee_floatt &i3,
123+
const ieee_floatt &fres,
124+
const float &f1,
125+
const float &f2,
126+
const float &f3)
127+
{
128+
const unsigned op = i % 3;
129+
const char *opsym = binopsyms[op];
130+
131+
std::cout << i1 << opsym << i2 << " != " << fres << '\n';
132+
std::cout << f1 << opsym << f2 << " == " << f3 << '\n';
133+
std::cout << integer2binary(i1.get_exponent(), i1.spec.e) << " "
134+
<< integer2binary(i1.get_fraction(), i1.spec.f + 1) << opsym
135+
<< integer2binary(i2.get_exponent(), i1.spec.e) << " "
136+
<< integer2binary(i2.get_fraction(), i1.spec.f + 1) << " != "
137+
<< integer2binary(fres.get_exponent(), i1.spec.e) << " "
138+
<< integer2binary(fres.get_fraction(), i1.spec.f + 1) << '\n';
139+
std::cout << integer2binary(i1.get_exponent(), i1.spec.e) << " "
140+
<< integer2binary(i1.get_fraction(), i1.spec.f + 1) << opsym
141+
<< integer2binary(i2.get_exponent(), i1.spec.e) << " "
142+
<< integer2binary(i2.get_fraction(), i1.spec.f + 1) << " == "
143+
<< integer2binary(i3.get_exponent(), i1.spec.e) << " "
144+
<< integer2binary(i3.get_fraction(), i1.spec.f + 1) << '\n';
145+
}
146+
147+
SCENARIO("float_utils", "[core][solvers][floatbv][float_utils]")
148+
{
149+
ieee_floatt i1, i2, i3;
150+
float f1, f2, f3;
151+
152+
std::random_device rd;
153+
std::mt19937 gen(rd());
154+
distt dist(0, std::numeric_limits<unsigned>::max());
155+
156+
for(unsigned i = 0; i < 200; i++)
157+
{
158+
satcheckt satcheck;
159+
float_utilst float_utils(satcheck);
160+
161+
GIVEN("Two random floating point numbers")
162+
{
163+
f3 = set_values(dist, gen, float_utils, f1, f2, i1, i2);
164+
bvt res = compute(i, float_utils, f2, f3, i1, i2);
165+
166+
THEN("Machine execution yields the same result as symbolic computation")
167+
{
168+
i3.from_float(f3);
169+
170+
const satcheckt::resultt result = satcheck.prop_solve();
171+
REQUIRE(result == satcheckt::resultt::P_SATISFIABLE);
172+
173+
const ieee_floatt fres = float_utils.get(res);
174+
175+
if(!eq(fres, i3))
176+
print(i, i1, i2, i3, fres, f1, f2, f3);
177+
178+
REQUIRE(eq(fres, i3));
179+
}
180+
}
181+
}
182+
}
183+
184+
SCENARIO("float_approximation", "[core][solvers][floatbv][float_approximation]")
185+
{
186+
ieee_floatt i1, i2, i3;
187+
float f1, f2, f3;
188+
189+
std::random_device rd;
190+
std::mt19937 gen(rd());
191+
distt dist(0, std::numeric_limits<unsigned>::max());
192+
193+
for(unsigned i = 0; i < 200; i++)
194+
{
195+
satcheckt satcheck;
196+
float_approximationt float_utils(satcheck);
197+
198+
GIVEN("Two random floating point numbers")
199+
{
200+
f3 = set_values(dist, gen, float_utils, f1, f2, i1, i2);
201+
bvt res = compute(i, float_utils, f2, f3, i1, i2);
202+
203+
THEN("Machine execution yields the same result as symbolic computation")
204+
{
205+
i3.from_float(f3);
206+
207+
const satcheckt::resultt result = satcheck.prop_solve();
208+
REQUIRE(result == satcheckt::resultt::P_SATISFIABLE);
209+
210+
const ieee_floatt fres = float_utils.get(res);
211+
212+
if(!eq(fres, i3))
213+
print(i, i1, i2, i3, fres, f1, f2, f3);
214+
215+
REQUIRE(eq(fres, i3));
216+
}
217+
}
218+
}
219+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
solvers/floatbv
2+
solvers/sat
3+
testing-utils
4+
util

0 commit comments

Comments
 (0)