继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

由两个byte类型的数相加而得的关于精度损失的小思考

Sean_Chou
关注TA
已关注
手记 4
粉丝 5
获赞 29

一个正在学习Java基础的朋友前两天问了一个问题,是关于精度损失的问题,当时对于我来说,有点模棱两可。
遇到的每个小问题,都值得我们去思考。
【说明】下面的代码片段都是在编译器中通过编译的正确的代码。

// 1
byte b=3;
b=(byte) (b+4);
System.out.println(b);

这位朋友是在字符命令界面运行的Java程序,不像编译器可以直接给出语法提示。在使用javac命令进行编译的时候,给出了“可能损失精度”的错误提示,我当时说是因为你加了个4是int型的(也就是说类型不同),所以在计算的时候转换成int型来计算,最终再转换回去,可是再看下面的例子时,就不好解释了:

//2
byte a1=3;
byte a2=4;
byte a3 = (byte) (a1+a2);
System.out.println(a3);

这里两个byte类型数据相加,计算加法时仍要转换类型,并且可以看到(a1+a2)是int型的。还有下面的例子:

//3
float c1 = 1.2f;
float c2 = 2;
float c3 = c1+c2;
System.out.println(c3);

考虑到大小类型的相互转换以及可能带来的数据溢出(精度损失),我是认为int型(2)往float型转换,当然不会带来精度损失,可是同样会有代码2的问题:都已经声明好了类型了,为什么还会进行类型转换?
现在看来,这里面应该至少存在两个问题:

  1. 类型转换的问题;
  2. 变量运算的问题。
    对于第一个问题,在网上查到了这样一段话:

java核心技术中有这样一句话:
当使用数值进行二元操作时(+, -, *, /),先要将两个操作数转换为同一类型,然后再进行运算。
1.如果两个操作数中有一个是double类型的,另一个操作数就会转换为double类型。
2.否则,如果其中一个操作数是float类型的,另一个操作数将会转换为float类型。
3.否则,如果其中一个操作数是long类型的,另一个操作数将会装换为long类型。
4.否则,两个操作数都将转换为int类型。

这种定论或者总结规律的突然出现,大概会让我惊慌失措。
另外,关于变量,《Java语言程序设计》的定义是:

变量用于表示在程序中可能被改变的值。

在网上又找到了这样的表述:

a和b是“变量”意味着这两值不确定、可能随时变化,编译器无法检查,也无法确定是否在byte字节范围之内, 它检查不了就会报错(可能丢失精度),如果是“常量”编译器就能够判断了。
当两个数是常量时才进行判断常量是否在byte类型范围内:若在,就相加;若不在,就报错,因为可能会丢失精度。

似乎这是对的,两个byte变量转化为int(这一步是没有精度损失的)后相加得到int型的和,接下来要转换为byte型,可是编译器无法检查和转换为byte是否可行,所以就报错“可能会有精度丢失”,而常量是不一样的。
图片描述

//4
final byte s1=3;
final byte s2=4;
byte s3 = s1+s2;
System.out.println(s3);

s1,s2被声明为常量,在后来的计算过程中确实没有再进行类型转换。


时间仓促,这一篇可能现在只是有问题就针对问题,以后再来完善。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP