If a machine can save only 3 significant digits, the float numbers 12300 and 12358.9 are considered equal since they are both saved as 0.123×1050.123 imes 10^50.123×105 with simple chopping. Now given the number of significant digits on a machine and two float numbers, you are supposed to tell if they are treated equal in that machine.
Input Specification:
Each input file contains one test case which gives three numbers NNN, AAA and BBB, where NNN (<100<100<100) is the number of significant digits, and AAA and BBB are the two float numbers to be compared. Each float number is non-negative, no greater than 1010010^{100}10100, and that its total digit number is less than 100.
Output Specification:
For each test case, print in a line YES
if the two numbers are treated equal, and then the number in the standard form 0.d[1]...d[N]*10^k
(d[1]
>0 unless the number is 0); or NO
if they are not treated equal, and then the two numbers in their standard form. All the terms must be separated by a space, with no extra space at the end of a line.
Note: Simple chopping is assumed without rounding.
Sample Input 1:
3 12300 12358.9
Sample Output 1:
YES 0.123*10^5
Sample Input 2:
3 120 128
Sample Output 2:
NO 0.120*10^3 0.128*10^3
我的解答:
1 #include<cstdio> 2 #include<cstring> 3 const int maxn=110; 4 int n; 5 6 struct bign{ 7 int d[maxn]; //记录 0.xxxx 记录maxn次就会 8 int len; // 表示幂级次数 9 bign(){ 10 len=0; 11 memset(d,0,sizeof(d)); 12 } 13 }; 14 15 bign change(char str1[]){ 16 bign a; 17 int len1 = strlen(str1); 18 bool flag = false; // 标识是否找到了首位位置 19 int i=0,k=0; // i反馈目前str1的执行位置;最终停在flag==true的时候 20 int dot_p = len1; //记录小数点dot的位置,默认他的值在最后。 21 int first_p = len1; // 默认第一个数值是在最后,也就是此数值为空。这样可以减少逻辑判断 22 while(i < len1){ 23 // 确定小数点位置,只有一个,如果到最后都没有找到,那就默认是在尾部 24 if(str1[i] == '.'){ 25 dot_p = i; 26 } 27 // 确定首个非零非dot位置 28 if(flag==false && str1[i] - '0' >= 1 && str1[i] - '0' <= 9){ 29 flag = true; 30 first_p = i; 31 } 32 // 保存有效数字,尾部不需要处理,默认就是0; 33 if(flag == true && str1[i] != '.'){ 34 a.d[k++] = str1[i] - '0'; 35 } 36 i++; 37 } 38 // 利用小数点和首位有效数字位置,确定a.len的大小;分成三类情况 39 if(first_p == len1) a.len=0; // 用于解决0,0.0这样的特殊情况; 40 else if(dot_p > first_p) a.len = dot_p - first_p; //对应大于1的情况 41 else if(dot_p < first_p) a.len = dot_p - first_p + 1; //对应小于1的情况 42 return a; 43 } 44 45 bool isequal(bign a, bign b){ 46 bool flag = true; 47 if(a.len == b.len){ 48 for(int i=0;i<n;i++){ 49 if(a.d[i] != b.d[i]){ 50 flag = false; 51 break; 52 } 53 } 54 }else{ 55 flag = false; 56 } 57 return flag; 58 } 59 60 61 void print_a(bign a){ 62 printf("0."); 63 for(int i=0;i<n;i++){ 64 printf("%d",a.d[i]); 65 } 66 printf("*10^%d",a.len); 67 } 68 69 int main(){ 70 char str1[maxn],str2[maxn]; 71 scanf("%d%s%s",&n,str1,str2); 72 bign a = change(str1); 73 bign b = change(str2); 74 bool res = isequal(a, b); 75 if(res){ 76 printf("YES "); 77 print_a(a); 78 }else{ 79 printf("NO "); 80 print_a(a); 81 printf(" "); 82 print_a(b); 83 } 84 return 0; 85 }
总结:
1 教材中推荐的方法是使用string,上学的时候我特别喜欢用string。本题刚开始只是想学以致用,希望利用自己构造的结构体解决问题。并且认为自己构造的结构体只需要遍历一次就可以获取到所有计算必要的元素。从而得到结果。
2 从使用的结果可见,在打印结果和比较结果的过程中,比较麻烦。但是基本不需要动脑,按照惯例抒写即可。
3 而课本说的方法,选择逐步完成,第一次遍历需要去除string左边连续是0的部分,直到出现正整数 or dot;(实际上这次遍历复杂度只是1而已)
第二次遍历是直接计算出len,依然需要借助dot的位置,分情况讨论。并且获得无dot的有效数字部分;
第三次遍历是不足右边有效数字部分;同样,对于0,0.0的情况一定要特殊处理。
4 另一方面,应该特别重视s.erase(s.begin());的用法;也是非常理想的容器。经过时间测算,方法一确实要比string快很多。