Java:添加/减去Math.ulp()与Math.nextAfter()

时间:2017-11-14 11:51:07

标签: java floating-point

我正在尝试更详细地了解Java中的浮点运算。如果我正确阅读文档,则对于任何给定的双x,以下内容成立:

x - Math.ulp(x) == Math.nextAfter(x, Double.NEGATIVE_INFINITY);
x + Math.ulp(x) == Math.nextAfter(x, Double.POSITIVE_INFINITY);

问题:这种情况总是如此,或者是否有一些特殊情况会导致结果不同?

2 个答案:

答案 0 :(得分:10)

这个程序:

#cssmenu,
#cssmenu ul,
#cssmenu ul li,
#cssmenu ul li a {
margin: 0;
padding: 0;
border: 0;
list-style: none;
line-height: 1;
display: block;
position: relative;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#cssmenu:after,
#cssmenu > ul:after {
  content: ".";
display: block;
clear: both;
visibility: hidden;
line-height: 0;
height: 0;
}
#cssmenu {
width: 100%;
border-bottom: 3px solid #a24fef;
font-family: Raleway, sans-serif;
line-height: 1;
}
#cssmenu ul {
background: rgb(220, 220, 0);
background: rgba(220, 220, 0, 0);
}
#cssmenu > ul > li {
float: left;
}
#cssmenu.align-center > ul {
font-size: 0;
text-align: center;
}
#cssmenu.align-center > ul > li {
  display: inline-block;
  float: none;
}
#cssmenu.align-right > ul > li {
  float: right;
}
#cssmenu.align-right > ul > li > a {
  margin-right: 0;
  margin-left: -4px;
}
#cssmenu > ul > li > a {
  z-index: 2;
  padding: 18px 25px 12px 25px;
  font-size: 25px;
  font-weight: 400;
  text-decoration: none;
  color: #444444;
  -webkit-transition: all 1s ease;
  -moz-transition: all 1s ease;
  -ms-transition: all 1s ease;
      -o-transition: all 1s ease;
  transition: all 1s ease;
  margin-right: -4px;
}
#cssmenu > ul > li.active > a,
#cssmenu > ul > li:hover > a,
#cssmenu > ul > li > a:hover {
  color: #ffffff;
}
#cssmenu > ul > li > a:after {
  position: absolute;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: -1;
  width: 100%;
  height: 120%;
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  content: "";
  -webkit-transition: all 1s ease;
  -o-transition: all 1s ease;
  transition: all 1s ease;
  -webkit-transform: perspective(5px) rotateX(2deg);
  -webkit-transform-origin: bottom;
  -moz-transform: perspective(5px) rotateX(2deg);
  -moz-transform-origin: bottom;
  transform: perspective(5px) rotateX(2deg);
  transform-origin: bottom;
}
#cssmenu > ul > li.active > a:after,
#cssmenu > ul > li:hover > a:after,
#cssmenu > ul > li > a:hover:after {
  background: #a24fef;
}

输出:

public class Test {
  public static void main(String[] args) {
    double x = 1;
    System.out.println(x - Math.ulp(x) == Math.nextAfter(x, Double.NEGATIVE_INFINITY));
    System.out.println(x + Math.ulp(x) == Math.nextAfter(x, Double.POSITIVE_INFINITY));
  }
}

连续双精度之间的差异在每个正常整数幂为2时发生变化,包括1.0。其中一项测试必须失败,因为它假设不断有差异。 Math.ulp(double)被定义为返回“此浮点值与接下来更大的双值之间的正距离”,因此当距离不同时,减法命题为假。

答案 1 :(得分:4)

我想要检查的直接情况是0,+无穷大和-infinity和NaN:

static void check(double x) {
  double a, b;
  System.out.printf(
      "%9s %9s %23s %5s%n",
      x, a = x - Math.ulp(x), b = Math.nextAfter(x, Double.NEGATIVE_INFINITY), a == b);
  System.out.printf(
      "%9s %9s %23s %5s%n",
      x, a = x + Math.ulp(x), b = Math.nextAfter(x, Double.POSITIVE_INFINITY), a == b);
  System.out.println();
}

public static void main(String[] args) throws java.lang.Exception {
  check(0);
  check(Double.POSITIVE_INFINITY);
  check(Double.NEGATIVE_INFINITY);
  check(Double.NaN);
}

Ideone demo

输出:

      0.0 -4.9E-324               -4.9E-324  true
      0.0  4.9E-324                4.9E-324  true

 Infinity       NaN  1.7976931348623157E308 false
 Infinity  Infinity                Infinity  true

-Infinity -Infinity               -Infinity  true
-Infinity       NaN -1.7976931348623157E308 false

      NaN       NaN                     NaN false
      NaN       NaN                     NaN false

表达式在NaN情况下不相等并不令人惊讶(根据NaN的定义);但这些表达式对于+ infinity和-infinity也不是真的(见最后一栏)。

这个答案并不是为了提供有问题的值的详尽列表,而是为了表明存在一些有问题的值。