C#, al igual que muchos lenguajes de tipado estático, ofrece varios tipos que representan números enteros, cada uno con su propio rango de valores. En el extremo inferior, el tipo sbyte tiene un valor mínimo de -128 y un valor máximo de 127. Como en todos los tipos enteros, estos valores están disponibles como <type>.MinValue y <type>.MaxValue. En el extremo superior, el tipo long tiene un valor mínimo de -9,223,372,036,854,775,808 y un valor máximo de 9,223,372,036,854,775,807. Entre ambos se encuentran los tipos short e int.
Los rangos están determinados por el ancho de almacenamiento que el sistema asigna a cada tipo. Por ejemplo, un byte usa 8 bits y un long usa 64 bits.
Cada uno de los tipos anteriores tiene su equivalente sin signo: sbyte/byte, short/ushort, int/uint y long/ulong. En todos los casos, el rango de valores va de 0 al máximo negativo con signo multiplicado por 2 más 1.
| Tipo | Ancho | Mínimo | Máximo |
|---|---|---|---|
| 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 |
Una variable (o expresión) de un tipo se puede convertir fácilmente a otro. Por ejemplo, en una operación de asignación, si el tipo del valor que se asigna (lhs) garantiza que el valor estará dentro del rango del tipo al que se asigna (rhs), entonces hay una asignación simple:
uint ui = uint.MaxValue;
ulong ul = ui; // no problem
Por otro lado, si el rango del tipo desde el que se asigna no es un subconjunto del rango de valores del tipo de destino, entonces se requiere una conversión explícita mediante (), incluso si el valor concreto está dentro del rango del tipo de destino:
short s = 42;
uint ui = (uint)s;
La clase BitConverter ofrece una forma práctica de convertir tipos enteros desde y hacia array de bytes.
El proyecto del carro de control remoto continúa. El ancho de banda del sistema de telemetría es muy limitado, así que te han pedido implementar un protocolo de mensajes para comunicar los datos de telemetría.
Los datos se transmiten en un búfer (array de bytes). Cuando se envían números enteros, el tamaño del búfer se reduce empleando el protocolo que se describe a continuación.
Cada valor debe representarse con el tipo entero más pequeño posible (los tipos byte y sbyte no se incluyen, ya que el ahorro sería insignificante):
| De | A | 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 |
El valor debe convertirse a la cantidad de bytes apropiada para el tipo que se le asigne. El búfer completo se compone de un byte que indica la cantidad de bytes adicionales en el búfer (byte de prefijo) seguido de los bytes que contienen el número entero (bytes de carga útil).
Algunos de los tipos usan una cantidad idéntica de bytes (por ejemplo, los tipos uint e int). Normalmente tendrían el mismo byte de prefijo, pero eso haría que la decodificación fuera problemática. Para contrarrestarlo, el protocolo introduce un pequeño truco: en los tipos con signo, el valor de su byte de prefijo es 256 menos la cantidad de bytes adicionales en el búfer.
En la comunicación solo se enviarán el byte de prefijo y la cantidad de bytes siguientes que este indique. De forma interna se usa un búfer de 9 bytes (con ceros al final, según sea necesario), tanto en las rutinas de envío como en las de recepción.
Implementa el método estático TelemetryBuffer.ToBuffer() para codificar un búfer tomando el parámetro que se le pasa al 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 };
Implementa el método estático TelemetryBuffer.FromBuffer() para decodificar el búfer recibido y devolver el valor en forma de long.
TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 })
// => 2147483647
Si el byte de prefijo tiene un valor inesperado, se debe devolver 0.
Regístrate en Exercism para aprender y dominar C# con 62 conceptos178 ejercicios y mentoría humana real, todo gratis.