C++ 当我使用C++;带整数的数学函数?
例如,由于浮点数的精度,下面的代码将给出不理想的结果C++ 当我使用C++;带整数的数学函数?,c++,algorithm,math,floating-point,floating-accuracy,C++,Algorithm,Math,Floating Point,Floating Accuracy,例如,由于浮点数的精度,下面的代码将给出不理想的结果 double a = 1 / 3.0; int b = a * 3; // b will be 0 here 我想知道如果我使用数学函数,是否会出现类似的问题。比如说 int a = sqrt(4); // Do I have guarantee that I will always get 2 here? int b = log2(8); // Do I have guarantee that I wil
double a = 1 / 3.0;
int b = a * 3; // b will be 0 here
我想知道如果我使用数学函数,是否会出现类似的问题。比如说
int a = sqrt(4); // Do I have guarantee that I will always get 2 here?
int b = log2(8); // Do I have guarantee that I will always get 3 here?
如果没有,如何解决这个问题
编辑:
实际上,我在为算法任务编程时遇到了这个问题。我想去那里
最大整数,为2的幂,小于或等于整数N
所以圆函数不能解决我的问题。我知道我可以通过一个循环来解决这个问题,但它似乎不是很优雅
我想知道
int a = pow(2, static_cast<int>(log2(N)));
inta=pow(2,静态_-cast(log2(N));
总是能给出正确的结果。例如,如果N==8,是否有可能log2(N)会给出类似于2.99999999999的结果,最终结果会变成4而不是8?不准确的操作数与不准确的结果
我想知道如果我使用数学函数,是否会出现类似的问题
实际上,对于基本操作(包括*
),不存在可能阻止log2(8)
变为3的问题。但是它存在于log2
函数中
您混淆了两个不同的问题:
double a = 1 / 3.0;
int b = a * 3; // b will be 0 here
在上面的示例中,a
不完全是1/3,因此a*3
可能不会产生1.0
。该产品可能碰巧达到了1.0
,但事实并非如此。然而,如果a
以某种方式正好是1/3,那么a
乘以3的乘积将正好是1.0
,因为这就是IEEE 754浮点运算的工作原理:基本运算的结果是与相同操作数上相同运算的数学结果最接近的可表示值。当精确的结果可以表示为浮点数时,则该表示就是您得到的结果
sqrt和log2的准确性
sqrt
是“基本操作”的一部分,因此sqrt(4)
在IEEE 754系统中始终是2.0
,毫无例外
log2
不是基本操作的一部分。IEEE 754标准不保证该函数的实现结果与数学结果最接近。它可以是更远的另一个可表示的数字。因此,如果没有更多关于您使用的log2
函数的假设,就不可能知道log2(8.0)
可以是什么
然而,对于诸如log2
之类的基本函数,大多数具有合理质量的实现都保证了实现的结果在数学结果的1以内。当数学结果不可表示时,这意味着上面或下面的可表示值(但不一定是两者中最接近的一个)。当数学结果完全可表示时(如3.0
),则此表示仍然是唯一保证返回的表示
因此,关于log2(8)
,答案是“如果您对log2
有一个合理的质量实现,您可以预期结果为3.0`”
不幸的是,并不是每个基本函数的每个实现都是高质量的实现。看到这一点,这是由于广泛使用的pow
实现在计算pow(10.0,2.0)
时不准确超过1 ULP,从而返回99.0
而不是100.0
四舍五入到最接近的整数
接下来,在每种情况下,通过隐式转换将浮点赋值给int
。此转换在C++标准中定义为截断浮点值(即舍入零)。如果希望浮点计算的结果为整数,则可以在赋值之前将浮点值四舍五入到最接近的整数。它将有助于在误差累积值不大于1/2的所有情况下获得所需答案:
int b = std::nearbyint(log2(8.0));
以一个简单明了的标题来结束这个问题:是的,当使用浮点函数来生成整数最终结果时,您应该担心精度。这些函数即使在基本操作的保证下也不会出现。 < P>不幸的是,通过在C++中删除小数部分,从浮点数到整数的默认转换实际上是疯狂的。 这不好有两个原因:
int(x+0.5)
将无法合理工作,因为它会将负数取整
有一个合理的round
函数,但不幸的是返回另一个浮点数,因此需要编写int(round(x))
使用C99或C++11时,可以使用lround(x)
请注意,唯一可以用浮点正确表示的数字是商,其中分母是2的整数幂
例如,1/65536=0.0000152587890625
可以正确表示,但即使仅0.1
也不可能正确表示,因此涉及该数量的任何计算都将是近似值
当然,当使用0.1近似值时,可能会抵消偶尔留下的正确结果,但即使只是将0.1的十倍相加,在使用IE进行计算时也不会得到1.0的结果