轨道
/
C#
C#
/
练习
/
超级优化的遥测
超级优化的遥测

超级优化的遥测

学习练习

简介

整数

C# 和许多静态类型语言一样,提供了多种用于表示整数的类型,每种类型都有自己的取值范围。在数值范围的低端,sbyte 类型的最小值为 -128,最大值为 127。和所有整数类型一样,这些值都可以通过 <type>.MinValue 和 <type>.MaxValue 获取。在高端,long 类型的最小值为 -9,223,372,036,854,775,808,最大值为 9,223,372,036,854,775,807。介于两者之间的是 short 和 int 类型。

这些取值范围由类型在系统中分配的存储宽度决定。例如,byte 占 8 位,long 占 64 位。

上述每种类型都有一个对应的无符号版本:sbyte/byte、short/ushort、int/uint 和 long/ulong。在所有情况下,取值范围都是从 0 到有符号最大值的相反数乘以 2 再加 1。

类型 宽度 最小值 最大值
sbyte 8 位 -128 +127
short 16 位 -32_768 +32_767
int 32 位 -2_147_483_648 +2_147_483_647
long 64 位 -9_223_372_036_854_775_808 +9_223_372_036_854_775_807
byte 8 位 0 +255
ushort 16 位 0 +65_535
uint 32 位 0 +4_294_967_295
ulong 64 位 0 +18_446_744_073_709_551_615

一种类型的变量(或表达式)可以很方便地转换为另一种类型。例如,在赋值操作中,如果要赋的值(lhs)的类型能确保该值落在赋值目标类型(rhs)的取值范围内,那么这就是一次简单赋值:

uint ui = uint.MaxValue;
ulong ul = ui;    // no problem

反过来,如果被赋值来源类型的取值范围不是目标类型取值范围的子集,那么即使具体的值落在目标类型的取值范围内,也仍然需要强制转换(() 操作):

short s = 42;
uint ui = (uint)s;

位转换

BitConverter 类提供了一种便捷的方式,用于在整数类型和字节数组之间相互转换。

说明

遥控车项目的工作还在继续。遥测系统的带宽十分紧张,你被要求实现一套用于传输遥测数据的消息协议。

数据通过缓冲区(字节数组)传输。发送整数时,会采用下面描述的协议来减小缓冲区的大小。

每个值都应使用尽可能小的整数类型来表示(不包含 byte 和 sbyte 类型,因为那样节省的空间微乎其微):

起始值 结束值 类型
4_294_967_296 9_223_372_036_854_775_807 long
2_147_483_648 4_294_967_295 uint
65_536 2_147_483_647 int
0 65_535 ushort
-32_768 -1 short
-2_147_483_648 -32_769 int
-9_223_372_036_854_775_808 -2_147_483_649 long

值应转换为与其分配到的类型相对应的字节数。完整的缓冲区由一个表示缓冲区中额外字节数的字节(前缀字节)以及随后存放该整数的字节(载荷字节)组成。

有些类型使用的字节数相同(例如 uint 和 int 类型)。通常它们会拥有相同的_前缀字节_,但这会让解码变得困难。为此,协议引入了一个小技巧:对于有符号类型,其_前缀字节_的值等于 256 减去缓冲区中额外的字节数。

通信中只会发送前缀字节以及由该前缀指明数量的后续字节。在内部,发送和接收例程都会使用一个 9 字节的缓冲区(必要时补上末尾的零)。

1. 将整数值编码以便发送

请实现静态方法 TelemetryBuffer.ToBuffer(),把传入该方法的参数编码进缓冲区。

// Type: ushort, bytes: 2, signed: no, prefix byte: 2
TelemetryBuffer.ToBuffer(5)
// => {0x2, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };

// Type: int, bytes: 4, signed: yes, prefix byte: 256 - 4
TelemetryBuffer.ToBuffer(Int32.MaxValue)
// => {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 };

2. 解码接收到的缓冲区

请实现静态方法 TelemetryBuffer.FromBuffer(),解码接收到的缓冲区,并以 long 的形式返回该值。

TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 })
// => 2147483647

如果前缀字节的值不符合预期,则应返回 0。

通过 GitHub 编辑 链接将在新窗口或新标签页中打开
C# Exercism

准备好开始 超级优化的遥测 了吗?

注册 Exercism,借助 62 个概念178 个练习 和真人导师指导,学习并掌握 C#,全部免费。