为什么在REPL中0.0 == 0.0为false,但在本机执行时为true?

Rob*_*obz 6 floating-point ocaml

0.0 == 0.0false当我在交互式REPL中执行该表达式时:

$ ocaml
        OCaml version 4.02.3

# 0.0 == 0.0;;
- : bool = false
# 0.0 = 0.0;;
- : bool = true
Run Code Online (Sandbox Code Playgroud)

但是true如果我编译并运行这个程序:

let _ =                                                                                                                                                                                                                                                                  
  print_endline (string_of_bool (0.0 == 0.0));
  print_endline (string_of_bool (0.0 = 0.0))
Run Code Online (Sandbox Code Playgroud)

沙丘文件:

(executable (name main))
Run Code Online (Sandbox Code Playgroud)

编译并运行它:

$ dune --version
1.0.0
$ dune exec ./main.exe
true
true
Run Code Online (Sandbox Code Playgroud)

怎么可能0.0 == 0.0永远是false,为什么会它本身执行该代码时是不同的值?

Pat*_*atJ 11

OCaml初学者的注意事项:"正常"平等=.该==运营商的测试如果两个值具有相同的内存地址.

==运营商有时会很难理解.引用OCaml手册:

在非可变类型上,(==)的行为是依赖于实现的; 但是,它保证e1 == e2暗示compare e1 e2 = 0.

float 作为一种不可变的类型,不能保证它在两个相等的值上的行为.

现在,让我们看看到底发生了什么.

对于解释器,您的表达式在没有太多优化的情况下进行评估.关键是要快速执行代码,而不是让代码快速运行.因此,当它看到一个0.0常量时,程序会分配一个包含适当数据"float 0.0" 的新物理内存块.分配相同的常量两次,你会得到两个不同的内存地址.因此0.0 == 0.0回报false

现在,本机代码编译器更加智能.它试图最小化内存使用和执行时间.当它看到相同的不可变常量被分配两次时,它认为"两次分配同一个东西是没有意义的,让我们分配一次".

在某种程度上,编译器会0.0 == 0.0进入let c = 0.0 in c == c.这就是你得到的原因true.

  • 存储的存储方式与其他所有存储方式不同.它们按值存储,而不是通过引用存储.因此`==`和`=`是整数上的相同运算符. (3认同)
  • 整数不是唯一按值存储的东西。不带参数的变型构造函数,[]和char也是如此。基本上任何适合31位(或64位cpus上为63位)的东西都留有1位以将某物标记为按值或引用存储。ocaml中的浮点数为64位,因此无法按值存储。 (2认同)