64位整数和64位浮点同类表示法

时间:2019-07-24 15:47:34

标签: algorithm performance

假设我们有一些序列作为输入。出于性能原因,我们可能希望将其转换为同类表示形式。为了将其转换为同类表示,我们正在尝试将其转换为相同类型。这里让我们只考虑输入中的2种类型-int64float64(在我的简单代码中,我将使用numpy和python;这与问题无关紧要-人们可能只考虑64位整数和64位浮点数。

首先,我们可以尝试将所有内容强制转换为float64。 因此,我们需要像这样的输入:

31 1.2 -1234

将转换为float64。如果我们拥有所有int64,则可以将其保留不变(“已经同质”),或者如果找到其他内容,我们将返回“不同质”。非常简单。


但这是问题所在。考虑一下修改后的输入:

31000000 1.2 -1234

想法很明确-我们需要检查“ caster”是否能够正确处理绝对值int64

format(np.float64(31000000), '.0f')  # just convert to float64 and print
'31000000'

似乎根本不是问题。因此,让我们立即进行交易:

im = np.iinfo(np.int64).max  # maximum of int64 type

format(np.float64(im), '.0f')
format(np.float64(im-100), '.0f')
'9223372036854775808'
'9223372036854775808'

现在它真的是不需要的-我们丢失了一些可能需要的信息。即我们要保留输入序列中提供的所有信息。

因此,我们的imim-100值强制转换为相同的float64表示形式。这样做的原因很明显-float64在总共64位中只有53个有效位。这就是为什么其精度足以表示log10(2^53) ~= 15.95,即大约所有16长度的int64而没有任何信息丢失的原因。但是int64类型最多可以包含19位数字。

  

因此,我们最终得到大约[10^16; 10^19](更准确地说是[10^log10(53); int64.max])范围,其中每个int64都可能表示信息丢失。

问:在这种情况下,应该做出什么决定才能统一代表int64float64

我现在看到几个选项:

  1. 只需将所有int64范围转换为float64并“忘记”可能的信息丢失。
    • 动机是“大多数输入几乎不会是> 10^16 int64值”。
    • 编辑:此子句具有误导性。在明确的表述中,我们不考虑此类解决方案(但出于完整性考虑而保留)。
  2. 完全不要进行此类自动转换。仅在明确指定的情况下。
    • 即我们同意性能方面的弊端。对于 any int-float数组。即使是最简单的第一种情况也是如此。
  3. 计算在不损失任何信息的情况下转换为float64的阈值。并在决定投放时使用它。如果发现int64高于此阈值-请勿进行转换(返回“不均匀”)。
    • 我们已经计算出此阈值。它是log10(2^53)舍入的。
  4. 创建新类型"fint64"。这是一个异乎寻常的决定,但我甚至还在考虑这样做的完整性。
    • 这里的动机包括2点。第一个:用户想要将intfloat类型存储在一起时经常出现这种情况。其次-是float64类型的结构。我不太了解为什么如果有效数字仅由其中的~308个组成,而其他~16本身就是一个噪声,那么为什么将需要~292个数字的值范围。因此,我们可以使用float64指数位之一来指示其floatint是否存储在此处。但是对于int64,丢失1位肯定是缺点。原因会减小我们的整数范围两次。但是我们将有可能将intfloat一起自由存储,而没有任何额外的开销。
    • 编辑:虽然我最初的想法是“异国情调”的决定,但实际上这只是另一种解决方案的变体-我们表示的复合类型(请参见5子句)。但需要在这里补充一下,我的第一作曲有一定的弊端-float64int64失去了一定的范围。我们宁愿做的-不是减去1位而是添加一位,代表存储在后面64位中的intfloat类型的标志。
  5. 如@Brendan所建议的,可以使用由“ 2个或更多原始类型的组合”组成的复合类型。因此,使用其他原语,例如,我们可以覆盖int64的“问题”范围,并获得这种“新”类型的同类表示形式。

编辑

  1. 因为这里出现问题,所以我需要尝试非常具体:所讨论的应用程序会执行以下操作-将int64float64的序列转换为某种同构表示,如果可能的话,应无损。通过性能比较解决方案(例如,表示所需的总过量RAM)。就这些。这里没有考虑任何其他要求(因为我们应该在最小状态下考虑问题-而不是编写整个应用程序)。相应地,以均匀状态表示我们的数据的算法无损(我们确定我们不会丢失任何信息)适合我们的应用程序。

  2. 我已决定从问题中删除“ app”和“ user”一词-这也具有误导性。

2 个答案:

答案 0 :(得分:1)

选择数据类型时有3个要求:

  • 如果值可能具有不同的符号
  • 需要精度
  • 所需范围

当然,硬件并没有提供很多类型可供选择;因此您需要选择下一个提供的最大类型。例如,如果要以8位精度存储范围从0到500的值;那么硬件将无法提供此类功能,您将需要使用16位整数或32位浮点数。

选择同构表示时,有3个要求:

  • 如果值可能具有不同的符号;根据代表的所有原始类型的要求确定
  • 所需的精度;根据代表的所有原始类型的要求确定
  • 所需范围;根据代表的所有原始类型的要求确定

例如,如果您具有从-10到+10000000000的整数,则需要一个不存在的35位整数类型,因此您将使用64位整数,并且如果需要从-2到... +2(31位精度),那么您需要一个不存在的33位浮点类型,因此您将使用64位浮点类型;从这两种原始类型的要求中,您将知道同构表示将需要符号标志,33位有效数字(带有隐含位)和1位指数。它不存在,因此您将使用64位浮点类型作为同类表示形式。

但是;如果您对原始数据类型的要求一无所知(并且只知道由于要求导致选择64位整数类型和64位浮点类型),那么您将必须承担“最坏的情况”。这导致需要具有符号标志,62位精度(加上一个隐含的1位)和8位指数的同构表示。当然,这种71位浮点类型不存在,因此您需要选择下一个最大的类型。

还请注意,有时没有硬件支持的“下一个最大类型”。发生这种情况时,您需要求助于“组合类型”-2个或更多原始类型的组合。可以包含不超过“大有理数”(以“分子/除数*(1 <<指数)”形式的3个大整数表示的数)的任何内容。

当然,如果原始类型(64位整数类型和64位浮点类型)是原始类型,并且您的同类表示形式需要使用“组合类型”;那么您的“ 出于性能原因,我们可能希望将其转换为同类表示形式”的假设可能是错误的(出于性能原因,您可能希望避免使用同类表示形式)。

换句话说:

如果您对原始数据类型的要求一无所知,出于性能原因,您可能希望避免使用同质表示。

现在...

让我们将您的问题改写为“如何处理设计失败(选择不符合要求的错误类型)?”。只有一个答案,那就是避免设计失败。运行时检查(例如,如果转换为同类表示形式导致精度损失,则引发异常)除了将开发失败通知开发人员之外,没有其他用途。

答案 1 :(得分:1)

这实际上是非常基本的:使用64位浮点。浮点数 是一个近似值,您将失去许多整数的精度。但是除了“可能原先是不可或缺的”和“原始值是否偏离1.0以上”之外没有其他不确定性。

我知道一个非标准的浮点表示形式会更强大(可以在网上找到)。这可能(或可能不会)帮助覆盖整数。

拥有精确的int映射的唯一方法是减小int范围,并保证(例如)60位int是精确的,其余范围由浮点近似。浮点数也必须减小,要么是提到的指数范围,要么是精度(尾数)。