I have an array of interleaved signed 24-bit ints (complex numbers) in little endian order that I would like to convert to a complex array of floats or doubles. By interleaved, I mean:
R1 R2 R3 I1 I2 I3 R4 R5 R6 I4 I5 I6 . . .
Where each item is an 8-bit byte, and each three together are a 24-bit int, with R = real and I = imaginary.
What's the most efficient way to do this in C#? The code has to run many times, so I'm trying to squeeze every last cycle out of it I can. I'm hoping for something more efficient than a brute force shift, or and cast.
I wouldn't mind using unsafe code in this case, if it would help.
Here's the baseline, brute-force approach with the second number of the pair commented out, and with sign handling ignored for the moment, to simplify the IDL:
class Program
{
const int Size = 10000000;
static void Main(string[] args)
{
//
// Array of little-endian 24-bit complex ints
// (least significant byte first)
//
byte[] buf = new byte[3 * 2 * Size];
float[] real = new float[Size];
//float[] imag = new float[Size];
//
// The brute-force way
//
int j = 0;
Stopwatch timer = new Stopwatch();
timer.Start();
for (int i = 0; i < Size; i++)
{
real[i] = (float)(buf[j] | (buf[j + 1] << 8) | (buf[j + 2] << 16));
j += 3;
// imag[i] = (float)(buf[j] | (buf[j + 1] << 8) | (buf[j + 2] << 16));
j += 3;
}
timer.Stop();
Console.WriteLine("result = " +
(float)(timer.ElapsedMilliseconds * 1000.0f / Size) +
" microseconds per complex number");
Console.ReadLine();
}
}
and the associated IDL:
IL_0024: ldc.i4.0
IL_0025: stloc.s i
IL_0027: br.s IL_0050
IL_0029: ldloc.1
IL_002a: ldloc.s i
IL_002c: ldloc.0
IL_002d: ldloc.2
IL_002e: ldelem.u1
IL_002f: ldloc.0
IL_0030: ldloc.2
IL_0031: ldc.i4.1
IL_0032: add
IL_0033: ldelem.u1
IL_0034: ldc.i4.8
IL_0035: shl
IL_0036: or
IL_0037: ldloc.0
IL_0038: ldloc.2
IL_0039: ldc.i4.2
IL_003a: add
IL_003b: ldelem.u1
IL_003c: ldc.i4.s 16
IL_003e: shl
IL_003f: or
IL_0040: conv.r4
IL_0041: stelem.r4
IL_0042: ldloc.2
IL_0043: ldc.i4.3
IL_0044: add
IL_0045: stloc.2
IL_0046: ldloc.2
IL_0047: ldc.i4.3
IL_0048: add
IL_0049: stloc.2
IL_004a: ldloc.s i
IL_004c: ldc.i4.1
IL_004d: add
IL_004e: stloc.s i
IL_0050: ldloc.s i
IL_0052: ldc.i4 0x989680
IL_0057: blt.s IL_0029