6.3文字列の一般的な使用法の詳細な説明
質問A:文字列処理(質問バンクの質問が原因の間違った回答)
タイトル説明
2つの文字列を読み取ります。数字に加えて、文字列には「—」、「E」、「e」、および「」が含まれる場合があります。'、加算後の出力結果。浮動小数点型の場合は、指数表記(有効数字10桁まで)で表現する必要があります。
入力
入力には、テストデータの複数のセットが含まれます。
入力の各グループは2行で1行に1つの文字列を占めます。テストデータは、文字列の構成がタイトルの説明に厳密に従っていることを確認します。
出力
出力グループごとに1行ずつ、2つの数値を加算した結果を出力します。
入力例
34.56
2.45e2
出力例
2.7956e2
午後のために書かれた考えですが、何が悪いのか本当にわかりません。ityangerのACコードは確かにACですが、間違いもあります(入力1および1.245e-2の場合、出力は1.1245e0です。)、Codeupのテストポイントがどこにあるのかわかりません。
2020.4.2の夕方に追加:テストバンクを購入しました。元のテストバンクの出力は、0をジャンプする操作です(入力1および1.245e-2、出力1.1245e0)、酔っている... 私のコードの欠点の1つは、大きな整数でも科学表記法が出力されるため、最初のブロックのコンテンツを変更する必要があることです(現在の最初のコンテンツは小数点を多く処理しすぎて自動的に科学を出力します)集計方法の問題)、更新します。
2020.4.2泊の補足:コードが更新され、テストしました。すべてのテストバンクのデータ出力は正しいです(テストバンクのデータに問題がある0をスキップする部分を除く)。 stringstreamとstringstreamの両方に精度の問題があります(小数点以下の桁数が多すぎるという事実によって表されますが、どちらも現時点では精度の問題がありますが、科学表記を使用すると、to_stringには精度の問題があり、stringstreamにはありません)。数値が大きすぎるか小さすぎる場合は、to_stringまたはstringstream変換出力のいずれかに問題があります。
あなたはこのピットの父の質問バンクを見ることができます(左側の回答出力と右側の私の出力):
これらはカーソル出力データに対応する2つの入力です(3行目は私のプログラムの出力です):
私の考えはdoubleタイプを定義することです2つの数値を入力した後、それらの合計を文字列型に変換します(double型は計算用の科学表記法を自動的に認識するため、加算の結果を操作するだけで済みます)。ここには3つのケースがあります:①小数点以下の桁数が多すぎ、doubleタイプは科学表記法を自動的に出力しますが、デフォルトの科学表記法は正の符号と0を使用します(サンプルのデフォルトの表記法出力は2.7956e + 002など)。また、処理する必要があります;②通常の出力小数の場合は、科学表記法を出力するために処理する必要があります;整数は科学表記法では出力されません。
ここでの2番目のケースは、e が10 0の場合に出力eに変更されます(たとえば、入力1および1.245e-2出力1.01245、1.01245e0は出力されませんでした)。補足:上記の質問バンクの出力を読み取った後、e0を出力する必要があります。)
また、C ++ 11のto_string関数を使用する場合、変換精度は6ビットのみです。より高い精度が必要な場合は、stringstreamを使用してdoubleデータを変換する必要があります。
ここではACコードと私のコードの両方を配置しますが、ACコードを注意深く見ていませんでした。詳細なコメントを確認したい場合は、次のブログ投稿を参照してください:
codeup string processing problem A 1983
code
- CodeupACで利用可能なコード
#include<stdio.h>
int main()
{
char str1[50],str2[50];
long long s,s1,s2,ans;
int i,a1,a2,a,b,c,w,flag;
while(scanf("%s %s",str1,str2)!=EOF){
s1=s2=flag=b=c=a1=0;
for(i=0;str1[i];i++){
if(str1[i]=='-')
flag=1;
else if(str1[i]=='.')
c=1;
else if(str1[i]=='e'||str1[i]=='E'){
sscanf(str1+i+1,"%d",&b);
a1+=b;
break;
}
else{
s1=s1*10+str1[i]-'0';
a1-=c;
}
}
if(flag) s1=-s1;
flag=b=c=a2=0;
for(i=0;str2[i];i++){
if(str2[i]=='-')
flag=1;
else if(str2[i]=='.')
c=1;
else if(str2[i]=='e'||str2[i]=='E'){
sscanf(str2+i+1,"%d",&b);
a2+=b;
break;
}
else{
s2=s2*10+str2[i]-'0';
a2-=c;
}
}
if(flag) s2=-s2;
if(a1<a2)
for(;a1<a2;a2--)
s2*=10;
else if(a1>a2)
for(;a1>a2;a1--)
s1*=10;
a=a1;s=s1+s2;
if(!s){
printf("0\n");
continue;
}
while(a<0&&s%10==0){
s/=10;
a++;
}
if(a>=0){
printf("%lld",s);
for(i=0;i<a;i++)
printf("0");
printf("\n");
continue;
}
flag=0;
if(s<0){
s=-s;
flag=1;
}
ans=1;w=0;
while(ans<=s){
ans*=10;
w++;
}
if(ans>1){
ans/=10;
w--;
}
if(flag)
printf("-");
printf("%lld",s/ans);
if(ans>1)
printf(".%lld",s%ans);
printf("e%d\n",a+w);
}
return 0;
}
- 私のコード(変更、スキップ0部分のデータ出力を除いて、他の出力は正しい)
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<string>
#include<iostream>
#include<iomanip>
#include<sstream>
//#include<fstream>
using namespace std;
int main(){
double a, b;
while(cin>>a>>b){
stringstream s;//使用stringstream,控制转换为字符串后的有效数字能达到10位
s<<setprecision(10)<<a+b;
string str = s.str();
//////判断是否是大整数//////
bool integer = false;
//判断是否是整数,因为stringstream会自动科学计数法
//然而to_string虽然能完整保存整数,但是又有精度问题(小数点后一定只有6位,而且小数点位数过多to_string直接是0)
string sss = to_string(a+b);
int PointPosition = sss.find(".");//标记小数点的位置
int cntzero = 0;//数0的个数
for(int i=PointPosition+1;i<sss.length();i++) if(sss[i]=='0') cntzero++;
if(cntzero==sss.length()-1-PointPosition && sss[0]!='0' || str[0]=='0' && str.length()==1){
//保证不是因为精度问题而输出0.000000的情况,但又不能把本来就是0的情况排除
integer = true;//如果小数点之后全是0,就是大整数
sss.erase(PointPosition, sss.length()-PointPosition);//删除小数点和后面的0
}
///////////////////////////
//ofstream ofs;
//ofs.open("C:\\Users\\kykj\\Desktop\\aaaa.txt", ios::out|ios::app);
string temp = "e";//用于处理e及后面的数字
if(str.find("e") != string::npos && integer==false){//如果自动输出了科学计数法,且是小数
int pos = str.find("e");//记录e的位置
int pos2 = 0;//记录e后面第一个非0数的位置
bool flag = false;//记录是否是负号
string tmp;
for(int i=pos+1;i<str.length();i++){
if(str[i]=='-'){
flag = true;
continue;
}
if(str[i]!='0'){
pos2 = i;
break;
}
}
if(flag==true) str.erase(pos+2, pos2-(pos+2));
else str.erase(pos+1,pos2-(pos+1));
//ofs<<str<<endl;
cout<<str<<endl;
}
else if(str.find(".") != string::npos && integer==false){//如果相加之后是浮点型
bool flag = false;//默认不是负数
bool dot = false;
int pos = str.find(".");//记录小数点所在的位置
int ff = 0;//记录第一个非0数字出现的位置
str.erase(str.begin()+pos);//删除小数点
if(str[0]=='-'){
flag = true;//如果true,表明结果是个负数
str.erase(str.begin());//把负号先删了
}
for(int i=0;i<str.length();i++){
if(str[i]!='0'){
ff = i;
str.erase(0, i);//删除前面多余的0
break;
}
}
if(str.length()==1) dot = true;//只有一位有效数字
if(dot==false) str.insert(1, ".");//如果不止一位有效数字,则直接在第一个数后面插入小数点
if(flag==true){
ff = ff+1+1;//如果是负数,ff加上原本删去的负号和小数点
str.insert(0, "-");//放回负号
}
else ff = ff+1;//如果是非负数,则只加上原来的小数点即可
if(pos-ff>=0){
string num = to_string(pos-ff);
temp += num;
str += temp;
}
else{
temp += "-";
string num = to_string(abs(pos-ff));
temp += num;
str += temp;
}
//ofs<<str<<endl;
cout<<str<<endl;
}
else{//如果不是浮点型
//ofs<<sss<<endl;
cout<<sss<<endl;//这里输出to_string后的sss
}
//ofs.close();
}
return 0;
}
まとめ
C ++文字列は非常に使いやすく、特に挿入操作と削除操作(これら2つが最も一般的に使用されていると感じます)はC文字配列よりもはるかに便利です。また、C ++ 11にはto_stringのような関数もあります。数値型を文字列型に直接変換しますが、文字列型から数値型にカプセル化された関数はなく、atoiまたはstringstreamメソッドのみを使用できますか?(おそらく)
詳細な方法は、次のブログ投稿で確認できます:
C ++ string to int