diff --git a/src/kernel_services/ast_queries/cil_datatype.ml b/src/kernel_services/ast_queries/cil_datatype.ml
index 539184f0204551c371fafc3292e6e754666cf95e..21f1075b8811610caaba1513e962b69ff2b4bca7 100644
--- a/src/kernel_services/ast_queries/cil_datatype.ml
+++ b/src/kernel_services/ast_queries/cil_datatype.ml
@@ -909,15 +909,26 @@ module Enumitem = struct
       end)
 end
 
-let compare_constant c1 c2 = match c1, c2 with
-  | CInt64(v1,k1,_), CInt64(v2,k2,_) ->
-    compare_chain Integer.compare v1 v2 Extlib.compare_basic k1 k2
+(* If [strict] is true, the comparaison of integer and floating-point constants
+   takes into account their textual representation (if any). Otherwise,
+   constants with the same type and value are equal even if their textual
+   representations differ. *)
+let compare_constant ~strict c1 c2 = match c1, c2 with
+  | CInt64(v1,k1,s1), CInt64(v2,k2,s2) ->
+    let r = compare_chain Integer.compare v1 v2 Extlib.compare_basic k1 k2 in
+    if r = 0 && strict
+    then Option.compare Datatype.String.compare s1 s2
+    else r
   | CStr s1, CStr s2 -> Datatype.String.compare s1 s2
   | CWStr s1, CWStr s2 -> compare_list Datatype.Int64.compare s1 s2
   | CChr c1, CChr c2 -> Datatype.Char.compare c1 c2
-  | CReal (f1,k1,_), CReal(f2,k2,_) ->
-    compare_chain Datatype.Float.compare f1 f2
-      Extlib.compare_basic k1 k2
+  | CReal (f1,k1,s1), CReal(f2,k2,s2) ->
+    let r =
+      compare_chain Datatype.Float.compare f1 f2 Extlib.compare_basic k1 k2
+    in
+    if r = 0 && strict
+    then Option.compare Datatype.String.compare s1 s2
+    else r
   | CEnum e1, CEnum e2 -> Enumitem.compare e1 e2
   | (CInt64 _, (CStr _ | CWStr _ | CChr _ | CReal _ | CEnum _)) -> 1
   | (CStr _, (CWStr _ | CChr _ | CReal _ | CEnum _)) -> 1
@@ -934,16 +945,41 @@ let hash_const c =
   | CInt64 (n,k,_) -> Integer.hash n + Hashtbl.hash k
   | CEnum ei -> 95 + Enumitem.hash ei
 
+module type Make_cmp_input = sig
+  include Datatype.Make_input
+  val compare: strict:bool -> t -> t -> int
+end
+
+module Make_compare_non_strict(M: Make_cmp_input) =
+  Datatype.Make_with_collections(
+  struct
+    include M
+    let compare = M.compare ~strict:false
+  end)
+
+module Make_compare_strict(M: Make_cmp_input) =
+  Datatype.Make_with_collections(
+  struct
+    include M
+    let compare = M.compare ~strict:true
+    let name = M.name ^ "Strict"
+  end)
+
 module StructEq =
 struct
-  let rec compare_exp e1 e2 =
+  (* If [strict] is true, the comparaison of integer and floating-point constants
+     takes into account their textual representation (if any). Otherwise,
+     constants with the same type and value are equal even if their textual
+     representations differ. *)
+  let rec compare_exp ~strict e1 e2 =
+    let compare_exp = compare_exp ~strict in
     match e1.enode, e2.enode with
     | Const (CStr _), Const (CStr _)
     | Const (CWStr _), Const (CWStr _) -> compare e1.eid e2.eid
-    | Const c1, Const c2 -> compare_constant c1 c2
+    | Const c1, Const c2 -> compare_constant ~strict c1 c2
     | Const _, _ -> 1
     | _, Const _ -> -1
-    | Lval lv1, Lval lv2 -> compare_lval lv1 lv2
+    | Lval lv1, Lval lv2 -> compare_lval ~strict lv1 lv2
     | Lval _, _ -> 1
     | _, Lval _ -> -1
     | SizeOf t1, SizeOf t2 -> Typ.compare t1 t2
@@ -985,40 +1021,40 @@ struct
       if res = 0 then compare_exp e1 e2 else res
     | CastE _, _ -> 1
     | _, CastE _ -> -1
-    | AddrOf lv1, AddrOf lv2 -> compare_lval lv1 lv2
+    | AddrOf lv1, AddrOf lv2 -> compare_lval ~strict lv1 lv2
     | AddrOf _, _ -> 1
     | _, AddrOf _ -> -1
-    | StartOf lv1, StartOf lv2 -> compare_lval lv1 lv2
+    | StartOf lv1, StartOf lv2 -> compare_lval ~strict lv1 lv2
     | StartOf _, _ -> 1
     | _, StartOf _ -> -1
     | Info _, Info _ ->
       Cmdline.Kernel_log.fatal
         "[exp_compare] Info node is obsolete. Do not use it"
 
-  and compare_lval (h1,o1) (h2,o2) =
-    let res = compare_lhost h1 h2 in
-    if res = 0 then compare_offset o1 o2 else res
+  and compare_lval ~strict (h1,o1) (h2,o2) =
+    let res = compare_lhost ~strict h1 h2 in
+    if res = 0 then compare_offset ~strict o1 o2 else res
 
-  and compare_lhost h1 h2 =
+  and compare_lhost ~strict h1 h2 =
     match h1, h2 with
     | Var v1, Var v2 -> Varinfo.compare v1 v2
     | Var _, Mem _ -> 1
-    | Mem e1, Mem e2 -> compare_exp e1 e2
+    | Mem e1, Mem e2 -> compare_exp ~strict e1 e2
     | Mem _, Var _ -> -1
 
-  and compare_offset o1 o2 =
+  and compare_offset ~strict o1 o2 =
     match o1, o2 with
     | NoOffset, NoOffset -> 0
     | NoOffset, _ -> 1
     | _, NoOffset -> -1
     | Field(f1,o1), Field(f2, o2) ->
       let res = Fieldinfo.compare f1 f2 in
-      if res = 0 then compare_offset o1 o2 else res
+      if res = 0 then compare_offset ~strict o1 o2 else res
     | Field _, _ -> 1
     | _, Field _ -> -1
     | Index(e1, o1), Index(e2, o2) ->
-      let res = compare_exp e1 e2 in
-      if res = 0 then compare_offset o1 o2 else res
+      let res = compare_exp ~strict e1 e2 in
+      if res = 0 then compare_offset ~strict o1 o2 else res
 
   let prime = 83047
   let rec hash_exp acc e =
@@ -1060,35 +1096,43 @@ module Wide_string =
   Datatype.List_with_collections(Datatype.Int64)
     (struct let module_name = "Cil_datatype.Wide_string" end)
 
-module Constant =
+module Constant_input =
 struct
   let pretty_ref = Extlib.mk_fun "Cil_datatype.Constant.pretty_ref"
-  include Make_with_collections
-      (struct
-        include Datatype.Undefined
-        type t = constant
-        let name = "Constant"
-        let reprs = [ CInt64(Integer.zero, IInt, Some "0") ]
-        let compare = compare_constant
-        let hash = hash_const
-        let equal = Datatype.from_compare
-        let pretty fmt t = !pretty_ref fmt t
-      end)
+  include Datatype.Serializable_undefined
+  type t = constant
+  let name = "Constant"
+  let reprs = [ CInt64(Integer.zero, IInt, Some "0") ]
+  let compare = compare_constant
+  let hash = hash_const
+  let equal = Datatype.from_compare
+  let pretty fmt t = !pretty_ref fmt t
 end
 
-module ExpStructEq =
-  Make_with_collections
-    (struct
-      include Datatype.Undefined
-      type t = exp
-      let name = "ExpStructEq"
-      let reprs = [ Exp.dummy ]
-      let compare = StructEq.compare_exp
-      let hash = StructEq.hash_exp 7863
-      let equal = Datatype.from_compare
-      let pretty fmt t = !Exp.pretty_ref fmt t
-    end)
+module Constant = struct
+  include
+    Make_compare_non_strict(Constant_input)
+  let pretty_ref = Constant_input.pretty_ref
+end
+
+module ConstantStrict =
+  Make_compare_strict(Constant_input)
+
+module ExpStructEq_input = struct
+  include Datatype.Serializable_undefined
+  type t = exp
+  let name = "ExpStructEq"
+  let structural_descr = Structural_descr.t_abstract
+  let reprs = [ Exp.dummy ]
+  let compare = StructEq.compare_exp
+  let hash = StructEq.hash_exp 7863
+  let equal = Datatype.from_compare
+  let pretty fmt t = !Exp.pretty_ref fmt t
+end
+
+module ExpStructEq = Make_compare_non_strict(ExpStructEq_input)
 let () = compare_exp_struct_eq := ExpStructEq.compare
+module ExpStructEqStrict = Make_compare_strict(ExpStructEq_input)
 
 module Block = struct
   let pretty_ref = Extlib.mk_fun "Cil_datatype.Block.pretty_ref"
@@ -1174,20 +1218,24 @@ module Lval = struct
       end)
 end
 
-module LvalStructEq =
-  Make_with_collections
-    (struct
-      type t = lval
-      let name = "LvalStructEq"
-      let reprs = List.map (fun v -> Var v, NoOffset) Varinfo.reprs
-      let compare = StructEq.compare_lval
-      let equal = Datatype.from_compare
-      let hash = StructEq.hash_lval 13598
-      let copy = Datatype.undefined
-      let internal_pretty_code = Datatype.undefined
-      let pretty fmt x = !Lval.pretty_ref fmt x
-      let varname _ = "lv"
-    end)
+module LvalStructEq_input = struct
+  include Datatype.Serializable_undefined
+  type t = lval
+  let name = "LvalStructEq"
+  let reprs = List.map (fun v -> Var v, NoOffset) Varinfo.reprs
+  let structural_descr = Structural_descr.t_abstract
+  let compare = StructEq.compare_lval
+  let equal = Datatype.from_compare
+  let hash = StructEq.hash_lval 13598
+  let copy = Datatype.undefined
+  let internal_pretty_code = Datatype.undefined
+  let pretty fmt x = !Lval.pretty_ref fmt x
+  let varname _ = "lv"
+end
+
+module LvalStructEq = Make_compare_non_strict(LvalStructEq_input)
+
+module LvalStructEqStrict = Make_compare_strict(LvalStructEq_input)
 
 module Offset = struct
   let pretty_ref = ref (fun _ -> assert false)
@@ -1206,20 +1254,23 @@ module Offset = struct
       end)
 end
 
-module OffsetStructEq =
-  Make_with_collections
-    (struct
-      type t = offset
-      let name = "OffsetStructEq"
-      let reprs = [NoOffset]
-      let compare = StructEq.compare_offset
-      let equal = Datatype.from_compare
-      let hash = StructEq.hash_offset 75489
-      let copy = Datatype.undefined
-      let internal_pretty_code = Datatype.undefined
-      let pretty fmt x = !Offset.pretty_ref fmt x
-      let varname _ = "offs"
-    end)
+module OffsetStructEq_input = struct
+  include Datatype.Serializable_undefined
+  type t = offset
+  let name = "OffsetStructEq"
+  let reprs = [NoOffset]
+  let structural_descr = Structural_descr.t_abstract
+  let compare = StructEq.compare_offset
+  let equal = Datatype.from_compare
+  let hash = StructEq.hash_offset 75489
+  let copy = Datatype.undefined
+  let internal_pretty_code = Datatype.undefined
+  let pretty fmt x = !Offset.pretty_ref fmt x
+  let varname _ = "offs"
+end
+
+module OffsetStructEq = Make_compare_non_strict(OffsetStructEq_input)
+module OffsetStructEqStrict = Make_compare_strict(OffsetStructEq_input)
 
 (**************************************************************************)
 (** {3 ACSL types} *)
diff --git a/src/kernel_services/ast_queries/cil_datatype.mli b/src/kernel_services/ast_queries/cil_datatype.mli
index b3e80ccb83eb9781d9bff8923a40a0f92ed82512..a5e968d0bdb612cc05ab9a85817ce9bcb3624e12 100644
--- a/src/kernel_services/ast_queries/cil_datatype.mli
+++ b/src/kernel_services/ast_queries/cil_datatype.mli
@@ -124,10 +124,21 @@ module Enumitem: S_with_collections_pretty with type t = enumitem
 *)
 module Wide_string: S_with_collections with type t = int64 list
 
+
 (**
    @since Oxygen-20120901
 *)
-module Constant: S_with_collections_pretty with type t = constant
+module Constant: sig
+  include S_with_collections with type t = constant
+  val pretty_ref: (Format.formatter -> t -> unit) ref
+end
+
+(**
+   Same as {!Constant}, but comparison is strict, in the sense that it will take
+   into account textual representation if provided.
+   @since Frama-C+dev
+*)
+module ConstantStrict: S_with_collections with type t = constant
 
 (** Note that the equality is based on eid. For structural equality, use
     {!ExpStructEq} *)
@@ -138,6 +149,12 @@ end
 
 module ExpStructEq: S_with_collections with type t = exp
 
+(**
+   structural equality, with strict constant comparison as in {!ConstantStrict}
+   @since Frama-C+dev
+*)
+module ExpStructEqStrict: S_with_collections with type t = exp
+
 module Fieldinfo: S_with_collections_pretty with type t = fieldinfo
 
 module File: S with type t = file
@@ -175,6 +192,12 @@ module Lval: S_with_collections_pretty with type t = lval
 *)
 module LvalStructEq: S_with_collections with type t = lval
 
+(**
+   structural equality, with strict constant comparison as in {!ConstantStrict}
+   @since Frama-C+dev
+*)
+module LvalStructEqStrict: S_with_collections with type t = lval
+
 (** Same remark as for Lval.
     For structural equality, use {!OffsetStructEq}. *)
 module Offset: S_with_collections_pretty with type t = offset
@@ -182,6 +205,12 @@ module Offset: S_with_collections_pretty with type t = offset
 (** @since Oxygen-20120901 *)
 module OffsetStructEq: S_with_collections with type t = offset
 
+(**
+   structural equality, with strict constant comparison as in {!ConstantStrict}
+   @since Frama-C+dev
+*)
+module OffsetStructEqStrict: S_with_collections with type t = offset
+
 module Stmt_Id:  Hptmap.Id_Datatype with type t = stmt
 module Stmt: sig
   include S_with_collections_pretty with type t = stmt
diff --git a/src/plugins/value/domains/hcexprs.ml b/src/plugins/value/domains/hcexprs.ml
index b4fa7fa020a46b1932ba121a8e38cfbb284bca91..89c8ddc4839c37947a3910bd7bb58ae1728d0b33 100644
--- a/src/plugins/value/domains/hcexprs.ml
+++ b/src/plugins/value/domains/hcexprs.ml
@@ -22,8 +22,20 @@
 
 open Cil_types
 
-module Exp = Cil_datatype.ExpStructEq
-module Lval = Cil_datatype.LvalStructEq
+(* The default comparison of Cil_datatype does not distinguish constants
+   with different textual representations in the source code when they
+   represent the same value.
+   However, when option -eva-all-rounding-modes-constants is enabled, the
+   evaluation of floating-point constants may differ according to their
+   textual representation: when the constant is not exactly representable in the
+   floating-point type, an interval is used instead of the nearest singleton
+   value. In this case, two constants with the same nearest value but different
+   textual representation may not be equal. We thus use the [compare_strict]
+   comparison, which also compares the textual representation of constants. *)
+
+module Exp = Cil_datatype.ExpStructEqStrict
+
+module Lval = Cil_datatype.LvalStructEqStrict
 
 (* lvalues are never stored under a constructor [E]. *)
 type unhashconsed_exprs = E of Exp.t | LV of Lval.t
diff --git a/tests/float/oracle_equality/dr.2.res.oracle b/tests/float/oracle_equality/dr.2.res.oracle
deleted file mode 100644
index 10fe6f869598523c6f022e1f593f9c0dfd617337..0000000000000000000000000000000000000000
--- a/tests/float/oracle_equality/dr.2.res.oracle
+++ /dev/null
@@ -1,8 +0,0 @@
-27c27
-< [eva] tests/float/dr.i:26: Frama_C_show_each: {0; 1}, {0; 1}
----
-> [eva] tests/float/dr.i:26: Frama_C_show_each: {1}, {0; 1}
-32c32
-<   e1 ∈ {0; 1}
----
->   e1 ∈ {1}