Java_语法基础_浮点数 最近舍入模式

例:

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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值