杰瑞科技汇

java float和double

floatdouble 都是 Java 用来表示带有小数部分的数字(浮点数)的基本数据类型。double 的精度和范围是 float 的两倍,是 Java 中最常用的浮点类型。

java float和double-图1
(图片来源网络,侵删)

基本定义与用途

特性 float (单精度浮点数) double (双精度浮点数)
类型名称 float double
内存占用 32位 (4字节) 64位 (8字节)
精度 大约 7 位十进制有效数字 大约 15-16 位十进制有效数字
表示范围 大约 ±3.4E-38 到 ±3.4E+38 大约 ±1.7E-308 到 ±1.7E+308
默认类型 不是默认类型 默认类型
使用场景 对内存要求极其严格,且精度要求不高的场景(如:游戏中的坐标、图形学) 科学计算、金融、大多数需要高精度的场景

精度和范围详解

这是理解 floatdouble 最关键的部分。

精度

精度指的是数字能够被准确表示的十进制位数。

  • float: 只能保证大约 7 位十进制数的准确性。
    • 90f 是准确的。
    • 01f 可能会被存储为 0,小数点后的精度就丢失了。
  • double: 能保证大约 15-16 位十进制数的准确性。
    • 67 这样的数字,double 可以精确表示。
    • 只有当数字超过 16 位时,才会开始丢失精度。

代码示例:

public class PrecisionTest {
    public static void main(String[] args) {
        float f = 123456789.0f; // 9位数字
        double d = 123456789.0;
        System.out.println("Float value: " + f); // 输出可能不是 123456789.0
        System.out.println("Double value: " + d); // 输出会是 123456789.0
        // 一个更明显的例子
        float f1 = 1.123456789f;
        double d1 = 1.123456789;
        System.out.println("Float f1: " + f1); // 输出可能是 1.1234568
        System.out.println("Double d1: " + d1); // 输出是 1.123456789
    }
}

范围

范围指的是数字可以表示的最大值和最小值(接近于零)。

java float和double-图2
(图片来源网络,侵删)

double 的范围比 float 大得多,可以表示更大或更小的数字。


在 Java 代码中的使用(关键语法)

1 字面量

直接在代码中写一个数字,它默认是什么类型?

  • 默认为 double14, 01, -9.8 这些带小数点的数字,在 Java 中都被默认视为 double 类型。
  • 如何表示 float 字面量:在数字后面加上 fF
    • float pi = 3.14f; // 正确
    • float pi = 3.14; // 编译错误! 因为 3.14 是 double,不能直接赋值给一个 float(会丢失精度),除非你进行强制类型转换。

2 声明和初始化

// 声明一个 float 变量
float myFloat;
// 初始化
myFloat = 10.5f; // 必须带 f
// 声明并初始化
double myDouble = 10.5; // 默认就是 double,不需要 d (但可以写 10.5d)
// 科学计数法
float f2 = 1.23e5f; // 1.23 * 10^5
double d2 = 1.23E-5; // 1.23 * 10^-5

3 类型转换

由于 double 的精度更高,Java 的类型转换规则如下:

  1. double -> float: 这是缩小转换,会丢失精度,Java 编译器会报错,除非你使用强制类型转换。

    java float和double-图3
    (图片来源网络,侵删)
    double d = 9.78;
    // float f = d; // 编译错误: 不兼容的类型: 从double转换到float可能会有损失
    float f = (float) d; // 正确,但精度可能丢失
  2. float -> double: 这是扩大转换,不会丢失信息,编译器会自动完成。

    float f = 3.14f;
    double d = f; // 正确,自动转换
  3. int -> floatdouble: 整数可以自动转换为浮点数,因为浮点数的范围通常比 int 大。

    int i = 100;
    float f = i; // 正确
    double d = i; // 正确

何时选择 float,何时选择 float

这是一个非常实际的问题。

优先选择 double (99% 的情况)

  • 默认选择:除非你有非常充分的理由,否则在处理任何需要小数的计算时,都应该使用 double
  • 性能:在现代的 64 位处理器上,double 的计算速度通常和 float 一样快,甚至更快,因为硬件原生支持 64 位浮点运算。
  • 精度double 的高精度可以避免很多意想不到的精度问题,尤其是在金融、科学计算等关键领域。
  • API 兼容性:Java 的大多数数学库函数(如 Math.sqrt())和 System.out.println() 在处理浮点数时,都默认使用 double

仅仅在以下情况考虑使用 float

  • 内存敏感型应用:当你需要处理海量的浮点数数据,并且内存成为瓶颈时,在移动设备或嵌入式系统中处理大型 3D 模型的顶点坐标(数百万个点),使用 float 可以节省一半的内存。
  • 文件存储和网络传输:当需要将大量浮点数据写入文件或通过网络发送时,使用 float 可以减少 I/O 带宽和存储空间。

重要的注意事项:浮点数不精确

这是所有使用浮点数的程序员必须了解的核心概念。

浮点数在计算机中是以二进制科学计数法存储的,而很多十进制小数在二进制中是无限循环的,无法精确表示。

经典示例:

public class FloatingPointTrap {
    public static void main(String[] args) {
        // 预期结果应该是 0.1
        System.out.println(0.1 + 0.2); // 输出: 0.30000000000000004
        // 预期结果应该是 false
        System.out.println(0.1 + 0.2 == 0.3); // 输出: false
    }
}

为什么会这样? 12 在二进制中都是无限循环小数,计算机只能存储它们的近似值,当这两个近似值相加时,结果也只是一个近似值,它不等于 3 的近似值。

如何正确比较浮点数? 不要使用 或 来直接比较浮点数,应该判断它们的差值是否在一个非常小的“误差范围”(epsilon)内。

public class FloatingPointComparison {
    public static void main(String[] args) {
        double a = 0.1 + 0.2;
        double b = 0.3;
        // 定义一个很小的误差范围
        double epsilon = 0.000001;
        // 判断 a 和 b 的差值是否在误差范围内
        if (Math.abs(a - b) < epsilon) {
            System.out.println("a 和 b 在误差范围内被认为是相等的。");
        } else {
            System.out.println("a 和 b 不相等。");
        }
    }
}

特性 float double
核心思想 32位单精度 64位双精度
何时用 内存极其紧张时 默认选择,绝大多数情况
精度 ~7位 ~15-16位
字面量 数字后加 fF 默认,数字后可加 dD
最大陷阱 精度不足 浮点数不精确,不能直接用 比较

记住这个黄金法则:除非你明确知道需要 float 并且有充分的理由(如内存限制),否则请始终使用 double

分享:
扫描分享到社交APP
上一篇
下一篇