1060 Are They Equal (25 分)
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×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 N, A and B, where N (<100) is the number of significant digits, and A and B are the two float numbers to be compared. Each float number is non-negative, no greater than 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
/**
本题题意就是: 给出一个精确位(eg:3 就是保留3位小数.) 然后给出两个浮点型数字,
此时需要写出两个浮点型数字经过小数保留后 观察它们的有效位 和科
学计数法的指数位是否相同
本题问题:
条件比较多, 没有考虑完全, 代码冗余
本题思路:
两个浮点型小数用string类型表示,(运用stl中的方法对字符串进行处理)
本题注意点有4个:
1. 对于 0.00 与 0 的情况 应该相等 并且科学计数法的指数为 0
通过记录两个字符串0 和 .的个数, 最终判断 0的长度 与字符串的长度是否相等,如果相同就直接将s1 , s2 置 0
2. 对于 数字可以能存在前导 0 的情况 eg: 005 , 与 00.5 这种情况就该去除前导0
a.当字符串的整形值 < 1时 截取 0.后的字符串(包括0.)
b.当字符串为整形值 >= 1时 截取非0后的字符串
3. 对于 a, b情况要分别处理 a.记录除了0. 以外0的个数就是指数的值
b. 记录小数点前的所有数值个数就是指数的值(记住在保留值时要去除小数点)
4. 当输入浮点类型数字不足保留n位小数时 记得需要添0来补充
判断字符串的长度 与 n的大小, 长度不够 用0来凑。( s += '0';)
**/
未化简代码:
#include<iostream>
using namespace std;
int n;
string a, b;
bool isZero = false;
void change(string &s){
s = s.substr(0, n);
if(s.size() < n + 1){
int length = n - s.size();
while(length--){
s += '0';
}
}
}
int save(string &s){
int cnt = 0;
if(s[0] != '0'){ //string类型 != 整形 是不会报错了
for(int i = 0; i < s.size(); i++){
if(s[i] == '.')
{
s.erase(s.begin() + i); //出错点主要是没有考虑到保留小数时 原小数点需要去掉, 才能继续保留余下位置
return cnt;
}
cnt++;
}
return cnt;
}else{
for(int i = 2; i < s.size(); i++){
if(s[i] != '0'){
s = s.substr(2 + abs(cnt));
return cnt;
}
cnt--;
}
if(s.size() > 1)
s = s.substr(2 + abs(cnt));
return cnt;
}
}
void judgeZero(string &s1, string &s2){ //判断是否为0 (需要优化。)
int length = max(s1.size(), s2.size()), cnt1 = 0, cnt2 = 0;
for(int i = 0; i < length; i++){
if(i < s1.size())
if(s1[i] == '0' || s1[i] == '.')
cnt1++;
if(i < s2.size())
if(s2[i] == '0' || s2[i] == '.')
cnt2++;
}
if(cnt1 == s1.size())
s1 = "0";
if(cnt2 == s2.size())
s2 = "0";
}
void delPreZero(string &s){ //去除前导0
if(s.size() >= 2 && s[0] == '0' && s[1] != '.')
for(int i = 0; i < s.size(); i++){
if(s[i] == '.'){
s = s.substr(i - 1);
break;
}else if(s[i] != '0'){
s = s.substr(i);
break;
}
}
}
int main(){
int g;
int k1 = 0, k2 = 0;
cin >> n >> a >> b;
judgeZero(a, b);
delPreZero(a);
delPreZero(b);
k1 = save(a);
k2 = save(b);
change(a);
change(b);
if(k1 == k2 && a == b)
printf("YES 0.%s*10^%d\n", a.c_str(), k1);
else
printf("NO 0.%s*10^%d 0.%s*10^%d\n", a.c_str(), k1, b.c_str(), k2);
return 0;
}
化简后的代码:
思路:
/**
本题思路
化简了代码 逻辑也更加清晰, 具体的步骤是
1. 先去除前导0,
2. 判断字符串转换为int型数值 是 >= 1 或是 < 1的情形
a.如果 < 1 表示此时 s[0] 为 '.'因为去除了前导0
判断时 需要知道.之后0的数量, 遇到0 就s.erase[0]
(删除0{要注意删除元素时 , 字符串长度也在改变})元素,
e--(指数减1) 当遇到了非0元素就跳出循环
b. 如果 >= 1, 当遇到 '.'时就跳出循环 并删除 '.'(保留小数时,更方便处理小数
后的数字),没遇到'.'时 e++(指数 +1);
3. 此时处理完了字符串 此时的字符串都会是存数字形势:
eg 0.123 会变为 123的形势 , 00123依然是 123, 123也是123的形势
至于需要特殊处理的0元素, 此时在 2步骤 的a条件下已经将0 删除完毕,
当s.size() = 0时 就是0元素, 此时将 指数 赋值 为 0
4.最后保留小数, 先截取字符串 s.substr(0,n), 当s的长度小于 < n时
就在字符串后添加0. eg: s += '0';
**/
#include<iostream>
using namespace std;
int n;
void del(string &s, int &e){
while(s.size() > 0 && s[0] == '0')
s.erase(s.begin());
if(s[0] == '.'){ //数值 > 0 时
s.erase(s.begin());
for(int i = 0; i < s.size(); ){ //s.size()也在变化 ,因此此处不能 i++ (一定要注意) 最好还是用while(s.size > 0)
if(s[0] != '0'){
break;
}
s.erase(s.begin());
e--;
}
}else{ //数值 > 1时
for(int i = 0; i < s.size(); i++){
if(s[i] == '.'){
s.erase(s.begin() + i);
break;
}
e++;
}
}
if(s.size() == 0)
e = 0;
s = s.substr(0, n);
while(s.length() < n){
s += '0';
}
}
int main(){
string a, b;
int e1 = 0, e2 = 0;
cin >> n >> a >> b;
del(a, e1);
del(b, e2);
if(a == b && e1 == e2)
printf("YES 0.%s*10^%d\n", a.c_str(), e1);
else
printf("NO 0.%s*10^%d 0.%s*10^%d\n", a.c_str(), e1, b.c_str(), e2);
return 0;
}
参考柳神代码思路: 通过char类型数组实现小数保留:
https://blog.csdn.net/liuchuo/article/details/52262703
思路:
/**
细心最后输出时 输出的是A数组
思路:
主要是设置 为 a,b字符串分别设置4个游标(可以假设为指针)
主要是定义 p, q, cnta, cntb (p, cnta是一组, q, cntb 是一组)
q指向 a字符串中第一个非0 非 .的数字
cnta 默认长度为 strlen(a)
1. 当cnta > p时 这时 就可以得出 指数a为 cnta - p;
2. 当cnta < p时 这时 就可以得出 指数a为 cntb - p + 1;
3. 当cnta == p时 这时就是特殊情况0的时候, 指数a为0
最终保留小数时, 以p为下标遍历a数组(此步就去除了前导0), 将a数组中的值赋值给A数组, 如果 A数组中的长度不满足 n位
就在A数组后补0;
**/
具体代码实现:
#include<iostream>
#include<cstring>
using namespace std;
const int maxsize = 1e4 + 5;
int main(){
char a[maxsize], b[maxsize], A[maxsize], B[maxsize];
int n,cnta, cntb, eA, eB, p = 0, q = 0;
scanf("%d%s%s", &n, a, b);
// cin >> n >> a >> b;
int lengA = strlen(a);
int lengB = strlen(b);
cnta = lengA;
cntb = lengB;
for(int i = 0; i < lengA; i++){
if(a[i] == '.'){
cnta = i;
break;
}
}
for(int i = 0; i < lengB; i++){
if(b[i] == '.'){
cntb = i;
break;
}
}
while(a[p] == '0' || a[p] == '.') p++;
while(b[q] == '0' || b[q] == '.') q++;
if(cnta >= p)
eA = cnta - p;
else
eA = cnta - p + 1;
if(cntb >= q)
eB = cntb - q;
else
eB = cntb - q + 1;
if(p == lengA)
eA = 0;
if(q == lengB)
eB = 0;
int indexA = 0, indexB = 0;
while(indexA < n){
if(p < lengA && a[p] != '.')
A[indexA++] = a[p];
else if(p >= lengA)
A[indexA++] = '0';
p++;
}
while(indexB < n){
if(q < lengB && b[q] != '.')
B[indexB++] = b[q];
else if(q >= lengB)
B[indexB++] = '0';
q++;
}
if(strcmp(A, B) == 0 && eA == eB)
printf("YES 0.%s*10^%d\n", A, eA);
else
printf("NO 0.%s*10^%d 0.%s*10^%d\n",A, eA, B, eB);
return 0;
}