OCaml如何管理浮动添加?

时间:2014-06-30 10:48:23

标签: floating-point ocaml

在Java中,如果您执行0.2 + 0.01,则会获得0.21000000000000002

这是由于 IEEE 754

但是,在OCaml中,如果您执行0.2 +. 0.01,则会得到正确的结果0.21

我认为OCaml也服从 IEEE 754 for floats,为什么OCaml可以提供正确的结果,而Java却不能?

3 个答案:

答案 0 :(得分:10)

哪一个是#34;正确"在这种情况下?从浮点算术的角度来看,Java在这里是正确的。无论如何,

OCaml toplevel中的值由genprintval.ml打印,float值由print_float打印,string_of_float使用pervasives.ml。其定义在let string_of_float f = valid_float_lexem (format_float "%.12g" f)

0.21

正如您在此处看到的那样,使用printf格式打印浮动"%。12g"。小于10 ^ { - 12}的东西被简单地丢弃。这就是为什么你看到"错误"回答# Printf.sprintf "%.20g" (0.2 +. 0.01);; - : string = "0.21000000000000002" 。如果升高精度,则输出与Java相同:

{{1}}

答案 1 :(得分:6)

OCaml,对于它所调用的类型float,使用底层C / Unix平台的double类型,该平台通常由该平台定义为IEEE 754的binary64格式。

在OCaml中,转换为十进制是以老式的方式完成的,具有固定的位数(camlspotter已经挖出了格式%.12g,在OCaml中的含义与此相同格式有C)。

在现代语言(Java,Javascript,Ruby)中,时尚是通过精确地发送十进制表示所需的数字来转换为十进制,如果转换回另一个方向,则转换回原始浮点数。所以在Java 0.21中打印的double仅用于最接近0.21的float,这不是理性的21/100,因为这个数字不能完全表示为二进制浮点数。

一种方法并不比另一种方法好。他们都对未经警告的开发人员产生了令人惊讶的副作用。特别是,Java转换方法导致了许多“为什么我的double的值在我将其转换为(double)0.1fquestions时会在StackOverflow上发生变化(答案:它没有&#39} ; t,但0.100000double之后打印了许多其他数字,因为类型float包含的值多于0.2 + 0.01。)

无论如何,OCaml和Java都为{{1}}计算相同的浮点数,因为它们都严格遵循IEEE 754.它们只是以不同的方式打印它们。 OCaml打印固定数量的数字,这些数字不足以显示该数字既不是21/100,也不是最接近21/100的双精度浮点表示。 Java打印足够的数字以显示该数字不是最接近21/100。

答案 2 :(得分:2)

我猜您是通过打印浮点数来查看的,但除非您使用像this one之类的无损表示,否则永远不会依赖它来推断浮点计算的属性。相反:

# 0.21 = 0.2 +. 0.01;;
- : bool = false
# 0.21000000000000002 = 0.2 +. 0.01;;
- : bool = true