作业
原码、反码和补码
原码
原码是最直观的表示方法,用第一位表示符号(0为正,1为负),其余位表示数值本身。
例如:
+5 的原码是 0101(假设我们使用4位二进制数)
-5 的原码是 1101
反码
反码用于简化计算机中的减法操作。对于正数的反码与其原码相同;对于负数,其反码是将原码中除符号位外的所有位取反(0变1,1变0)。
例如:
+5 的反码是 0101
-5 的反码是 1010
补码
补码也是用于简化计算机中的减法操作。正数的补码与其原码相同;负数的补码是其反码加1。
例如:
+5 的补码是 0101
-5 的补码是 1011
Java中的表示
Java中的整数默认是采用补码形式表示的。
示例程序
以下是一个Java程序,它将执行位操作并显示结果,我们可以用这些结果来验证Java中整数的表示方式。
public class BitwiseOperations {
public static void main(String[] args) {
int positiveNumber = 5;
int negativeNumber = -5;
// 输出原码、反码和补码
System.out.println("正数 +5 的二进制表示(补码形式,Java中的实际表示): " + Integer.toBinaryString(positiveNumber));
System.out.println("负数 -5 的二进制表示(补码形式,Java中的实际表示): " + Integer.toBinaryString(negativeNumber));
// 手动计算反码和补码进行验证
String positiveBinary = Integer.toBinaryString(positiveNumber);
String negativeBinary = Integer.toBinaryString(negativeNumber);
// 正数的原码、反码、补码相同
System.out.println("正数 +5 的原码: " + positiveBinary);
System.out.println("正数 +5 的反码: " + positiveBinary);
System.out.println("正数 +5 的补码: " + positiveBinary);
// 负数的原码
String negativeOriginal = "1" + positiveBinary.substring(1);
System.out.println("负数 -5 的原码: " + negativeOriginal);
// 负数的反码(除符号位外取反)
String negativeOnesComplement = negativeOriginal.chars()
.mapToObj(c -> c == '0' ? "1" : "0")
.collect(Collectors.joining());
System.out.println("负数 -5 的反码: " + negativeOnesComplement);
// 负数的补码(反码+1)
int negativeTwosComplement = Integer.parseInt(negativeOnesComplement, 2) + 1;
System.out.println("负数 -5 的补码: " + Integer.toBinaryString(negativeTwosComplement));
// 验证Java中的表示
System.out.println("Java中的负数 -5 补码表示(预期与上面计算得到的补码相同): " + negativeBinary);
}
}
手工计算与程序输出比对
当你运行上述程序时,观察到输出结果,并将其与手工计算的结果进行比对。对于正数,原码、反码、补码都是相同的,而对于负数,Java中的表示(即补码)应该与你手工计算得到的补码一致。
这表明Java确实使用的是补码来表示整数。
Java中的变量具有特定的作用域
它决定了变量的可见性和生命周期。下面我将编写一个Java示例程序,在不同的作用域中定义同名的变量,并观察输出的值。
public class ScopeExample {
// 类变量
static int variable = 10;
public static void main(String[] args) {
// 方法中的局部变量,屏蔽了类变量
int variable = 20;
System.out.println("方法中的局部变量: " + variable); // 输出局部变量的值
// 在方法内部定义一个代码块,创建一个新的作用域
{
// 在代码块中定义一个同名的局部变量,屏蔽了外层的局部变量
int variable = 30;
System.out.println("代码块中的局部变量: " + variable); // 输出代码块中的局部变量
}
// 代码块结束后,这里的变量引用的是最外层的局部变量
System.out.println("代码块外的局部变量: " + variable); // 输出方法中的局部变量
// 使用类名调用类变量,避免屏蔽问题
System.out.println("类变量: " + ScopeExample.variable); // 输出类变量的值
}
}
输出结果:
方法中的局部变量: 20
代码块中的局部变量: 30
代码块外的局部变量: 20
类变量: 10
类变量variable被初始化为10。
在main方法中,定义了一个同名的局部变量variable,其值为20,这屏蔽了类变量。
在main方法内部的一个代码块中,定义了另一个同名的局部变量variable,其值为30,这屏蔽了外层的局部变量。
当代码块结束时,代码块外的variable仍然引用的是main方法中的局部变量,因此输出20。
为了访问被屏蔽的类变量,我们使用了ScopeExample.variable,输出类变量的值,即10。
示例:
java中的类型转换
看着这个图,再查查Java中每个数据类型所占的位数,和表示数值的范围,你能得出什么结论
可以总结出以下关于 Java 中基本数据类型的位宽、取值范围及其转换关系的结论:
byte:
位宽: 8 位(1 字节)
取值范围: -128 到 127
short:
位宽: 16 位(2 字节)
取值范围: -32768 到 32767
int:
位宽: 32 位(4 字节)
取值范围: -2147483648 到 2147483647
long:
位宽: 64 位(8 字节)
取值范围: -9223372036854775808 到 9223372036854775807
float:
位宽: 32 位(4 字节)
取值范围: 约 ±3.40282347E38F(有效数字约6~7位)
double:
位宽: 64 位(8 字节)
取值范围: 约 ±1.79769313486231570E308(有效数字约15位)
从图中可以看出,不同数据类型之间的转换关系如下:
无精度损失转换:
byte -> short -> int -> long
char -> int -> long
这些转换不会导致数值精度的丢失,因为目标类型的位宽至少与源类型相同或更大。
有精度损失转换:
int -> float
long -> double
float -> double
这些转换可能会导致数值精度的丢失,特别是当从一个整数类型转换为浮点数类型时,可能会出现舍入误差。
浮点数的表示方法
计算机使用 IEEE 754 标准来表示浮点数,这种表示方法包括三个部分:符号位、指数位和小数位(也称为尾数位或有效数字位)。以下是 IEEE 754 标准的一些关键点:
符号位:决定数值的正负,0 表示正数,1 表示负数。
指数位:表示 2 的幂次,用于缩放尾数。
尾数位:表示实际的数字信息,通常是 2 的幂次的分数。
精度限制
尾数位的限制:由于存储空间的限制,double 类型通常有 52 位用于尾数(加上一个隐含的前导 1,总共 53 位精度),这意味着它不能精确表示所有的十进制小数。例如,0.1 在二进制中是一个无限循环小数,因此不能完全精确地表示为 double。
指数位的限制:指数位决定了数值的范围,但是也有最大和最小的限制。超出这个范围,数值就会变成无穷大或者非常接近零。
舍入误差
当一个数不能精确表示时,必须进行舍入。IEEE 754 标准定义了几种舍入模式,例如向最接近的值舍入、向上舍入或向下舍入。这种舍入过程会导致误差。
运算误差累积
在进行多次浮点运算时,舍入误差会累积,导致最终结果与数学上的精确结果有较大偏差。
示例
public class FloatingPointPrecision {
public static void main(String[] args) {
double a = 0.1;
double b = 0.2;
double sum = a + b;
System.out.println("The sum of 0.1 and 0.2 is: " + sum); // 输出可能不是 0.3
}
}
a + b 的结果可能不会是精确的 0.3,因为 0.1 和 0.2 在二进制表示中都不是精确的,它们的和自然也不会是精确的。
在需要高精度计算的应用中,通常会使用 BigDecimal 类或其他专门的数值计算库来避免这些问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!