45
45
make_boolean /0 ,
46
46
make_cons /2 ,
47
47
make_float /1 ,
48
- make_float /2 ,
49
48
make_integer /1 ,
50
49
make_integer /2 ]).
51
50
@@ -479,8 +478,7 @@ is_bs_matchable_type(Type) ->
479
478
Result :: {ok , term ()} | error .
480
479
get_singleton_value (# t_atom {elements = [Atom ]}) ->
481
480
{ok , Atom };
482
- get_singleton_value (# t_float {elements = {Float ,Float }}) when Float /= 0 ->
483
- % % 0.0 is not actually a singleton as it has two encodings: 0.0 and -0.0
481
+ get_singleton_value (# t_float {elements = {Float ,Float }}) ->
484
482
{ok , Float };
485
483
get_singleton_value (# t_integer {elements = {Int ,Int }}) ->
486
484
{ok , Int };
@@ -697,11 +695,7 @@ make_cons(Head0, Tail) ->
697
695
698
696
-spec make_float (float ()) -> type ().
699
697
make_float (Float ) when is_float (Float ) ->
700
- make_float (Float , Float ).
701
-
702
- -spec make_float (float (), float ()) -> type ().
703
- make_float (Min , Max ) when is_float (Min ), is_float (Max ), Min =< Max ->
704
- # t_float {elements = {Min , Max }}.
698
+ # t_float {elements = {Float ,Float }}.
705
699
706
700
-spec make_integer (integer ()) -> type ().
707
701
make_integer (Int ) when is_integer (Int ) ->
@@ -1053,9 +1047,9 @@ lub(#t_cons{type=Type,terminator=Term}, nil) ->
1053
1047
lub (# t_float {elements = R1 }, # t_float {elements = R2 }) ->
1054
1048
float_from_range (lub_ranges (R1 , R2 ));
1055
1049
lub (# t_float {elements = R1 }, # t_integer {elements = R2 }) ->
1056
- number_from_range (lub_ranges (R1 , R2 ));
1050
+ number_from_range (widen_range ( lub_ranges (R1 , R2 ) ));
1057
1051
lub (# t_float {elements = R1 }, # t_number {elements = R2 }) ->
1058
- number_from_range (lub_ranges (R1 , R2 ));
1052
+ number_from_range (widen_range ( lub_ranges (R1 , R2 ) ));
1059
1053
lub (# t_fun {arity = SameArity ,target = SameTarget ,type = TypeA },
1060
1054
# t_fun {arity = SameArity ,target = SameTarget ,type = TypeB }) ->
1061
1055
# t_fun {arity = SameArity ,target = SameTarget ,type = join (TypeA , TypeB )};
@@ -1066,9 +1060,9 @@ lub(#t_fun{type=TypeA}, #t_fun{type=TypeB}) ->
1066
1060
lub (# t_integer {elements = R1 }, # t_integer {elements = R2 }) ->
1067
1061
integer_from_range (lub_ranges (R1 , R2 ));
1068
1062
lub (# t_integer {elements = R1 }, # t_float {elements = R2 }) ->
1069
- number_from_range (lub_ranges (R1 , R2 ));
1063
+ number_from_range (widen_range ( lub_ranges (R1 , R2 ) ));
1070
1064
lub (# t_integer {elements = R1 }, # t_number {elements = R2 }) ->
1071
- number_from_range (lub_ranges (R1 , R2 ));
1065
+ number_from_range (widen_range ( lub_ranges (R1 , R2 ) ));
1072
1066
lub (# t_list {type = TypeA ,terminator = TermA },
1073
1067
# t_list {type = TypeB ,terminator = TermB }) ->
1074
1068
# t_list {type = join (TypeA , TypeB ),terminator = join (TermA , TermB )};
@@ -1081,11 +1075,11 @@ lub(nil, #t_list{}=T) ->
1081
1075
lub (# t_list {}= T , nil ) ->
1082
1076
T ;
1083
1077
lub (# t_number {elements = R1 }, # t_number {elements = R2 }) ->
1084
- number_from_range (lub_ranges (R1 , R2 ));
1078
+ number_from_range (widen_range ( lub_ranges (R1 , R2 ) ));
1085
1079
lub (# t_number {elements = R1 }, # t_integer {elements = R2 }) ->
1086
- number_from_range (lub_ranges (R1 , R2 ));
1080
+ number_from_range (widen_range ( lub_ranges (R1 , R2 ) ));
1087
1081
lub (# t_number {elements = R1 }, # t_float {elements = R2 }) ->
1088
- number_from_range (lub_ranges (R1 , R2 ));
1082
+ number_from_range (widen_range ( lub_ranges (R1 , R2 ) ));
1089
1083
lub (# t_map {super_key = SKeyA ,super_value = SValueA },
1090
1084
# t_map {super_key = SKeyB ,super_value = SValueB }) ->
1091
1085
% % Note the use of join/2; elements don't need to be normal types.
@@ -1132,6 +1126,14 @@ lub_ranges({MinA,MaxA}, {MinB,MaxB}) ->
1132
1126
lub_ranges (_ , _ ) ->
1133
1127
any .
1134
1128
1129
+ % % Expands integer 0 to `-0.0 .. +0.0`
1130
+ widen_range ({Min , 0 }) ->
1131
+ widen_range ({Min , + 0.0 });
1132
+ widen_range ({0 , Max }) ->
1133
+ widen_range ({- 0.0 , Max });
1134
+ widen_range (Other ) ->
1135
+ Other .
1136
+
1135
1137
lub_bs_matchable (UnitA , UnitB ) ->
1136
1138
# t_bs_matchable {tail_unit = gcd (UnitA , UnitB )}.
1137
1139
@@ -1179,12 +1181,13 @@ float_from_range(none) ->
1179
1181
none ;
1180
1182
float_from_range (any ) ->
1181
1183
# t_float {};
1182
- float_from_range ({Min0 ,Max0 }) ->
1183
- case {safe_float (Min0 ),safe_float (Max0 )} of
1184
+ float_from_range ({Min0 , Max0 }) ->
1185
+ true = inf_le (Min0 , Max0 ), % Assertion.
1186
+ case {safe_float (Min0 ), safe_float (Max0 )} of
1184
1187
{'-inf' ,'+inf' } ->
1185
1188
# t_float {};
1186
- {Min ,Max } ->
1187
- # t_float {elements = {Min ,Max }}
1189
+ {Min , Max } ->
1190
+ # t_float {elements = {Min , Max }}
1188
1191
end .
1189
1192
1190
1193
safe_float (N ) when is_number (N ) ->
@@ -1218,21 +1221,104 @@ number_from_range(N) ->
1218
1221
none
1219
1222
end .
1220
1223
1221
- inf_le ('-inf' , _ ) -> true ;
1222
- inf_le (A , B ) -> A =< B .
1223
-
1224
- inf_ge (_ , '-inf' ) -> true ;
1225
- inf_ge ('-inf' , _ ) -> false ;
1226
- inf_ge (A , B ) -> A >= B .
1224
+ inf_le ('-inf' , _ ) ->
1225
+ true ;
1226
+ inf_le (A , B ) when is_float (A ), is_float (B ) ->
1227
+ % % When float ranges are compared to float ranges, the total ordering
1228
+ % % function must be used to preserve `-0.0 =/= +0.0`.
1229
+ float_comparable (A ) =< float_comparable (B );
1230
+ inf_le (A , B ) ->
1231
+ A =< B .
1232
+
1233
+ inf_ge (_ , '-inf' ) ->
1234
+ true ;
1235
+ inf_ge ('-inf' , _ ) ->
1236
+ false ;
1237
+ inf_ge (A , B ) when is_float (A ), is_float (B ) ->
1238
+ float_comparable (A ) >= float_comparable (B );
1239
+ inf_ge (A , B ) ->
1240
+ A >= B .
1241
+
1242
+ inf_min (A , B ) when A =:= '-inf' ; B =:= '-inf' ->
1243
+ '-inf' ;
1244
+ inf_min (A , B ) when is_float (A ), is_float (B ) ->
1245
+ case float_comparable (A ) =< float_comparable (B ) of
1246
+ true -> A ;
1247
+ false -> B
1248
+ end ;
1249
+ inf_min (A , B ) when A =< B ->
1250
+ A ;
1251
+ inf_min (A , B ) when A > B ->
1252
+ B .
1227
1253
1228
- inf_min (A , B ) when A =:= '-inf' ; B =:= '-inf' -> '-inf' ;
1229
- inf_min (A , B ) when A =< B -> A ;
1230
- inf_min (A , B ) when A > B -> B .
1254
+ inf_max ('-inf' , B ) ->
1255
+ B ;
1256
+ inf_max (A , '-inf' ) ->
1257
+ A ;
1258
+ inf_max (A , B ) when is_float (A ), is_float (B ) ->
1259
+ case float_comparable (A ) >= float_comparable (B ) of
1260
+ true -> A ;
1261
+ false -> B
1262
+ end ;
1263
+ inf_max (A , B ) when A >= B ->
1264
+ A ;
1265
+ inf_max (A , B ) when A < B ->
1266
+ B .
1231
1267
1232
- inf_max ('-inf' , B ) -> B ;
1233
- inf_max (A , '-inf' ) -> A ;
1234
- inf_max (A , B ) when A >= B -> A ;
1235
- inf_max (A , B ) when A < B -> B .
1268
+ % % Converts a float to a number which, when compared with other such converted
1269
+ % % floats, is ordered the same as '<' on the original inputs aside from the
1270
+ % % fact that -0.0 < +0.0 as required by the term equivalence order.
1271
+ % %
1272
+ % % This has been proven correct with the SMT-LIB model below:
1273
+ % %
1274
+ % % (define-const SignBit_bv (_ BitVec 64) #x8000000000000000)
1275
+ % %
1276
+ % % ; Two finite floats X and Y of unknown value
1277
+ % % (declare-const X (_ FloatingPoint 11 53))
1278
+ % % (declare-const Y (_ FloatingPoint 11 53))
1279
+ % % (assert (= false (fp.isInfinite X) (fp.isInfinite Y)
1280
+ % % (fp.isNaN X) (fp.isNaN Y)))
1281
+ % %
1282
+ % % ; ... the bit representations of the aforementioned floats. The Z3 floating-
1283
+ % % ; point extension lacks a way to directly bit-cast a vector to a float, so
1284
+ % % ; we rely on equivalence here.
1285
+ % % (declare-const X_bv (_ BitVec 64))
1286
+ % % (declare-const Y_bv (_ BitVec 64))
1287
+ % % (assert (= ((_ to_fp 11 53) X_bv) X))
1288
+ % % (assert (= ((_ to_fp 11 53) Y_bv) Y))
1289
+ % %
1290
+ % % ; The bit hack we're going to test
1291
+ % % (define-fun float_sortable ((value (_ BitVec 64))) (_ BitVec 64)
1292
+ % % (ite (distinct (bvand value SignBit_bv) SignBit_bv)
1293
+ % % (bvxor value SignBit_bv)
1294
+ % % (bvnot value)))
1295
+ % %
1296
+ % % (define-fun float_bv_lt ((LHS (_ BitVec 64))
1297
+ % % (RHS (_ BitVec 64))) Bool
1298
+ % % (bvult (float_sortable LHS) (float_sortable RHS)))
1299
+ % %
1300
+ % % (push 1)
1301
+ % % ; When either of X or Y are non-zero, (X < Y) = (bvX < bvY)
1302
+ % % (assert (not (and (fp.isZero X) (fp.isZero Y))))
1303
+ % % (assert (distinct (fp.lt X Y) (float_bv_lt X_bv Y_bv)))
1304
+ % % (check-sat) ; unsat, proving by negation that the above always holds
1305
+ % % (pop 1)
1306
+ % %
1307
+ % % (push 1)
1308
+ % % ; Negative zero should sort lower than positive zero
1309
+ % % (assert (and (fp.isNegative X) (fp.isPositive Y)
1310
+ % % (fp.isZero X) (fp.isZero Y)))
1311
+ % % (assert (not (float_bv_lt X_bv Y_bv)))
1312
+ % % (check-sat) ; unsat
1313
+ % % (pop 1)
1314
+ float_comparable (V0 ) when is_float (V0 ) ->
1315
+ Sign = 16#8000000000000000 ,
1316
+ Mask = 16#FFFFFFFFFFFFFFFF ,
1317
+ <<V_bv :64 /unsigned >> = <<V0 /float >>,
1318
+ case V_bv band Sign of
1319
+ 0 -> (V_bv bxor Sign ) band Mask ;
1320
+ Sign -> (bnot V_bv ) band Mask
1321
+ end .
1236
1322
1237
1323
% %
1238
1324
0 commit comments