问题 启发式以识别一系列4字节数据块是整数还是浮点数


什么是最好的启发式,我可以用来确定一个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 ++,但您可以使用任何语言,伪代码或英语进行回答。


9061
2018-03-21 00:53


起源

请考虑选择其他答案。约翰的问题很多。 - Potatoswatter
我认为任何需要依赖启发式来区分整数和浮点数的系统都存在基本的设计缺陷。你可以更好地修复这些缺陷,而不是用启发式方法来修补裂缝......这可能会偶尔给你错误的答案。 - Stephen C
@Stephen:我使用这样的东西来节省内存。但是,在没有首先指定排他数值范围的情况下要求启发式算法是一个麻烦的迹象。 - Potatoswatter
@Stephen在大多数情况下你可能是对的,但它本身就是一个非常有趣的问题,我无法抗拒至少在思考它。 - MatrixFrog
@MatrixFrog - 我没有问题:-) - Stephen 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为止。


0
2018-03-21 01:03



我在这里看到的每一个断言都是完全错误的。符号+指数包含在上部 9 位。 0x00始终有效;如果下一位为0,则该数字被非规范化。 0x80表示小的负值。 0xff在任何大的负值,负无穷大或NAN之前。 - Potatoswatter
0x80 绝对有效作为浮点的高位字节(具体来说,它是负零的高位字节或非常小的负数)。更普遍, 一切 32位整数是有效的浮点编码(有些是NaN,但那些仍然是有效的编码)。 0xFF 实际上是一个非常高的字节 大 负数(或-infinity,或NaN)。 0x00 也是一个有效的高位字节(零或小的正数)。 - Stephen Canon
@Patatoswatter:你是对的 - 我所说的更具启发性而非技术性。它是高9位,非规范化浮点数是FPU可容忍的合法值。但事实并非如此 正常 因此可以用作合理性检查。鉴于你的反对意见,我扩大了答案。 - John Knoeller
@Stephen Canon:这取决于你的意思是有效的。我的意思是 合理地找到实际数据。我将授予您每个32位值对FPU具有已定义的含义,但某些位模式不会出现在浮点值中 出 FPU和其他数据不太可能出现在由随机数生成器以外的某些进程生成的数据中。 - John Knoeller
对不起,但这仍然是不正确的。 (大多数)FPU可以作为算术或转换的结果产生非规范化值,因此完全可以从“FPU”中获得非规范化值。更一般地说,这个词 有效 在英语中有一个共同的含义,它不是“预期的”。虽然一些FPU不会生成一些位模式(通常是可能的NaN编码的子集),但是没有标准可以保证所有FPU都是如此(实际上,它不是)。 - Stephen Canon


你的例子中的“常识”启发式似乎基本上等于范围检查。如果一个解释非常大(或一小部分,接近零),那可能是错误的。检查浮点解释的指数,并将其与整数解释的正确静态强制转换为浮点数的指数进行比较。


9
2018-03-21 01:12



如果进行整数比较,这是安全的。如果进行浮点比较,则可能会导致加载NaN并从比较操作中获得异常或意外结果。 - John Knoeller
如果只想比较指数,则需要屏蔽这些位并比较为整数。不涉及浮动比较。 - Alan


看起来像 kolmogorov复杂性 问题。基本上,从您显示的示例中,较短的数字(当打印为字符串以供人阅读时),无论是整数还是浮点数,都是启发式的正确答案。

此外,显然如果值是一个不正确的浮点数,它是一个整数:-)

似乎足够直接实施。


4
2018-03-21 23:50



感谢好主意:) - JesusFreke


您可以通过查看高位来“检测”它,浮点数通常是非零的,使用整数,除非您处理的是非常大的数字,否则它们将是“检测”它。那么......你可以试试看是否 (2^30) & number 回报 0 或不。


1
2018-03-21 00:59





如果两个数字都是正数,那么您的浮点数相当大(大于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之间的相同内容。


1
2018-03-21 01:45





人类可以轻松地做到这一点

一个人根本做不到。 Ergo也不能用电脑。有2 ^ 32个有效的int值。其中大量也是有效的浮点值。除了标记数据之外,没有办法区分数据的意图,或者首先没有进入这样的混乱。

不要尝试这个。


1
2018-03-21 23:43





如果您知道您的浮点数都是实际值(没有NaN,INF,非正规值或其他异常值),那么您可以使用此标准。通常,一个int数组很可能包含“坏”浮点值。


0
2018-03-21 10:27





我假设如下:

  • 你的意思是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;
}

0
2018-06-01 21:28





简化艾伦所说的,我只看整数形式。并且说,如果数字大于99999999那么它几乎肯定是一个浮点数。

这样做的优点是快速,简单,并避免了纳米问题。

它有一个缺点,它几乎充满了废话...我实际上并没有看到这些代表或任何东西的浮动,但从你的例子看起来合理......

在任何情况下,这都是一种启发式方法,所以它的GONNA充满了垃圾,而且无论如何都无法工作......

用千分尺测量,用粉笔标记,用斧头切割。


0
2018-06-01 21:39