std :: numeric_limits :: is_exact ...什么是可用的定义?

时间:2013-01-07 20:38:08

标签: c++ numeric-limits

正如我所解释的那样,numeric_limits::is_exact的{​​{3}}几乎总是错误的:

  

[this]类型的[全部]计算没有舍入错误。

并且MSDN's definition几乎总是如此:(或者是循环定义,取决于你如何阅读它)

  

一种对其所有值都有精确表示的类型

我确定的是,我可以在2double中同时存储long,并且它们都会被表示 >。

然后我可以将它们除以10,并且两者都不会将数学结果完全

鉴于任何数字数据类型T,定义std::numeric_limits<T>::is_exact的正确方法是什么?

编辑: 我已根据许多答案中提供的详细信息向IBM's definition发布了此问题。 what I think is an accurate answer

6 个答案:

答案 0 :(得分:7)

标准中的定义(参见NPE的答案)不是很精确,是吗?相反,它是循环和模糊的。

鉴于IEC浮点标准具有“不精确”数字的概念(并且当计算产生不精确的数字时是一个不精确的异常),我怀疑这是名称is_exact的起源。请注意,在标准类型中,is_exact仅对floatdoublelong double为false。

目的是指明完全类型是否代表基础数学类型的所有数字。对于整数类型,基础数学类型是整数的一些有限子集。由于每个整数类型精确地表示该类型所针对的整数子集的每个成员,因此is_exact对于所有整数类型都是正确的。对于浮点类型,基础数学类型是实数的一些有限范围子集。 (有限范围子集的一个例子是“0和1之间的所有实数”。)没有办法准确表示实数的有限范围子集;几乎所有都是不可计算的。 IEC / IEEE格式使事情变得更糟。使用这种格式,计算机甚至不能准确地表示有理数的有限范围子集(更不用说可计算数字的有限范围子集)。

我怀疑术语is_exact的起源是各种浮点表示模型中“不精确”数字的长期概念。或许更好的名字可能是is_complete

<强>附录
由语言定义的数字类型不是“数字”的全部和最终表示。固定点表示本质上是整数,因此它们也是精确的(表示中没有孔)。将有理数表示为一对标准整数类型(例如,int/int)并不准确,但是将理性表示为Bignum对的类至少在理论上是“精确的”。

实际情况怎么样?没有办法完全代表实数,因为几乎所有的实数都是不可计算的。我们可以用计算机做的最好的是可计算的数字。这需要将数字表示为某种算法。虽然从理论上讲这可能是有用的,但从实用的角度来看,它根本没用。

第二个附录
开始的地方是标准。 C ++ 03和C ++ 11都将is_exact定义为

  

如果类型使用精确表示,则为True。

这既模糊又循环。这毫无意义。不完全没有意义的是,整数类型(charshortintlong等)是由法定的“精确”:

  

所有整数类型都是精确的,......

其他算术类型怎么样?首先要注意的是,唯一的其他算法类型是浮点类型floatdoublelong double(3.9.1 / 8):

  

有三种浮点类型:floatdoublelong double。 ...浮点类型的值表示是实现定义的。积分和浮动类型统称为算术类型。

C ++中浮点类型的含义非常模糊。与Fortran比较:

  

真实数据是处理器近似于实数的值。

与ISO / IEC 10967-1,语言无关算术(C ++标准在脚注中引用,但从未作为规范性参考)进行比较:

  

浮点类型 F 应为ℝ的有限子集。

另一方面,对于浮点类型应该表示的内容,C ++没有实际意义。据我所知,实施可以让float成为int的同义词,double成为long的同义词,long double成为同义词为long long

再次出自is_exact的标准:

  

...但并非所有确切类型都是整数。例如,有理和固定指数表示是精确但不是整数。

这显然不适用于用户开发的扩展,原因很简单,不允许用户定义std::whatever<MyType>。这样做,你正在调用未定义的行为。最后一个条款只适用于

的实现
  • 以某种特殊方式定义floatdoublelong double,或
  • 提供一些非标准的理性或定点类型作为算术类型,并决定为这些非标准扩展提供std::numeric_limits<non_standard_type>

答案 1 :(得分:5)

如果该类型的所有文字都具有其确切的值,我建议is_exact为true。因此浮点类型的is_exact为false,因为文字0.1的值不完全是0.1。

根据Christian Rau的评论,当类型的任何两个值之间的四个算术运算的结果超出范围或者可以精确表示时,我们可以将is_exact定义为真,使用该操作的定义type(即截断整数除法,unsigned wraparound)。使用此定义,您可以确定浮点运算已定义以生成最接近的可表示值。不要: - )

答案 2 :(得分:3)

exactnes的问题不仅限于C,所以让我们进一步研究。

Germane关于标准的编辑的讨论,不精确必须适用于需要舍入以表示相同类型的结果的数学运算。例如,Scheme通过精确运算和精确的字面常量对精确性/不精确性进行了这种定义,参见R5RS§6。 http://www.schemers.org/Documents/Standards/R5RS/HTML

的标准程序

对于double x=0.1的情况,我们要么认为0.1是一个定义良好的双重文字,或者如在Scheme中那样,文字是由不精确的编译时操作形成的不精确常量(舍入到最接近的结果的两倍)操作1/10,其在Q)中明确定义。所以我们总是以操作为终结。

让我们专注于+,其他人可以通过+和group属性在数学上定义。

不精确性的可能定义可能是:

If there exists any pair of values (a,b) of a type such that a+b-a-b != 0,
then this type is inexact (in the sense that + operation is inexact).

对于我们所知道的每个浮点表示(nan和inf分离的平凡情况),显然存在这样的对,因此我们可以判断float(操作)是不精确的。

对于定义良好的无符号算术模型,+是精确的。

对于signed int,我们在出现溢出时遇到UB的问题,所以不保证准确性......除非我们改进规则以应对这个破坏的算术模型:

If there exists any pair (a,b) such that (a+b) is well defined
and a+b-a-b != 0,
then the + operation is inexact.

以上定义明确可以帮助我们扩展到其他操作,但这不是必要的 然后我们必须考虑/作为错误多态而不是不精确的情况 (/被定义为Euclidean division for int的商)。

当然,这不是官方规则,这个答案的有效性仅限于理性思考的努力

答案 3 :(得分:2)

C ++标准中给出的定义似乎相当明确:

  

static constexpr bool is_exact;

     

如果类型使用精确表示,则为True。所有整数类型都是精确的,但不是所有的确切类型都是   整数。例如,有理和固定指数表示是精确但不是整数。

     

对所有专业都有意义。

答案 4 :(得分:2)

在C ++中,int类型用于表示数学整数类型(即{...,-1,0,1,...}的集合之一)。由于实现的实际限制,该语言定义了该类型应该保留的minimum range of values,并且必须在所有已知体系结构中表示该范围内的所有有效值。

该标准还定义了用于保存浮点数的类型,每个类型都有自己的有效值范围。您找不到的是有效浮点数列表。同样,由于实际限制,该标准允许这些类型的近似。许多人试图说,只有可以用IEEE浮点标准表示的数字才是这些类型的精确值,但这不是标准的一部分。虽然二进制计算机上的语言实现确实具有表示double和float的标准,但语言中没有任何内容表明它必须在二进制计算机上实现。换句话说,浮点数不是由IEEE标准定义的,IEEE标准只是一个可接受的实现。因此,如果有一个实现可以在定义double和float的值范围内保存任何值而没有舍入规则或估计,则可以说is_exact对于该平台是真的。

严格来说,T不能成为判断类型是否为“is_exact”的唯一参数,但我们可以推断出其他一些参数。因为您可能正在使用具有标准硬件和任何公开可用的C ++编译器的二进制计算机,所以当您为.1(在浮点类型的可接受范围内)分配双倍时,这不是计算机的数字。用于计算该变量。它使用IEEE标准定义的最接近的近似值。当然,如果你将文字与自身进行比较,你的编译器应该返回true,因为IEEE标准非常明确。我们知道计算机没有无限的精度,因此我们期望得到的值为.1的计算不一定会得到与文字值相同的近似表示。输入可怕的epsilon比较。

要实际回答你的问题,我会说,对于任何需要进行epsilon比较以测试近似相等的类型,is_exact应该返回false。如果对该类型进行严格比较,则应返回true。

答案 5 :(得分:2)

std::numeric_limits<T>::is_exact应为false当且仅当T的定义允许值可能不存在时。

C ++认为任何浮点文字都是其类型的有效值。并且允许实现决定哪些值具有精确存储的表示。

因此,对于允许范围内的每个实数(例如2.00.2),C ++ 始终承诺该数字是有效的double从不承诺可以准确存储该值。

这意味着在问题中做出的两个假设 - 对于无处不在的IEEE floating point标准来说是正确的 - 对于C ++定义不正确:

  

我确信我可以准确地将2存储在双精度中。

     

然后我可以将[它]除以10,[双倍]持有   数学结果完全