我想在C#中操纵浮点数的按位表示。 BinaryWriter和BinaryReader这样做:
public virtual unsafe void Write(double value)
{
ulong num = *((ulong*) &value);
...
}
public virtual unsafe double ReadDouble()
{
...
ulong num3 = ...;
return *((double*) &num3);
}
有没有办法在没有不安全代码的情况下执行此操作,并且没有实际使用BinaryWriter和BinaryReader的开销?
答案 0 :(得分:8)
另一种方法是使用具有显式布局的自定义结构,该结构在偏移0处定义long
和double
。这相当于C中的union
。
这样的事情:
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
struct DoubleLongUnion
{
[FieldOffset(0)]
public long Long;
[FieldOffset(0)]
public double Double;
}
然后使用:
var union = new DoubleLongUnion();
union.Double = 1.234d;
var longBytes = union.Long;
这将避免任何不安全的代码,并且当您在堆栈上执行转换时也应该执行得非常快。
我没有尝试/编译过这个,但我认为它应该可以工作:)
修改强>
我刚试过这个并且它有效。上面longBytes
的值是4608236261112822104。
其他一些价值观:
0d -> 0L
double.NaN -> -2251799813685248L
double.MinValue -> -4503599627370497L
double.MaxValue -> 9218868437227405311L
这是一种可以实现您想要的方法:
public static long DoubleToLong(double d)
{
return new DoubleLongUnion { Double = d }.Long;
}
答案 1 :(得分:6)
你可以使用byte[] BitConverter.GetBytes(double)
和long BitConverter.ToInt64(byte[],int)
(传递0作为起始索引),但内部 IIRC这些使用不安全的代码,加上数组的开销。选择你的毒药......
答案 2 :(得分:4)
您是在尝试完全避免使用不安全的代码,还是只想在BinaryReader
和BinaryWriter
上替换这些特定方法?
您可以使用BitConverter.DoubleToInt64Bits
和BitConverter.Int64BitsToDouble
,它们可以完全满足您的需求,但我认为他们使用与BinaryReader
/一样的幕后不安全转换BinaryWriter
方法。