1.四舍五入实数
正如我们已经讨论过的,当一个实数被分配给一个int
变量时,它总是被四舍五入到最接近的更小的整数——小数部分被简单地丢弃。
但是很容易想象这样一种情况,当一个小数需要在任一方向上四舍五入到最接近的整数,甚至四舍五入。在这种情况下你会怎么做?
对于这种情况和许多类似的情况,Java 有类Math
,它有round()
、ceil()
和floor()
方法。
Math.round()
方法
该Math.round()
方法将数字四舍五入为最接近的整数:
long x = Math.round(real_number)
但这里还有另一个细微差别:此方法返回一个long
整数(不是int
)。因为实数可能非常大,Java 的创建者决定使用 Java 最大的可用整数类型:long
.
因此,如果程序员想要将结果分配给一个int
变量,那么她必须明确地向编译器表明她接受可能的数据丢失(如果结果数字不适合某种类型int
)。
int x = (int) Math.round(real_number)
例子:
陈述 | 结果 |
---|---|
|
|
|
|
|
|
Math.ceil()
方法
该Math.ceil()
方法将数字四舍五入为整数。以下是示例:
陈述 | 结果 |
---|---|
|
|
|
|
|
|
Math.floor()
方法
该Math.floor()
方法将数字向下舍入为整数。以下是示例:
陈述 | 结果 |
---|---|
|
|
|
|
|
|
当然,当将数字向下舍入为整数时,简单地使用类型转换运算符会更容易:(int)
陈述 | 结果 |
---|---|
|
|
如果您觉得很难记住这些名字,简短的英语课会有所帮助:
Math
意味着数学Round
表示圆形Ceiling
意味着天花板Floor
意味着地板
2. 浮点数的结构
该类型可以存储从到double
范围内的值。这种巨大的值范围(与类型相比)是由于类型(以及)具有与整数类型完全不同的内部结构这一事实。在内部,该类型将其值编码为两个数字:第一个称为尾数,第二个称为指数。-1.7*10308
+1.7*10308
int
double
float
double
假设我们有数字123456789
并将其存储在一个double
变量中。当我们这样做时,数字被转换为,并且在内部类型存储两个数字 —和。尾数(“数字的重要部分”或尾数)以红色突出显示,而指数以蓝色突出显示。1.23456789*108
double
23456789
8
这种方法可以存储非常大的数字和非常小的数字。但是由于数字的表示限制为 8 个字节(64 位),并且其中一些位用于存储指数(以及尾数的符号和指数的符号),因此可用于表示尾数的最大位数是15 岁。
这是对实数结构的非常简化的描述。
3. 处理实数时精度损失
使用实数时,请始终牢记实数 并不精确。从十进制转换为二进制时,可能总是会出现舍入错误和转换错误。此外,最常见的错误来源是在完全不同的尺度上添加/减去数字时的精度损失。
最后一个事实对于新手程序员来说有点令人兴奋。
如果我们从 中减去,我们得到。1/109
109
109
在完全不同的尺度上减去数字 | 解释 |
---|---|
|
第二个数字非常小,这将导致其有效数字(以灰色突出显示)被忽略。15位有效数字以橙色突出显示。 |
我们能说什么,编程与数学不同。
4.比较实数时的陷阱
另一个危险在于等待程序员比较实数。它在处理实数时出现,因为舍入误差会累积。结果是,在某些情况下,预期实数相等,但事实并非如此。反之亦然:数字应该不同,但它们是相等的。
例子:
陈述 | 解释 |
---|---|
|
The value of the variable a will be1000000000.0 变量的值 c 将是1000000000.0 (变量中的数字 b 过小) |
在上面的例子中,a
andc
不应该相等,但它们是。
或者我们再举一个例子:
陈述 | 解释 |
---|---|
|
变量的值a 将是1.0 变量的值 b 将是1.0 |
5. 一个有趣的事实strictfp
Java有一个特殊的关键字strictfp
(strict floating point ),这是其他编程语言所没有的。你知道你为什么需要它吗?它会降低浮点数运算的准确性。这是它是如何形成的故事:
GO TO FULL VERSION