整形运算是c语言基础运算之一,也就是数学中整数可加和数乘概念的编程实现。
在实际使用过程中,c语言编译器的运算模式是以一次计算作为运算的基础单元,每次计算结束后都会取整。由于int 型数据结束本次运算后自动向下取整的特性,常常会导致除数中无法被整除的部分直接丢失,例如计算(7/4)*4,数学运算的结果为7,编程实现的结果为4。
以洛谷P1150为例,来看看重复规律运算中极易被忽略的整形运算类精度丢失问题。
题目:
Peter 有 n 根烟,他每吸完一根烟就把烟蒂保存起来,k(k>1)个烟蒂可以换一个新的烟,那么 Peter 最终能吸到多少根烟呢?
与某些脑筋急转弯不同的是,Peter 并不能从异次元借到烟蒂,抽完后再还回去。
输入格式
每组测试数据一行包括两个整数 n,k(1<n,k≤10^8)
输出格式
对于每组测试数据,输出一行包括一个整数表示最终烟的根数。
看似简单,实则暗藏杀机。
问题一:烟蒂循环换烟,抽完烟留下烟蒂,当烟蒂大于某个数时,又可以换取烟。
问题二:测试用例的数据下很多代码都可以得到正确答案,但是当k取一个稍微大一点的值时,由于整数运算的自动向下取整特性,导致精度丢失。即每一次n/k都会丢失一个>0&&<k的烟蒂值,假设它为d,当总循环次数的d之和大于k时,就会导致反映在答案中的误差。
难点三:把无法被k整除的一部分烟蒂取出放下下一次的烟蒂兑换中,从而弥补丢失的精度。
程序如下:
#include<stdio.h>
int main()
{
int a,b,c=0;
int j=0;
scanf("%d %d",&a,&b);
c+=a;
while(a>=b)
{
j=a%b;//把无法被b整除的部分存入变量
a/=b;
c+=a;
a+=j;//取出无法被b整除的部分,加入到后续烟蒂兑换中
}
printf("%d",c);
return 0;
}