tags:

views:

106

answers:

4

In the good old days of C. I could cast a float to an int (assuming 32 bit system), do some bit manipluation ( bitwise and, right shift, ect ), and get the upper and lower 16 bit hex representations of the floating point number, which I could then store in two short values. I'm not seeing an easy way of doing this in C#.
System.Convert.ToUInt16 just does a float to int convert (even after I shift right), which leaves a vlaue of 0 if the float is less than 0, which is not the desired effect.

//useless leaves me witg a value 0f 0
UIN16 s1 = (UInt16)((System.Convert.ToUInt32(d2) & 0xffff0000) >> 16);    //capture the high word
UInt16 s2 = (UInt16)(System.Convert.ToUInt32(d2) & 0xffff);              //capture the low word

A basic cast (UInt32) doesn't work either.

A: 

There is this class - BitConverter which has some nice and useful methods. I'm sure You will find it useful too :)

For example the method GetBytes can convert variables of many different types into a byte array, and the method ToUInt16 returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.

Maciej Hehl
+6  A: 

I think you're after the BitConverter class.

http://msdn.microsoft.com/en-us/library/system.bitconverter.aspx

        float value = 1.1f;
        byte[] bytes = BitConverter.GetBytes(value);
        short upper = BitConverter.ToInt16(bytes, 0);
        short lower = BitConverter.ToInt16(bytes, 2);
Daniel Renshaw
+1  A: 

The closest direct equivelent to your C method would be to do this with unsafe code, and pointers:

private static unsafe void SplitToWords(float f, out ushort s1, out ushort s2)
{
    unsafe
    {
        float* ptr = &f;
        UInt16* s2ptr = (UInt16*) ptr;
        UInt16* s1ptr = s2ptr + 1;

        s1 = *s1ptr;
        s2 = *s2ptr;
    }
}

This lets you do:

public static void Main()
{
    float f = -23984.123f;
    ushort s1;
    ushort s2;
    SplitToWords(f, out s1, out s2);

    Console.WriteLine("{0} : {1}/{2}", f, s1, s2);
    Console.ReadKey();
}

However, the more common managed way would be to use BitConverter.

byte[] fBytes = BitConverter.GetBytes(f);
s1 = BitConverter.ToUInt16(fBytes, 2);
s2 = BitConverter.ToUInt16(fBytes, 0);

You can see these produce the same thing here:

public static void Main()
{
    float f = -23984.123f;
    ushort s1;
    ushort s2;
    SplitToWords(f, out s1, out s2);

    Console.WriteLine("{0} : {1}/{2}", f, s1, s2);

    byte[] fBytes = BitConverter.GetBytes(f);
    s2 = BitConverter.ToUInt16(fBytes, 0);
    s1 = BitConverter.ToUInt16(fBytes, 2);
    Console.WriteLine("{0} : {1}/{2}", f, s1, s2);

    Console.ReadKey();
}
Reed Copsey
A: 

Short answer: Don't do it!

Long explanation: In the good old days these hacks have been done because doing the float to int conversion (and vice vesa) was a lot faster than letting the FPU do the job. I could be wrong, but I think I remember a success story of such an optimization for the pc-game Decent (anyone remember it? good old quake 1 days). In this case it made 30% of a difference. At least so I remember..

Nowadays this is not true anymore, in fact the opposite is true. If you compile your code against the legacy x86 fpu any bit-fiddling must be done in the integer unit, and each transition from the float to int unit must be done via memory. This cost a lot of cycles. You usually don't mix float and int operations of the same value, and the CPU is not optimized for this use-case.

If otoh the code gets compiled against the SSE instruction set you could take a shortcut. There is no extra cost to do integer operations on float data or vice versa, but straight int<->float conversions via SSE is faster at the first place, so why bother?

It gets much worse with other architectures.. On the ARM Cortex-A8 for examples such tricks will stall the entire CPU for at least 21 cycles... I've read horror stories about mixing int and float on the PowerPC as well (load/modify/store anyone?)

In summary: Don't do it unless you write for Pentium-I legacy hardware. If so contact me, I still have all the timings and example codes on my hard-disk.

Nils Pipenbrinck