文章目录
- 结论
- 两个 int 变量的除法运算 结果的精度问题
- Java中其他基本类型的运算规则 && 数值存储规则
- 延伸
结论
不可以两个int
变量直接做除法,会丢失精度。
推荐:将其中一个int
变量强制转换类型为小数即可。
两个 int 变量的除法运算 结果的精度问题
代码如下:
public class Test {
public static void main(String[] args) {
// / 的两个操作数都为int变量,则运算结果也为int
System.out.println(5 / 2); // 2
// 将其中任意一个操作数转换为浮点数,则运算为:int和double的运算,结果也为double。
System.out.println(5 / 2.0); // 2.5
System.out.println(5.0 / 2); // 2.5
// 模拟 int / int
int a = 5;
int b = 2;
int result = a / b;
System.out.println(result); // 2
}
}
两个int
类型加减、乘法都没有问题。但是除法:
两个int
进行除法运算,结果依旧是int
类型。
所以像5 / 2
这样,结果明明为2.5
,但是小数部分会直接省略(int只用于存整数,没有存储浮点数的机制)。
问题可大可小。
当多则运算层层嵌套的时候,最内层的运算一般不做四舍五入,而是用分数表示。
等运算执行到最外层再对最终的运算结果进行四舍五入,可以减少误差。
Java中其他基本类型的运算规则 && 数值存储规则
4种整数:byte, short, int, long
2种小数:float, double
当在代码中写下整数的数值常量(如123
),其类型默认为int
,
若要指定整数数值常量的类型为long
,需要加后缀l
或L
,例:
// long a1 = 12345678901111; // 错误: 过大的整数
long a2 = 12345678901111L;
而写下小数,则类型默认为double
。
若要指定小数数值常量的类型为float
,则加后缀f
或F
,例:
// float f1 = 2.34; // 错误: 不兼容的类型: 从double转换到float可能会有损失
float f2 = 2.34F;
那么不同类型的变量之间进行运算,运算结果的类型如何?
- 整数之间
byte, short, int
这三种类型的整数之间运算,结果都为int
类型。
证明:
short a = 1;
short b = 2;
// short c = a + b; // 错误: 不兼容的类型: 从int转换到short可能会有损失
可见:两个整数常量的运算,结果默认为int
类型。
而long
比int
范围大。long
与其他三种整数类型参与运算,结果为long
。向上提升(范围)
向上提升范围是为了有足够多的空间存储结果的数据。
- 小数之间
不用测试,已知:
浮点数类型默认为double
结果的存储范围向上提升。
那么:
float与float、float与double、double与double之间的运算,结果终为double。
- 整数和小数混合
小数,也称浮点数,在计算机中的存储很复杂,有三个部分SEM
分别为:
S sign 符号位
E exponent 指数位
M
详情可百度关键字计算机 浮点数 存储机制
。
总之有两点:
- 计算机内无法存储完整的无理数,存储表示浮点数都是在确定精度范围内的近似值
- 浮点数的存储,要比整数花费更多的空间(运算复杂度也是)。
注意第二点:浮点数比整数使用更多的存储空间
基于之前的:两个数值常量运算,其结果为保证范围足够大,会向上提升范围。
那么:
当一个整数和一个浮点数运算,其结果必然为浮点数。
这也是5 / 2
结果为2
而5 / 2.0
结果为2.5
的原因。
应用方面,要特别注意一些基本方法(计算模块)的实现层代码。
如果有两个int
变量进行除法计算,一定对其中一个int
进行类型的强制转换。
如:
// a, b 为两个 int 类型的参数
int a = 5;
int b = 2;
// double result = a / b; // 错误
double result = a / ((double) b); // 将其中一个运算数做类型的强制转换
否则会在很运算很早期的时候,就丢失精度,进而产生蝴蝶效应。
延伸
- JavaScript是弱类型语言,其声明变量就用一个
var
(或let
,const
)。
在JS中5 / 2
结果一定为2.5
,因为JS中的数值,都是64位浮点数。
那么JS其实存整数挺浪费空间的。
但在JS中,数值运算其实还存在更大的精度问题(不只是数值运算),如:
3.5 - 3.4
0.10000000000000009
这是因为JS的作者Brendan Eich实现JS的时候用时太短(10天),语言设计的一些缺陷|特色:
大佬的微笑: