6

I am developing a portable class library in C# and I want to bit convert a double to a long. The most straightforward solution to this issue would be to use the BitConverter.DoubleToInt64Bits method, but unfortunately this method is not available in the Portable Library subset of the .NET class library.

As an alternative I have come up with the following "two-pass" bit conversion:

var result = BitConverter.ToInt64(BitConverter.GetBytes(x), 0);

My tests show that this expression consistently produces the same result as DoubleToInt64Bits. However, my benchmark tests also show that this alternative formulation is approximately four times slower than DoubleToInt64Bits when implemented in a full .NET Framework application.

Using only the Portable Library subset, is it possible to implement a replacement of DoubleToInt64Bits that is quicker than my formulation above?

Anders Gustafsson
  • 15,837
  • 8
  • 56
  • 114

2 Answers2

5

How about using a union?

[StructLayout(LayoutKind.Explicit)]
public struct DoubleLongUnion
{
    [FieldOffset(0)]
    public double Double;

    [FieldOffset(0)]
    public long Long;
}

public static long DoubleToInt64Bits(double value)
{
    var union = new DoubleLongUnion {Double = value};
    return union.Long;
}
Omer Mor
  • 5,216
  • 2
  • 34
  • 39
  • 1
    Great, what a clever solution, many thanks Omer! Your solution is slower than the full framework `DoubleToInt64Bits` method, but more than twice as fast as my "two-pass" solution. For a while I was a little bit worried that this would not work in a portable library, since there is no indication on MSDN that the Portable Library subset supports the [FieldOffset attribute](http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.fieldoffsetattribute.aspx). However, the implementation works so it only seems to be an oversight in the MSDN documentation. – Anders Gustafsson May 09 '12 at 18:45
  • 1
    An additional benefit with your solution is that I can easily add a `ulong ULong` field to the `Union` struct, and analogously implement a `DoubleToUInt64Bits` method returning a `ulong` value. This flexibility is much appreciated :-) – Anders Gustafsson May 09 '12 at 18:50
  • BTW, a potential speed boost might be to declare the union instance as a static field, outside of the method, and only change its value in the method. Then you won't have to allocate the stack space every time you call the method. However the downside is that it will not be thread-safe anymore. – Omer Mor May 09 '12 at 20:17
3

If you're able to flag your assembly as unsafe then you could just lift the DoubleToInt64Bits implementation into your own library:

public static unsafe long DoubleToInt64Bits(double value)
{
    return *(((long*) &value));
}
Sean
  • 60,939
  • 11
  • 97
  • 136
  • Thanks for the suggestion! I made a quick benchmark test of your method, and it seems to be about _as_ fast as the `DoubleToInt64Bits` method. Unfortunately, since it is a portable library(potentially aimed also for Silverlight, WP7 and Metro applications), `unsafe` is not an option. – Anders Gustafsson May 09 '12 at 14:52
  • Of course, your method is bound to be as fast as `DoubleToInt64Bits`. I read your answer too quickly the first time and missed the part that this is the way `DoubleToInt64Bits` is implemented :-) Sorry for my confusion. – Anders Gustafsson May 09 '12 at 15:12