Modo più veloce per convertire int a 4 byte in C#

Che cosa è un modo più veloce per convertire int a 4 byte in C# ?

Più veloce come in tempo di esecuzione non è il tempo di sviluppo.

La mia soluzione è questo codice:

byte[] bytes = new byte[4];
unchecked
{
 bytes[0] = (byte)(data >> 24);
 bytes[1] = (byte)(data >> 16);
 bytes[2] = (byte)(data >> 8);
 bytes[3] = (byte)(data);
}

Adesso vedo che la mia soluzione supera sia struct e BitConverter da un paio di zecche.

Penso che il rischio è probabilmente l’opzione più veloce e di accettare che, come risposta, ma preferirei usare un gestiti opzione.

  • Da fastest vuoi dire a) quantità minima di codice o b) prestazioni migliori?
  • Migliori prestazioni
  • ‘Più veloce’ dipende da dove vuoi quei byte di andare.
  • Quanta memoria hai? Se i numeri sono tutti +ve e l’intervallo di valori non è enorme, come su una ricerca di matrice? (non sono sicuro che sarà più veloce di uno bitshift però).
  • Esso non è applicabile nel mio caso, ma è originale :).
  • Interessante, MA: hai provato riordino e shifitng i dati “nuovo”. Posso vedere questo andare con 3 x >> 8 (totale 24 turni) invece di 48.
  • Non credo che ho capito il tuo suggerimento
  • che sarebbe solo peggio. Non c’è nessuna tale cosa come “totale turni” – lo spostamento da qualsiasi offset è un singolo ciclo di funzionamento. Ma non ci sarebbe improvvisamente una dipendenza di dati, precludendo superscalar esecuzione.
  • buona pesca. molto interessante. non sapevo che il livello assembler qualsiasi spostamento numero è unica operazione. Si impara sempre 😉
  • Per riferimento, come indicato nella Specifiche del Linguaggio C#, Operatori di Shift: le operazioni di Turno non causare overflow e produrre gli stessi risultati checked e unchecked contesti. In modo incontrollato dichiarazione in questione è eccessivo.

InformationsquelleAutor MichaelT | 2012-01-11



9 Replies
  1. 15

    Un byte* fusione, utilizzando il codice unsafe è la più veloce in assoluto:

        unsafe static void Main(string[] args) {
            int i = 0x12345678;
            byte* pi = (byte*)&i;
            byte lsb = pi[0];  
            //etc..
        }

    Che BitConverter fa pure, questo codice evita il costo di creazione matrice.

    • 😉 in realtà non è sicuro – e questo non è necessario 😉 Davvero. Anotehr cassetta di sicurezza (!) la soluzione ha una simile velocità.
    • Sì, perché si utilizza il non sicuri parola chiave. Che è molto disponibile a fare esattamente questo, scrivere codice più veloce. L’OP è richiesta per veloce, non simili.
    • Abbastanza interessante, che non cambia il fatto che per questo particolare problema c’è una soluzione che sia il più veloce e SICURO. Ergo il rischio, la soluzione è di peggio. Questo è diverso per altri problemi, ma questo particolare potrebbe ottenere un secondo posto in una recensione da me per il codice unsafe – passato, si prega di riscrivere.
    • Avrei dovuto immaginare che non lavoro per Microsoft. Il problema con metodi che contengono le strutture che non vengono sostituite. Almeno BitConverter.GetBytes() ottiene inline.
    • L’ho fatto una volta come consulente in realtà – SQL Server supporto di livello 3. In questi giorni faccio un sacco di roba in movimento alcune piccole quantità di dati, per lo più di dati finanziari, che viene fornito in byte forma codificata. Quando si massa del carico di centinaia di milioni di righe più velocemente possibile si avvia spingendo per la velocità.
    • Può essere perfettamente sicuro da usare unsafe, a condizione che si può eseguire in un contesto di fiducia, e finché c’è qualche modo per indicare che essa potrebbe essere pericoloso se non esaminato attentamente. Come avere la parola “pericoloso” da qualche parte vicino il codice come una sorta di indicatore.
    • Questo non mi sembra corretto secondo le mie indagini, il modo più veloce è davvero assegnazione con il cambiamento come l’autore della domanda suggerito (e permette anche di fare grande/piccolo endianess). Questo è il più veloce per lungo, comunque, si prega di vedere la mia risposta per i dettagli e il confronto.
    • Forse l’autore vuole chiedere per il più breve, più cool, perfetto modo per convertire 😉

  2. 16

    Che cosa è un modo più veloce per convertire int a 4 byte in C# ?

    Utilizzando un BitConverter e GetBytes overload che accetta un numero intero a 32 bit:

    int i = 123;
    byte[] buffer = BitConverter.GetBytes(i);
    • In realtà di fatto di sbagliato.
    • cura di elaborare?
    • Sarebbe pericoloso essere più veloce o qualcosa del genere poi?
    • Si sono probabilmente dimenticare il fatto che BitConverter.GetBytes utilizza il codice unsafe per accedere direttamente all’indirizzo di memoria in cui l’intero è memorizzato e super veloce.
    • Guarda la mia risposta. nessun metodo è necessario. BitConverter è flexbile che significa lento. La conversione byte int non richiede alcuna logica o chiamata al metodo, solo una comprensione di come – bene – le strutture con esplicito lavoro di layout. Unsafe ha la usi, ma c’è una soluzione sicura, mediante un’unione di una struttura. Stessa velocità.
    • soluzione interessante. Ma se è simile velocità, preferisco un BCL chiamata al metodo che è anche più breve e meno soggetto ad errori. Non c’è bisogno di marcare la vostra assemblea pericoloso come BitConverter.GetBytes è un BCL metodo. Sono d’accordo, è pericoloso. Come sono sicuri enormemente un sacco di metodi di BCL che stiamo usando tutto il tempo.
    • Suscettibili di errore: nessuna differenza. E beh, si può scegliere il metodo più lento, ma questo non cambia il fatto che la tua risposta è sbagliata – il poster chiesto esplicitamente il modo più VELOCE. SOLO la velocità. Anche la facilità d’uso è esplicitamente tolto la matrice di decisione.
    • OK, io non ho intenzione di litigare con te. Né si sta andando a farmi cambiare la mia mente, né ho intenzione di farti cambiare idea. Così ho preferito non continuare questa discussione sta diventando inutile per me. Ho esposto la mia soluzione e hai esposto il tuo e io rispetto la tua. Ecco perché Stack Overflow è un ottimo posto. Perché siamo in grado di vedere i diversi approcci per affrontare i problemi. Penso che la comunità può solo trarre beneficio da questa diversità.
    • Cordiali saluti, editato il mio post con la prova di velocità (in BitConverter‘s favore).
    • grande, grazie.
    • La soluzione non prendere in considerazione che di solito avete bisogno di scrivere un array esistente. E in questo caso BitConverter è molto più lento, in quanto è necessario creare un nuovo array e poi copiarlo. Si prega di dare un’occhiata alla mia risposta, ho fatto il confronto tra diversi metodi.

  3. 10

    Ho fatto una ricerca sui tempi necessari per serializzare un tipo di base di array di byte. L’ho fatto per il caso in cui si dispone già di una matrice e di offset in cui si desidera inserire i tuoi dati. Direi che è davvero un caso importante rispetto al teorico ottenere un array di 4 byte, perché quando si sta serializzando qualcosa che poi è esattamente quello di cui hai bisogno. Ho capito che la risposta alla domanda che cosa è il metodo più veloce dipende da che tipo di file si desidera serializzare. Ho provato alcuni metodi:

    1. Pericoloso di riferimento, con un ulteriore controllo di buffer overrun
    2. GetBytes + conseguente Buffer.BulkCopy (Questo è essenzialmente lo stesso come 1 più generali)
    3. Assegnazione diretta con shift (
      m_Bytes[offset] = (byte)(value >> 8)
    4. Assegnazione diretta con shift e bit per bit &
      m_Bytes[offset] = (byte)((i >> 8) & 0xFF)

    Ho eseguito tutti i test di 10 milioni di volte. Qui di seguito i risultati in millisecondi

     Long Int Breve Byte Float Double 
    1 29 32 31 30 29 34 
    2 209 233 220 212 208 228 
    3 63 24 13 8 24 44 
    4 72 29 14 
    

    Come si può vedere il modo non protetto è molto più veloce e lunga il doppio (unsigned versioni sono circa lo stesso come il loro versioni firmate in modo che non sono in tabella). Per il breve/int/float il modo più veloce è il 2/4/4 assegnazioni con shift. Per byte il più veloce è, ovviamente, la semplice assegnazione. Quindi, per quanto riguarda la domanda originaria – l’assegnazione è il miglior modo. Questo è l’esempio di una funzione in un modo più veloce:

        public static void WriteInt(byte[] buffer, int offset, int value)
        {
            m_BytesInt[offset] = (byte)(value >> 24);
            m_BytesInt[offset + 1] = (byte)(value >> 16);
            m_BytesInt[offset + 2] = (byte)(value >> 8);
            m_BytesInt[offset + 3] = (byte) value;
        }

    P. S. I test sono stati eseguiti su x64 ambiente con il codice compilato per qualsiasi cpu (che è stato x64 su “esegui”) in modalità di rilascio.

    • Sarebbe ++offset velocità di questo un po’?
    • Si potrebbe essere corretto, non ho pensato per qualche motivo, ma lo si può controllare e condividere i risultati qui 🙂
  4. 9

    Il modo più veloce è con una struct contenente 4 byte.

    • In un layout definito (in byte in posizione 0, 1, 2, 3
    • E un int32 che inizia alla posizione 0.
    • Mettere le 4 variabili, lettura di un byte.
    • Finito.

    Notevolmente più veloce rispetto a BitConverter.

    http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx

    ha l’attributo necessario.

    [StructLayout(LayoutKind.Explicit)]
    struct FooUnion
    {
        [FieldOffset(0)]
        public byte byte0;
        [FieldOffset(1)]
        public byte byte1;
        [FieldOffset(2)]
        public byte byte2;
        [FieldOffset(3)]
        public byte byte3;
    
        [FieldOffset(0)]
        public int integer;
    
    }
    • Mi piace bravura della soluzione
    • Anche a Me… vorrei solo che fosse più facile da leggere (la risposta, non il codice) e aveva alcuni parametri di riferimento con esso. +1 comunque
    • Pulito, semplice, facile da capire. Non riuscivo a cura di prestazioni quando il codice è questo a prova di proiettile. ++
    • Questo codice è perfetto se non sono solo la conversione di byte, ma la necessità di avere entrambe le confezionati e sfusi valori disponibili per le successive. Per esempio, la memorizzazione di R,G,B, e Alfa byte valori imballato in un int quando si lavora con i colori.
  5. 7

    Nota la BitConverter potrebbe non essere il più veloce, come il test qui sotto mostra.

    Utilizzare il BitConverter classe, in particolare il GetBytes metodo che accetta un Int32 parametro:

    var myInt = 123;
    var bytes = BitConverter.GetBytes(myInt);

    È possibile utilizzare BitConverter.IsLittlEndian per determinare l’ordine di byte basato sull’architettura della CPU.


    EDIT: Il test di seguito non è conclusiva, a causa delle ottimizzazioni del compilatore.


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    namespace ConsoleApplication1
    {
        [StructLayout(LayoutKind.Explicit)]
        struct FooUnion
        {
            [FieldOffset(0)]
            public byte byte0;
            [FieldOffset(1)]
            public byte byte1;
            [FieldOffset(2)]
            public byte byte2;
            [FieldOffset(3)]
            public byte byte3;
    
            [FieldOffset(0)]
            public int integer;
        }
        class Program
        {
            static void Main(string[] args)
            {
                testUnion();
                testBitConverter();
    
                Stopwatch Timer = new Stopwatch();
    
                Timer.Start();
                testUnion();
                Timer.Stop();
    
                Console.WriteLine(Timer.ElapsedTicks);
    
                Timer = new Stopwatch();
    
                Timer.Start();
                testBitConverter();
                Timer.Stop();
    
                Console.WriteLine(Timer.ElapsedTicks);
                Console.ReadKey();
            }
    
            static void testBitConverter()
            {
                byte[] UnionBytes;
    
                for (int i = 0; i < 10000; i++)
                {
                    UnionBytes = BitConverter.GetBytes(i);
                }
            }
    
            static void testUnion()
            {
                byte[] UnionBytes;
    
                for (int i = 0; i < 10000; i++)
                {
                    FooUnion union = new FooUnion() { integer = i };
    
                    UnionBytes = new byte[] { union.byte0, union.byte1, union.byte2, union.byte3 };
    
                }
            }
        }
    }
    • Troppo lento, mi dispiace. Ci sono metodi più veloci che non implicano alcun metodo.
    • Vedere la mia modifica per un test di velocità, non sono sicuro se ho fatto un errore, ma non la penso così. Mostra BitConverter è più veloce se avete bisogno di un array (anche se non è esattamente molto).
    • L’intenzione di farmi eseguire questo di me??? Boo!!! ;-P
    • A cura!
    • E dove, nel post originale, vuol dire che c’è una matrice in partenza? Si dice 4 byte. Io uso la struttura di offset per il mercato finanziario gestione dei dati (5 byte 8 byte struct – 4 byte numero di tick, 1 byte tick di codifica). Con una velocità disarmante.
    • Si può ritenere sicuro non c’è matrice, a cui si aggiunge la creazione di array e la raccolta dei rifiuti come overhead per OP specifiche.
    • Copiate il codice e corse (build di Rilascio), e BitConverter è stato più lento di quasi 10 volte. Se eseguo una build di Debug, vedo tempi che sono simili tra i due.
    • Ha modificato la sua domanda, per la mostra che ha bisogno di un array, anche se a quanto pare la soluzione è meglio di tutti noi (lol).
    • sono di destra, mi trovo corretto (anche se non sono sicuro di quello che è stato ottimizzato out).
    • il motivo visto che questo è perché in modalità di Rilascio, il compilatore ha ottimizzato il codice e rimosso il UnionBytes = new byte[] { union.byte0, union.byte1, union.byte2, union.byte3 }; linea da MSIL rendering unione soluzione inutile. Ecco perché è 10 volte più veloce in modalità di Rilascio. Perché non viene mai eseguito.
    • Sembra che la morale è, l’attuazione di ogni uno nel codice reale e test.
    • Duckett non ho necessario bisogno di matrice
    • È lento perché si sono semplicemente l’allocazione di un array istanza di nuovo e di nuovo con il metodo dell’unione, che non è diverso da quello che BitConverter sta facendo. Se hai riutilizzato la matrice dell’esempio e semplicemente assegnati è cels con i rispettivi byte della nuova unione istanza, quindi potremmo vedere un miglioramento.

  6. 4

    Come molti qui sembrano discutere se BitConverter è beter di un dedicato struct. Basato su BCL codice sorgente il BitConverter.GetBytes() assomiglia a questo:

    public static unsafe byte[] GetBytes(int value)
    {
        byte[] buffer = new byte[4];
        fixed (byte* bufferRef = buffer)
        {
            *((int*)bufferRef) = value;
        }
        return buffer;
    }

    Che dal mio punto di vista è più pulito e sembra più veloce di 1 intero + 4 byte assegnazioni per un esplicito di una struttura come questa.

    [StructLayout(LayoutKind.Explicit)]
    struct IntByte
    {
      [FieldOffset(0)]
      public int IntVal;
      [FieldOffset(0)]
      public byte Byte0;
      [FieldOffset(1)]
      public byte Byte1;
      [FieldOffset(2)]
      public byte Byte2;
      [FieldOffset(3)]
      public byte Byte3;
    }
    
    new IntByte { IntVal = 10 } -> Byte0, Byte1, Byte2, Byte3.
  7. 2
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            unsafe{
                byte[] byteArray = new byte[4];
                for(int i = 0; i != int.MaxValue; ++i)
                {
                fixed(byte* asByte = byteArray)
                   *((int*)asByte) = 43;
                   }
            }
            Console.WriteLine(sw.ElapsedMilliseconds);
            Console.Read();
        }
    }

    Medie intorno 2770ms sulla mia macchina mentre

    [StructLayout(LayoutKind.Explicit)]
    struct Switcher
    {
      [FieldOffset(0)]
      public int intVal;
      [FieldOffset(0)]
      public byte b0;
      [FieldOffset(1)]
      public byte b1;
      [FieldOffset(2)]
      public byte b2;
      [FieldOffset(3)]
      public byte b3;
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            byte[] byteArray = new byte[4];
            Switcher swi = new Switcher();
            for(int i = 0; i != int.MaxValue; ++i)
            {
              swi.intVal = 43;
              byteArray[0] = swi.b0;
              byteArray[1] = swi.b1;
              byteArray[2] = swi.b2;
              byteArray[3] = swi.b3;
            }
            Console.WriteLine(sw.ElapsedMilliseconds);
            Console.Read();
        }
    }

    Medie intorno 4510ms.

    • Falso test – fites nuove condizioni. Non c’è stata alcuna parola in origine di una matrice e si sostituisce un puntatore arithmethid con cassetta di sicurezza confine codice testato matrici in modo che il test è inclinata verso la matrice di controllo di limite negativamente alla struct soluzione.
    • Naturalmente si tratta di un falso test, tutti i test sono falsi tranne che di vedere come funziona nella vita reale. In nessuno dei due fa di tutto ottenere ottimizzato di distanza per uno di loro, in modo che essa serve. Si potrebbe sostituire la copia dell’array con l’immissione in quattro byte e ancora questioni che realmente ottenere il byte da qualche parte, si aggiunge alla struct approccio. E ‘ una buona soluzione per i casi in cui non è possibile utilizzare unsafe, è veloce a circa la metà di un miliardo di cicli al secondo mentre farà la differenza.
  8. 1

    Penso che questo potrebbe essere il modo più veloce in C#.. (con matrice di byte inizializzato a 4x int stream w/int32

            private MemoryStream Convert(int[] Num, byte[] Bytes)
        {
            Buffer.BlockCopy(Num, 0, Bytes, 0, Bytes.Length);
            MemoryStream stream = new MemoryStream(Bytes);
            return stream;
        }
  9. 1

    Unione è il modo più veloce di divisione di un numero intero in byte. Qui di seguito è un programma completo, in cui il C# optimizer non è possibile ottimizzare il byte operazione di separazione, perché ogni byte viene riassunto e la somma viene stampato.

    I tempi sul mio portatile sono 419 millisecondi per l’Unione e 461 millisecondi per il BitConverter. Il guadagno in velocità, tuttavia, è molto maggiore.

    Questo metodo è utilizzato in un open source ad alte prestazioni di algoritmi di HPCsharp biblioteca, dove l’Unione metodo fornisce un bel incremento di prestazioni per il Radix Sort.

    Unione è più veloce in quanto non esegue alcuna operazione bit a bit di mascheramento e nessun bit-shift, ma semplicemente legge il byte appropriati di 4 byte integer.

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    namespace SplitIntIntoBytes
    {
        [StructLayout(LayoutKind.Explicit)]
        struct FooUnion
        {
            [FieldOffset(0)]
            public byte byte0;
            [FieldOffset(1)]
            public byte byte1;
            [FieldOffset(2)]
            public byte byte2;
            [FieldOffset(3)]
            public byte byte3;
    
            [FieldOffset(0)]
            public int integer;
        }
        class Program
        {
            static void Main(string[] args)
            {
                testUnion();
                testBitConverter();
    
                Stopwatch Timer = new Stopwatch();
    
                Timer.Start();
                int sumTestUnion = testUnion();
                Timer.Stop();
    
                Console.WriteLine("time of Union:        " + Timer.ElapsedTicks + " milliseconds,  sum: " + sumTestUnion);
    
                Timer.Restart();
                int sumBitConverter = testBitConverter();
                Timer.Stop();
    
                Console.WriteLine("time of BitConverter: " + Timer.ElapsedTicks + " milliseconds,  sum: " + sumBitConverter);
                Console.ReadKey();
            }
    
            static int testBitConverter()
            {
                byte[] UnionBytes = new byte[4];
                byte[] SumOfBytes = new byte[4];
                SumOfBytes[0] = SumOfBytes[1] = SumOfBytes[2] = SumOfBytes[3] = 0;
    
                for (int i = 0; i < 10000; i++)
                {
                    UnionBytes = BitConverter.GetBytes(i);
                    SumOfBytes[0] += UnionBytes[0];
                    SumOfBytes[1] += UnionBytes[1];
                    SumOfBytes[2] += UnionBytes[2];
                    SumOfBytes[3] += UnionBytes[3];
                }
                return SumOfBytes[0] + SumOfBytes[1] + SumOfBytes[2] + SumOfBytes[3];
            }
    
            static int testUnion()
            {
                byte[] UnionBytes;
                byte[] SumOfBytes = new byte[4];
                SumOfBytes[0] = SumOfBytes[1] = SumOfBytes[2] = SumOfBytes[3] = 0;
    
                FooUnion union = new FooUnion();
    
                for (int i = 0; i < 10000; i++)
                {
                    union.integer = i;
                    UnionBytes = new byte[] { union.byte0, union.byte1, union.byte2, union.byte3 };
                    SumOfBytes[0] += UnionBytes[0];
                    SumOfBytes[1] += UnionBytes[1];
                    SumOfBytes[2] += UnionBytes[2];
                    SumOfBytes[3] += UnionBytes[3];
                }
                return SumOfBytes[0] + SumOfBytes[1] + SumOfBytes[2] + SumOfBytes[3];
            }
        }
    }

Lascia un commento