1. 负整数的二进制怎样表示
- 二进制使用最高位表示符号位,用 1 表示负数,用 0 表示正数
- 但负数表示不是简单地将最高位变为 1。负数的二进制表示就是对应的正数的补码
- 补码 = 原码取反 + 1
2. 给定一个负数的二进制表示,怎样知道它的十进制。试写出 10010010
的十进制表示
- 可以采用相同的补码运算,类似于十进制中的负负得正
- 对于
10010010
。首先得到正数:对10010010
做补码运算。首先取反,变为01101101
;然后加 1,变为01101110
- 其次转换为十进制:
01101110
的十进制值为 110,所以原值就是 -110
3. 负整数的二进制为什么采用对应正数的补码这种奇怪的表示形式
- 因为计算机只能做加法,1 - 1 其实就是 1 + (-1)
- 只有这种形式,计算机才能实现正确的加减法。如果用原码表示,计算结果是不对的
- 虽然看上去比较奇怪和难以理解,但这种表示其实是非常严谨和正确的
4. 为什么正数的运算结果可能出现负数
- 当计算结果超出表示范围的时候,最高位往往是 1,然后就会被看做负数
5. Java 中怎样表示二进制位或二进制常量
- Java 7 之前不支持直接写二进制常量。比如,想写二进制形式的 11001,Java 7 之前不能直接写,可以在前面补 0,补足 8 位,为 00011001,然后用 16 进制表示,即 0x19
- Java 7 开始支持二进制常量,在前面加
0b
或0B
即可。比如:int a = 0b11001;
6. Java 中位运算都有哪些
- 移位运算:
- 左移:操作符为
<<
- 无符号右移:操作符为
>>>
- 有符号右移:操作符为
>>
- 左移:操作符为
- 逻辑运算:
- 按位与:
&
- 按位或:
|
- 按位取反:
~
- 按位异或:
^
- 按位与:
7. 计算机中很多数不能精确表示和计算的原因是
- 本质原因是计算机根本就不能精确地表示很多数
- 计算机的底层是二进制,而二进制只能表示那些可以表述为 2 的多少次方和的数,所以很多数只能无限接近但不能精确表示
8. 为什么计算机中不能用我们熟悉的十进制
- 计算机的底层使用的电子元器件只能表示为两个状态,通常是低压和高压,对应 0 和 1,使用二进制容易基于这些电子元器件构建硬件设备和进行运算
- 如果非要使用十进制,则这些硬件就会复杂很多,并且效率低下
9. 下面的代码:System.out.println(0.1f + 0.1f);
和 System.out.println(0.1f * 0.1f);
为什么小数的加法结果正确而乘法却不精确
- 第一行输出 0.2,第二行输出 0.010000001。0.2 看似是准确的,其实这只是 Java 语言给我们造成的假象
- 真实计算结果其实也是不精确的,但是由于结果和 0.2 足够接近,在输出的时候,Java 选择输出 0.2 这个看上去非常精简的数字,而不是一个中间有很多 0 的小数
- 在误差足够小的时候,结果看上去是精确的,但不精确其实才是常态
10. 实际开发中,面对计算不精确的情况,作为开发者如何解决这个问题
- 大部分情况下,我们不需要那么高的精度,可以四舍五入,或者在输出的时候只保留固定个数的小数位
- 如果真的需要比较高的精度,有两种方法:
- 一种方法是将小数转化为整数进行运算,运算结果再转化为小数
- 另一种方法是使用十进制的数据类型,这个并没有统一的规范。在 Java 中是
BigDecimal
,运算更准确,但效率比较低
11. 怎么理解浮点数
- 浮点数其实就是小数,但在概念上比小数更加严谨
- 这是因为小数的二进制表示中,表示那个小数点的时候,点不是固定的,而是浮动的
12. 十进制有科学计数法,二进制怎样表示小数
- 和十进制的科学计数法类似:
m *(2 ^ e)
。m
称为尾数,e
称为指数
13. NaN 什么意思
- 几乎所有的硬件和编程语言表示小数的二进制格式都是一样的。这种格式是一个标准,叫做 IEEE 754 标准,它定义了两种格式,一种是 32 位的,对应于 Java 的
float
,一种是 64 位的,对应于 Java 的double
- 在两种格式中,除了表示正常的数,IEEE 754 标准还规定了一些特殊的二进制形式表示一些特殊的值,比如负无穷、正无穷、0、
NaN
NaN
表示非数值,比如 0 乘以无穷大