パスワードを忘れた? アカウント作成
13936862 journal
日記

quaternionの日記: ループ、再帰、gotoを使わずに1から100までを印字するC++プログラムは書けますか? 29

日記 by quaternion

「ループ、再帰、gotoを使わずに1から100までを印字するC++プログラムは書けますか?」という質問に英語版Quoraで興味深い回答が集まっていたので,一部抜き出して翻訳してみた.

原理的にはループ,再帰を封じられると残るは逐次書いていくしかないのだが,C++のようにイオタ関数を使える言語ならば,表面的にはループを隠せるのでそれを使ってしまうのが手っ取り早い.

回答にはほかに,クラス内の静的メンバをカウンタとして使うテクニックを応用したものも見られた.こちらはインスタンスを配列として定義する必要があるが,配列の各要素の初期化がどのような順序であったとしても,1から100まで順序通り印字される.この方法も表面的にはループを隠せるし,実装によってはループ以外の方法で実行されるかもしれない.

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • C++なら、再帰的テンプレートでコンパイル時に計算したいところだけど、
    再起禁止っていうのがコンパイル時も含むなら除外かなあ。
    ってことで、$title。

  • C言語レベルですが

    #include <iostream>
    #define macro1 std::cout << x++ << std::endl
    #define macro4 macro1; macro1; macro1; macro1
    #define macro20 macro4; macro4; macro4; macro4; macro4
    #define macro100 macro20; macro20; macro20; macro20; macro20
    int main() { int x = 1; macro100; return 0;}

    100=5×5×4って、ことで、3回に分けてloop unroll

    • by Anonymous Coward

      これ、macro1をprintf("%d\n", x++);にすればC言語で行けるのでは

      • C言語でいけますね.
        親コメント
        • 最初C言語で書いてたんですが、書き上げたところで「あっ、C++か」と、申し訳程度にiostreamに変えました。
          元のコードは

          #include <stdio.h>
          #define macro1(x) printf("%d\n", (x))
          #define macro4(x) do { macro1((x)); macro1((x)+1); macro1((x)+2); macro1((x)+3); } while (0)
          #define macro20(x) do { macro4((x)); macro4((x)+4); macro4((x)+8); macro4((x)+12); macro4((x)+16); } while (0)
          #define macro100(x) do { macro20((x)); macro20((x)+20); macro20((x)+40); macro20((x)+60); macro20((x)+80); } while (0)
          int main() { macro100(1); return 0;}

          こんなの。iostreamに変えるついでに、コードを出来るだけ短くしたのが元のコメントです。

          あとは、もうちょっと変態なので

          #include <stdio.h>
           
          #define num1(x) #x "\n"
          #define num2(x, y) num1(x##y)
          #define num3(x, y, z) num2(x, y##z)
           
          #define str_1_9 \
                  num1(1) num1(2) num1(3) num1(4) \
                  num1(5) num1(6) num1(7) num1(8) num1(9)
           
          #define str_x0_x9(x) \
                  num2(x,0) num2(x,1) num2(x,2) num2(x,3) num2(x,4) \
                  num2(x,5) num2(x,6) num2(x,7) num2(x,8) num2(x,9)
           
          #define str_10_99 \
                  str_x0_x9(1) str_x0_x9(2) str_x0_x9(3) str_x0_x9(4) str_x0_x9(5) \
                  str_x0_x9(6) str_x0_x9(7) str_x0_x9(8) str_x0_x9(9)
           
          #define str_100 num3(1,0,0)
           
          #define str_1_100 str_1_9 str_10_99 str_100
           
          int main() {
                  fputs(str_1_100, stdout);
                  return 0;
          }

          なんてのも書いてみたんですが、「1~100って面倒だよなぁ。0~99ならもっと簡単なのに」と思いつつ没ったのでした。

          親コメント
    • by Anonymous Coward

      これは現場で見たら頭抱える/(^o^)\

  • 1から100まで書かれたテキストファイルは事前に準備すること。

  • by Anonymous Coward on 2019年06月18日 13時18分 (#3635528)

    上級がおかしい
    (1-x)^2→(1-x)^-2
    999^-2/1000→1000/999^2
    前者は写し間違いで後者は元が間違ってる。
    ちなみに「そうすると…」の段で1000で割ってる。(1/1000)^0=1だからね。

    上級がやっぱり一番エレガントだとは思う
    C#勢としては初級〜中級と中級〜上級が分かり辛いが、まぁだいたいわかるし常識的な発想だな。
    上級も1/81を知ってれば思いつくかもしれんが、少なくとも自分が問われた時には思い浮かばない答えだ。
    決して難しくはないだけに悔しい感はあるな。こういう答えを思いつきたい。

    • by quaternion (18655) on 2019年06月18日 14時28分 (#3635559) 日記
      ありがとうございます.
      親コメント
    • by Anonymous Coward

      追記:
      他にC++でできそうで中級~上級っぽいもの。

      • インラインアセンブラ(普通だけどぱっと見上級感ある)
      • インラインアセンブラだけど半端な場所にジャンプさせて一見全く別のコードに見せかける(難読化ではたまに見るテクニック。逆アセンブルすれば割と簡単?)
      • コンパイル結果を定数で持っておいてジャンプする(できるの?)。
      • zlibかなんかで圧縮する。libpngとか画像圧縮を介するのも面白いかも。
      • telnetとかで拾う。
      • ちょっとしたインタープリターを作る(ループなしでどうやって?)

      ついでにジャンプは明示的に禁止した方が良いと思う。
      std::make_integer_sequence{}
      とかも便利過ぎてちょっとな。Enumerable.Range()使うようなもんでしょ。
      できて当然。

      • by Anonymous Coward

        追記:もしかして関数ポインタへの加算とか使えばアセンブラなしでループやジャンプを隠蔽できる?と思ったけど関数ポインタへの算術演算は流石に禁止されてた。
        コンパイラによってはオプションで可能らしい。
        エレガントにやれば超上級だと思うな。

    • by Anonymous Coward

      初級がおかしい。

      cout << "1\n"
              "2\n"
              ...
              "100" << endl;

      こうしない理由がないだろ。

    • by Anonymous Coward

      (初級を除けば)上級以外は、結局のところ表現が違うだけで本質的にはループや再起、ジャンプを使用している。
      そういう意味でも上級はポイントが高いと思う。
      大学の教養レベルの数学知識で解けるのもいい。

  • by Anonymous Coward on 2019年06月18日 13時23分 (#3635529)

    タイトルのみ

  • by Anonymous Coward on 2019年06月18日 23時31分 (#3635987)

    お前教員なんだろ
    こんなカスみたいなパズルはやるなよ

  • by Anonymous Coward on 2019年06月19日 3時27分 (#3636057)

    べたに書いてもいいんじゃね?

    • by Anonymous Coward

      ベタに書くのはめんどくさいからベタのコードを吐くコードをまず書こう

  • by Anonymous Coward on 2019年06月22日 12時54分 (#3638373)

    C++でループ、再帰、gotoを使わず任意精度演算するというのは単に1から100まで表示するよりはるかに難しそうでたしかに上級にふさわしいな。それとも処理系の指定はされていないから、単にfloat型に300桁以上の精度があればいいのかな。systemでseqコマンドを使うのもありだから適当にライブラリ使えばいいのかな。

typodupeerror

開いた括弧は必ず閉じる -- あるプログラマー

読み込み中...