
quaternionの日記: ループ、再帰、gotoを使わずに1から100までを印字するC++プログラムは書けますか? 29
日記 by
quaternion
「ループ、再帰、gotoを使わずに1から100までを印字するC++プログラムは書けますか?」という質問に英語版Quoraで興味深い回答が集まっていたので,一部抜き出して翻訳してみた.
原理的にはループ,再帰を封じられると残るは逐次書いていくしかないのだが,C++のようにイオタ関数を使える言語ならば,表面的にはループを隠せるのでそれを使ってしまうのが手っ取り早い.
回答にはほかに,クラス内の静的メンバをカウンタとして使うテクニックを応用したものも見られた.こちらはインスタンスを配列として定義する必要があるが,配列の各要素の初期化がどのような順序であったとしても,1から100まで順序通り印字される.この方法も表面的にはループを隠せるし,実装によってはループ以外の方法で実行されるかもしれない.
gotoがだめならsetjmp()、longjmp()すれば良いじゃない (スコア:1)
C++なら、再帰的テンプレートでコンパイル時に計算したいところだけど、
再起禁止っていうのがコンパイル時も含むなら除外かなあ。
ってことで、$title。
Re:gotoがだめならsetjmp()、longjmp()すれば良いじゃない (スコア:2)
Re:gotoがだめならsetjmp()、longjmp()すれば良いじゃない (スコア:1)
ああ、とても行儀の良いコードですね。
特に、数値の出力がきちんと print_n に関数化されていて、longjmp がただのgoto代替品じゃなく、ロングジャンプらしい威力を発揮してるあたりが。
私が思い付いたのはせいぜいこんなのです。
#include <iostream>
#include <csetjmp>
std::jmp_buf jump_buffer;
int main(void) {
int count = 1 + setjmp(jump_buffer);
if (count <= 100) {
std::cout << count << std::endl;
std::longjmp(jump_buffer, count);
}
return 0;
}
あとは、凄く行儀悪いですがこんなのも行けそうな(やめとけ)
#include <iostream>
#include <csetjmp>
std::jmp_buf jump_buffer;
int main(void) {
volatile int count = 1;
std::cout << (count += setjmp(jump_buffer)) << std::endl;
if (count < 100) {
std::longjmp(jump_buffer, 1);
}
return 0;
}
Re:gotoがだめならsetjmp()、longjmp()すれば良いじゃない (スコア:2)
Re: (スコア:0)
そもそも「ループ、再帰、gotoを使わずに」という条件の定義が曖昧だなぁと思いました
例えばシグナルハンドラを使う方法はOKですか?
try catch は?
スレッドは?コルーチンは?(TCPの受信処理をコルーチンとかスレッドで起動,echoサーバにパケットを投げる,コルーチンで受信,受信したら次のコルーチンを起動,で100まで数える)
条件はもう少し具体的に,
プログラムの実行コンテキスト内でスタックやループ変数などの状態を保持せずに,以下略
ぐらい定義して欲しいなぁと思います
Re:gotoがだめならsetjmp()、longjmp()すれば良いじゃない (スコア:2)
たぶん初級レベル (スコア:1)
C言語レベルですが
100=5×5×4って、ことで、3回に分けてloop unroll
Re: (スコア:0)
これ、macro1をprintf("%d\n", x++);にすればC言語で行けるのでは
Re:たぶん初級レベル (スコア:2)
Re:たぶん初級レベル (スコア:1)
最初C言語で書いてたんですが、書き上げたところで「あっ、C++か」と、申し訳程度にiostreamに変えました。
元のコードは
こんなの。iostreamに変えるついでに、コードを出来るだけ短くしたのが元のコメントです。
あとは、もうちょっと変態なので
なんてのも書いてみたんですが、「1~100って面倒だよなぁ。0~99ならもっと簡単なのに」と思いつつ没ったのでした。
Re: (スコア:0)
これは現場で見たら頭抱える/(^o^)\
ファイル一括読み込み、コンソール出力 (スコア:1)
1から100まで書かれたテキストファイルは事前に準備すること。
Re:ファイル一括読み込み、コンソール出力 (スコア:2)
上級がおかしい (スコア:0)
上級がおかしい
(1-x)^2→(1-x)^-2
999^-2/1000→1000/999^2
前者は写し間違いで後者は元が間違ってる。
ちなみに「そうすると…」の段で1000で割ってる。(1/1000)^0=1だからね。
上級がやっぱり一番エレガントだとは思う
C#勢としては初級〜中級と中級〜上級が分かり辛いが、まぁだいたいわかるし常識的な発想だな。
上級も1/81を知ってれば思いつくかもしれんが、少なくとも自分が問われた時には思い浮かばない答えだ。
決して難しくはないだけに悔しい感はあるな。こういう答えを思いつきたい。
Re:上級がおかしい (スコア:2)
Re: (スコア:0)
追記:
他にC++でできそうで中級~上級っぽいもの。
ついでにジャンプは明示的に禁止した方が良いと思う。
std::make_integer_sequence{}
とかも便利過ぎてちょっとな。Enumerable.Range()使うようなもんでしょ。
できて当然。
Re: (スコア:0)
追記:もしかして関数ポインタへの加算とか使えばアセンブラなしでループやジャンプを隠蔽できる?と思ったけど関数ポインタへの算術演算は流石に禁止されてた。
コンパイラによってはオプションで可能らしい。
エレガントにやれば超上級だと思うな。
Re:上級がおかしい (スコア:2)
Re: (スコア:0)
初級がおかしい。
cout << "1\n"
"2\n"
...
"100" << endl;
こうしない理由がないだろ。
Re:上級がおかしい (スコア:2)
Re: (スコア:0)
(初級を除けば)上級以外は、結局のところ表現が違うだけで本質的にはループや再起、ジャンプを使用している。
そういう意味でも上級はポイントが高いと思う。
大学の教養レベルの数学知識で解けるのもいい。
exec系とかどうでしょ (スコア:0)
タイトルのみ
Re:exec系とかどうでしょ (スコア:2)
くだらないことはやるな (スコア:0)
お前教員なんだろ
こんなカスみたいなパズルはやるなよ
Re:くだらないことはやるな (スコア:2)
この条件なら (スコア:0)
べたに書いてもいいんじゃね?
Re: (スコア:0)
ベタに書くのはめんどくさいからベタのコードを吐くコードをまず書こう
任意精度演算が組み込みの言語ならともかく (スコア:0)
C++でループ、再帰、gotoを使わず任意精度演算するというのは単に1から100まで表示するよりはるかに難しそうでたしかに上級にふさわしいな。それとも処理系の指定はされていないから、単にfloat型に300桁以上の精度があればいいのかな。systemでseqコマンドを使うのもありだから適当にライブラリ使えばいいのかな。
Re:任意精度演算が組み込みの言語ならともかく (スコア:2)