例:
package deep;
public class RoundToNearest {
public static void main(String[] args) {
float left = 1.2345678f;
float right = Math.nextUp(left);
System.out.println("左边值:" + left);
System.out.println("右边值:" + right);
System.out.println("float类型数据测试:");
float[] f = new float[10];
for (int i = 0; i < f.length; ++i) {
String s = "1.2345678" + i;
f[i] = Float.valueOf(s).floatValue();
System.out.print("原值:" + s + " ");
System.out.println("实际值:" + f[i]);
}
}
}
运行结果:
左边值:1.2345678
右边值:1.2345679
float类型数据测试:
原值:1.23456780 实际值:1.2345678
原值:1.23456781 实际值:1.2345678
原值:1.23456782 实际值:1.2345678
原值:1.23456783 实际值:1.2345679
原值:1.23456784 实际值:1.2345679
原值:1.23456785 实际值:1.2345679
原值:1.23456786 实际值:1.2345679
原值:1.23456787 实际值:1.2345679
原值:1.23456788 实际值:1.2345679
原值:1.23456789 实际值:1.2345679
由于float只能表示7~8个有效数字,当最后一位是0~2时,使用左边值1.2345678代替,当最后一位是3~9时,使用右边值1.2345679代替,从这个结果似乎看不出什么规律来,不过至少可以说明一点,就是取值模式肯定不是数学上的四舍五入模式。
接下来我们使用BigDecimal来得到更精确的值:
package deep;
import java.math.BigDecimal;
public class RoundToNearest2 {
public static void main(String[] args) {
float left = 1.2345678f;
float right = Math.nextUp(left);
System.out.println("验证测试结果:");
BigDecimal exactLeft = new BigDecimal(left);
BigDecimal exactRight = new BigDecimal(right);
System.out.println("更精确的left值:" + exactLeft);
System.out.println("更精确的right值:" + exactRight);
for (int i = 0; i <= 9; ++i) {
System.out.println("--------------------");
String s = "1.2345678" + i;
BigDecimal bd = new BigDecimal(s);
// 调用abs方法取左右间隙的绝对值
BigDecimal leftGap = bd.subtract(exactLeft).abs();
BigDecimal rightGap = bd.subtract(exactRight).abs();
float f = bd.floatValue();
System.out.println("浮点值:" + bd + "选择的近似代替值:" + f);
System.out.println(s + "左间隙:" + leftGap);
System.out.println(s + "右间隙:" + rightGap);
int value = leftGap.compareTo(rightGap);
if (value > 0) {
System.out.print("左间隙大于右间隙,");
} else if (value == 0) {
System.out.print("左间隙等于右间隙,");
} else {
System.out.print("左间隙小于右间隙,");
}
if (f == left) {
System.out.println("选择左边的值作为代替值。");
} else if (f == right) {
System.out.println("选择右边的值作为代替值。");
} else {
System.out.println("选择其他值作为代替值。");
}
}
}
}
运行结果:
验证测试结果:
更精确的left值:1.23456776142120361328125
更精确的right值:1.2345678806304931640625
——————–
浮点值:1.23456780选择的近似代替值:1.2345678
1.23456780左间隙:3.857879638671875E-8
1.23456780右间隙:8.06304931640625E-8
左间隙小于右间隙,选择左边的值作为代替值。
——————–
浮点值:1.23456781选择的近似代替值:1.2345678
1.23456781左间隙:4.857879638671875E-8
1.23456781右间隙:7.06304931640625E-8
左间隙小于右间隙,选择左边的值作为代替值。
——————–
浮点值:1.23456782选择的近似代替值:1.2345678
1.23456782左间隙:5.857879638671875E-8
1.23456782右间隙:6.06304931640625E-8
左间隙小于右间隙,选择左边的值作为代替值。
——————–
浮点值:1.23456783选择的近似代替值:1.2345679
1.23456783左间隙:6.857879638671875E-8
1.23456783右间隙:5.06304931640625E-8
左间隙大于右间隙,选择右边的值作为代替值。
——————–
浮点值:1.23456784选择的近似代替值:1.2345679
1.23456784左间隙:7.857879638671875E-8
1.23456784右间隙:4.06304931640625E-8
左间隙大于右间隙,选择右边的值作为代替值。
——————–
浮点值:1.23456785选择的近似代替值:1.2345679
1.23456785左间隙:8.857879638671875E-8
1.23456785右间隙:3.06304931640625E-8
左间隙大于右间隙,选择右边的值作为代替值。
——————–
浮点值:1.23456786选择的近似代替值:1.2345679
1.23456786左间隙:9.857879638671875E-8
1.23456786右间隙:2.06304931640625E-8
左间隙大于右间隙,选择右边的值作为代替值。
——————–
浮点值:1.23456787选择的近似代替值:1.2345679
1.23456787左间隙:1.0857879638671875E-7
1.23456787右间隙:1.06304931640625E-8
左间隙大于右间隙,选择右边的值作为代替值。
——————–
浮点值:1.23456788选择的近似代替值:1.2345679
1.23456788左间隙:1.1857879638671875E-7
1.23456788右间隙:6.304931640625E-10
左间隙大于右间隙,选择右边的值作为代替值。
——————–
浮点值:1.23456789选择的近似代替值:1.2345679
1.23456789左间隙:1.2857879638671875E-7
1.23456789右间隙:9.3695068359375E-9
左间隙大于右间隙,选择右边的值作为代替值。
代替值会选取间隙小的那一个。
但如果左右两边的间隙相等怎么办呢?
package deep;
import java.math.BigDecimal;
public class RoundToNearest3 {
public static void main(String[] args) {
BigDecimal left = new BigDecimal(16777216);
BigDecimal right = new BigDecimal(16777218);
BigDecimal bd = new BigDecimal(16777217);
System.out.println("左边值:" + left.floatValue());
System.out.println("右边值:" + right.floatValue());
BigDecimal leftGap = bd.subtract(left).abs();
BigDecimal rightGap = bd.subtract(right).abs();
System.out.println("左间隙:" + leftGap);
System.out.println("右间隙:" + rightGap);
if (leftGap.compareTo(rightGap) == 0) {
System.out.println("左右间隙值相等");
} else {
System.out.println("左右间隙值不相等");
}
System.out.println("代替值为:" + bd.floatValue());
}
}
运行结果:
左边值:1.6777216E7
右边值:1.6777218E7
左间隙:1
右间隙:1
左右间隙值相等
代替值为:1.6777216E7
当左右间隙相等的时候,选取代替值的标准就是选择有效位数最低位为0的那个。以本程序来说,1.6777216f的32位存储为:
0 10010111 00000000000000000000000
1.6777218f的32位存储为:
0 10010111 00000000000000000000001
因此,最后选取的代替值是1.6777216f。