编程语言中的数据类型对数据进行分类并表示特定类别中的数据,该类别确定可以存储在变量中的值的类型。不同的编程语言提供不同的,包括整数、浮点数、字符、字符串和布尔值。
在本篇文章中,我们将重点关注 float 和 double 之间的差异。
float 和 double 之间的区别在于它们的精度。Float 是 32 位单精度浮点类型,而 double 是 64 位双精度浮点类型。
然而,关于这些数据类型还有更多需要了解,例如它们是如何存储的?他们的用例是什么?更重要的是,Java 中的 float 和 double 有什么区别吗?
浮点数的两种表示形式
二进制系统中的数字由三部分组成:
- 符号:表示数字是正数还是负数。通常用一个位来表示,00表示积极和11表示负数。
- 整数:表示小数点前出现的整数。
- 分数:表示小数点后出现的分数。
二进制系统中数字的表示
二进制数的定点表示对整数和小数部分使用固定位数。虽然方便,但定点表示的精度有限,并且取决于分配给小数部分的位数。
以一个16位的3.1416为例,我们用7位表示整数,用8位表示小数点后的小数。剩余的1位保留给符号位。
- 符号位将是00因为数字是正数。
- 整数3转换为二进制为00000110000011。
- 分数0.1416转换为二进制为0010010000100100。
另一种方法可以是固定数字的位数和另一组位以指示小数点在该数字内的位置。这称为浮点表示。我们将没有小数点的数字称为尾数,将小数点的位置称为指数。浮点表示对于数值范围较大且精度要求较高的应用非常有利。
浮点表示
我们继续前面的例子,看看如何3.1416以 16 位浮点表示形式表示。考虑到10尾数位和5对于指数,符号位将为s=0因为数字是正数。对于尾数,我们从相当于的二进制开始3.1416=11.00100100,可以写成11.00100100×2^1。现在尾数将是1100100100,指数是二进制表示1=00001。
Java 中的float与double
理解了浮点表示的概念后,区分 float 和 double 就变得很容易了。正如前面所述,float 和 double 之间的主要区别在于它们的精度。
根据 IEEE 754 标准,float是 32 位二进制格式,而double是 64 位二进制格式。下表总结了指数和尾数所用位数的差异:
Float |
Double |
|
符号 |
1 |
1 |
指数 |
8 |
11 |
尾数 |
23 |
52 |
全部 |
32 |
64 |
现在我们知道了 float 和 double 中的位分布,我们可以确定数据类型的范围——可以存储的最大值和最小值。
- float 可以存储大约范围为:±1.5×10^-45到±3.4×10^38(大约6-7位的有效数字)。
- double 可以存储大约范围为:±5×10^-324到±1.7×10^308(大约15位的有效数字)。
应用领域比较
Float
一般来说,精度要求较低、受处理能力限制或受存储限制的应用程序适合使用 float 而不是 double。这些应用程序的一些常见示例如下:
- 移动设备:移动设备的存储空间通常有限,因此浮动成为显而易见的选择。与 double 相比,Float 需要更少的内存并且处理能力更高效。
- 时间关键型系统:时间关键型系统通常受到延迟的限制,这使得它们成为使用浮动的明显用例。一个典型的例子是自动驾驶汽车,其中更快的处理速度和低处理延迟至关重要。请注意,使用浮点将使处理速度更快,但会牺牲精度。
- 图形和音频处理:由于浮点精度较低,因此它也适用于图形和音频处理——它可以提供足够精度的应用程序。
Double
由于 double 提供了更高的精度,因此与 float 相比,用例是不同的。以下是一些适合使用双精度而不是浮点的示例:
- 财务计算:由于精度是这里的关键,因此在财务计算中优选使用 double 以避免舍入误差。
- 科学计算: double 的另一个用例是需要准确性的科学计算。示例包括物理模拟、统计模拟、气候建模等。
- 防御系统:防御系统是精度至关重要的重要应用。这是因为在导弹制导系统等防御系统中,表示坐标至关重要,并且会显着影响结果的准确性。
下图简要总结了如何在浮点型和双精度型之间进行选择。衡量底层应用程序的要求进行选择。
具有精度、延迟和存能力的蜘蛛图
舍入误差
浮点数的算术运算并不精确,可能会导致舍入错误。这些舍入误差会随着时间的推移而累积,从而导致意外的结果。
让我们来看一个简单的例子,在Java中 fractinotallow=1/10 加十次。理想情况下,它应该导致1. 我们来看看浮点运算是如何计算的。
public class Main {
public static void main(String[] args) {
float exp_result = 1.0f;
float fraction = 1.0f / 10.0f;
System.out.println();
float sum = 0.0f;
for (int i = 0; i < 10; i++) {
sum += fraction;
}
System.out.println("预期结果: " + exp_result);
System.out.println("实际总和: " + sum);
if (exp_result == sum)
System.out.println("预期结果等于计算结果");
else
System.out.println("预期结果不等于计算结果");
}
}
算术运算中的舍入误差示例
在这里,我们在第 3-4 行f附加或F到值以声明浮点数。我们在第 4 行定义一个fraction并在for循环中将sum添加到第 9-11 行的变量fraction十次。最后,第 16-19 行比较了预期结果和实际结果。
运行结果
注意:即使我们将第 3-4 行的变量类型从 float 更改为 double,输出也不会改变。
输出显示实际结果与预期结果不同。这是因为舍入误差随着时间的推移而累积。
公差使用
使用浮点数时,使用适当的公差值比精确更重要。这可以避免在比较浮点数时出现意外结果。公差的选择取决于应用和所需的精度。让我们看看如何在示例中使用公差值。
public class Main {
public static void main(String[] args) {
float exp_result = 1.0f;
float fraction = 1.0f / 10.0f;
float tolerance = 0.000001f;
System.out.println();
float sum = 0.0f;
for (int i = 0; i < 10; i++) {
sum += fraction;
}
System.out.println("预期结果: " + exp_result);
System.out.println("实际总和 : " + sum);
if (Math.abs(exp_result - sum) < tolerance)
System.out.println("预期结果等于计算结果");
else
System.out.println("预期结果不等于计算结果");
}
}
比较两个浮点数与容差的示例
在这里,我们在第 5 行定义了一个变量tolerance来比较第 17 行实际结果和预期结果之间的绝对差异。现在输出符合预期。
总结
在Java中,"float"和"double"是用于表示浮点数的两种数据类型。它们用于存储具有小数部分的数值,区别在于精度和存储空间。
- 精度:double类型提供更高的精度,因为它具有更多的有效数字位数。这使得它在需要更高精度的计算和存储要求较高的场景中更加适用。
- 存储空间:float类型占用32位的存储空间,而double类型占用64位的存储空间。这意味着double类型需要更多的内存来存储数值,但也提供了更大的范围和精度。
在选择使用float还是double时,需要根据具体需求和性能要求进行权衡。通常情况下,如果需要更高的精度或处理较大的数值范围,建议使用double类型。然而,如果内存占用是一个关键因素,或者对精度要求不是特别高,可以考虑使用float类型以节省内存空间。