最近のコンパイラの実装を良くわかっていないので素人っぽい質問になりますが、switch-case文の効率ってナイーブな方法よりはましになっているのでしょうか?
ナイーブな実装だと、単純に条件分岐を繰り返すだけですよね。
switch (b) {
case 1:
...
case 2:
...
case 3:
...
}
だと、馬鹿正直に順に書けば、
mov a, b
sui 1
jz case 1の処理
mov a, b
sui 2
jz case 2の処理
...
のような感じでしょうか。どのcaseにヒットするかあまり傾向がないとすると、分岐予測ミスが頻発し予測ミスのフラッシュもしくはパイプラインストールしまくりで恐ろしく効率悪い。
例えば上から順にジャンプベクタを用意して(上記例ではcaseが連番ですが、そうでない場合でも結果的に連番になるようにマッピングする処理を書いておくとして)、bの値によってベクタに書かれたアドレスをメモリからフェッチして即値アドレスジャンプ、なんて実装だったら速いですよね。
bは基底アドレスからのオフセットになるように変換されていて、基底アドレスから順にとび先がメモリに格納されている前提で、
mov a, b
sui case文の最大値
jc defaultの処理←ヒット率低めのはず
movi a, ベクタの基底アドレス
add b
call [a]
な感じの実装だと条件分岐が少なくて嬉しいような気がします。
なんか最近、ソースコードの書きやすさから安易にswitch-case文を書いてしまっているのですが、気にしなくてもいいのか、やはり気にした方がいいのか(最終的に効率よさげなCプログラムは如何様ににでも書き方はあると思います、無駄な配列を用意するとか)どっちなんでしょうか。
A 回答 (5件)
- 最新から表示
- 回答順に表示
No.5
- 回答日時:
> もちろん、傾向がつかめる分岐ならこの限りではないと思いますけど。
GreenHills社のコンパイラは、実際に実行したプロファイラの結果を最適化に戻して、使い方にあった個別の最適化を行うような機能がありますね。
No.4
- 回答日時:
調べてみるとちょっと古い例ですが
http://www.codeproject.com/Articles/100473/Somet …
というのがヒットしました.
もちろん今現在どうなっているかはわかりませんが.
No.3
- 回答日時:
昔はCPUが遅かったので、テーブルを引くようにコンパイルされてたと思いますが(テーブルサイズとのトレードオフは当然あり。
メモリも狭かったので)、今時はCPUが速いので、ifと同じようにコンパイルされるケースが増えてると思いますよ。ありがとうございます。
>今時はCPUが速いので、ifと同じようにコンパイルされるケースが増えてると思いますよ。
へー、それは興味深いですね。今時は半導体のプロセスが微細になりパイプライン段数が深くなっているのと、スーパースケーラでALUをいくつも並べて並列実行が可能なので、できるだけALUをふんだんに使う処理を行うほうが効率よく、唯一のボトルネックである条件分岐によるミスペナルティが増大する傾向にあると思っていました。もちろん、傾向がつかめる分岐ならこの限りではないと思いますけど。
No.2
- 回答日時:
この辺は処理系依存だから「実際にやってみる」しかない.
ただ, テーブル参照なんてのは 20~30年も前から普通に使われているはず. もちろんそれに加えて
・単純な if~else への変換
・バイナリ―サーチ
なども入ってるんじゃないかな (case の値が連続しない場合に「連番になるようにマッピングする」のと「バイナリ―サーチ」のどっちが速いかは知らん).
まあ, 本気で実行速度を考えるなら C で書いたりしないと思う.
ありがとうございます。
単純なif~elseへの変換は、私が例示した書き方ですね。まさに単純なif~elseの変換です。
ところで、バイナリサーチが分岐命令なしに作れるのでしょうか?ちょっと驚きです。もしよろしければどんな処理になるのか教えていただけないでしょうか。
>まあ, 本気で実行速度を考えるなら C で書いたりしないと思う.
それはその通りですね。C言語の教科書では「速い」とか謳っているものもありますが、CPU本来の表現力と比較すればCは表現力が貧弱なので、本気で効率を考えたらCで書くのは間違っていると思います、というかOSも要らない。
No.1
- 回答日時:
組み込みなら気にするかも。
処理時間が伸び縮みするのを嫌ってキャッシュOFFにしたりしてた。
あなたの目の前にある処理性能数百MIPS、主記憶1GB以上の計算機なら書きやすさの方を優先。
ご回答ありがとうございます。
>あなたの目の前にある処理性能数百MIPS、主記憶1GB以上の計算機なら書きやすさの方を優先。
世の中そういう流れなのですね。まあ、数百MIPSのCPUならパイプラインストールもさほど気にするレベルではない世代のものだとは思いますが。
ただ質問の趣旨としては、書きやすいcase-switch文を使ってもそこそこましなコードにコンパイルしてくれるのか否か、という点です。10回や20回同じswitch-case文をループで回すぐらいだったら何の気にもしませんが、数億回とか回す処理だとさすがに多少は気にした方がいいように思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C++のcinの動作 5 2023/02/26 00:13
- C言語・C++・C# C++のcase文の書き方 4 2023/02/24 20:50
- JavaScript jsで、switch文で書かれた分をif文にできませんか。 1 2022/07/28 15:10
- JavaScript switch文のswitch(n)の部分を複数の値にするか、if文に変えてほしいです。 1 2022/07/27 17:18
- Visual Basic(VBA) 先ほど、回答者様によって教えていただいたのですがどうしたらいいか分かりません。 ユーザーフォーム上に 2 2023/02/21 22:25
- 情報処理技術者・Microsoft認定資格 (パイプライン処理)基本情報技術者の演習問題について 1 2023/03/11 17:47
- Visual Basic(VBA) 【Excel VBA】自動メール送信の機能追加 5 2022/09/29 12:53
- Visual Basic(VBA) 【変更】ファイルを閉じてダイアログで保存した時、更新したシートだけの処理の実行をする 5 2022/03/26 18:31
- Excel(エクセル) Excel コンボボックス バックカラー 1 2023/02/18 08:06
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
絶対パスの取得について
-
Excelでのセル内容の高速消去方法
-
小数点を含む数値かどうか判断...
-
Excel VBA での処理時間計測結...
-
再帰処理について
-
WebBrowserの読み込み待ちの処...
-
clispの実行方法
-
DoEvents関数って何?
-
Typescript が必要な理由
-
C言語 時刻差分の算出方法
-
ポインターの横に輪が回ってる。
-
プログラミングの授業でPython...
-
VB 電卓 メモリー機能
-
音程とテンポを独立して変化さ...
-
VBAでリアルタイムで計算結果を...
-
Excel2000 セルに設定された計...
-
WindowsMessage(ウィンドウメッ...
-
Excel(VBA)でSetTimer関数を使...
-
ファミリーベーシックのDATAの...
-
プログラム上のCPU稼働率低減に...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Excelでのセル内容の高速消去方法
-
DoEvents関数って何?
-
win10で、正確な待ち時間の作り方
-
小数点を含む数値かどうか判断...
-
Excel VBAにて、2GB超の点群デ...
-
SQLの速度をあげるには・・・
-
絶対パスの取得について
-
WebBrowserの読み込み待ちの処...
-
プログラム上のCPU稼働率低減に...
-
C言語 再帰処理のメリットとデ...
-
テキストファイルの空行をスキ...
-
実行時のCPU使用率を増やしたい
-
C言語 時刻差分の算出方法
-
Excel VBA データ削除の高速化
-
VBでの簡易電卓の作成(減算方...
-
Excel(VBA)でSetTimer関数を使...
-
プログラミングの授業でPython...
-
If Not c Is Nothing Then ~延...
-
C言語で、文字とか入力されなく...
-
C言語:関数を使うメリットとデ...
おすすめ情報