Треки
/
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

Змінну (або вираз) одного типу можна легко перетворити в інший тип. Наприклад, під час присвоєння, якщо тип значення, яке присвоюють (ліва частина), гарантує, що значення лежить у межах діапазону типу, якому присвоюють (права частина), то присвоєння буде простим:

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, щоб вивчати й опановувати C#, а також 62 концепції178 вправ та справжнє наставництво від людей, і все це безкоштовно.