
La spécification IEEE 754 définit de nombreux types à virgule flottante, notamment:
binary16,
binary32,
binary64 et
binary128. La plupart des développeurs sont des habitués de
binary32 (équivalent à
float en C#) et
binary64 (équivalent à
double en C#). Ils fournissent un format standard pour représenter une large gamme de valeurs avec une précision acceptable pour de nombreuses applications. .NET a toujours eu
float et
double et avec .NET 5 Preview 7, Microsoft a ajouté un nouveau type
Half (équivalent à
binary16)!
Half est un nombre binaire à virgule flottante qui occupe donc 16 bits (deux octets). Avec la moitié du nombre de bits en virgule flottante,
Half peut représenter des valeurs dans la plage ±65504. Plus formellement, le type
Half est défini comme un format d'échange 16 bits de base 2 destiné à prendre en charge l'échange de données en virgule flottante entre les implémentations. L'un des principaux cas d'utilisation du type
Half est d'économiser de l'espace de stockage où le résultat calculé n'a pas besoin d'être stocké avec une précision totale. De nombreuses charges de travail de calcul profitent déjà du type
Half : le machine learning, les cartes graphiques, les derniers processeurs, les bibliothèques SIMD natives, etc.
Les 16 bits du type
Half sont divisés en:
- Bit de signe (bit dans une représentation de nombres signés qui indique le signe d’un nombre): 1 bit.
- Bits d'exposants: 5 bits.
- Bits significatifs: 10 bits (avec 1 bit implicite non stocké).
Malgré le fait que les bits significatifs comportent 10 bits, Prashanth Govindarajan de l'équipe .NET explique que la précision totale est en réalité de 11 bits. Le format est supposé avoir un bit de tête implicite de valeur 1 (sauf si le champ d'exposant est composé entièrement de zéros, auquel cas le bit de tête a la valeur 0). Pour représenter le nombre 1 au format
Half, nous utiliserons les bits:

Envoyé par
Half
0 01111 0000000000 = 1
Le bit de tête (notre bit de signe) est 0, indiquant un nombre positif. Les bits d'exposant sont 01111, ou 15 en décimal. Cependant, les bits d'exposant ne représentent pas directement l'exposant. Au lieu de cela, un biais d'exposant est défini qui permet au format de représenter à la fois des exposants positifs et négatifs. Pour le type
Half, ce biais d'exposant est 15. Le vrai exposant est dérivé en soustrayant 15 de l'exposant stocké. Par conséquent, 01111 représente l'exposant
e = 01111 (en binaire) - 15 (le biais de l'exposant) = 0. Le bit significatif est 0000000000, qui peut être interprété comme le nombre
.bit_significatif(en base 2) en base 2, soit
0 dans notre cas . Si, par exemple, le bit significatif était
0000011010 (26 en décimal), on peut diviser sa valeur décimale 26 par le nombre de valeurs représentables en
10 bits (1 << 10): donc le bit significatif
0000011010 (en binaire) est
26 / ( 1 << 10) = 26/1024 = 0,025390625 en décimal. Enfin, comme nos bits d'exposant stockés (01111) ne sont pas tous à 0, nous avons un bit de tête implicite de 1. Par conséquent :

Envoyé par
Half
0 01111 0000000000 = 2^0 * (1 + 2^0) = 1
En général, les 16 bits d'une valeur
Half sont interprétés comme
-1 ^ (bit de signe) * 2 ^ (exposant stocké - 15) * (bit implicit + (bit significatif / 1024)). Un cas particulier existe pour l'exposant stocké 00000. Dans ce cas, les bits sont interprétés comme
-1 ^ (bit de signe) * 2 ^ (- 14) * (0 + (bit significatif / 1024)). Examinons les représentations binaires de certains autres nombres au format
Half:
Plus petite valeur positive non nulle

Envoyé par
Half
0 00000 0000000001 = -1^(0) * 2^(-14) * (0 + 1/1024) ≈ 0.000000059604645
(Notez que le bit implicite est 0 ici, car les bits des exposants stockés sont tous 0)
Le plus grand nombre normal

Envoyé par
Half
0 11110 1111111111 = -1^(0) * 2^(15) * (1 + 1023/1024) ≈ 65504
Infini négatif

Envoyé par
Half
1 11111 0000000000 = -Infinité
Une particularité du format est qu'il définit à la fois 0 positif et négatif:

Envoyé par
Half
1 00000 0000000000 = -0

Envoyé par
Half
0 00000 0000000000 = +0
Conversions vers / de float / doubleUn
Half peut être converti en / à partir d'un
float /
double en le lançant simplement:
float f = (float)half; Half h = (Half)floatValue;
Toute valeur
Half, étant donné que
Half utilise seulement 16 bits, peut être représentée sous la forme d'un
float/double sans perte de précision. Cependant, l'inverse n'est pas vrai. Une certaine précision peut être perdue lors du passage de
float/double à
Half. Dans .NET 5.0, le type
Half est principalement un type d'échange sans opérateur arithmétique défini dessus. Il ne prend en charge que les opérateurs d'analyse, de formatage et de comparaison. Toutes les opérations arithmétiques nécessiteront une conversion explicite en
float/double. Les versions futures envisageront d'ajouter des opérateurs arithmétiques directement sur
Half.
L'un des points que Microsoft considère est la possibilité ou non d'ajouter la prise en charge de
Half sur un langage comme C# à l'avenir. La prise en charge au niveau du langage permettrait un identifiant tel que
f16 (similaire au
f qui existe aujourd'hui) et des conversions implicites / explicites. Ainsi, le type
Half défini par la bibliothèque doit être défini d'une manière qui n'entraîne aucun changement de rupture si
Half venait à être implémenté. Plus précisément, l'éditeur estime devoir faire attention lors de l'ajout des opérateurs au type
Half. Les conversions implicites en
float / double pourraient conduire à des changements de rupture potentiels si la prise en charge du langage était ajoutée.
Source :
Microsoft