零基础鸿蒙应用开发第十节:计算机进制与存储单位

零基础鸿蒙应用开发学习计划表

【教学目标】

  1. 掌握二进制、八进制、十进制、十六进制的定义及ArkTS中的表示与转换方法。
  2. 理解位(bit)、字节(Byte)、半字节(Nibble)的核心概念与换算关系。
  3. 彻底搞懂ASCII码的本质、表示形式及在ArkTS中的实际应用。
  4. 理解二进制科学计数法的规范化表示,为后续浮点数存储(IEEE 754标准)打基础。
  5. 建立“计算机存储依赖二进制”的认知,为后续整数/浮点数存储打基础,理解“0.1+0.2≠0.3”的底层伏笔。

【本节重点】

  • 进制本质:计算机为何选择二进制,十六进制、八进制如何简化二进制表示。
  • 转换核心:十进制与二进制、二进制与十六进制/八进制的互转规则。
  • 存储单位:位、字节、半字节的关系,字节作为存储基本单位的原因。
  • ASCII码:字符与数字的“翻译字典”,核心规律与代码实操。
  • 科学计数法:二进制规范化表示(1.xxx×2^e),浮点数存储的底层基础。

一、工程结构

本节我们将创建名为NumberSystemStorageDemo的工程,基于 鸿蒙5.0(API12) 开发,使用 DevEco Studio 6.0+ 工具,项目结构目录如下:

NumberSystemStorageDemo/
├── AppScope                 # 应用全局配置
├── entry/
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/
│   │   │   │   ├── entryability/  # 应用入口
│   │   │   │   │   └── EntryAbility.ets
│   │   │   │   ├── pages/         # 页面代码
│   │   │   │   │   └── Index.ets  # 核心页面
│   │   │   │   ├── utils/       
│   │   │   │   │   └── NumberSystemTest.ets  # 进制/存储相关的学习内容
│   │   │   ├── resources/         # 资源文件
│   │   │   └── module.json5       # 模块配置

二、开篇现象:0.1+0.2≠0.3的底层谜题

在ArkTS开发中,你会遇到一个反直觉的现象:简单的小数运算结果却不符合预期。这并非代码错误,而是计算机底层数据存储规则导致的——而要解开这个谜题,我们必须先掌握进制存储单位二进制科学计数法的核心知识。

// 运行后会发现结果并非0.3和0.02
let num1: number = 0.1;
let num2: number = 0.2;
console.log(`0.1+0.2 = ${num1 + num2}`); // 输出:0.30000000000000004
console.log(`0.1×0.2 = ${num1 * num2}`); // 输出:0.020000000000000004

核心原因:0.1的二进制表示是无限循环小数,而计算机的存储单位(如字节)只能提供有限的位数来存储数据;同时,计算机采用二进制科学计数法存储浮点数,会对无限循环的二进制小数进行截断和近似处理,最终导致运算误差。

// 打印0.1的二进制近似值(循环节为1100,无限循环)
console.log((0.1).toString(2));
// 输出:0.0001100110011001100110011001100110011001100110011001101

三、进制本质与转换:计算机的“语言规则”

3.1 进制的本质:满基数进1的计数规则

进制是“满基数进1”的计数方式,不同进制的核心特征如下:

进制 基数(满几进1) 数字范围 核心价值
十进制 10 0-9 符合人类直觉,日常沟通首选
二进制 2 0-1 硬件天然适配,数据存储/运算底层
八进制 8 0-7 简化二进制(1位=3位二进制),适合短二进制场景
十六进制 16 0-9,A-F 高频简化二进制(1位=4位二进制),开发首选

3.2 计算机为什么非要用二进制?

不是计算机“想”用,而是硬件只能识别二进制
计算机的核心组件是晶体管,晶体管只有“导通”(有电流)和“截止”(无电流)两种稳定状态,恰好对应二进制的0和1。这是硬件层面的天然适配,没有其他选择——而这也是“有限位数存储”的根源。

3.3 进制的表示方法

在ArkTS中,不同进制需用前缀区分,无论用哪种进制声明,变量存储类型均为number(本质是64位双精度浮点数,后续会详解):

进制 ArkTS前缀 示例(表示数字26) 注意事项
十进制 26 无需前缀,直接书写数字
二进制 0b/0B 0b11010 前缀0b不可省略,否则视为十进制
八进制 0o/0O 0o32 必须加0o前缀!禁止仅用0开头(如032在严格模式下报错)
十六进制 0x/0X 0x1A 前缀0x不可省略,A-F不区分大小写

说明:八进制在开发中使用频率远低于十六进制,但在传统系统开发(如Unix)和部分硬件调试场景中仍会遇到,需掌握基础表示与转换;十六进制推荐小写(如0x1a)。

3.4 进制声明:(utils/NumberSystemTest.ets)

/**
 * 测试不同进制的声明(均表示数字26)
 * 验证:无论哪种进制声明,最终均为十进制数值
 */
export function testRadixDeclaration(): void {
  console.log("========== 进制声明测试 ==========");
  // 1. 十进制(默认)
  const decimalNum: number = 26;
  // 2. 二进制(前缀0b)
  const binaryNum: number = 0b11010;
  // 3. 八进制(前缀0o)
  const octalNum: number = 0o32;
  // 4. 十六进制(前缀0x)
  const hexNum: number = 0x1A;

  // 验证:所有进制最终都会转换为十进制数值
  console.log("十进制26:", decimalNum); // 输出:26
  console.log("二进制0b11010转十进制:", binaryNum); // 输出:26
  console.log("八进制0o32转十进制:", octalNum); // 输出:26
  console.log("十六进制0x1A转十进制:", hexNum); // 输出:26

  // 错误示例:仅用0开头的八进制(严格模式下报错,不推荐)
  // const errorOctal: number = 032; // 编译报错:Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o32'. <ArkTSCheck>
}

四、核心转换规则

4.1 十进制整数 ↔ 二进制:除2取余法

步骤:将整数反复除以2,记录每次的余数,直到商为0,最后将余数倒序拼接
演算示例:十进制23转二进制

23 ÷ 2 = 11 余 1
11 ÷ 2 = 5  余 1
5 ÷ 2 = 2   余 1
2 ÷ 2 = 1   余 0
1 ÷ 2 = 0   余 1
→ 余数倒序:1 0 1 1 1 → 0b10111

代码示例:十进制23转二进制

const decimalNum = 23; // 十进制基准数
// toString(2):将十进制数转为二进制字符串(无0b前缀)
const binaryStr = decimalNum.toString(2); 
console.log(`十进制${decimalNum}转二进制:`, binaryStr); // 输出:10111
// 如需带二进制前缀0b,可拼接字符串
console.log(`带前缀的二进制表示:0b${binaryStr}`); // 输出:0b10111

4.2 十进制小数 → 二进制:乘2取整法

步骤:小数部分反复乘2,取每次的整数部分(0或1),直到小数为0或达到精度要求,最后将整数部分顺序拼接

示例1(能除尽):0.625转二进制

0.625 × 2 = 1.25 → 取整1(高位),剩余小数0.25
0.25 × 2 = 0.5   → 取整0,剩余小数0.5
0.5 × 2 = 1.0    → 取整1(低位),剩余小数0
→ 结果:0.101(即0b0.101)

代码示例:0.625转二进制

const decimalFloat = 0.625;
console.log(`十进制${decimalFloat}转二进制:`, decimalFloat.toString(2)); // 输出:0.101

示例2(无限循环):0.1转二进制(核心痛点根源)

0.1 × 2 = 0.2 → 取0
0.2 × 2 = 0.4 → 取0
0.4 × 2 = 0.8 → 取0
0.8 × 2 = 1.6 → 取1
0.6 × 2 = 1.2 → 取1
0.2 × 2 = 0.4 → 取0(开始循环“1100”)
→ 结果:0.0001100110011...(无限循环,无法用有限位数精确表示)

代码示例:0.1转二进制(截取前30位)

const decimalFloat2 = 0.1;
console.log(`十进制${decimalFloat2}转二进制(前30位):`, decimalFloat2.toString(2).substring(0, 30));
// 输出:0.000110011001100110011001100110

这就是“0.1+0.2≠0.3”的底层原因之一——计算机无法用有限位数存储无限循环二进制小数,只能取近似值。

4.3 二进制 ↔ 八进制:3位分组法

八进制的核心价值是“1位=3位二进制”,适合简化短长度的二进制数据:
步骤:从右往左每3位分一组,左侧不足3位补0,每组对应1个八进制数(0-7)。
示例:二进制0b110101(十进制53)转八进制

原始二进制:110101(6位)
步骤1:每3位分组 → 110 101
步骤2:每组转十进制 → 110=6,101=5
步骤3:结果 → 0o65(验证:6×8 + 5 = 53)

代码示例

const binaryToOctalNum = 53;
console.log(`二进制${binaryToOctalNum.toString(2)}转八进制:`, binaryToOctalNum.toString(8)); // 输出:65

4.4 八进制 → 二进制

步骤:每1位八进制数拆分为3位二进制数,合并后去掉左侧前导0。
示例:八进制0o73(十进制59)转二进制

原始八进制:73
步骤1:每位转十进制 → 7=7,3=3
步骤2:每位拆3位二进制 → 7→111,3→011
步骤3:合并 → 111011 → 去掉前导0→111011(0b111011)
验证:1×32 + 1×16 + 1×8 + 0×4 + 1×2 + 1×1 = 59

代码示例

console.log(`八进制65转二进制:`, parseInt("65", 8).toString(2)); // 输出:110101

4.5 二进制 ↔ 十六进制:4位分组法

二进制位数太长(如1字节=8位),人类读写容易出错,十六进制是“最优简化方案”(1位=4位二进制):
步骤:从右往左每4位分一组,左侧不足4位补0,每组对应1个十六进制数(0-9→0-9,10-15→A-F)。
示例:二进制0b1101011(十进制107)转十六进制

原始二进制:1101011(7位)
步骤1:补前导0,每4位分组 → 0110 1011
步骤2:每组转十进制 → 0110=6,1011=11
步骤3:十进制转十六进制 → 6→6,11→B
→ 结果:0x6B

代码示例

const binaryToHexNum = 107;
console.log(`二进制${binaryToHexNum.toString(2)}转十六进制:`, binaryToHexNum.toString(16).toUpperCase()); // 输出:6B

4.6 十六进制 → 二进制

步骤:每1位十六进制数拆分为4位二进制数,合并后去掉左侧前导0。
示例:十六进制0x1A(十进制26)转二进制

原始十六进制:1A
步骤1:每位转十进制 → 1=1,A=10
步骤2:每位拆4位二进制 → 1→0001,10→1010
步骤3:合并 → 00011010 → 去掉前导0→11010
→ 结果:0b11010

代码示例

const hexToBinaryNum = 26;
console.log(`十六进制${hexToBinaryNum.toString(16).toUpperCase()}转二进制:`, hexToBinaryNum.toString(2)); // 输出:11010

4.7 进制转换:(utils/NumberSystemTest.ets)

/**
 * 测试进制转换(开发中常用)
 * - toString(base):十进制转其他进制(base范围2-36)
 * - parseInt(str, base):其他进制转十进制(base范围2-36)
 */
export function testRadixConversion(): void {
  console.log("\n========== 进制转换测试 ==========");
  const decimalNum = 26; // 十进制基准数

  // 1. 十进制转其他进制(toString(base),base为目标进制)
  console.log(`十进制${decimalNum}转二进制:`, decimalNum.toString(2)); // 输出:11010
  console.log(`十进制${decimalNum}转八进制:`, decimalNum.toString(8)); // 输出:32
  console.log(`十进制${decimalNum}转十六进制:`, decimalNum.toString(16).toUpperCase()); // 输出:1A

  // 2. 其他进制转十进制
  const binaryStr = "11010";
  const octalStr = "32";
  const hexStr = "1A";
  console.log(`二进制${binaryStr}转十进制:`, parseInt(binaryStr, 2)); // 输出:26
  console.log(`八进制${octalStr}转十进制:`, parseInt(octalStr, 8)); // 输出:26
  console.log(`十六进制${hexStr}转十进制:`, parseInt(hexStr, 16)); // 输出:26

  // 额外测试:八进制与十六进制间接转换(通过十进制中转)
  const octalToHex = parseInt(octalStr, 8).toString(16).toUpperCase();
  console.log(`八进制${octalStr}转十六进制:`, octalToHex); // 输出:1A
}

/**
 * 验证核心转换规则(十进制↔二进制、二进制↔八进制/十六进制)
 * 重点验证:小数的二进制表示(能除尽 vs 无限循环)
 * 新增:二进制科学计数法的验证
 */
export function testCoreConversionRules(): void {
  console.log("\n========== 核心转换规则验证 ==========");
  // 1. 十进制↔二进制
  const intNum = 23;
  const floatNum = 0.625; // 能除尽的小数
  const floatNum2 = 0.1; // 无限循环的小数
  console.log(`十进制${intNum}转二进制:`, intNum.toString(2)); // 10111
  console.log(`十进制${floatNum}转二进制:`, floatNum.toString(2)); // 0.101(能除尽)
  console.log(`十进制${floatNum2}转二进制(前30位):`, floatNum2.toString(2).substring(0, 30)); // 0.000110011001100110011001100110

  // 2. 二进制↔八进制
  const binaryToOctalNum = 53; // 二进制110101
  console.log(`二进制${binaryToOctalNum.toString(2)}转八进制:`, binaryToOctalNum.toString(8)); // 65
  console.log(`八进制65转二进制:`, parseInt("65", 8).toString(2)); // 110101

  // 3. 二进制↔十六进制
  const binaryToHexNum = 107; // 二进制1101011
  const hexToBinaryNum = 26; // 十六进制1A
  console.log(`二进制${binaryToHexNum.toString(2)}转十六进制:`, binaryToHexNum.toString(16).toUpperCase()); // 6B
  console.log(`十六进制${hexToBinaryNum.toString(16).toUpperCase()}转二进制:`, hexToBinaryNum.toString(2)); // 11010

  // 4. 二进制科学计数法验证(手动计算)
  console.log("\n--- 二进制科学计数法验证 ---");
  const num26 = 26; // 二进制11010 → 1.1010×2^4
  const num01 = 0.1; // 二进制0.000110011... → 1.10011...×2^-4
  console.log(`十进制26的二进制:${num26.toString(2)} → 二进制科学计数法:1.1010×2^4`);
  console.log(`十进制0.1的二进制(前10位小数):${num01.toString(2).substring(0, 12)} → 二进制科学计数法:1.10011...×2^-4`);
}

五、二进制科学计数法:浮点数存储的底层基础

在理解了进制转换后,我们需要掌握二进制科学计数法——这是现代计算机存储浮点数(小数、大数)的核心规则,也是连接进制和浮点数存储的关键桥梁。

5.1 十进制科学计数法

我们日常使用的十进制科学计数法,核心是规范化表示

  • 格式:数值 = 尾数 × 10^指数
  • 要求:1 ≤ 尾数 < 10(尾数必须是“1.xxx”的形式,称为规范化尾数)
  • 示例:
    • 26 = 2.6 × 10^1(尾数2.6,指数1)
    • 0.1 = 1.0 × 10^-1(尾数1.0,指数-1)
    • 123.45 = 1.2345 × 10^2(尾数1.2345,指数2)

5.2 二进制科学计数法

二进制同样遵循科学计数法的逻辑,只是基数从10换成了2,且规范化要求更严格(这是IEEE 754浮点数标准的核心):

  • 格式:数值 = 尾数 × 2^指数
  • 要求:1 ≤ 尾数 < 2(尾数必须是“1.xxx”的二进制形式,这是关键!)
  • 示例1:二进制整数11010(十进制26)
    二进制11010 = 1.1010 × 2^4
    解析:
    - 尾数:1.1010(满足1≤尾数<2的规范化要求)
    - 指数:4(表示将尾数的小数点向右移动4位,得到原数)
    
  • 示例2:二进制小数0.000110011(十进制0.1)
    二进制0.000110011 = 1.10011 × 2^-4
    解析:
    - 尾数:1.10011(满足1≤尾数<2的规范化要求)
    - 指数:-4(表示将尾数的小数点向左移动4位,得到原数)
    

5.3 为什么需要二进制科学计数法?

  • 统一格式:无论数值是整数、小数还是大数,都能转换成“1.xxx×2^e”的统一格式,方便计算机设计存储结构。
  • 节省存储空间:由于规范化尾数的整数部分永远是1,计算机存储时可以省略这个1,只存储小数部分(xxx),从而节省1位的存储空间(这是IEEE 754标准的优化技巧)。
  • 解释精度问题:0.1的二进制科学计数法中,尾数是无限循环的1.100110011...,计算机存储时只能截取有限位数的尾数,这是“0.1无法精确存储”的直接技术原因(后续讲解IEEE 754时会详细拆解)。

说明:二进制科学计数法的“规范化尾数(1.xxx)”是IEEE 754浮点数标准的灵魂,记住这个规则,后续学习浮点数存储会事半功倍。

六、位与字节:数据存储的基本单位

进制是“计数规则”,但数据最终需要通过物理单位存储,位、字节就是计算机存储的“基本积木”——而这些单位的有限性,正是“无法精确存储无限循环二进制小数”的直接原因。

6.1 核心概念与换算关系(必须熟记)

单位名称 英文缩写 核心定义 换算关系
位(比特) bit 最小信息单位,只能表示0或1 1bit = 0/1的状态
半字节(四比特) Nibble 辅助单位,连接字节与十六进制 1Nibble = 4bit(=1位十六进制)
字节 Byte(B) 计算机基本存储/操作单位 1Byte = 8bit = 2Nibble(=2位十六进制=3位八进制余2位)

可视化示例:

  • 1位(bit):01(最小单位,无法存储复杂数据)
  • 1半字节(Nibble):0101(4位,对应十六进制5
  • 1字节(Byte):01011011(8位,对应十六进制0x5B、八进制0o133)——计算机的最小操作单位

6.2 为什么“字节”是存储基本单位?

不是随意规定的,而是硬件设计和实际需求的共同选择:

  1. 硬件限制:CPU、内存、硬盘的最小“寻址单位”是字节,无法直接操作单个位(比如你不能让CPU只读取1位数据)。
  2. 需求匹配:早期计算机需要存储ASCII码(英文字母、数字、符号),ASCII码共128个字符,恰好需要7位二进制(2⁷=128)。为了预留1位“校验位”(检测数据传输错误),将字节定为8位,完美匹配需求。
  3. 效率最优:8是2的整数次幂(2³),硬件电路通过移位、逻辑运算处理8位数据时,效率最高,成本最低。

6.3 存储容量换算

我们买硬盘、内存时说的“1GB”“1TB”,都是以字节为基础换算的:

  • 1KB = 1024 Byte(2¹⁰ Byte)
  • 1MB = 1024 KB = 1024×1024 Byte
  • 1GB = 1024 MB
  • 1TB = 1024 GB

说明:开发中计算文件大小、内存占用时,需以字节为单位换算,比如“1KB文本”就是1024个字节的字符;而硬盘厂商通常用1000作为换算单位(1KB=1000Byte),这就是为什么“1TB硬盘”实际可用容量只有约931GB的原因。

七、ASCII码:字符与数字的“翻译字典”

可能你会觉得ASCII码抽象,其实它的本质特别简单——计算机只认0和1,却要处理人类的字符,ASCII码就是提前定好的“字符-数字”对应表,相当于一本翻译字典。

7.1 ASCII码的核心逻辑

  • 人类输入A,计算机先查字典找到A对应的数字65,再把65转换成二进制01000001存起来;
  • 计算机要显示内容时,先把二进制01000001转成数字65,再查字典找到对应的A显示给人类看。

7.2 ASCII码的编码范围

  • 基本ASCII码:使用7位二进制表示,范围是0000000(十进制0)~1111111(十进制127),共128个字符,涵盖常用的控制字符、数字、字母、标点。
  • 扩展ASCII码:使用8位二进制表示(即1个字节),范围是10000000(十进制128)~11111111(十进制255),用于表示特殊符号、非英语字符(后续会学的Unicode是更全面的字符编码)。

7.3 ASCII码规律(不用背全表,记这几个节点就够了)

这是ASCII码的核心规律,记住后能快速推导所有常用字符的编码:

字符类型 十进制范围 关键节点(十进制) 规律总结
数字0-9 48 ~ 57 数字0对应48 数字n的ASCII码 = 48 + n(比如5对应53)
大写字母A-Z 65 ~ 90 大写A对应65 大写字母N的ASCII码 = 65 + 字母顺序(比如B=66,Z=90)
小写字母a-z 97 ~ 122 小写a对应97 小写字母n的ASCII码 = 97 + 字母顺序(比如b=98,z=122)
空格 32 空格对应32 唯一的空白字符,记住32就行

说明:同一个字母的小写比大写的ASCII码大32(比如a=97,A=65,97-65=32),这是故意设计的,方便计算机处理大小写转换。

7.4 ASCII码与存储单位(utils/NumberSystemTest.ets)

/**
 * ASCII码的获取与转换
 */
export function testAsciiCodeConversion(): void {
  console.log("\n========== ASCII码的获取与转换 ==========");
  // 1. 获取字符的ASCII码(十进制)
  const charSpace = ' ';
  const char0 = '0';
  const charA = 'A';
  const chara = 'a';

  console.log(`字符"${charSpace}"的ASCII码(十进制):`, charSpace.charCodeAt(0)); // 32
  console.log(`字符"${char0}"的ASCII码(十进制):`, char0.charCodeAt(0)); // 48
  console.log(`字符"${charA}"的ASCII码(十进制):`, charA.charCodeAt(0)); // 65
  console.log(`字符"${chara}"的ASCII码(十进制):`, chara.charCodeAt(0)); // 97

  // 2. 将ASCII码(十进制)转换为字符
  const ascii32 = 32;
  const ascii65 = 65;
  console.log(`ASCII码${ascii32}对应的字符:`, String.fromCharCode(ascii32)); // 空格
  console.log(`ASCII码${ascii65}对应的字符:`, String.fromCharCode(ascii65)); // A

  // 3. 十进制ASCII码转二进制、十六进制(看计算机存储形式)
  const asciiA = 65;
  console.log(`字母A的ASCII码(十进制):${asciiA}`); // 65
  console.log(`字母A的ASCII码(二进制,7位):`, asciiA.toString(2).padStart(7, '0')); // 1000001
  console.log(`字母A的ASCII码(十六进制):`, asciiA.toString(16).toUpperCase()); // 41
}

/**
 * 存储单位可视化(帮助理解位、半字节、字节的关系,以及与ASCII码的关联)
 */
export function testStorageUnitVisualization(): void {
  console.log("\n========== 存储单位与ASCII码可视化 ==========");
  // 1字节 = 8位 = 2个半字节 = 2位十六进制 = 3位八进制余2位
  const byteValue = 0x5B; // 十六进制5B,对应1字节
  const binaryStr = byteValue.toString(2).padStart(8, '0'); // 补前导零到8位
  console.log(`1字节(0x5B)的二进制:`, binaryStr); // 01011011(8位)
  console.log(`前4位(半字节):`, binaryStr.slice(0, 4)); // 0101(对应5)
  console.log(`后4位(半字节):`, binaryStr.slice(4)); // 1011(对应B)
  console.log(`1字节(0x5B)的八进制:`, byteValue.toString(8)); // 133

  // 关联ASCII码:以字母A为例(ASCII码65,对应二进制01000001,1字节)
  const charA = 'A';
  const asciiA = charA.charCodeAt(0); // 65
  console.log(`\n字母A的ASCII码(65)对应的二进制(1字节):`, asciiA.toString(2).padStart(8, '0')); // 01000001
  console.log(`字母A的ASCII码(65)对应的十六进制:`, asciiA.toString(16).toUpperCase()); // 41
}

八、统一执行所有测试函数

8.1 统一调用(utils/NumberSystemTest.ets)

/**
 * 统一调用所有测试函数
 * 在aboutToAppear中仅需调用此函数即可执行全部测试逻辑
 */
export function allTest(): void {
  testRadixDeclaration();
  testRadixConversion();
  testCoreConversionRules();
  testAsciiCodeConversion();
  testStorageUnitVisualization();
}

8.2 页面代码:触发测试(pages/Index.ets)

// pages/Index.ets
import { allTest } from '../utils/NumberSystemTest'; // 导入工具函数

@Entry
@Component
struct Index {
  // 页面加载时执行测试逻辑
  aboutToAppear(): void {
    // 1. 打印开篇现象:0.1+0.2≠0.3
    console.log("========== 开篇现象 ==========");
    const num1: number = 0.1;
    const num2: number = 0.2;
    console.log(`0.1+0.2 = ${num1 + num2}`); // 输出:0.30000000000000004
    console.log(`0.1×0.2 = ${num1 * num2}`); // 输出:0.020000000000000004
    console.log(`0.1的二进制(前30位):${num1.toString(2).substring(0, 30)}`);

    // 2. 统一执行所有测试函数
    allTest();
  }

  build() {
    Column() {
      Text("ArkTS进制与存储单位(上)")
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center);
  }
}

九、内容总结

关键点回顾

  1. 代码架构优化:将测试函数抽离为utils下的独立导出函数,通过allTest()统一调用,符合鸿蒙模块化开发规范,便于后续复用和维护;
  2. 进制核心:十进制整数转二进制用除2取余法,小数转二进制用乘2取整法(0.1等小数无限循环),二进制与八/十六进制通过3/4位分组法转换;
  3. 存储与编码:1字节=8位是计算机基本存储单位,ASCII码是字符与数字的映射表,记住关键节点(0=48、A=65、a=97)即可快速推导;
  4. 底层伏笔:二进制无限循环、字节有限位数、二进制科学计数法的截断处理,共同导致“0.1+0.2≠0.3”的运算误差,是后续浮点数存储学习的关键铺垫。

十、代码仓库

十一、下节预告:原码、反码、补码与整数存储

下一节将重点解决“负数如何存储”的核心问题,带你彻底理解计算机存储整数的底层逻辑:

  1. 痛点引入:直接用二进制表示负数会导致减法运算出错,为什么?
  2. 原码:最简单的负数表示方式,存在什么致命缺陷?
  3. 反码:对原码的改进方案,为什么仍无法解决问题?
  4. 补码:现代计算机的标准方案,如何完美解决负数存储和减法运算?
  5. 存储范围:32位/64位整数的存储上限与下限,溢出问题如何处理?
  6. 代码实操:在ArkTS中验证整数的存储范围与溢出行为。

通过下一节的学习,你将明白计算机不仅存储正数有规则,存储负数同样有一套精妙的设计!

posted @ 2026-01-18 22:37  鸿蒙-散修  阅读(4)  评论(0)    收藏  举报