14

1. How can I reinterpret cast a float to an int (or a double to a long)?

float f = 2.0f;
int i = (int)f; // causes conversion

I only want to copy the bit-pattern from f to i. How can this be done?

2. The implicit and explicit operators in C# uses one intermediate object because the operator function is static

public static implicit operator MyClass(double s)
{
    return new MyClass(s);
} 
..
..
MyClass m = 2.2; // this code uses 'm' and one intermediate object.

This is fine for reference types, but for value-types which are big (say 20-30 bytes), this will cause unnecessary data copy. Is my understanding correct? And If yes, then why doesn't C# have a non-static conversion operator or user-defined assignment operator so that the conversion/assignment takes place on 'this'? If it does, whats the way to do it?

Nathan Smith
  • 683
  • 1
  • 10
  • 24

5 Answers5

12

Barring unsafe code - this is the fastest method I know of to perform a reinterpret:

    [StructLayout(LayoutKind.Explicit)]
    private struct IntFloat
    {
        [FieldOffset(0)]
        public int IntValue;
        [FieldOffset(0)]
        public float FloatValue;
    }
    private static float Foo(float x)
    {
        var intFloat = new IntFloat { FloatValue = x };
        var floatAsInt = intFloat.IntValue;
        ...

Hope this helps someone.

Ani
  • 10,826
  • 3
  • 27
  • 46
12

1: BitConverter (as sixlettervariables) is an option; as is unsafe code (which doesn't need an intermediate buffer):

    float f = 2.0f;
    int i;
    // perform unsafe cast (preserving raw binary)
    unsafe
    {
        float* fRef = &f;
        i = *((int*)fRef);
    }
    Console.WriteLine(i);

    // prove same answer long-hand
    byte[] raw = BitConverter.GetBytes(f);
    int j = BitConverter.ToInt32(raw, 0);        
    Console.WriteLine(j);

2: note that you should limit the size of structs. I can't find a citation fr it, but the number "16 bytes" (max, as a recommendation) seems to stick in my mind. Above this, consider an immutable reference-type (class).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
8
  1. The BitConverter class can retrieve the bytes for any primitive type, which you can then use to create an int. Another option is Buffer.BlockCopy if you have large amounts of converting to do.

    float ff = 2.0f;
    int ii = BitConverter.ToInt32(BitConverter.GetBytes(ff), 0);
    
    float[] ff = new float[...];
    int[] ii = new int[ff.Length];
    Buffer.BlockCopy(ff, 0, ii, 0, ff.Length * 4); // byte-wise copy of ff into ii
    
  2. No there is no other option given in C#, however, I think that while you're correct in the sense that there will be a copy made, any sufficiently simple implementation will have JIT optimizations done, possibly removing the need for a copy.

user7116
  • 63,008
  • 17
  • 141
  • 172
  • It's not clear that making the operator an instance operator would remove the need for the copy anyway. The question seems somewhat confused to me. – Jon Skeet Oct 15 '12 at 15:18
  • Back in '08 I'd made assumptions that the JIT would behave similar to a C++ compiler w.r.t. member methods, but I've yet to see it work like that in practice. – user7116 Oct 15 '12 at 15:24
2

This approach, while unsafe, works as a generic solution

static unsafe TDest ReinterpretCast<TSource, TDest>(TSource source)
{
    var tr = __makeref(source);
    TDest w = default(TDest);
    var trw = __makeref(w);
    *((IntPtr*)&trw) = *((IntPtr*)&tr);
    return __refvalue(trw, TDest);
}
Nick Strupat
  • 4,928
  • 4
  • 44
  • 56
2

This should be the fastest and cleanest way to do it:

public static class ReinterpretCastExtensions {
   public static unsafe float AsFloat( this int n ) => *(float*)&n;
   public static unsafe int AsInt( this float n ) => *(int*)&n;
}

public static class MainClass {
   public static void Main( string[] args ) {
      Console.WriteLine( 1.0f.AsInt() );
      Console.WriteLine( 1.AsFloat() );
   }
}