Percursos
/
C#
C#
/
Exercícios
/
Telemetria hiperotimizada
Telemetria hiperotimizada

Telemetria hiperotimizada

Exercício de aprendizagem

Introdução

Números inteiros

O C#, tal como muitas linguagens de tipagem estática, disponibiliza vários tipos que representam números inteiros, cada um com o seu próprio intervalo de valores. No extremo inferior, o tipo sbyte tem um valor mínimo de -128 e um valor máximo de 127. Tal como em todos os tipos inteiros, estes valores estão disponíveis como <type>.MinValue e <type>.MaxValue. No extremo superior, o tipo long tem um valor mínimo de -9,223,372,036,854,775,808 e um valor máximo de 9,223,372,036,854,775,807. Entre os dois ficam os tipos short e int.

Os intervalos são determinados pela largura de armazenamento que o sistema atribui a cada tipo. Por exemplo, um byte usa 8 bits e um long usa 64 bits.

Cada um dos tipos acima tem um equivalente sem sinal: sbyte/byte, short/ushort, int/uint e long/ulong. Em todos os casos, o intervalo de valores vai de 0 até ao máximo negativo do tipo com sinal multiplicado por 2 e somado a 1.

Type Width Minimum Maximum
sbyte 8 bit -128 +127
short 16 bit -32_768 +32_767
int 32 bit -2_147_483_648 +2_147_483_647
long 64 bit -9_223_372_036_854_775_808 +9_223_372_036_854_775_807
byte 8 bit 0 +255
ushort 16 bit 0 +65_535
uint 32 bit 0 +4_294_967_295
ulong 64 bit 0 +18_446_744_073_709_551_615

Uma variável (ou expressão) de um tipo pode ser facilmente convertida noutro. Por exemplo, numa operação de atribuição, se o tipo do valor que está a ser atribuído (lhs) garantir que o valor fica dentro do intervalo do tipo a que se atribui (rhs), basta uma atribuição simples:

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

Por outro lado, se o intervalo do tipo de origem não for um subconjunto do intervalo de valores do tipo de destino, é necessária uma operação de cast, (), mesmo que o valor em questão esteja dentro do intervalo do tipo de destino:

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

Conversão de bits

A classe BitConverter oferece uma forma prática de converter tipos inteiros de e para arrays de bytes.

Instruções

O trabalho no projeto do carro telecomandado continua. A largura de banda do sistema de telemetria é escassa e foi-te pedido que implementes um protocolo de mensagens para comunicar dados de telemetria.

Os dados são transmitidos num buffer (vetor de bytes). Quando se enviam números inteiros, o tamanho do buffer é reduzido através do protocolo descrito abaixo.

Cada valor deve ser representado no menor tipo inteiro possível (os tipos byte e sbyte não estão incluídos, pois a poupança seria trivial):

De Para Tipo
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

O valor deve ser convertido no número de bytes adequado ao tipo que lhe for atribuído. O buffer completo é composto por um byte que indica o número de bytes adicionais no buffer (byte de prefixo), seguido dos bytes que contêm o número inteiro (bytes de carga útil).

Alguns dos tipos usam um número idêntico de bytes (por exemplo, os tipos uint e int). Normalmente, teriam o mesmo byte de prefixo, mas isso tornaria a descodificação problemática. Para contornar isto, o protocolo introduz um pequeno truque: nos tipos com sinal, o valor do byte de prefixo é 256 menos o número de bytes adicionais no buffer.

Na comunicação, só são enviados o byte de prefixo e o número de bytes seguintes indicado pelo prefixo. Internamente, é usado um buffer de 9 bytes (com zeros à direita, se necessário), tanto pelas rotinas de envio como pelas de receção.

1. Codifica um valor inteiro pronto a enviar

Implementa o método estático TelemetryBuffer.ToBuffer() para codificar um buffer com o parâmetro passado ao método.

// 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. Descodifica um buffer recebido

Implementa o método estático TelemetryBuffer.FromBuffer() para descodificar o buffer recebido e devolver o valor sob a forma de um long.

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

Se o byte de prefixo tiver um valor inesperado, deve ser devolvido 0.

Editar via GitHub A ligação abre numa nova janela ou separador
C# Exercism

Estás pronto para começar Telemetria hiperotimizada?

Inscreve-te no Exercism para aprenderes e dominares C# com 62 conceitos178 exercícios, e mentoria humana real, tudo grátis.