- ベストアンサー
ruby for文
for文を用いる s=1+2+5+10+17...+50 s=0;i=1;j=1 for i in 1..100 s+=1 i+=j if i>50 break end j+=2 end puts s この問題の意味がよくわかりません。。 よかったら説明してくれると助かります。。 j+=2 ここはなんで2なんしょうか? 特にここのところはなんでこうなっているんですか? iとかjとかを使っている意味がわかりません。。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
そもそも、s=...の式とプログラムとが一致してないので、説明もなにもないですが。 実行したら 18 と表示されました。 1=1 2=1+1 5=2+3 10=5+5 17=10+7 26=17+9 ←書いてないけど、それまでのパターンから推測 37=26+11 ←書いてないけど、それまでのパターンから推測 50=37+13 と、奇数分の分増えているように見えます。なので、 i: sに加える値 j: 次のiへの増分(連続した奇数) とすると、 > j+=2 は、「次の奇数」を計算するためのもの という説明は付くと思います。 > s+=1 はループ回数を数えるだけのものになっているので、 s+=i の間違いではないかと予想されます。 そうなってくると > for i in 1..100 が問題です。 rubyのforは、リスト状のものを連続で処理するものです。CやBasicのように、変数の値を計算するものではありません。 例えば、i=2のときj=3になっているはずなので i+=j → i=2+3=5 になります。 次のループになったとき、Cでfor(i=1;i<=100;i++)だったら、 i<=100とi++ はこの i=5 に対して評価、計算します。 しかし、rubyでは、1..100での2の次である3になってしまいます。 for k in 1..100 と、関係無い変数にすれば、一応期待通りの計算にはなりますが、美しくは無いですね。
その他の回答 (2)
- kanemoto_s
- ベストアンサー率45% (112/244)
まず、 s=1+2+5+10+17+... について。そんなことはもう分かっているかも知れませんが、 数列におなじみでなければ、何故このように増えていくのか意味不明の方もいらっしゃると思います。 a(n)=1,2,5,10,17, ... 数列で困ったら各項の差を並べて b(n)=1,3,5,7, ... まあ、奇数が並んでるのが分かる人にはわかりますが、分からなければもう一度各項の差を並べて c(n)=2,2,2, ... となり、規則的に並んでいるのが分かります。 このように各項の差を取ることが、数列を解析するとき最初に確かめることです。 (差をとって駄目なら、商をとります。一般常識問題ならほぼ間違いなくどちらかです。) ご質問の j+ = 2 の2はc(n)の各項の2と言うことになります。 さて、プログラムの方は、#1の方も #2の方も述べられている通り、かなり問題の多いプログラムです。 s+=1 が s+= i なのはまあ、すぐ気付くとして無視します。 プログラムが動いて、結果が正しければいいというのは、非常に危険です。 プログラムは、他人が見て容易に理解可能でなければ社会で通用しません。 もし、あなたがプログラマを目指すのであれば、必ず他人が理解可能なプログラムを書くように心がけてください。 プログラマであれば、他人と共同でプログラムを作りますし、他人が作ったプログラムを修正するのは日常茶飯事です。 ご質問のようなプログラムは、あなたにも理解できなかったように他人に迷惑をかけてしまうことになりかねません。 このプログラムの最大の問題は、 (1) ループ変数をループの中で破壊的に書き換えている (2) ループの正常終了条件がループの中にある という2点により非常に難解になっています。2つとも言語共通のプログラミング作法に反しています。 特に(1)は致命的なバグに繋がっています。何故バグなのかは#1の方の発言に譲ります。 この二つの問題を取り除けば、#2の方の最初のプログラムにたどり着くと思います。 ・ループ条件に使用する変数をループ中に変更したい場合は、for - stepやfor - each形式ではなく、while形式、もしくはdo - while形式を使用する。 プログラムの世界では常識なので覚えておいてください。 #2の方、借用おそれいります。 s=0;i=1;j=1 until i>50 s+=i i+=j j+=2 end puts s until i>50 は、初心者なら while i<=50 のほうがいいかもしれません。(until文は他の言語にほとんどないので) 私はこれが一番シンプルで美しいのではないかと思います。 初心者でも何をやっているか、すぐ分かるのではないかと思います。 最後に、他人の作ったプログラムが何をやっているか分からないとき。 (1) デバッガを使用して、一行ずつ実行して変数を監視する (2) 変数をその都度出力する。 (1)は統合環境を作成(インストール)しないと動かないので、初心者なら(2)ですね。 ご質問のプログラムなら s+=i の後ろに、 print "i=",i.inspect ," j=",j.inspect," s=",s.inspect,"\n" を入れて、forループ毎に変数の出力を行えば、何が起こっているか理解する助けになります。 ( .inspect は数値なら不要ですが、配列など複雑なオブジェクトになると見栄えがよくなってきます) 例えば、最初の書いてあるものでは、 i=1 j=1 s=1 i=2 j=3 s=2 i=3 j=5 s=3 i=4 j=7 s=4 .. i=18 j=35 s=18 となり、 ・i が期待通りに増加していない(正しければ、1,2,5,10,17, ...,50) ・sが期待通りに増加していない(正しければ、1,3,8,35,...) ・j は期待通り増加している ことが理解できますし、プログラムを修正する毎に、経過を確認することができるようになります。
- hitomura
- ベストアンサー率48% (325/664)
まず、 1,2,5,10,17,... と言う数列がどういうものか考えます。すると、 1 +1=2, 2 +3=5, 5 +5=10, 10+7=17,... という風に、一つ前の数に奇数を順に足していって作れることがわかります。 そこで、jで奇数を順に生成し、それをiに足して問題の数列の要素を順に生成していき、その総計をsに……って、"s+=1"の部分は"s+=i"の書き写し間違いですよね? とにかく、それで問題の数列の合計が出ます。 言い換えると、iとjの値は i:1,2,5,10,17,...という数列の各要素 j:上記を生成するための、奇数列の各要素(初期値が1なので、+2し続けると順に奇数が出てくる) を表しています。 ……しかし、ヒドいコードだなぁ。 この仕様ならはっきり言ってforは使わず、 s=0;i=1;j=1 until i>50 s+=i i+=j j+=2 end puts s としたほうがコードが短いし、変数名と行数をケチらず values=[] value=1 odd_number=1 until value>50 values << value value+=odd_number odd_number+=2 end sum=0 values.each do |v| sum +=v end puts sum としたほうが処理の流れが分かりやすくなると思うのですが……。 (もっと簡単になるかもしれないけど)