C++相談室 part132
■ このスレッドは過去ログ倉庫に格納されています
次スレを立てる時は本文の1行目に以下を追加して下さい !extend:on:vvvvv:1000:512 C++に関する質問やら話題やらはこちらへどうぞ。 ただし質問の前にはFAQに一通り目を通してください。 IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。 前スレ C++相談室 part131 http://mevius.2ch.net/test/read.cgi/tech/1501295308/ このスレもよろしくね。 【初心者歓迎】C/C++室 Ver.101【環境依存OK】 http://mevius.2ch.net/test/read.cgi/tech/1500329247/ ■長いソースを貼るときはここへ。■ http://codepad.org/ https://ideone.com/ [C++ FAQ] https://isocpp.org/wiki/faq/ http://www.bohyoh.com/CandCPP/FAQ/ (日本語) VIPQ2_EXTDAT: default:vvvvv:1000:512:----: EXT was configured >>699 実装も前者の方が楽そうですな。 前の値と比べて差が広かったらグループ追加。 >>699 その部分は数値の比較と書きました 要素グループのvectorのvectorですか どのような感じで書けばいいとかどのような調べかたをすれば良いか教えて頂けないでしょうか 取っ掛かりが分からなくて >>697 参考までに聞きたいんだが この処理を何に使うの? >>704 ある方法で手に入れたいくつかの数値を先頭値から見ていき、 前後で差が小さいもの同士でグループ分けしていったあと そのグループ毎の平均値を出していきたいだけです こういう泥臭いのは人に聞くよりもスクリプトでもなんでも良いから書いて試行錯誤すればいいと思うのよ >>705 ruby2.2〜ならchunk_while/slice_whenで出来る >>705 思い付くまま書くとこうなるがもう少し短く出来そうな気もする Ideone.com - dOQm10 - Online C++ Compiler & Debugging Tool https://ideone.com/dOQm10 >>711 ありがとう参考にする しかし、よくこうスラッとプログラム書けるよなぁ 凄いわ 自分なりにやってみた。 https://ideone.com/ugURi1 >>711 vector::insertで領域の再確保が起こると既存のイテレータが破壊されるんで 24-25行あたりの処理はヤバイ。 すれちがいだけど、 C++が出る前のC言語で、STLが必要な処理はどうしてたの? >>716 固定バッファとか、ヒープとか、自己参照構造体などで管理してたはず。 一応つっこみ。 型の一般化がテンプレートと思うが マクロじゃなくてテンプレート使えって書いてた本もあったような 気がする。 >>716 STL 等はあれば便利なだけで「それが必要な処理」などない。 >>716 STLで使われているアルゴリズムはC++前からあったものばっかだよ 汎用アルゴリズムのコードを業界で共通化することもなく、みんなが各々で実装してたんですか?というアンチテーゼだろ まぁ、ライブラリとして偏在はしてたんだろうけど、あの会社はあのライブラリこの会社はこのライブラリってややこしいことになってたと思う。 リンクリストと平衡二分木ぐらいなら雑に書いても500行ぐらいでできる みんな大学の復習と思って書いてたんじゃないかな? 自力で書いてる人の方が多かった STLがあっても用途によっては独自になるよな ディスク上に作るとか、JPEGのハフマン符号みたいに表現が決まってる物とか STLはあくまでお手軽用途 表現縛りがなかったとしても、 ガチガチに最適化する用途では使えない if ( オーバーヘッドがない != 最適化される ) 最近は凝ったアルゴリズムより単純な配列(vector)の方が速かったりするうえに、余程古いかクソな標準ライブラリを使用してない限りstd::vectorを最適化する余地なんてほぼ無いわな。 最適化はコンパイラに任せてソースは読み易さ重視 std使っとけばデバッガでも追いやすいし 拡張ライブラリが有ったとしたら、名前空間はstxになるのかね。 Qtでウェブサイト作ったら何の問題もなくずっと動き続けてびっくりですよ。 Javaスレの人たちがC++は稼働し続けるとメモリーの分断化で落ちるとか言ってたから、 早く書き直さなきゃって思ってたんだけど。 クライアント用のQtがサーバーで頑健だったのは意外だった。 >>741 クソJavaプログラマーがC++を書くとほぼ間違いなくやるただのメモリリークを俺のせいじゃないということにしたかっただけというのに1票 自分のコードでさえ後で読むと読みやすく書いたつもりが裏目に出ていたりする 俺も最近unique_ptrに任せっきりでdeleteってほとんど書かねえわ コピコンの=deleteとかは書くけど >>739 古いコンパイラ(つっても10年くらい)だと、クラス内の配列をイジるとクラスオブジェクト自体がイジられたことになるので最適化放棄とかしてたしなー そういうのだとvectorなんて最適化放棄しまくり。 >>748 オブジェクトXに対するアクセスの最適化放棄はコンパイラの知りえない形での Xへの副作用が有り得ると判断された場合に行われるがこれは現用コンパイラでも変わらん 改善したというのはコンパイラの能力向上というよりは、テンプレートによるインライン展開のご利益なのでは… (つまりstd::vectorは元来最適化向きの進化である 例: 次のコードの並びにおいて、 1と3の読み込み結果は同一とはみなされず、1〜3を通してのX.aのレジスタ割り当ては行われない 1. Xのメンバaを読む 2. 外部リンケージ(かつ素性の知れた組み込み関数以外)の関数foo()を呼ぶ 3. Xのメンバaを読む 特効薬はfoo()のインライン展開 なお手動を厭わないなら次の風にしても良い: 0. auto変数v = X.a 1. X.aを読む代りにvを読む 2. 外部リンケージ(かつ素性の知れた組み込み関数以外)の関数foo()を呼ぶ 3. X.aを読む代りにvを読む これならいくら古いコンパイラでもvを1〜3を通してレジスタ割り当てすることが気体できる 浮動小数点をすべて網羅するループが書きたいのですがどうすればいいでしょうか。 http://takashiijiri.com/study/miscs/fastsqrt.html やりたいことは、上のサイトにある高速根号計算の精度検証です。 サイト内では2の根号に対して精度検証していますが すべての倍精度実数に対して検証をしたいと考えています。 64bitの整数のビット表現を、同じビット表現の倍精度実数に変換できれば 整数についてループを回すことで網羅できると考えています。 変換の方法をご存知の方がいれば教えて頂けないでしょうか。 >>757 reinterpret_castでいい予感。 >>755 ところでその検証、何年ぐらい時間かけていい話なの? >>759 未定義動作でも「いい」と言うなら、そう。 みなさま、レスありがとうございます。 >>757 memcpyでできそうです。ありがとうございます。 int main() { double f = 0; for (unsigned long long i = 0; i <= -1; ++i) { void* fp = static_cast<void*>(&f); void* ip = static_cast<void*>(&i); std::memcpy(fp, ip, sizeof(i)); std::cout << f << std::endl; } system("pause"); } >>760 そんなに時間かかるんですかね。。。 1週間ぐらいは覚悟してたんですが。 とりあえず回してみます。 >>763 https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/ > ... you can test every float bit-pattern (all four billion!) in about ninety seconds. ... 32bit が 90 秒ほどで済ませられるそうな。 64bit だと単純計算で・・・ 735439.6... 年ぐらいかな。 1週間で済ませようと思ったら 38347922 並列ぐらいで走らせればよさそう。 検証する計算内容によっても変わるだろうけど、まぁがんばれ。 とりあえず範囲を絞って回してみて、 力任せの方法で受け入れられる処理時間なら単純なプログラムのまま、 時間かかりすぎるようなら先にプログラムを洗練させる、としないと。 >>764 ありがとうございます。 32bitと64bitが桁違いですね 範囲を絞ったり、間隔あけてサンプリングしたりしてみます。 isnan()でnanチェック入れたほうが良さそう >>761 未定義にはならなくね?ポインタtoポインタだからそのまま、で終わりでは。 なお、Cなら *(long long*)&f = i; // mov命令でコピー または f = *(double*)&i; // fmov命令でコピー >>766 まず仮数部53bit+指数部の偶奇で54bit分でいい。 非正規化数もいらないだろうから仮数部52bit扱いでもいい。 意味が分からないのなら仕様読め>>758 >>768 type-based aliasing rule (strict aliasing rule) というものがあってな。 (詳しく調べると闇に落ちるから言語オタクでもなければ深堀りはおすすめしない。) mempcy なら動作が定義されてるかというとそうでもないんで、 明示的に未定義といわれているかどうか(=最適化で問題を起こしやすいかどうか)の違いしかないんだけど。 なんか古い書き方だから2000年ごろからの年季の入ったソースかと思ったら最近の奴なんだな >>774 古臭い技術専門が時代遅れのために作っているもんだから、古いと言われても仕方ない。 auto、C++11が使えるclang++に移行したい。 >>769 調べたけどこれでいいのか? https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule これならreinterpret_cast関係ないじゃん。static_castにしたところで変わらん。 ただそれ以前に該当しないだろ。 「同一のメモリを違う型としてaliasしたときにコンパイラがそれに気づけず最適化で削除してしまう」という問題であり、 今回はそうではない。 > mempcy なら動作が定義されてるかというとそうでもないんで ほんとか?それじゃmemcpyマトモに使えないじゃん。 void*は++で1増えるって仕様に決まったはずで、、、と思ったがこれがgcc拡張だという話があり、このことを言っているのか? ならグダグダ言わずにCキャストで書けよもう、としか思わないが。 或いはC++的には許せないのかもしれんが static_cast<double>にしてしまうとかか? すまんミスった × static_cast<double> ○ static_cast<double*> >>776 static_cast じゃコンパイル通らない。 "*(long long*)&f = i" は double 型のオブジェクトに long long 型の参照を通してアクセスしているので 未定義動作になる。結果は「最適化で削除してしまう」に限らず、何でもアリだよ。 これが「「同一のメモリを違う型としてalias」に該当しないという理屈も無いでしょ。 memcpy の結果が定義されてるのは、同じ型のオブジェクト間でのコピーだけだったかと。 違う型の間で memcpy した結果の値が実は定義されてるということなら実に興味深いので ぜひ規格の該当箇所を示して欲しい。 この場合の C スタイルキャストの動作は reinterpret_cast に丸投げされるだけなので話は変わらないよ。 ここまでnextafter/nexttowardが出てきていない >>778 > "*(long long*)&f = i" は double 型のオブジェクトに long long 型の参照を通してアクセスしているので してないぞ。 それは「fのアドレスを(long long*)にキャスト(この時点でlong long*型)したアドレスに対しiを書き込め」 であって、つまり long long に long long を書いている。だからmovが出る。 逆に f = *(double*)&i; は double に double を書くから fmov が出る。 その後の最適化で変更されるのはまた別の話。 > static_cast じゃコンパイル通らない。 だったら最初から>>759 の言うとおり、reinterpret_castでいいだろ。 > 違う型の間で memcpy した結果の値が実は定義されてる void* と void* なんだから同じ型だろ。何言ってんだ? お前、基本的に理解がずれてね? >>780 なるほど、オブジェクトの型と式の型との区別がついてないんだね。 そこの理解無しで aliasing rule に関する話は無理だから、 C++ の規格を読み直すなりして区別が付くようになってからの出直しをおすすめする。 >>781 俺には君が全く理解出来てないように見えるけどね。 まあ平行線だろうし、終わりでいいけど。 >>782 そうなると GCC も「全く理解出来てない」ことになるねぇ。 https://wandbox.org/permlink/WMFUTpXAgs2oZuos > prog.cc:5:17: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] > *(long long*)&f = i; > ^ > prog.cc:6:18: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] > f = *(double*)&i; > ^ まあ未定義な動作がどこまで行っても未定義な動作であって(教条主義的には)悪なのは確かだが >>784 のリンク先のを読むと >ストアによってPの値が変わる可能性を考慮しなくてはいけないからだ。 という理由で最適化できないケースがあるから考慮する代りに未定義動作ということにしますた! というだけで、ストアによってPの値が変わらないなら特に問題を生じないように思える… で、ストアによってPの値が変わるケースというのは int main() { P = (float*)&P; // このキャストによって zero_array の中で TBAA 違反となる zero_array(); } みたいな変態的なケースしかなさげ; >>784 答え書いてんじゃねーかよ。 > この種の未定義な振る舞いは、-fno-strict-aliasing フラグを指定することで無効にすることができ つまり指定すれば万事解決だ。 ただその前にwarning出てても動作するとは思うが。 > この種の型の乱用はあまり一般的ではないので、標準委員会は、"妥当な" 型のキャストによる予期しない結果と引き換えに、大幅なパフォーマンス向上を選んだ。 これっていつから?LLVMに乗せた頃からっぽいが、、、日付や元URL見るかぎりC++11からか? あとこれって、Cもか? (Cでは俺が書いたようなキャストは常用されているから) 知っている人がいたらよろしく。 つかmemset(buf, ch, nのbufって__restrictじゃなかったのか… 今知った…… C89からずーっとそうだよ お前が書いてるコードが動いてるのは、コンパイラがそうしないという保証を独自に与えているか(-fno-strict-aliasingはその一例) さもなくばたまたま動いてるだけ >>786 広く知れ渡ったのは gcc 2.95 で実際にそのルールに基づく最適化が行われるようになってからかな。 https://www.gnu.org/software/gcc/gcc-2.95/features.html > - Type based alias analysis is enabled by default. ... そこから数えてももう 20 年近く経つわけだが。 知らずにそんなキャスト常用してるなら是非悔い改めてくれ。 (ま、__restrictな形でしかポインタしか使わない漏れには関係ないし… ちなみに-fno-strict-aliasing付けるとこんな基本的な最適化さえ出来なくなって パフォーマンスが激悪化する可能性があるからな それを完全に理解した上で万事解決だと言ってるならそれでもいいけどさ int foo(double* pd){ int k = 42; *pd = 666; return k * 2; } -fno-strict-aliasingを付けた場合、戻り値を"84"に最適化することは出来ない なぜならpdのアドレスが&kを指してるかもしれないから (strict aliasing ruleが効いてればdouble*がintを指してたら未定義動作なのでケアする必要がなく最適化できる) >>791 引数で受け取った(有効な)ポインタが関数内のローカル変数を指すことは不可能だから、その例は最適化できるよ。 有効なポインタならね デタラメなポインタがたまたま&kを指してるかもしれない 普通はそんなのは未定義動作だからケアしないんだけどそれをケアしろって言うのが-fno-strict-aliasing >>789 > mempcy なら動作が定義されてるかというとそうでもないんで (>>769 ) これは間違いだろ。784内見る限り、 > Cは、このような型変換をmemcpyを使って実現することを要求している。 なら、memcpy使えば正しい結果が得られるはずだし、そうじゃないとコンパイラのバグになる。 つまり、>>763 のコードは正しく動くはず、と読めるが。 ちなみに>>783 のページで色々試してみた。(もし編集が残っているようならすまん) 全てgcc 7.2.0 で、結果は以下。 ・CはC11/C11(GNU)の両方でwarinigも何もでない。 ・C++はこの中の一番古いC++03/C++03(GNU)の両方でwarinigは出る。 ということはかなり昔からC++ではそうだった、ということだね。全く知らんかったわ。 ここら辺がCの連中がC++を嫌っているところなのかもしれない。 >>788 おお、サンクス、C++89からか。 俺環はVC++2008だからね。MS側が吸収してくれてるわけか。 >>789 いや俺環では問題ないしな。 つかたぶんこれC++の話で、上記試した限りCなら問題ないんだよ。 ただ俺はbetterCの人だから、まあ微妙なわけだが、、、VC++2017とかに移行するときは気をつけるよ。 さてそのリンク先 https://www.gnu.org/software/gcc/news/alias.html も読んでみたが、つまり s->x_m[i] は s->a_m と型が違うから上書きしないはず、 だからループ内で毎回 s->a_m を取らずに前回の値をそのまま使っていい、ということらしい。(s->b_mも同様) ただこれなら for (unsigned long long i = 0; i <= -1; ++i) *(long long*)&f = i; は確実に動くけどな。ここで端折られるのはfのアドレス確認 &f 部分だけだから。 ただしstackoverflowの連中は言っていることが少し違うから、もうちょっと確認が必要だが。 >>791 周回遅れですまんが俺には794に書いたとおり、 ・型違いは全てmemcpy使え。 と読める。だから763のコードはOKだと。 >>791-793 の内容は理解した。 さて再度だが、やはり以下は動くだろ。 for (unsigned long long i = 0; i <= -1; ++i) *(long long*)&f = i; ここで問題なのは、「fがiのアドレスをさしてたら未定義動作(&f==&i等)」であって、 i をコピーしてやらない、ではない。 791-793の言い分どおりなら、これはwarningが出てるだけで全く問題なく動くはず。 ただしstackoverflowの連中はちょっと違うことを言っているが。 >>794 C の aliasing rule には memcpy, memmove によって宣言型を持たない(たとえば malloc で確保した)オブジェクトの型 (effective type) を変更できるという規定がある。 引用された「memcpyを使って実現することを要求している」はこのことだろう。 でも、 C++ にはこれに相当する規定が無い。 >>796 残念、まだ理解できてないよ。 答えは >778 にある。 > "*(long long*)&f = i" は double 型のオブジェクトに long long 型の参照を通してアクセスしているので > 未定義動作になる。結果は「最適化で削除してしまう」に限らず、何でもアリだよ。 これ以上は規格見てからしゃべってくれ。 てゆーか、見てなかったけど763はfor文回らねーじゃねーかよ! >>798 ちょうどよかったので今>>795 を改造してアセンブラ見てるんだが、、、すまんが今日は寝る。 昼前にはまた書くよ。 未定義動作マジコエー;;(>>784 のリンク先の次のページ ttp://blog-ja.intransient.info/2011/05/c-23.html ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.1 2024/04/28 Walang Kapalit ★ | Donguri System Team 5ちゃんねる