トラック
/
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

値は、割り当てられた型に応じたバイト数に変換します。バッファ全体は、バッファ内の追加バイト数を示す1バイト(プレフィックスバイト)と、そのあとに続く整数を保持するバイト列(ペイロードバイト)で構成されます。

型によっては、同じバイト数を使うものもあります(たとえば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. 受信したバッファをデコードする

受信したバッファをデコードし、その値をlongの形で返す、静的メソッドTelemetryBuffer.FromBuffer()を実装してください。

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

プレフィックスバイトが想定外の値だった場合は、0を返します。

GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
C# Exercism

超最適化テレメトリを始める準備はできましたか?

Exercismに登録すれば、62個のコンセプト178個の演習、そして本物の人間によるメンタリングとともに、C#を学んでマスターできます。すべて無料です。