Самый быстрый способ в С# для чтения блока байтов из файла и преобразования в число с плавающей запятой []

Мне нужен быстрый способ преобразования/преобразования массива байтов в С#, кодирующего одно короткое (int16) значение для 2 байтов в представление с плавающей запятой, как можно быстрее. Узким местом производительности был метод:

samples[sample] = (float)binraryReader.readInt16();

(огромное количество вызовов ввода-вывода, поэтому мне пришлось преобразовать их в блочное чтение)

В основном у меня есть файл, содержащий блок звуковых образцов (~ 100-600 МБ) типа short, затем, поскольку я могу блокировать только набор байтов для чтения, мне нужно построить короткий из каждой пары байтов, а затем преобразовать этот короткий в float представление, так как мне нужно хранить образцы в виде поплавков.

мой текущий код выглядит примерно так (улучшение производительности примерно в 2 раза по сравнению с описанным выше методом, но все же слишком долго):

    float[] samples = new float[_samplesPerSplit];
    byte[] data = new byte[_samplesPerSplit * 2];

    for (int c = 0; c < numberOfChunks; c += 1)
    {
        br.Read(data, 0, _samplesPerSplit * 2);

        fixed (byte* bytePtr = data)
        {
            fixed (float* floatPtr = samples)
            {
                byte* rPos = bytePtr;
                float* fPos = floatPtr;

                byte byte0;
                byte byte1;
                short sampleShort;

                for (int sample = 0; sample < _samplesPerSplit; sample += 1)
                {
                    byte1 = *(rPos++);
                    byte0 = *(rPos++);

                    // I occasionaly get 
                    //          "Negating  the minimum value of a 
                    //          twos complement number is invalid" 
                    // error if i skip this check, but it slows down 
                    // whole process even more
                    if (byte0 == 128 && byte1 == 0)
                    {
                        sampleShort = 32767;
                    }
                    else
                    {
                        sampleShort = (short)(((ushort)(byte0)) << 8 | ((ushort)(byte1)));
                    }

                    *(fPos++) = (float)sampleShort;
                }
            }
        }
        ProcessChunk(samples);
    }

person Oscar    schedule 04.06.2010    source источник


Ответы (2)


вы можете попробовать это:

    fixed (byte* bytePtr = data)
    {
        fixed (float* floatPtr = samples)
        {
            short* rPos = (short*)bytePtr;
            float* fPos = floatPtr;

            for (int sample = 0; sample < _samplesPerSplit; sample += 1)
            {
                *fPos++ = (float)(*rPos++);
            }

        }
    }
person max    schedule 04.06.2010
comment
Спасибо, кажется, что у меня аппаратное обеспечение диска ограничено, но я все еще получил около 10 или около того процентов времени, так что я думаю, что сейчас все хорошо, поскольку я не могу представить ничего быстрее: P - person Oscar; 04.06.2010

Вы пытались использовать побитовую операцию

Я мало что о них знаю, но из Вики и МОИХ предыдущего SO вот что я узнал об этом:

Побитовые операции обычно выполняются значительно быстрее операций умножения и деления.

person adopilot    schedule 04.06.2010
comment
Он уже использует оператор сдвига влево во втором примере. - person Hinek; 04.06.2010