アカウント名:
パスワード:
うしろから羽交い絞めにして、「やめろ、やめるんだ!!」「はなせっ離してくれっっ、ここを最適化しないと…ここを最適化しないとっっ」「ばかっ、そこで苦労してどうする。今じゃもう、gcc とかの最適化がそんな事は全部やってくれるんだっっ」「な…なんだって… じゃぁ、俺の今までの苦労は…」
うん。もう同情に涙が止まりませんよ。gccの最適化の強靭さを見た瞬間の感動を君にも分けてあげたい。
.
ただ、そのためにコードを読みにくくするのは昔のコードであってもお勧めできません。
「アセンブラで組め」「インライン アセンブリコードで組め」
で、コメントにCの読みやすいコードを書くんだ。「いつか、良いコンパイラが出てきたら、このアセンブリコードは破棄するように」というコメントをつけて。
コンパイラは「共通部分式の削除」だといった「小手先の最適化」はできますけど、アルゴリズムレベルでの最適化は無理ですね。計算量のオーダーは変わらない。計算量そのものが変わってくるような、例えば
int sum(int n) { int i, accum = 0; for (i = 1; i <= n; i++) accum += i; return accum;}
を
int sum(int n) { return (n+1)*n/2; }
に書き換えるような最適化はコンパイラには無理で、そういうの手で書くしかないし、それを突き進めていくと、どうしても可読性は悪くなるんですよね。
昔の自分が書いたコードで、
蛇足ですが、上の関数と、下の関数は同じじゃないですよ。だからコンパイラがどんなに賢くなってもその最適化は出来ない。
> (n+1)*n
で、n >= sqrt(2^31) になった場合、オーバーフローが起きて計算結果が負になります。(32bit CPUの場合) ですがfor-loopの場合、accum >= 2^31 になるまでオーバーフローしません。
> オーバーフローが起きて計算結果が負になります。(32bit CPUの場合)いえ、結果は未定義です。ゼロ除算のように、例外が発生してプログラムが強制終了したっていっこうにかまいません。インテルのCPUにもそのための命令(INTO)があるのですが、アライメントチェックと同様まったくと言っていいほど使われていませんね。
さらに言うならmov eax,[n]mov edx,eaxinc eaxmov ecx, 2imul edxidiv ecxみたいなコードを生成するコンパイラがあったってかまわない。そういう環境ではn >= sqrt(2^31)でも(たまたま)「正しい」結果が得られるけど、移植性がない(ほかの環境に持って行くと黙って間違った答えを返すようになったり不正終了したりその他あらゆることが起きうる)プログラムになる。オーバーフローしなかった場合の結果さえ規格通りなら、オーバーフローが起きた場合は文字通りどんな動作をしてもかまわない。C言語っておそろしいね。INTOやBOUNDの1つ実行するコストさえもったいなかった時代には妥当な設計だったんだろうけど、今やセキュリティホールの温床。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
ソースを見ろ -- ある4桁UID
良い言い訳 (スコア:1)
出来る限りの最適化を加えてた結果としてどうしょうもなく読みにくくなって、それを緩和すべくくどい説明を添えることぐらいは許してください。
単純なところでは、
strcpy(dst + a + b + c, src); // 意図はstrcat(dst, src); ここまでの処理でstrlen(dst) == a + b + cなので
みたいな、(この例だと変数名が最悪なのは置いといて)分かってる値を使い回してステップ数を減らすところから、もっと凝りに凝った最適化まで。
ぱっと見て何が書いてあるのか分からない、
Re: (スコア:2, 参考になる)
うしろから羽交い絞めにして、
「やめろ、やめるんだ!!」
「はなせっ離してくれっっ、ここを最適化しないと…ここを最適化しないとっっ」
「ばかっ、そこで苦労してどうする。今じゃもう、gcc とかの最適化がそんな事は全部やってくれるんだっっ」
「な…なんだって… じゃぁ、俺の今までの苦労は…」
うん。もう同情に涙が止まりませんよ。gccの最適化の強靭さを見た瞬間の感動を君にも分けてあげたい。
.
ただ、そのためにコードを読みにくくするのは昔のコードであってもお勧めできません。
「アセンブラで組め」
「インライン アセンブリコードで組め」
で、コメントにCの読みやすいコードを書くんだ。
「いつか、良いコンパイラが出てきたら、このアセンブリコードは破棄するように」
というコメントをつけて。
fjの教祖様
Re: (スコア:1, 興味深い)
コンパイラは「共通部分式の削除」だといった「小手先の最適化」はできますけど、
アルゴリズムレベルでの最適化は無理ですね。計算量のオーダーは変わらない。
計算量そのものが変わってくるような、例えば
を
に書き換えるような最適化はコンパイラには無理で、そういうの手で書くしかないし、それを突き進めていくと、どうしても可読性は悪くなるんですよね。
昔の自分が書いたコードで、
Re: (スコア:1, すばらしい洞察)
蛇足ですが、上の関数と、下の関数は同じじゃないですよ。だからコンパイラ
がどんなに賢くなってもその最適化は出来ない。
> (n+1)*n
で、n >= sqrt(2^31) になった場合、オーバーフローが起きて計算結果が負に
なります。(32bit CPUの場合) ですがfor-loopの場合、accum >= 2^31 になる
までオーバーフローしません。
Re: (スコア:0)
> オーバーフローが起きて計算結果が負になります。(32bit CPUの場合)
いえ、結果は未定義です。ゼロ除算のように、例外が発生してプログラムが強制終了したっていっこうにかまいません。インテルのCPUにもそのための命令(INTO)があるのですが、アライメントチェックと同様まったくと言っていいほど使われていませんね。
Re:良い言い訳 (スコア:0)
さらに言うなら
mov eax,[n]
mov edx,eax
inc eax
mov ecx, 2
imul edx
idiv ecx
みたいなコードを生成するコンパイラがあったってかまわない。そういう環境ではn >= sqrt(2^31)でも(たまたま)「正しい」結果が得られるけど、移植性がない(ほかの環境に持って行くと黙って間違った答えを返すようになったり不正終了したりその他あらゆることが起きうる)プログラムになる。
オーバーフローしなかった場合の結果さえ規格通りなら、オーバーフローが起きた場合は文字通りどんな動作をしてもかまわない。C言語っておそろしいね。INTOやBOUNDの1つ実行するコストさえもったいなかった時代には妥当な設計だったんだろうけど、今やセキュリティホールの温床。