什么是最好的启发式,我可以用来确定一个X 4字节的块是整数还是浮点数?人类可以轻松地做到这一点,但我想以编程方式进行。
我意识到,由于每个位组合都会产生一个有效的整数和(几乎?)所有这些组合也会产生一个有效的浮点数,因此无法确定。但我仍然想确定最有可能的候选人(这几乎总是正确的;或者至少,人类可以做到这一点)。
例如,让我们先取一系列4字节的原始数据,然后先将它们作为整数打印,然后再作为浮点数打印:
1 1.4013e-45
10 1.4013e-44
44 6.16571e-44
5000 7.00649e-42
1024 1.43493e-42
0 0
0 0
-5-南
11 1.54143e-44
显然他们将是整数。
现在,另一个例子:
1065353216 1
1084227584 5
1085276160 5.5
1068149391 1.33333
1083179008 4.5
1120403456 100
0 0
-1110651699 -0.1
1195593728 50000
这些显然是漂浮物。
PS:我使用的是C ++,但您可以使用任何语言,伪代码或英语进行回答。
您将要查看高8位或9位。这就是浮点值的符号和尾数。对于有效的浮点数据,这里的值0x00 0x80和0xFF非常罕见。
特别是如果高9位全部为0,则仅当所有32位都为0时,这可能是有效的浮点值。另一种说法是,如果指数为0,则尾数也应为零。如果高位为1且接下来的8位为0,则这是合法的,但也不可能有效。它代表-0.0,这是一个合法的浮点值,但是没有意义。
把它放到数字术语中。如果高位字节是0x00(或0x80),则该值的大小为 最多 2.35e-38。普朗克常数为6.62e-34 m2kg / s,大4个数量级。质子的估计直径远远大于(估计为1.6e-15米)。音频数据的最小非零值约为2.3e-10。您不太可能看到浮点值是真实的小于2.35e-38的合法测量值 不 零。
如果高位字节为0xFF,则向另一个方向移动,则该值为无限,NaN或大于3.4e + 38的大小。宇宙的年龄估计为1.3e + 10年(1.3e + 25飞秒)。可观察的宇宙大约有e + 23颗星,Avagadro的数字是6.02e + 23。再次浮动值大于e + 38很少出现在合法测量中。
这并不是说FPU无法加载或生成这样的值,如果您正在使用现代FPU,您肯定会在计算的中间值中看到它们。现代FPU将加载一个浮点值,其指数为0,但其他位不为0.这些值被调用 非规范化 值。这就是为什么你看到小的正整数显示为e-42范围内的浮点值,即使浮点数的正常范围仅下降到e-38
所有1的指数代表无穷大。您可能不会在数据中找到无穷大,但您会比I更好。-Infinity是0xFF800000,+ Infinity是0x7F800000,Infinity尾数中除0以外的任何值都是格格不入的。畸形无穷大被用作NaNs。
将NaN加载到浮点寄存器中会导致它抛出异常,因此您需要使用整数数学来猜测数据是浮点数还是int数,直到您确定它是int为止。
你的例子中的“常识”启发式似乎基本上等于范围检查。如果一个解释非常大(或一小部分,接近零),那可能是错误的。检查浮点解释的指数,并将其与整数解释的正确静态强制转换为浮点数的指数进行比较。
看起来像 kolmogorov复杂性 问题。基本上,从您显示的示例中,较短的数字(当打印为字符串以供人阅读时),无论是整数还是浮点数,都是启发式的正确答案。
此外,显然如果值是一个不正确的浮点数,它是一个整数:-)
似乎足够直接实施。
您可以通过查看高位来“检测”它,浮点数通常是非零的,使用整数,除非您处理的是非常大的数字,否则它们将是“检测”它。那么......你可以试试看是否 (2^30) & number
回报 0
或不。
如果两个数字都是正数,那么您的浮点数相当大(大于10 ^ -42),并且您的整数相当小(小于8 * 10 ^ 6),那么检查非常简单。将数据视为a float
并与最不规范化的浮点数进行比较。
union float_or_int {
float f;
int32_t i;
};
bool is_positive_normalized_float( float_or_int &u ) {
return u.f >= numeric_limits<float>::min();
}
这假定IEEE float
和CPU和FPU之间的相同内容。
人类可以轻松地做到这一点
一个人根本做不到。 Ergo也不能用电脑。有2 ^ 32个有效的int值。其中大量也是有效的浮点值。除了标记数据之外,没有办法区分数据的意图,或者首先没有进入这样的混乱。
不要尝试这个。
如果您知道您的浮点数都是实际值(没有NaN,INF,非正规值或其他异常值),那么您可以使用此标准。通常,一个int数组很可能包含“坏”浮点值。
我假设如下:
- 你的意思是IEEE 754单精度浮点数。
- float的符号位保存在int的MSB中。
所以我们走了:
static boolean probablyFloat(uint32_t bits) {
bool sign = (bits & 0x80000000U) != 0;
int exp = ((bits & 0x7f800000U) >> 23) - 127;
uint32_t mant = bits & 0x007fffff;
// +- 0.0
if (exp == -127 && mant == 0)
return true;
// +- 1 billionth to 1 billion
if (-30 <= exp && exp <= 30)
return true;
// some value with only a few binary digits
if ((mant & 0x0000ffff) == 0)
return true;
return false;
}
int main() {
assert(probablyFloat(1065353216));
assert(probablyFloat(1084227584));
assert(probablyFloat(1085276160));
assert(probablyFloat(1068149391));
assert(probablyFloat(1083179008));
assert(probablyFloat(1120403456));
assert(probablyFloat(0));
assert(probablyFloat(-1110651699));
assert(probablyFloat(1195593728));
return 0;
}
简化艾伦所说的,我只看整数形式。并且说,如果数字大于99999999那么它几乎肯定是一个浮点数。
这样做的优点是快速,简单,并避免了纳米问题。
它有一个缺点,它几乎充满了废话...我实际上并没有看到这些代表或任何东西的浮动,但从你的例子看起来合理......
在任何情况下,这都是一种启发式方法,所以它的GONNA充满了垃圾,而且无论如何都无法工作......
用千分尺测量,用粉笔标记,用斧头切割。