- ベストアンサー
最大50桁の実数の和・差・積を求めたい
C++で、2つの最大50桁の実数を入力して、その和・差・積を求めるプログラムを作りたいのです。 実数をchar型に入力させて、それを1桁ずつint型に変換したいのですが、どのようにやればよいのでしょうか? また、その際、符号や小数点はどうすればよいのでしょうか? 計算の流れとしては、 ○足し算 小数点を合わせる ⇒下位の桁から1桁ずつ足し算していく ⇒結果が10以上の場合、10を引き、左隣の桁の数字に1を加える ○引き算 小数点を合わせる ⇒下位の桁から1桁ずつ引き算していく ⇒引かれる数字のほうが引く数字より小さい場合、引かれる数字に10を足し、左隣の桁の引かれる数字から1を引く というような感じで考えているのですが、小数点の合わせ方がわかりません。 また、掛け算に関しては、筆算の要領でやろうと思うのですが、どのようにやればよいのでしょうか? 私はC++の勉強歴が短いので、できれば初心者向けのわかりやすい説明でお願いします。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
>小数点の合わせ方がわかりません。 小数点は、別に持っておく方が良いでしょう。もちろん、正負の符号も別に持ちます。 例えば… data1[0]=1 data1[1]=2 data1[2]=3 data1[3]=4 data1[4]=5 data1[5]~data[49]=0 expnum1=5 //小数点の位置 signflag1=0 //0なら正 の時(小数点の位置が5、データが123450~(略)~0の時)には「12345」を意味します。 data1[0]=1 data1[1]=2 data1[2]=3 data1[3]=4 data1[4]=5 data1[5]~data[49]=0 expnum1=3 //小数点の位置 signflag1=0 //0なら正 の時(小数点の位置が5、データが123450~(略)~0の時)には「123.45」を意味します。 data1[0]=1 data1[1]=2 data1[2]=3 data1[3]=4 data1[4]=5 data1[5]~data[49]=0 expnum1=7 //小数点の位置 signflag1=0 //0なら正 の時(小数点の位置が7、データが123450~(略)~0の時)には「1234500」を意味します。 で、小数点を合わせて加減算をする時は、以下のようにします。 1.足される数と足す数、引かれる数と引く数で、小数点の位置が小さい方を「小数点の位置の差」だけ右にズラします。 例:12345+123.45の時 片方は小数点の位置5、もう片方は小数点の位置3だとすると「5-3=2」で、小数点の位置3の方を右に2桁ズラします。 小数点の位置5:12345000000000000000000000000000000000000000000000 + 小数点の位置3:12345000000000000000000000000000000000000000000000 ↓ 小数点の位置5:12345000000000000000000000000000000000000000000000 + 小数点の位置5:00123450000000000000000000000000000000000000000000 右に2桁ズラした方の値の、下位の2桁は、はみ出して消えます。 また、ズラして空いた上位の2桁には0を補います。 2.小数点の位置が揃ったので、両方を加減算します。 小数点の位置5:12345000000000000000000000000000000000000000000000 + 小数点の位置5:00123450000000000000000000000000000000000000000000 || 小数点の位置5:12468450000000000000000000000000000000000000000000 3-A.もし足し算で桁溢れした場合は、結果を右に1桁ズラして、溢れた数を最上位に入れ、小数点の位置も1つ増やします。 例:567.89+987.65 小数点の位置3:56789000000000000000000000000000000000000000000000 + 小数点の位置3:98765000000000000000000000000000000000000000000000 || 小数点の位置3:55554000000000000000000000000000000000000000000000 最上位の「5+9」で「1」が溢れた。 ↓ 小数点の位置4:05555400000000000000000000000000000000000000000000 1桁左にズラして、小数点の位置を1増やす。 ↓ 小数点の位置4:15555400000000000000000000000000000000000000000000 加算時に溢れた「1」を空いた最上位に入れる。 3-B.もし引き算で、最上位が0になった場合、結果を左に1桁ズラして、小数点の位置も1つ減らします。 例:1555.54-567.89 小数点の位置4:15555400000000000000000000000000000000000000000000 | 小数点の位置4:09876500000000000000000000000000000000000000000000 (前述の1の処理で、小数点の位置を合わせ済み) || 小数点の位置4:05678900000000000000000000000000000000000000000000 ↓ 小数点の位置3:56789000000000000000000000000000000000000000000000 左に1桁ズラして、小数点の位置を1つ減らす。 ここまでが「小数点の合わせ方」です。 なお、加減算を行う前に、両方の数の正と負を見ておいて、正負の符号を外して「正の数同士の足し算、引き算」にしましょう。 A(正)+B(正)⇒A(正)+B(正) A(正)+B(負)⇒A(正)-B(正) A(負)+B(正)⇒B(正)-A(正) A(負)+B(負)⇒-(A(正)+B(正)) A(正)-B(正)⇒A(正)-B(正) A(正)-B(負)⇒A(正)+B(正) A(負)-B(正)⇒A(負)+B(負)⇒-(A(正)+B(正)) A(負)-B(負)⇒A(負)+B(正)⇒B(正)-A(正) そして、引き算、足し算を変換して「A(正)-B(正)」や「B(正)-A(正)」になった場合に「小さい数-大きい数」の時は、更に「-(大きい数-小さい数)」に変換します。 例:(-10)-(-4)を計算する 規則 A(負)-B(負)⇒A(負)+B(正)⇒B(正)-A(正) により 4-10 に変換する。 規則 「小さい数-大きい数」の時は、「-(大きい数-小さい数)」に変換 により 10-4 で6を求めてから正負の符号を変え-6にする。 このようにすると「加算と減算は、正の数だけしか扱わない」ので、とても楽になります。引き算も常に「大きい数-小さい数」しか行わないので「上の桁から借りて来る」のも楽になります。
その他の回答 (8)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★アドバイス ・次の2つを参考にどうぞ。 http://homepage2.nifty.com/DSS/PT/HTML/Win/BCDCalc.htm→『BCD演算』 http://www.vector.co.jp/soft/win95/prog/se438696.html→『BCD演算ルーチン』 解説はありませんが直ぐにでも利用できそうです。 時間があったら仕組みをソースから読み取りましょう。
- jacta
- ベストアンサー率26% (845/3158)
> C++をもっと勉強します。 今回の内容は、C++に限らない、プログラミング一般の問題でひっかかっているのですよね。だとすると、C++だけをいくら勉強しても解決にはいたりません。 紙と鉛筆で、どうやれば実現できるかを導けるようになって、はじめてC++固有の勉強が活きてきます。
- jacta
- ベストアンサー率26% (845/3158)
#1です。 > charの配列です。 なるほど。 それであれば、 int toint(char c) { return std::isdigit(static_cast<unsigned char>(c)) ? c - '0' : c; } といった関数を作っておいて、 char s[53]; // ←の配列に入力 int a[50 + 2]; std::size_t n = std::strlen(s); std::transform(s + 0, s + n, a, &toint); とでもしておけばどうでしょう。 > また、その際、符号や小数点はどうすればよいのでしょうか? 決めてください。 上の例ではそのままにしています。 > できれば初心者向けのわかりやすい説明でお願いします。 C++はCと同じで、初心者お断りのプログラム言語です。 C++自体の経験が浅いのは仕方ありませんが、少なくとも初心者を自称しないだけの覚悟が出来てから取り組みましょう。
お礼
回答ありがとうございます。 C++をもっと勉強します。
- zwi
- ベストアンサー率56% (730/1282)
多倍長演算ですね。 下記サイトにソース公開されたライブラリがありますので、そのまま使われるか、勉強用の参考用としてお使いください。 http://www5.airnet.ne.jp/tomy/cpro/csource.htm >できれば初心者向けのわかりやすい説明でお願いします ともかく苦労しないとC++は覚えれませんので、悩みましょう。
お礼
回答ありがとうございます。 紹介していただいたホームページ参考にしてみます。
- yama5140
- ベストアンサー率54% (136/250)
>C++で、2つの最大50桁の実数を入力して、・・・ 「丸投げ」?。 ひと月勉強して、それでも判らない場合、再度「丸投げ」したら如何でしょう。 http://service.okwave.jp/okwave/info/okwave/index.html#info_0216 ↑ここに、 >なお、「丸投げ・依頼」の改定につきましては、3月16日(月)12:00以降に・・ 「丸投げ・依頼」が解禁されるようです。 -------------------------------------------------- 「削除」されてしまうので、聞いても無駄かもしれませんが・・2点。 >私はC++の勉強歴が短いので、できれば初心者向けのわかりやすい説明でお願いします。 ・「勉強歴が短い」のに、なぜこの「プログラムを作りたい」と思ったのですか?。 ・「わかりやすい」とは、質問者様の判断ですよね、それを回答する側が想像して答えろ・・ですか?。 「超初心者対象の」ホームページを紹介します。「ひと月」頑張ってみてください。 http://www.kumei.ne.jp/c_lang/
補足
申し訳ありません。 確かに「丸投げ」のようなかたちになってしまいました。 紹介していただいたホームページを参考にしてみます。
- Situgyosya
- ベストアンサー率41% (21/51)
50桁だと、C/C++の標準型では処理できません。 つまり、整数(int long longlong __int64)等を 対象数値(50桁)の直接の演算には使用できません。 BCD演算ライブラリを使用するか、自分で BCDクラスを作って処理しましょう。 ちなみにBCDとは1Byteで0~9を表現して演算する方法です。 少数表現にはいろいろな方法が考えられますが、 1数値に対して多くて1つしか発生しませんので 1.少数点を意味する数値(0xF等)を入れる。 2.少数桁数を数値で付加しておく 等の方法などはどうでしょうか。 いずれにしても、初心者がいきなり挑戦すべき 課題ではありませんので、operatorのオーバーライドが できる程度になってから改めて挑戦しましょう。
補足
実数をchar配列に入れて、それを1桁ずつint型に変換するというのはできないということでしょうか? BCDについて勉強してみます。
- titokani
- ベストアンサー率19% (341/1726)
小数点以上を50桁、小数点以下も50桁とした固定小数点で扱う方法はどうでしょうか?
お礼
なるほど。参考にします。 ありがとうございました。
- jacta
- ベストアンサー率26% (845/3158)
> 実数をchar型に入力させて、それを1桁ずつint型に変換したいのですが、どのようにやればよいのでしょうか? char型が8ビットだとすると、10進法で2桁しか格納できないと思います。 charの配列ではないのですか? その場合、なぜstd::stringではいけないのですか?
補足
> charの配列ではないのですか? すいません。そのとおりです。 charの配列です。
お礼
とても丁寧な回答ありがとうございます。 例もつけていただいて、とても分かりやすかったです。 ありがとうございました。