Convertir efficacement le tableau d'octets à Virgule

Si j'ai un tableau d'octets et que vous voulez convertir une zone contiguë de 16 octets du bloc de ce tableau, contenant .net est la représentation d'un Decimal, dans une bonne Decimal struct, quel est le moyen le plus efficace de le faire?

Voici le code qui est apparu dans mon profiler comme la plus grande CPU consommateur dans un cas que je suis à l'optimisation.

public static decimal ByteArrayToDecimal(byte[] src, int offset)
{
    using (MemoryStream stream = new MemoryStream(src))
    {
        stream.Position = offset;
        using (BinaryReader reader = new BinaryReader(stream))
            return reader.ReadDecimal();
    }
}

Pour se débarrasser de MemoryStream et BinaryReader, j'ai pensé à l'alimentation d'une matrice de BitConverter.ToInt32(src, offset + x)s dans la Decimal(Int32[]) constructeur serait plus rapide que la solution que je vous présente ci-dessous, mais la version ci-dessous est, curieusement, deux fois plus rapide.

const byte DecimalSignBit = 128;
public static decimal ByteArrayToDecimal(byte[] src, int offset)
{
    return new decimal(
        BitConverter.ToInt32(src, offset),
        BitConverter.ToInt32(src, offset + 4),
        BitConverter.ToInt32(src, offset + 8),
        src[offset + 15] == DecimalSignBit,
        src[offset + 14]);
}

C'est 10 fois plus rapide comme le MemoryStream/BinaryReader combo, et je l'ai testé avec un tas de valeurs extrêmes pour s'assurer qu'il fonctionne, mais la représentation décimale n'est pas aussi simple que pour les autres types primitifs, donc je ne suis pas encore convaincu que cela fonctionne à 100% de la possible des valeurs décimales.

En théorie, cependant, il pourrait y avoir un moyen de copier ces 16 octets contigus à un autre endroit de la mémoire et de déclarer que, pour être une Virgule, sans aucune vérification. Quelqu'un est-il au courant d'une méthode pour faire cela?

(Il n'y a qu'un seul problème: Bien que les décimales sont représentés comme des 16 octets, certaines de ces valeurs ne constituent pas valide décimales, donc faire un décochémemcpy pourrait briser les choses...)

Ou est-il un autre moyen plus rapide?

Existe-il des cas où vous avez plusieurs valeurs décimales dans une ligne dans la matrice? Si non, je ne peux pas penser à un moyen plus rapide.
Le problème ici n'est pas que BinaryReader est si lent, c'est que le séparateur Décimal constructeur est donc très rapide. Si bien que la surcharge de la construction de ces objets devient perceptible dans l'A/B testing. La sécurité et la vitesse sont des objectifs contradictoires.
Je n'ai pas dit BinaryReader est lente. Mais inutile indirections que ce soit évidemment ralentit les choses, peu importe à quelle vitesse ils sont. Si j'avais eu un BinaryReader pour commencer, plutôt que d'un tableau d'octets, je doute qu'il y aurait de toute façon plus rapide de lire un nombre décimal à partir d'elle que de l'appeler à son ReadDecimal méthode.

OriginalL'auteur Eugene Beresovsky | 2013-06-07