パスワードを忘れた? アカウント作成
この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。

美しくなくても十分に機能するコードで良い?」記事へのコメント

  • パフォーマンスを重視すると、
    ある程度汚く読みにくくなるのは、
    仕方がないと思われますが。

    うちの仕事ものんびりした仕事は少ないので、
    とりあえず動くものということだと、
    金余分に貰ってそれをOSとDBにつぎ込んで
    VBできる人を集めて、ASPで作っちゃいます。

    Javaの「使える」エンジニアは常に不足気味ですから、
    なかなか現場の要求に迅
    • > パフォーマンスを重視すると、
      > ある程度汚く読みにくくなるのは、
      > 仕方がないと思われますが。

      これって昔から言われることですが, 本当にこれが当てはまるケースって今ではごく稀になっているのではないかと. おそらくは

      • 直接アセンブラを使ってディレイスロット等を入れる場合
      • パイプラインの長さを生かすためにループアンローリング等の技法を使う場合

      程度か, その類似の場合だけで, 多くの場合はむしろコンパイラが最適化しやすいように明瞭なプログラムの流れにした方が良いでしょう. それに手による最適化が必要な局面っ

      • 主旨には賛成ですが、いちおう突っこんでおきます。

        > 直接アセンブラを使ってディレイスロット等を入れる場合

        delay slot を手で埋めて最適化というのは、ちょっと古い気がします。
        命令スケジューラを完備した最適化コンパイラの場合、コンパイラに埋めさせた方が高速だと思います。

        p.s.

        delay slot に似たような話だと、プレディケイト命令があります。
        プレディケイト命令は使い所が難しくて静的なコンパイラだけでは痛し痒しなコードを出力しますが、
        (C言語の)処理系によっては、条件分岐を 3項演算子で書くと積極的にプレディケイト命令を使ってくれてハッピーな場合があります。

        特に EPIC の Itanium になると同時実行される命令スロットを埋めるために、
        プレディケイト命令を積極的に使う必要がありますから、高速化のために
        コーディングスタイルの変更を求められるかもしれません。

        p.p.s.

        コンパイラが最適化しやすいコードって、プログラマにとって明瞭な流れになるかなぁ?
        例えば「A と B の 2 つの処理を定数回繰り返す返すループ。ただし、cond1 が成立する場合には初回の A 処理を省略する」というルーチンの場合、どれが読みやすいですか?
        # コンパイラが最適化しやすいのは例 3。

        ● 例1
        if( cond1 )
            goto label;

        for( i=0 ; i<N ; i++ ){
            // A
        lable:
            // B
        }

        ● 例2
        if( !cond1 ){
            // A
        }
        // B
        for( i=1 ; i<N ; i++){
            // A -> B
        }

        ● 例3
        if( cond1 ){
            // B
            for( i=1 ; i<N ; i++){
                // A -> B
            }
        } else {
            for( i=0 ; i<N ; i++ ){
                // A → B
            }
        }

        ● 例4
        tmp = cond1;
        for( i=0 ; i<N ; i++ ){
            if( tmp )
                tmp = 0;
            else{
                // A
            }
            // B
        }
        --
        コンタミは発見の母
        親コメント
        • すいません。訂正させてください。

          ● 例1
          i=0;
          if( cond1 )
              goto label;

          for( ; i<N ; i++ ){
              // A
          lable:
              // B
          }
          --
          コンタミは発見の母
          親コメント
        • by albireo (7374) on 2002年09月19日 6時35分 (#168500) 日記
          ● 例5
          i=0;
          if( cond1 ){
              // B
              i++;
          }
          for( ; i<N ; i++ ){
              // A -> B
          }

          はどうでしょう?例2よりはちょっぴりましになるかも。

          保守性を考えると例1が好きですね。
          同じ処理を複数箇所に書くと、片方だけ修正して気づかないことがよくあるので。
          --
          うじゃうじゃ
          親コメント
          • > 保守性を考えると例1が好きですね。
            > 同じ処理を複数箇所に書くと、片方だけ修正して気づかないことがよくあるので。

            ですね。私も普通に書くときは例1のように書くと思います。
            goto はスパゲッティーコードの素と言われますが、使い方によってはプログラムを読みやすくしてくれます。

            p.s.
            例1は goto の代わりに switch を使うこともできます。
            --
            コンタミは発見の母
            親コメント
            • by boo (899) on 2002年09月19日 20時24分 (#168791) 日記
              > 例1は goto の代わりに switch を使うこともできます。

              switch (!cond) {
                  case 0: for (i=0; i<N; i++) {
                      // A
                  default:
                      // B
                  }
              }

              # 先生! 合ってますか?
              --
              あぁ、「ン」が消えてるんですよ。「ビーフン・カレー」ね。
              親コメント
              • by boo (899) on 2002年09月19日 20時37分 (#168797) 日記
                自己採点したら間違ってた (^^;

                i=0;
                switch (cond) {
                    case 0: for (; i<N; i++) {
                        // A
                    default:
                        // B
                    }
                }
                ですね。

                # 薀蓄をたれると Duff's device といいます。
                --
                あぁ、「ン」が消えてるんですよ。「ビーフン・カレー」ね。
                親コメント
              • ですね。

                でも、この手の怪しい記述のコードは薀蓄を語る時か、コンパイラ
                のデバッグをするときにしか使いませんよね。

                実際のプログラムでこういうコーディングをする人がいて、
                その人の書いたコードをデバッグすることになったら嫌だろうなぁ。
                --
                コンタミは発見の母
                親コメント
        • by boo (899) on 2002年09月19日 9時18分 (#168526) 日記
          例1と例4が最適化しにくいのは分かります。(1はループが強連結じゃない。4はループ内に分岐がある。)
          例3が例2より最適化しやすい理由がわかりません。よろしかったら教えてください。

          # 個人的には私なら2を選ぶだろうなと思います。
          --
          あぁ、「ン」が消えてるんですよ。「ビーフン・カレー」ね。
          親コメント
          • 例1のループはコンパイラの世界では簡略化不能なループ(irreducible loop)とか不自然なループ(unnatural loop)とか呼びます。ループ本体への入口が複数あるループですね。
            このままではほとんどの最適化手法が使えないので、最適化コンパイラはコードを複製して例3 に近い形に変形します。
            # irreducible loop が多段に入ると、びっくりするほど大きなオブジェクトコードが生成される
            # ことがあります。

            例3 はループ本体をコピーしているため、例2 よりループを周る回数を判断しやすいです。ループ系の最適化が効き易くなります。
            --
            コンタミは発見の母
            親コメント
            • > 例3 はループ本体をコピーしているため、例2 よりループを周る回数を判断しやすいです。
              この説明は嘘ですね。例2、3ともループの回数を判断できますから。
              ただ、ループに入る前の変数の状態の曖昧さ 例3 の方が少ないので、最適化は効き易いです。
              A が S++、B が空だとすると、以下のように最適化される可能性があります。

              ● 例2
              if(!cond1){
                  S++;
              }
              S += N-1;

              ● 例3
              if(cond1){
                  S += N-1;
              } else {
                  S += N;
              }

              # 例のコードの外側にさらにループがある場合には、例2 の方が有利かもしれません。
              --
              コンタミは発見の母
              親コメント
              • by boo (899) on 2002年09月19日 14時45分 (#168655) 日記
                > > 例3 はループ本体をコピーしているため、例2 よりループを周る回数を判断しやすいです。
                > この説明は嘘ですね。例2、3ともループの回数を判断できますから。

                ああ、そうでしたか。Nがcondに依存する変数のつもりで書かれたのかと思いました。

                > ただ、ループに入る前の変数の状態の曖昧さ 例3 の方が少ないので、最適化は効き易いです。

                なるほど、そのとおりですね。ご説明ありがとうございました。
                --
                あぁ、「ン」が消えてるんですよ。「ビーフン・カレー」ね。
                親コメント

Stableって古いって意味だっけ? -- Debian初級

処理中...