X



C++相談室 part149

レス数が1000を超えています。これ以上書き込みはできません。
0001デフォルトの名無しさん
垢版 |
2020/02/18(火) 06:19:41.54ID:xvjipUWj
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。

前スレ
C++相談室 part148
https://mevius.5ch.net/test/read.cgi/tech/1580471646/
このスレもよろしくね。
【初心者歓迎】C/C++室 Ver.105【環境依存OK】
http://mevius.5ch.net/test/read.cgi/tech/1556142878/

■長いソースを貼るときはここへ。■
 http://codepad.org/
 https://ideone.com/

[C++ FAQ]
https://isocpp.org/wiki/faq/
http://www.bohyoh.com/CandCPP/FAQ/ (日本語)
0902デフォルトの名無しさん
垢版 |
2020/03/21(土) 13:15:18.72ID:dTUZOuSg
>>901 あんたきのうの>881だよね?
たぶん「末尾再帰」の定義が他の人(たとえば Wikipedia の「自身の再帰呼び出しが、
その計算における最後のステップになっているような再帰」)と違いそうだから、まず定義を示してもらいたい。
0904デフォルトの名無しさん
垢版 |
2020/03/21(土) 15:20:30.30ID:dTUZOuSg
違うのか、悪かった。
で、あんたの「末尾再帰」の定義はどうなってんの?
0906デフォルトの名無しさん
垢版 |
2020/03/21(土) 15:52:49.00ID:QlEyGkfm
「自身の再帰呼び出しが、その計算における最後のステップになっているような再帰」
に異論ない。言葉通りだ
ただしそう定義したものは、>>898の性質を持つ
0907デフォルトの名無しさん
垢版 |
2020/03/21(土) 16:17:48.51ID:dTUZOuSg
>>906
そうなると >860 の "return n * factorial(n-1) ;" における「最後のステップ」は
再帰呼び出しではなく乗算なので、その末尾再帰の定義には合致しないのでは?
0909デフォルトの名無しさん
垢版 |
2020/03/21(土) 16:33:45.27ID:dTUZOuSg
>>908 いやサッパリ。
その g やら x やらが >860 の関数とどう関係してるか、示されてないように思うし、
関係が示されたところで "return n * factorial(n-1) ;" の最終ステップが何であるかに
影響するとは思えない。
0910デフォルトの名無しさん
垢版 |
2020/03/21(土) 16:51:25.25ID:QlEyGkfm
こう書いた方がよかったかな
f(n+1)x=f(n)g(n)x
f(n)g(n)=h(n)として
h(n+1)x=h(n)x
具体的には
(n+1)f(n+1)x=nf(n)x
例外は最上位の呼び出し元だけがf(n)xになっていることで、
実質h(n)=n * factorial(n-1)という関数の末尾再帰になっている
0912デフォルトの名無しさん
垢版 |
2020/03/21(土) 17:08:54.11ID:7OpdEFcp
まずfactorialを末尾再帰に書き換えられるって話なら、そんなの当たり前だし誰も否定してない
それに加えてお前の書き換え方はおかしい
二重に話が噛み合ってなくて訳がわからない
宇宙人か?
0915デフォルトの名無しさん
垢版 |
2020/03/21(土) 17:27:27.62ID:QlEyGkfm
おそらくわからないという人は、
末尾再帰⇔ループ
の書き換えがどうなっているのかわかっていない
末尾再帰な関数は、関数の戻り値以外のローカル変数はすべて再利用可能であるのでスタックする必要がない
そしてreturnが返しているのは戻り値である
n*はリターン値に含まれている
よってn * factorial(n-1)は一つの関数単位として扱われ得る
実際にそう扱っているかどうかは実装によるだろうが末尾再帰な関数の定義からは漏れていない
0916デフォルトの名無しさん
垢版 |
2020/03/21(土) 17:44:23.10ID:dTUZOuSg
>>915
仮に「n * factorial(n-1)は一つの関数単位として扱われ得る」を認めたところで
最終ステップはその「関数単位」とやらであって「自身の再帰呼び出し」ではないので、
末尾再帰とは言えないよね。

・・・ >860 を末尾再帰と言えないと死ぬ病気か何かなの?
0917デフォルトの名無しさん
垢版 |
2020/03/21(土) 17:51:24.98ID:QlEyGkfm
>>916
factorialの呼び元は大本の読み出し元以外はすべてnがかかっていること
実際にループに書き換えられること
よって>>860を否定する必要はないというだけのこと
否定する必要があるならそれでもいいが意味はあるか?
0918デフォルトの名無しさん
垢版 |
2020/03/21(土) 17:56:13.76ID:SLPXMQFT
>n*はリターン値に含まれている
>よってn * factorial(n-1)は一つの関数単位として扱われ得る

リターン値に含まれていようが関数の呼び出しに含まれていなんだから「一つの関数単位」にはならんわな。
0919デフォルトの名無しさん
垢版 |
2020/03/21(土) 18:04:37.39ID:lGRjmGfi
そもそもこの人の数学とやらが意味不明

> (n+1)f(n+1)x=nf(n)x

乗算なのか関数の適用なのかどっちだこれ?
左辺の(n+1)はどっからでてきたんだよ
0920デフォルトの名無しさん
垢版 |
2020/03/21(土) 18:17:58.54ID:dTUZOuSg
>>917
ループに書き換えられれば末尾再帰と言えるんならやっぱり Wikipedia の定義と違うんじゃん。

>>860は末尾再帰であると言える」を否定しないと「末尾再帰」の定義(共通認識)が変わってしまうし、
共通認識を壊す行いを認めることになる。それは害悪。やめてほしい。
0921デフォルトの名無しさん
垢版 |
2020/03/21(土) 18:57:31.20ID:vbC+9hSb
末尾再帰とかschemeじゃないと意味無い話
末尾再帰だとループに最適化されることが言語で保証されてるって前提なのだから

そこで言う末尾再帰ではn*f(n-1)みたいなのは違う
だから変形して末尾再帰にしろって話になるのだから
0922デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:00:28.44ID:QlEyGkfm
>>920
それは
return n * factorial(n-1);
と書いてはいけないと強制するということだろうか
だとしたらそれは間違っている
末尾再帰の定義を満たしているにもかかわらず認めないということはそういうことだ
0923デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:03:53.90ID:vbC+9hSb
末尾再帰は関数の最後で自身を呼び出してそれをそのままreturnするものだけ

末尾再帰に変形できる関数は末尾再帰に変形できる関数であって、末尾再帰関数ではない
0924デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:07:05.36ID:lGRjmGfi
>>922
強制とか間違ってるとか認めないとか
お前は誰と戦ってんの?
誰もそんな話してないんだが
読んでで怖いわ
0926◆QZaw55cn4c
垢版 |
2020/03/21(土) 19:07:50.34ID:KIEujNy0
>>915
>n*はリターン値に含まれている
>よってn * factorial(n-1)は一つの関数単位として扱われ得る

return 式
の式に全部書いてしまえるからといっても、その式の中に存在する演算が複数あれば、それぞれの演算に順序があるわけですから
一つに扱うことはできないでしょう、この場合、リターン値を得た後で * n しているのだから、これは一つじゃなく二つ

したがって >>902 の末尾再帰の定義
>「自身の再帰呼び出しが、その計算における最後のステップになっているような再帰」

には合致せず(なぜならば、この場合の最終ステップは * n をすることだから)、>>860 で引用されたプログラムは末尾再帰ではありませんね
0927◆QZaw55cn4c
垢版 |
2020/03/21(土) 19:10:16.03ID:KIEujNy0
>>922
>それは
>return n * factorial(n-1);
>と書いてはいけないと強制するということだろうか

いいえ、単に return * factorial(n-1) と書くのならば、末尾再帰ではなくなるというだけのことです。

>末尾再帰の定義を満たしているにもかかわらず認めないということはそういうことだ

もう一度ききましょう、あなたの「末尾再帰」の定義は何ですか?
0929デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:15:04.74ID:Pnykjrh9
やっぱりこいつ、末尾再帰と末尾呼び出しの区別がついていないとしか思えない
0931デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:18:51.72ID:SLPXMQFT
>わたしはn * factorial(n-1)は関数だと思います

これがfractional自身とは異なる以上、末尾再帰にはならんわけ。
0932デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:23:27.91ID:QlEyGkfm
>>931
では何がわからなくてここまでの長い議論をしていたのですか?
末尾再帰が理解したいというのなら、定義そのままを暗記するだけで済んだはず
一連の私の書き込みは単に理解の方法を提示したに過ぎず、
それを否定するということは定義が理解できていたということでしょう?
0933デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:23:55.22ID:bpzSUpq2
中置で書くから分かりづらくなる
ポーランドか逆ポーランドで書けば自明なのに
0934◆QZaw55cn4c
垢版 |
2020/03/21(土) 19:25:39.78ID:KIEujNy0
>>928
>あなたのいう、「関数」の定義は何ですか
>わたしはn * factorial(n-1)は関数だと思います

仮に関数の定義をあきらかにしたからといっても、それは末尾再帰の定義とは関係ないでしょうね

繰り返しますが、末尾再帰の定義は >>902
>>「自身の再帰呼び出しが、その計算における最後のステップになっているような再帰」
であり、>>860 で引用されたプログラムの「自身の再帰呼び出し」すなわち「return n * factorial(n-1);」
は、計算における最後のステップになっていない(なぜならば、最後のステップはこの場合 n * であるから)ので、
>>860 で引用されたプログラムは末尾再帰ではありませんね
0936デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:28:51.57ID:QlEyGkfm
>>934
それを最初から言っていれば、ここまでの無意味な議論はしなくて済んだでしょうね
よって示された
0938デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:38:43.38ID:g81eKbe5
ID:QlEyGkfmは何でもかんでもここのみんなに教えてもらおうとせず
まず落ち着いて自分のペースでしっかり考えてみたらどうかな
みんな呆れてるよ
0939◆QZaw55cn4c
垢版 |
2020/03/21(土) 19:46:19.04ID:KIEujNy0
>>938
昔私が末尾再帰を間違えていたとき、当時からこのコテで煽り気味にやっていたにもかかわらず、最上級の親切を示して
「末尾再帰はジャンプ最適化だ!」
と教えてくださった方がおられました、当時のその方ほどの忍耐力を今回発揮できず、申し訳ございません…
0940デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:49:38.39ID:QlEyGkfm
皆さんこそ落ち着いてください
nはスタック変数ではなく、ループのインクリメント変数なんですよ
0941デフォルトの名無しさん
垢版 |
2020/03/21(土) 19:59:14.68ID:uResqVEz
「末尾再帰」という情報処理用語を定義しているJIS規格票もしくは
"tail recursion" という情報処理用語を定義しているISO規格票の
条項を出せるやついるの?

これだけ上から目線でマウント取っといて
あげくオレ用語だったら恥ずかしいぞ
0943デフォルトの名無しさん
垢版 |
2020/03/21(土) 20:13:29.14ID:7OpdEFcp
江添が間違えたのが全部悪い
奴が間違えてなければ同じ勘違いをした気違いを呼び寄せることもなかった
0944デフォルトの名無しさん
垢版 |
2020/03/21(土) 20:38:49.06ID:g81eKbe5
江添氏は勘違いと言うより
末尾再帰というもんを単に知らなかったのではと思ってる

末尾再帰の最適化が保証されてる言語使ってる人じゃないだろうから
0945デフォルトの名無しさん
垢版 |
2020/03/21(土) 20:47:14.84ID:vbC+9hSb
消費税の計算を例題にあげたけど、計算方法間違ってたみたいなもの
c++的には関係ない分野の知識
0946デフォルトの名無しさん
垢版 |
2020/03/21(土) 20:58:18.89ID:lGRjmGfi
蒸し返して悪いんだけど
>>898 の数式解読できる人いる?
この人何を勘違いしてんのか興味でてきたんだが
0947デフォルトの名無しさん
垢版 |
2020/03/21(土) 21:07:53.04ID:XPOe/jnY
「添字を持つ添字」みたいなもんを上手に管理する方法ってある?

例えば、
0 <= i < n である全ての i について a[i] を 0 から m の範囲で動かす
みたいなループの構造を想定してる。
当然大きな多重ループになるから小さい n と m についてしか使えないと思うけど、デバッグなどのときにこういうのを簡潔にミスらず書けたらと思っての質問です
0949デフォルトの名無しさん
垢版 |
2020/03/21(土) 21:44:53.81ID:XPOe/jnY
>>948
for(a=0; a<m; a++)
 for(b=0; b<m; b++)
  for(c=0; c<m; c++)
   ...
という形の多重ループのループ変数 a, b, c,... を a[0], a[1], a[2],... にしたいという意味です。
TeX の文法で数式を書けば
\prod_{i=0}^{n} \sum_{a[i]=0}^{m}
という意味です。

・数式との対応が分かりやすい形で書きたい
・簡潔でミスしにくい形で書きたい
といった理由で質問させていただいてます。
0950デフォルトの名無しさん
垢版 |
2020/03/21(土) 21:46:40.54ID:XPOe/jnY
>>948-949
すみません。必ずしも和をとりたいだけではないので、式はあくまで例です。
あとレンジが1つずれてるのもすみません。
0951デフォルトの名無しさん
垢版 |
2020/03/21(土) 22:26:18.85ID:SLPXMQFT
>という形の多重ループのループ変数 a, b, c,... を a[0], a[1], a[2],... にしたいという意味です。

やればいいだけの話じゃなくて?質問は何だろう。
0953デフォルトの名無しさん
垢版 |
2020/03/21(土) 22:39:31.10ID:lGRjmGfi
>>949
ループのネストが可変なんだよね
templateが許されるなら再帰template
ダメならきれいには書けないと思う
0955デフォルトの名無しさん
垢版 |
2020/03/21(土) 22:49:54.75ID:XPOe/jnY
>>953-954
ありがとうございます。
再帰templateで調べてみます。

あと書いてて気付いたのですが、n桁のm進数にループ変数 a[0], a[1],... をエンコードするっていうのも一つの方法かなと思いました。
0956デフォルトの名無しさん
垢版 |
2020/03/21(土) 22:50:20.71ID:lGRjmGfi
確かにtemplateでなくても再帰で可能か
ただlambdaで渡せないからstd::functionで包む必要あるね
0957デフォルトの名無しさん
垢版 |
2020/03/21(土) 22:57:37.57ID:80zI/5JK
>>949
やりたいことは、係数をm^2の2次元配列xとm^3の3次元配列yに入れておいて、2番目のループではx[a][b], 3番目のループではy[a][b][c]を使用するということか?
サイズ可変でも動的に確保すればいいだけ。
0959デフォルトの名無しさん
垢版 |
2020/03/21(土) 23:07:32.20ID:XPOe/jnY
>>957-958
m^n 通りの添字 (a[i] for all i) の組み合わせを列挙し、その中でなんらかの処理をしたいという意味です。
説明の仕方が悪くて失礼しました。
0961デフォルトの名無しさん
垢版 |
2020/03/22(日) 01:21:14.83ID:GKarRavC
std::sortに並列化+ベクトル化指定つけて実行したら、コア数以上に高速化したんだけど、なんで?
0964デフォルトの名無しさん
垢版 |
2020/03/22(日) 02:31:12.30ID:7dJergc9
>>955
こういう解釈でいいのかな
ループがふたつになるかな

a=new int[n];
for(i=0;i<m^n;i++){
 for(j=0;j<n;j++){
  a[j]=i%m;
  i/=m;
 }
 function(a,n);
}
delete[] a;
0967デフォルトの名無しさん
垢版 |
2020/03/22(日) 11:56:28.35ID:GKarRavC
多重継承のときのCRTPについて説明してるサイトないですか
0969デフォルトの名無しさん
垢版 |
2020/03/22(日) 19:39:49.88ID:HvrypJyW
>>949
>TeX の文法で数式を書けば
>\prod_{i=0}^{n} \sum_{a[i]=0}^{m}
>という意味です。
絶対ではないが、標準的な数学の記法だと、その意味では、
\sum_{a[0]=0}^{m}・・・\sum_{a[n]=0}^{m}
と書くのがが普通だと思う。
ところでそれは量子力学の経路積分か何かですか?
経路積分の場合は、本によって上記の部分に割と独特の変な記号を使う場合があって、
あなたの書いたように書いてある本もあるかもしれません。
ただ、普通の数学記法だと余り使いませんよね、その書き方は。
0970デフォルトの名無しさん
垢版 |
2020/03/22(日) 19:46:47.90ID:HvrypJyW
>>969
補足すれば、普通の数学記法だと
\sum_{a[0]=0}^{m}・・・\sum_{a[n]=0}^{m} f(a[0],・・・,a[n])  //(1)
ですね。
\prod_{i=0}^{n} \sum_{a[i]=0}^{m}  //(2)
の記号の場合は、
X= \prod_{i=0}^{n} \sum_{a[i]=0}^{m} g_i(a[i])  //(3)
の場合は、
b[i] = \sum_{a[i]=0}^{m} g_i(a[i])  //(4)
(i=0, ・・・, n)
を先に計算しておいて、
X = \prod_{i=0}^{n} b[i]   //(5)
 = b[0]・・・b[i]   //(6)
の意味に解釈するのが標準的な数学の記号の使い方だと個人的には思います。
(1)と(3)ではかなり意味が違いますが、(2)の記号を、(1)の先頭に使えるかと言えば、
絶対使えないわけでは有りませんが、使う前に何らかの補足説明が必要になりそうです。
0973デフォルトの名無しさん
垢版 |
2020/03/23(月) 12:49:54.29ID:bf1cRh+B
int *pInts = new int[10]();
とした場合の最後の()の意味は何でしょうか?
付けない場合との差を教えてください。
0974はちみつ餃子 ◆8X2XSCHEME
垢版 |
2020/03/23(月) 13:29:11.05ID:FLdc410A
>>973
イニシャライザ。
普通のクラスではそれがないときはデフォルトコンストラクタで初期化される (空の括弧があっても無くても同じ挙動) けど、
int 等では初期化を明示しない限り初期化されない。
逆に言えばこの場合は初期化を明示しているので初期化される。 (0 が入る)
0975デフォルトの名無しさん
垢版 |
2020/03/23(月) 13:37:39.77ID:bf1cRh+B
>>974
有難うございます。では、
int *pInts = new int[3](1,2,3);  //(1)
int *pInts = new int[3]{1,2,3};  //(2)
の違いは何でしょうか?
0979デフォルトの名無しさん
垢版 |
2020/03/23(月) 14:18:32.74ID:bf1cRh+B
>>976
ちょっと待ってください。
>>973 の場合の () は、「集成体初期化」のうちの「中身が全く入ってない括弧」と解釈してよろしいのでしょうか?
0980はちみつ餃子 ◆8X2XSCHEME
垢版 |
2020/03/23(月) 14:39:25.62ID:FLdc410A
>>979
いいえ。

> initializer が空の括弧の場合、それぞれの要素は値初期化されます。

に該当する。
0981デフォルトの名無しさん
垢版 |
2020/03/23(月) 16:20:38.54ID:bf1cRh+B
>>980
最初は集成体初期化を使って、
int *pInts = new int[100](1,2,3);  //(1)
int *pInts = new int[100](1,2);  //(2)
int *pInts = new int[100](1);   //(3)
int *pInts = new int[100]();    //(4)
とどんどん()の中の項目を減らして行き、最後に0個にした場合、
推論的な延長線上にあると思えるか、それとも全く違った結果になるかどちらですか?
0982はちみつ餃子 ◆8X2XSCHEME
垢版 |
2020/03/23(月) 17:58:00.87ID:FLdc410A
>>981
C++20 的に言えば集成体初期化の文法に統合されたということにはなるんだと思うけど、経緯はよくしらない。
0983デフォルトの名無しさん
垢版 |
2020/03/23(月) 18:27:48.17ID:bf1cRh+B
もし、
{1,2,3,0,0,0,0,0}
{1,2,0,0,0,0,0,0}
{1,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0}
のようになるんであれば、()は(xxx)のxxxを書かない場合と捉えるのは数学的推論として
正しい見方になりますね。
実際に上のようになるのか、未初期化の部分が残るのかは知りませんが。
0984はちみつ餃子 ◆8X2XSCHEME
垢版 |
2020/03/23(月) 18:32:49.31ID:FLdc410A
>>983
足りない分はゼロ初期化されるよ。
C の時代からの配列の初期化の文法と一貫させてるつもりなんだと思う。
0985はちみつ餃子 ◆8X2XSCHEME
垢版 |
2020/03/23(月) 18:45:31.47ID:FLdc410A
>>983
空の丸括弧でゼロ初期化されるのは C++03 にはすでに有って、
波括弧で初期化する文法は C++11 から入って、
(そこから色々と条件の緩和やら変更やらがありつつ)
空ではない丸括弧で集成体初期化になるのは C++20 からという段階的な変化がある。

追加された文法が既存の文法となるべく一貫性を持つように統合しようとはしているけど、
互換性を壊さないようにというのも C++ の強い要件なので、
正確なルールはごちゃごちゃした条件の塊になりがち。

まあまあ整理されている部分もあるけど、
勝手な予想ではなくちゃんと資料にはあたった方がいいよ。
0987デフォルトの名無しさん
垢版 |
2020/03/23(月) 20:24:40.26ID:V7MpBiZM
結局、波括弧と丸括弧はどっちが良いの?
C++11の時点では、波括弧が使えるところでは波括弧使っとけってのがMayers神の教えだったけども
0989デフォルトの名無しさん
垢版 |
2020/03/23(月) 22:25:35.27ID:d94IfFIM
好きなようにやったところで法(規格なりデファクトスタンダード)にはならんだろw
0990デフォルトの名無しさん
垢版 |
2020/03/23(月) 23:44:35.50ID:Y58N/W/D
よし、じゃあ今から俺が法な。


ここの住人は全員システムハンガリアン強制
0992はちみつ餃子 ◆8X2XSCHEME
垢版 |
2020/03/24(火) 00:21:01.48ID:DmQItF6u
>>987
シンタクス的にどちらでも良いときには波括弧を優先した方がよいと思う。
波括弧は縮小変換を許さないので意図しない情報の欠落は防止できる可能性が高い。
縮小変換が必要な場面に限って丸括弧を使えばそこが要注意ポイントってのがわかりやすい。

----

ところで縮小変換より狭化変換という用語の方が好きなんだけど、
みんなどっち使ってる? やっぱ縮小変換の方が標準的かな?
0998デフォルトの名無しさん
垢版 |
2020/03/24(火) 22:49:16.96ID:T0vrM+QL
>>993
数学の記号法と言うのは本によって違ってるから。
特に物理学は必要に迫られて新しい記法を発明してしまう。
レス数が1000を超えています。これ以上書き込みはできません。

ニューススポーツなんでも実況