假设我有一个浮点数X.我想找到小于X的最大数字,并且可以无损地存储在浮点数中.
IIRC IEEE标准说你可以通过将float的位转换为int表示,减去1,然后转换回float来实现.
(编辑:对于不是NaN或inf的正数,这是正确的.对于负数,您必须添加.有关更多信息,请参阅Rawling的答案.)
要在表示之间进行更改,我只知道C#的(强制转换)运算符,它会截断.那不是我想要的.
有没有办法在C#中做到这一点?
以下是如何将a float转换为a int,更改它,然后将其转换为float:
float myFloat = 10.3f;
// Get the bytes making up the float
byte[] bytes = BitConverter.GetBytes(myFloat);
// Make an int out of them
int myInt = BitConverter.ToInt32(bytes, 0);
// Change it
myInt--;
// Get the bytes making up the int
bytes = BitConverter.GetBytes(myInt);
// Make a float out of them
myFloat = BitConverter.ToSingle(bytes, 0);
// gives 10.2999992 or so
Run Code Online (Sandbox Code Playgroud)
BitConverter 甚至有内置的64位等价物:
double myDouble = 10.3;
long myLong = BitConverter.DoubleToInt64Bits(myDouble);
myLong--;
myDouble = BitConverter.Int64BitsToDouble(myLong); // gives 10.2999999...
Run Code Online (Sandbox Code Playgroud)
然而,正如彼得·鲁德曼所指出的那样,基础的简单减少int并不能可靠地给你下一个最小的float.
特别是,对于负数,您需要递增整数以使浮点数更负.对于float零,下一个最小int实际上对应于NaN,所以你需要一个特殊情况.
这里有几个我已经碰到的功能,一般应该处理这些情况; 它也看起来像是在大数和正/负无穷大之间合理传播!我使用了不安全的转换来减少代码长度,但如果您愿意,可以坚持上面的字节转换:
static unsafe float Increment(float f)
{
int val = *(int*)&f;
if (f > 0)
val++;
else if (f < 0)
val--;
else if (f == 0)
return float.Epsilon;
return *(float*)&val;
}
static unsafe float Decrement(float f)
{
int val = *(int*)&f;
if (f > 0)
val--;
else if (f < 0)
val++;
else if (f == 0)
return -float.Epsilon; // thanks to Sebastian Negraszus
return *(float*)&val;
}
Run Code Online (Sandbox Code Playgroud)
正如Jeppe指出的那样,你可能也想要
if (float.IsNaN(f)) return f;,启动每个函数,这样你就不会意外地增加或减少a NaN并给出一个数字.float.PositiveInfinity或者.NegativeInfinity,从数学上讲,这些应该在增量/减量下保持不变.