使用 IEEE754 获取数字的小数部分
Get fractional part of a number using IEEE754
我有一个使用循环工作的代码,但我觉得它很糟糕,因为可以简化。我的意思是这个循环:
private static long GetFract(double d)
{
if (d < 0)
return GetFract(-d);
d -= Math.Truncate(d);
long result = 0;
checked
{
while (true)
{
try
{
d *= 10;
long tmp = (long)d;
if (Math.Abs(tmp - d) < double.Epsilon)
return tmp;
result = tmp;
}
catch
{
return result;
}
}
}
}
预期结果:2.3333
-> 3333
那么我们是否可以使用 IEEE754
来获取数字的小数部分而不使用 ToString()
、Split()
和其他函数,仅使用 FP 和整数数学?我的意思是有点魔法:
private static unsafe long GetFract(double d)
{
if (d < 0)
return GetFract(-d);
d -= Math.Truncate(d);
const long mask = 0xFFFFFFFFFFFFF; //some magic const here
long x = *((long*) &d);
return x & mask;
}
我们假设d总是在[0..1],long和double都是8字节
表示数字 3333
的位序列在 2.3333
的 IEEE 754 表示中找不到,也没有在 0.3333
中找到,因为 IEEE 754 使用二进制指数,而不是十进制。
也就是说,你正在寻找 3333 / 10000
中的分子,但内部表示是(当转换为十进制时) 6004199023210345 / 18014398509481984
(分母是 254)
没有任何黑客可以提取最初不存在的数据。
我有一个使用循环工作的代码,但我觉得它很糟糕,因为可以简化。我的意思是这个循环:
private static long GetFract(double d)
{
if (d < 0)
return GetFract(-d);
d -= Math.Truncate(d);
long result = 0;
checked
{
while (true)
{
try
{
d *= 10;
long tmp = (long)d;
if (Math.Abs(tmp - d) < double.Epsilon)
return tmp;
result = tmp;
}
catch
{
return result;
}
}
}
}
预期结果:2.3333
-> 3333
那么我们是否可以使用 IEEE754
来获取数字的小数部分而不使用 ToString()
、Split()
和其他函数,仅使用 FP 和整数数学?我的意思是有点魔法:
private static unsafe long GetFract(double d)
{
if (d < 0)
return GetFract(-d);
d -= Math.Truncate(d);
const long mask = 0xFFFFFFFFFFFFF; //some magic const here
long x = *((long*) &d);
return x & mask;
}
我们假设d总是在[0..1],long和double都是8字节
表示数字 3333
的位序列在 2.3333
的 IEEE 754 表示中找不到,也没有在 0.3333
中找到,因为 IEEE 754 使用二进制指数,而不是十进制。
也就是说,你正在寻找 3333 / 10000
中的分子,但内部表示是(当转换为十进制时) 6004199023210345 / 18014398509481984
(分母是 254)
没有任何黑客可以提取最初不存在的数据。