欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Java整数除法的精度问题: int / int

最编程 2023-12-27 11:34:04
...

文章目录

    • 结论
    • 两个 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,需要加后缀lL,例:

// long a1 = 12345678901111;	// 错误: 过大的整数
long a2 = 12345678901111L;

而写下小数,则类型默认为double
若要指定小数数值常量的类型为float,则加后缀fF,例:

// float f1 = 2.34;	// 错误: 不兼容的类型: 从double转换到float可能会有损失
float f2 = 2.34F;

那么不同类型的变量之间进行运算,运算结果的类型如何?

  1. 整数之间
    byte, short, int这三种类型的整数之间运算,结果都为int类型。
    证明:
short a = 1;
short b = 2;
// short c = a + b;	// 错误: 不兼容的类型: 从int转换到short可能会有损失

可见:两个整数常量的运算,结果默认为int类型。

longint范围大。
long与其他三种整数类型参与运算,结果为long向上提升(范围)

向上提升范围是为了有足够多的空间存储结果的数据。

  1. 小数之间

不用测试,已知:
浮点数类型默认为double
结果的存储范围向上提升。
那么:
float与float、float与double、double与double之间的运算,结果终为double。

  1. 整数和小数混合

小数,也称浮点数,在计算机中的存储很复杂,有三个部分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天),语言设计的一些缺陷|特色:

在这里插入图片描述
大佬的微笑:
在这里插入图片描述

推荐阅读