精度与除法
涉及用除法进行判断时 要想办法转变成乘法 避免精度丢失导致出错
!!!!
做除法的时候 一定要\(double c=(double)a/b\) 或者 \(a*1.0/b\)
!!!
概念
在C++这样的语言里,涉及到浮点数的除法运算常常会遇到精度问题。
这是因为计算机中浮点数的表示是有限的,并且可能无法精确表示一个数。例如,十进制数0.1在二进制表示中是一个无限循环小数,因此不能完全精确地存储在计算机中。
当进行除法运算时,如果结果是无限循环小数,计算机必须对其进行舍入处理,这可能导致精度损失。在一些算法中,特别是当你需要判断一个数是否能被另一个数整除时,这种精度损失可能会导致错误的结果。
转换为乘法可以帮助避免这个问题,原因如下:
- 整数运算(包括乘法)在计算机中通常是精确的,不涉及舍入。
- 通过转换为乘法,可以避免除以一个数,相反只需乘以它的倒数(如果这个倒数是精确的话)。
- 在判断是否整除的情况下,可以通过判断乘积是否等于原来的数来避免除法。这样,如果乘积和原来的数不同,就意味着原来的数不能被另一个数整除。
案例
目前碰到的三种情况:
- 整除判断:如果要判断
a是否能被b整除,可以判断a % b是否为0,而不是判断a / b的结果是否为整数。 凑算式 - 等比判断:比如判断序列是否等比,可以比较
a[i+1] * a[i-1]是否等于a[i] * a[i],而不是比较a[i+1] / a[i]是否等于a[i] / a[i-1]。 最大比例 - 算术/几何运算中:如果需要保持运算中间步骤的精确性,应尽可能使用整数运算。例如,当你需要计算斜率或其他几何属性时,使用整数的乘积和和差,而不是使用浮点数除法。 直线
分析
对于第三题中的斜率问题,用 (y2 - y1) / (x2 - x1) 计算斜率时,即使有精度损失,对于给定的点集,只要精度损失一致,仍然可以判断斜率是否相同。但如果尝试用这个可能已经丢失精度的斜率值去计算截距或做其他数学运算,就可能会因为这个初始的精度损失而得到错误的结果。
对于等比数列,a[i+1] / a[i] 是否等于 a[i] / a[i-1] 的判断本身并没有问题,因为这里的比较是比例关系,只要比例是一致的,即使有舍入误差,比较的结果也是正确的。这和斜率的情况是类似的。然而,如果等比数列中的数字非常大或非常小,那么除法运算可能会因为浮点数表示的限制而引入舍入误差,这些误差可能会累积并在某些情况下影响比较的结果。例如,如果 a[i+1] 和 a[i] 都非常大,直接相除可能会超过浮点数类型的表示范围,从而导致溢出或精度损失。如果想避免这种情况,一种方法是在比较时避免直接使用除法,转而使用乘法来检验比例。比如检查 a[i+1] * a[i-1] 是否等于 a[i] * a[i],这样即使 a[i] 非常大或非常小,只要乘法不溢出,就不会影响结果的正确性。
如何理解
本质就是 在同一个精度之下 做除法并不会影响两个值的判断 因为两个数都丢失了一样的东西(只有极少数可能 让两个不一样的数反而判断成相等) 但是如果要用这个除完后的数去进行新的计算 就会因为之前丢失的精度 而无法进行准确的计算 所以面对涉及除法的判断问题时 都尽可能的转变成乘法
总结
理解计算机中的数值表示
- 整数:计算机用固定数量的比特来精确表示整数,这意味着整数运算(加、减、乘、整除和取模)是精确的,除非有溢出发生。
- 浮点数:浮点数的表示是近似的,特别是对于无限循环小数和非常大或非常小的数。浮点运算(尤其是除法)可能会导致精度损失。
浮点数精度损失的常见原因
- 有限的位数:浮点数在内存中占用固定的空间,因此只能表示一定范围内的数值。
- 舍入误差:当数字不能精确表示时,计算机会舍入到最接近的可表示值。
- 累积误差:多次浮点运算可能导致误差累积,特别是在迭代过程中。
算法竞赛中处理精度问题的策略
- 尽可能使用整数运算:当你可以用整数来表示问题的所有部分时,避免使用浮点数。
- 使用高精度整数类型:当普通的
int或long类型可能导致溢出时,使用long long或其他更大的整数类型。 - 避免不必要的除法:如果可能,将除法运算转换为乘法,比如使用乘以逆元代替除法。
- 保持分数形式:对于需要比较比例的问题,保持分数的分子和分母,只有在最后必须时再进行计算或简化。
- 使用扩展精度浮点数:如果必须使用浮点数,使用
double而不是float提供更高的精度,或者使用long double(如果支持的话)。 - 浮点数比较:不要直接比较浮点数是否相等,而是使用一个小的
epsilon来判断两个数是否“足够接近”。 - 理解和使用数学恒等式和不等式:数学上的恒等式和不等式可以帮助避免不稳定的数学操作,比如先乘后除可能比连续两次除法更稳定。
算法竞赛中常见的数学问题和解法
- 整除判断:使用模运算
%而不是除法。 - 最大公约数和最小公倍数:使用欧几里得算法来避免大数的除法运算。
- 等比数列和等差数列:利用乘法和加法来避免除法造成的精度损失。
- 几何问题中的斜率和截距计算:使用整数或保持分数形式来避免浮点数的不精确。
- 动态规划中的概率和期望值计算:使用分数形式或增加状态来保持精度。
💬 评论