[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bep] 割り算の答えを小数で出すには? <Re: learning lisp: while



 r高橋@まだまだよしまです。

Reply TAKAHASHI Naoto <ntakahas@...>'s message:

} > ちゃんと覚えてはいないのですが、最初、ここを
} > (and (> x 3) (/= (% x 2) 0))
} > にしたらおかしなことになって、もう時間もないのでどさくさで(or)にしたら一
} > 応それらしい答えを表示してくれたので、「えい、これでいいや!」とポストし
} > てしまいました。
} > でも、どうして(and)だとだめだったんでしょう……? 今ゆっくり見てもわかり
} > ません。
} 
} while は、条件が成立し続ける間だけループを繰り返すからです。つまり、一
} 度条件が成立しなくなると、その時点でループは終了します。たとえ後もう一
} 回まわればまた成立するような場合でも同じです。確認のため、r高橋版プロ
} グラムの or を and に変えたものを下に示します。

 あちゃあ!! そうでした! (while)がそういうものだということを忘れてい
た……というか、忘れてはいなかったと思うのですが、気が回らなかったみたい
です(^^;;;)。丁寧に説明してくださってありがとうございました!

} (let ((x 1000) (y 3))
}   (while 
}       (and (> x 3) (/= (% x 2) 0))
}     (while 
}         (and (<= y (+ (/ x 2) 1))  
}              (/= (% x y) 0))
}       (setq y (+ y 1))
}       (when (= y (+ (/ x 2) 1)) 
}         (insert (format "%s\n" x)))) 
}     (setq x (- x 1))
}     (setq y 3))
}   (insert (format "%s\n" 3))  
}   (insert (format "%s\n" 2)))

} > xは最初1000で、これは (and (> x 3) (/= (% x 2) 0)) を満たします。
} 
} これすら満たしませんね。自分で「xは最初1000で」と書いていながら、初期
} 値は999だと思い込んでいたようです。

 はい、全然満たしていないこと、よくわかりました。どうしてこんなふうに考
えちゃったのか……もう、ほんとうにぼけぼけでした。

} そうです。たとえば12を2個の正の整数の積で表すことを考えてみます。この
} 場合可能な組み合わせは 1*12, 2*6, 3*4, 4*3, 6*2, 12*1 の6通りです。が、
} 掛算は*記号の右と左を入れ替えても答が同じになりますから、実際には*記号
} の左側の数が右側の数より大きくなったら、もうそれ以上調べる必要はありま
} せん。

 これも、すごく納得です。ありがとうございます。

} > でも、平方根って整数ではないですよね。その場合は、切り上げした整数を使え
} > ばいいですか?
} 
} 切り上げまで計算する必要はありません。切り捨てで充分です。今、素数かど
} うか調べたい数がnで、nの平方根の切り上げをi、さらに n/i=x とします。最
} 後の式を変形すると n=x*i ですが、iがnの平方根より大きいのですから、xは
} 当然nの平方根より小さくなります。つまりたとえxが整数であっても、もうす
} でに調べてあることになりますし、xが整数でなかったらそもそも調べる必要
} ありません。
} 
} nが12のときの例で言うと、ルート12は約3.46です。これを切り上げると4にな
} りますが、上で見たように切り捨ての3まで調べれば充分なことがわかります。

 ああ、そうですね! よくわかりました。

} (floor (sqrt x)) ですね。でもわざわざ整数に直す必要はありません。単に
} (sqrt x) と試し割りする整数の大小比較すればいいだけの話です。

 あっ、(floor)ってどこかで見たと思います。割り算の答えをどうするかで調べ
ていたときだったかも。いろいろな関数があるんですね。
でも、ここでわざわざ整数にせずに、ただ大小を比較すればいいんだということ
って、簡単なようで(私だと)なかなか思いつけない気がします。ちょっと見方
を変えてみられるといいみたい……?

} > } ;; n高橋スマートバージョン
} > } ;; 2は特別扱いして、奇数だけ調べる
} > } ;; xが素数かどうかは、(sqrt x) までの奇数で割って調べる
} > } (let ((x 3) y limit)                    ; 3から調べ始める
} > }   (insert "2\n")                        ; ここだけずるをする
} > }   (while (<= x 1000)
} > }     (setq y 3 limit (sqrt x))           ; 試し割りは3からルートxまで
} > }     (while (and (<= y limit) (/= 0 (% x y))) ; limitも試すので<=と等号が必要
} > }       (setq y (+ y 2)))                 ; 試し割りは奇数だけなので+2
} > }     (when (> y limit)                   ; limitで割り切れたときは合成数
} > }       (insert (format "%s\n" x)))       ;   だから>=でなくて>
} > }     (setq x (+ x 2))))                  ; 次の奇数を試す
} 
} >  (when (> y limit)                   ; limitで割り切れたときは合成数
} > というのがわかりません。
} …
} > あっ、もしかして、さっき書いた、平方根が整数だった時とそうじゃなかった時
} > の処理に関係している……?
} 
} そうです。xの平方根が整数になるとき、内側のループは y=limit まで回る可
} 能性があります。たとえばxが25だと、yは5まで大きくなります。ですから素
} 数かどうかのチェックはyがlimitよりも大きいかどうかで判断することになり
} ます。
} 
} と、ここまで書いたところでスマートバージョンの無駄に気付きました。もし
} xの平方根が整数になるならば、xは絶対に素数じゃありませんね。つまり内側
} のループの終了判定は (< y limit) でいいことになります。人生、勉強だ。

 ……ああ、そうですね。
こんなふうにどんどん無駄を落としていくんですね。でも、よーく考えていろい
ろ気がつけないと、おそろしいことになりそう。
 # ものすごく無意味なメールですみません。


**-***-***-***-***-***-***-***-***-***-***-***-**
           Reiko TAKAHASHI  (高橋玲子)
         E-mail:  HFC03614@...
         ICQ UIN: 85924121  (Twinkle)
**-***-***-***-***-***-***-***-***-***-***-***-**