Skip to content

Commit 5de7b26

Browse files
committed
Add IEEE 754 TiesToAway rounding mode
This adds IEEE 754 TiesToAway rounding mode, which rounds away from zero in case of a tie. The rounding mode is added to three distinct implementations: 1. The implementation for constants, in util/ieee_float.h 2. The implementation that creates a bit-level encoding, in src/solvers/floatbv/float_utils.h. 3. The implementation that creates a word-level encoding, in solvers/floatbv/float_bv.cpp.
1 parent 5c8766d commit 5de7b26

8 files changed

+63
-18
lines changed

src/solvers/floatbv/float_bv.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,14 @@ void float_bvt::rounding_mode_bitst::get(const exprt &rm)
282282
exprt round_to_minus_inf_const=
283283
from_integer(ieee_floatt::ROUND_TO_MINUS_INF, rm.type());
284284
exprt round_to_zero_const=from_integer(ieee_floatt::ROUND_TO_ZERO, rm.type());
285+
exprt round_to_away_const =
286+
from_integer(ieee_floatt::ROUND_TO_AWAY, rm.type());
285287

286288
round_to_even=equal_exprt(rm, round_to_even_const);
287289
round_to_plus_inf=equal_exprt(rm, round_to_plus_inf_const);
288290
round_to_minus_inf=equal_exprt(rm, round_to_minus_inf_const);
289291
round_to_zero=equal_exprt(rm, round_to_zero_const);
292+
round_to_away = equal_exprt(rm, round_to_away_const);
290293
}
291294

292295
exprt float_bvt::sign_bit(const exprt &op)
@@ -1166,12 +1169,18 @@ exprt float_bvt::fraction_rounding_decision(
11661169
// round to zero
11671170
false_exprt round_to_zero;
11681171

1172+
// round to away
1173+
const auto round_to_away = or_exprt(rounding_bit, sticky_bit);
1174+
11691175
// now select appropriate one
1176+
// clang-format off
11701177
return if_exprt(rounding_mode_bits.round_to_even, round_to_even,
11711178
if_exprt(rounding_mode_bits.round_to_plus_inf, round_to_plus_inf,
11721179
if_exprt(rounding_mode_bits.round_to_minus_inf, round_to_minus_inf,
11731180
if_exprt(rounding_mode_bits.round_to_zero, round_to_zero,
1174-
false_exprt())))); // otherwise zero
1181+
if_exprt(rounding_mode_bits.round_to_away, round_to_away,
1182+
false_exprt()))))); // otherwise zero
1183+
// clang-format off
11751184
}
11761185

11771186
void float_bvt::round_fraction(

src/solvers/floatbv/float_bv.h

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class float_bvt
104104
exprt round_to_zero;
105105
exprt round_to_plus_inf;
106106
exprt round_to_minus_inf;
107+
exprt round_to_away;
107108

108109
void get(const exprt &rm);
109110
explicit rounding_mode_bitst(const exprt &rm) { get(rm); }

src/solvers/floatbv/float_utils.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ void float_utilst::set_rounding_mode(const bvt &src)
2222
bv_utils.build_constant(ieee_floatt::ROUND_TO_MINUS_INF, src.size());
2323
bvt round_to_zero=
2424
bv_utils.build_constant(ieee_floatt::ROUND_TO_ZERO, src.size());
25+
bvt round_to_away =
26+
bv_utils.build_constant(ieee_floatt::ROUND_TO_AWAY, src.size());
2527

2628
rounding_mode_bits.round_to_even=bv_utils.equal(src, round_to_even);
2729
rounding_mode_bits.round_to_plus_inf=bv_utils.equal(src, round_to_plus_inf);
2830
rounding_mode_bits.round_to_minus_inf=bv_utils.equal(src, round_to_minus_inf);
2931
rounding_mode_bits.round_to_zero=bv_utils.equal(src, round_to_zero);
32+
rounding_mode_bits.round_to_away = bv_utils.equal(src, round_to_away);
3033
}
3134

3235
bvt float_utilst::from_signed_integer(const bvt &src)
@@ -990,12 +993,18 @@ literalt float_utilst::fraction_rounding_decision(
990993
literalt round_to_zero=
991994
const_literal(false);
992995

996+
// round to away
997+
literalt round_to_away = prop.lor(rounding_least, sticky_bit);
998+
993999
// now select appropriate one
1000+
// clang-format off
9941001
return prop.lselect(rounding_mode_bits.round_to_even, round_to_even,
9951002
prop.lselect(rounding_mode_bits.round_to_plus_inf, round_to_plus_inf,
9961003
prop.lselect(rounding_mode_bits.round_to_minus_inf, round_to_minus_inf,
9971004
prop.lselect(rounding_mode_bits.round_to_zero, round_to_zero,
998-
prop.new_variable())))); // otherwise non-det
1005+
prop.lselect(rounding_mode_bits.round_to_away, round_to_away,
1006+
prop.new_variable()))))); // otherwise non-det
1007+
// clang-format on
9991008
}
10001009

10011010
void float_utilst::round_fraction(unbiased_floatt &result)

src/solvers/floatbv/float_utils.h

+14-8
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,21 @@ class float_utilst
2525
literalt round_to_zero;
2626
literalt round_to_plus_inf;
2727
literalt round_to_minus_inf;
28-
29-
rounding_mode_bitst():
30-
round_to_even(const_literal(true)),
31-
round_to_zero(const_literal(false)),
32-
round_to_plus_inf(const_literal(false)),
33-
round_to_minus_inf(const_literal(false))
28+
literalt round_to_away;
29+
30+
rounding_mode_bitst()
31+
: round_to_even(const_literal(true)),
32+
round_to_zero(const_literal(false)),
33+
round_to_plus_inf(const_literal(false)),
34+
round_to_minus_inf(const_literal(false)),
35+
round_to_away(const_literal(false))
3436
{
3537
}
3638

3739
void set(const ieee_floatt::rounding_modet mode)
3840
{
39-
round_to_even=round_to_zero=round_to_plus_inf=round_to_minus_inf=
40-
const_literal(false);
41+
round_to_even = round_to_zero = round_to_plus_inf = round_to_minus_inf =
42+
round_to_away = const_literal(false);
4143

4244
switch(mode)
4345
{
@@ -57,6 +59,10 @@ class float_utilst
5759
round_to_zero=const_literal(true);
5860
break;
5961

62+
case ieee_floatt::ROUND_TO_AWAY:
63+
round_to_away = const_literal(true);
64+
break;
65+
6066
case ieee_floatt::NONDETERMINISTIC:
6167
case ieee_floatt::UNKNOWN:
6268
UNREACHABLE;

src/solvers/smt2/smt2_conv.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -3880,10 +3880,12 @@ void smt2_convt::convert_rounding_mode_FPA(const exprt &expr)
38803880
out << "roundTowardPositive";
38813881
else if(value==3)
38823882
out << "roundTowardZero";
3883+
else if(value == 4)
3884+
out << "roundNearestTiesToAway";
38833885
else
38843886
INVARIANT_WITH_DIAGNOSTICS(
38853887
false,
3886-
"Rounding mode should have value 0, 1, 2, or 3",
3888+
"Rounding mode should have value 0, 1, 2, 3, or 4",
38873889
id2string(cexpr.get_value()));
38883890
}
38893891
else
@@ -3903,10 +3905,14 @@ void smt2_convt::convert_rounding_mode_FPA(const exprt &expr)
39033905
convert_expr(expr);
39043906
out << ") roundTowardPositive ";
39053907

3908+
out << "(ite (= (_ bv3 " << width << ") ";
3909+
convert_expr(expr);
3910+
out << ") roundTowardZero ";
3911+
39063912
// TODO: add some kind of error checking here
3907-
out << "roundTowardZero";
3913+
out << "roundTowardAway";
39083914

3909-
out << ")))";
3915+
out << "))))";
39103916
}
39113917
}
39123918

src/solvers/smt2/smt2_parser.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -1093,12 +1093,14 @@ void smt2_parsert::setup_expressions()
10931093
return from_integer(ieee_floatt::ROUND_TO_EVEN, unsignedbv_typet(32));
10941094
};
10951095

1096-
expressions["roundNearestTiesToAway"] = [this]() -> exprt {
1097-
throw error("unsupported rounding mode");
1096+
expressions["roundNearestTiesToAway"] = [] {
1097+
// we encode as 32-bit unsignedbv
1098+
return from_integer(ieee_floatt::ROUND_TO_AWAY, unsignedbv_typet(32));
10981099
};
10991100

1100-
expressions["RNA"] = [this]() -> exprt {
1101-
throw error("unsupported rounding mode");
1101+
expressions["RNA"] = [] {
1102+
// we encode as 32-bit unsignedbv
1103+
return from_integer(ieee_floatt::ROUND_TO_AWAY, unsignedbv_typet(32));
11021104
};
11031105

11041106
expressions["roundTowardPositive"] = [] {

src/util/ieee_float.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,11 @@ void ieee_floatt::align()
894894
else
895895
make_fltmax(); // positive
896896
break;
897+
898+
case ROUND_TO_AWAY:
899+
// round towards + or - infinity
900+
infinity_flag = true;
901+
break;
897902
}
898903

899904
return; // done
@@ -969,6 +974,10 @@ void ieee_floatt::divide_and_round(
969974
++dividend;
970975
break;
971976

977+
case ROUND_TO_AWAY:
978+
++dividend;
979+
break;
980+
972981
case NONDETERMINISTIC:
973982
case UNKNOWN:
974983
UNREACHABLE;

src/util/ieee_float.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -331,14 +331,17 @@ class ieee_floatt : public ieee_float_valuet
331331
public:
332332
// ROUND_TO_EVEN is also known as "round to nearest, ties to even", and
333333
// is the IEEE default.
334+
// ROUND_TO_AWAY is also known as "round to infinity".
334335
// The numbering below is what x86 uses in the control word and
335-
// what is recommended in C11 5.2.4.2.2
336+
// what is recommended in C11 5.2.4.2.2.
337+
// The numbering of ROUND_TO_AWAY is not specified in C11 5.2.4.2.2.
336338
enum rounding_modet
337339
{
338340
ROUND_TO_EVEN = 0,
339341
ROUND_TO_MINUS_INF = 1,
340342
ROUND_TO_PLUS_INF = 2,
341343
ROUND_TO_ZERO = 3,
344+
ROUND_TO_AWAY = 4,
342345
UNKNOWN,
343346
NONDETERMINISTIC
344347
};

0 commit comments

Comments
 (0)