Skip to content

Commit 96be91c

Browse files
authored
Merge pull request #3809 from mtzguido/reals
Primops.Real: more simplifications
2 parents df24c8f + 8261612 commit 96be91c

File tree

5 files changed

+68
-23
lines changed

5 files changed

+68
-23
lines changed

src/basic/FStarC.Real.fst

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,45 @@
1414
limitations under the License.
1515
*)
1616
module FStarC.Real
17+
18+
module Z = FStarC.BigInt
19+
20+
let rec dropWhile f xs =
21+
match xs with
22+
| [] -> []
23+
| x::xs ->
24+
if f x
25+
then dropWhile f xs
26+
else x::xs
27+
28+
let int_frac (r : real): option (string & string) =
29+
match String.split ['.'] r._0 with
30+
| [i; f] ->
31+
let i = String.list_of_string i in
32+
let f = String.list_of_string f in
33+
let i = i |> dropWhile (fun c -> c = '0') in
34+
let f = f |> List.rev |> dropWhile (fun c -> c = '0') |> List.rev in
35+
Some (String.string_of_list i, String.string_of_list f)
36+
| _ -> None
37+
38+
let max x y =
39+
if x > y then x else y
40+
41+
let zeropad_match (f1 : string) (f2 : string): string & string =
42+
let len = max (String.length f1) (String.length f2) in
43+
let f1 = f1 ^ String.make (len - String.length f1) '0' in
44+
let f2 = f2 ^ String.make (len - String.length f2) '0' in
45+
f1, f2
46+
47+
let cmp (r1 r2 : real) : option order =
48+
match int_frac r1, int_frac r2 with
49+
| Some (i1, f1), Some (i2, f2) ->
50+
let f1, f2 = zeropad_match f1 f2 in
51+
let i1 = Z.to_int_fs <| Z.big_int_of_string i1 in
52+
let i2 = Z.to_int_fs <| Z.big_int_of_string i2 in
53+
let f1 = Z.to_int_fs <| Z.big_int_of_string f1 in
54+
let f2 = Z.to_int_fs <| Z.big_int_of_string f2 in
55+
Some <| FStarC.Class.Ord.cmp (i1, f1) (i2, f2) // lex order
56+
57+
| _ ->
58+
None

src/basic/FStarC.Real.fsti

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
*)
1616
module FStarC.Real
1717

18+
open FStarC.Effect
19+
open FStarC.Order
20+
1821
(* A type for embedded real constants. This allows to write embeddings for them
1922
(see FStarC.Syntax.Embeddings and FStarC.TypeChecker.NBETerm). *)
2023

2124
type real = | Real of string
25+
26+
(* Compares two reals, may return None if unknown. *)
27+
val cmp (r1 r2 : real) : option order

src/typechecker/FStarC.TypeChecker.Primops.Real.fst

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,14 @@ instance nbe_e_tf : TypeChecker.NBETerm.embedding tf =
5959
in
6060
mk_emb em un (fun () -> lid_as_typ PC.bool_lid [] []) (Syntax.Embeddings.emb_typ_of tf)
6161

62-
let cmp (r1 r2 : Real.real) : option order =
63-
match r1._0, r2._0 with
64-
| "0.0", "0.0" -> Some Eq
65-
| "0.0", "0.5" -> Some Lt
66-
| "0.0", "1.0" -> Some Lt
67-
| "0.5", "0.0" -> Some Gt
68-
| "0.5", "0.5" -> Some Eq
69-
| "0.5", "1.0" -> Some Lt
70-
| "1.0", "0.0" -> Some Gt
71-
| "1.0", "0.5" -> Some Gt
72-
| "1.0", "1.0" -> Some Eq
73-
| _ -> None
74-
7562
let lt (r1 r2 : Real.real) : option tf =
76-
cmp r1 r2 |> Class.Monad.fmap (function Lt -> T | _ -> F)
63+
Real.cmp r1 r2 |> Class.Monad.fmap (function Lt -> T | _ -> F)
7764
let le (r1 r2 : Real.real) : option tf =
78-
cmp r1 r2 |> Class.Monad.fmap (function Lt | Eq -> T | _ -> F)
65+
Real.cmp r1 r2 |> Class.Monad.fmap (function Lt | Eq -> T | _ -> F)
7966
let gt (r1 r2 : Real.real) : option tf =
80-
cmp r1 r2 |> Class.Monad.fmap (function Gt -> T | _ -> F)
67+
Real.cmp r1 r2 |> Class.Monad.fmap (function Gt -> T | _ -> F)
8168
let ge (r1 r2 : Real.real) : option tf =
82-
cmp r1 r2 |> Class.Monad.fmap (function Gt | Eq -> T | _ -> F)
69+
Real.cmp r1 r2 |> Class.Monad.fmap (function Gt | Eq -> T | _ -> F)
8370

8471
let of_int (i:Z.t) : Real.real =
8572
Real.Real (string_of_int (Z.to_int_fs i) ^ ".0")

src/typechecker/FStarC.TypeChecker.TermEqAndSimplify.fst

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,17 @@ let rec eq_tm (env:env_t) (t1:term) (t2:term) : eq_result =
164164
Unknown
165165

166166
| Tm_constant (Const_real r1), Tm_constant (Const_real r2) ->
167-
// We cannot decide equality of reals. Use a conservative approach here.
168-
// If the strings match, they are equal, otherwise we don't know. If this
169-
// goes via the eq_iff case below, it will falsely claim that "1.0R" and
170-
// "01.R" are different, since eq_const does not canonizalize the string
171-
// representations.
172-
equal_if (r1 = r2)
167+
// We cannot simply compare strings (they are not canonicalized, e.g.
168+
// "01.R" and "1.0R"). Call the proper comparison in FStarC.Real, which
169+
// returns None for unknown.
170+
begin match Real.cmp (Real.Real r1) (Real.Real r2) with
171+
| Some Order.Eq -> Equal
172+
| Some Order.Lt
173+
| Some Order.Gt -> NotEqual
174+
| None ->
175+
// We don't know.
176+
Unknown
177+
end
173178

174179
| Tm_constant c, Tm_constant d ->
175180
// NOTE: this relies on the fact that eq_const *correctly decides*

tests/micro-benchmarks/Test.Real.fst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ let _ = assert (0.0R >=. 0.0R)
8080
let _ = assert (0.0R <=. 0.0R)
8181
let _ = assert (1.0R >=. 1.0R)
8282
let _ = assert (1.0R <=. 1.0R)
83+
let _ = assert (1.0R <=. 2.0R)
84+
let _ = assert (1.R <=. 1.R)
85+
let _ = assert (1.R <=. 2.R)
86+
let _ = assert (1.0R <. 2.0R)
87+
let _ = assert (1001.0R <. 1002.00R)
8388
#pop-options
8489

8590
[@@expect_failure] let _ = assert (1.0R <. 0.0R)

0 commit comments

Comments
 (0)