C++相談室 part144
■ このスレッドは過去ログ倉庫に格納されています
C++に関する質問やら話題やらはこちらへどうぞ。 ただし質問の前にはFAQに一通り目を通してください。 IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。 前スレ C++相談室 part143 https://mevius.5ch.net/test/read.cgi/tech/1560574313/ このスレもよろしくね。 【初心者歓迎】C/C++室 Ver.105【環境依存OK】 https://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/ (日本語) ----- テンプレ ここまで -----
>>416 2パスをググってもそれらしいものがなかったのですが、どういうものなのでしょうか? あと、「各領域をリストで繋いて」というのはvectorに追加しながら最後に連結するということでしょうか? >>417 > 2パスをググってもそれらしいものがなかったのですが、どういうものなのでしょうか? 1回目(Pass 1)ではデータの格納はせずにサイズだけ取得する 合計サイズ分を確保して2回目(Pass 2)で実際に格納するってこと > あと、「各領域をリストで繋いて」というのはvectorに追加しながら最後に連結するということでしょうか? そう言うこと でかいデータはコピーにも時間がかかるからできるだけコピーしないようにした方がいい >>417 2パス良さそうですね。 gzread(rzp, data+data_size, MAX_BYTE) のところを下記のようにNULLにしてもちゃんとファイルの最後まで動いているようなのですが、これがデータ格納せずにサイズを取得するということでしょうか? gzread(rzp, NULL, MAX_BYTE) すみません、NULLだとそもそも一回も取得できずに終わっていました。。 データ格納せずに一回ファイル精査するのってどうするんでしょうか? >>420 固定長のバッファを1つ用意して、そこに上書きしながら繰り返し読み込めばいい。内容は上書きされて読めなくなるけど、読み捨てるつもりなので気にしない。 (最終的なところに)格納しないってことな 適当なバッファを1つ用意して毎回そこに格納しとけばいい >>421 ,422 そういうことですか、理解できましたありがとうございます。 vectorだって償却定時間なのに ホントに2回読む方が速いんか? valgrindってみんな開発に使ってるの?死ぬほど遅いんですが でかい領域のreallocで毎回コピーが発生するというのは都市伝説、 と言いたいところだが他のスレッドが動いているとそうとも言い切れないかそうか、 この場合の2パス方式はgzipが2回走るのがいかにも実行時間の無駄でいやすぐる 最初に大きめの領域をmallocして足りんかったら2パスに切り替えるという投機的なやり方のが良い だいたいいかにgzip様といってもファイルを毎回1/10まで圧縮できるわけはないのだから 読み込むファイルサイズの10倍を確保しておけばほぼ1パスで済む 展開後の実サイズがわかったら展開後の実サイズぴったりにreallocで縮小すれば良い ちなメモリの断片化はガン無視 実使用サイズの倍のメモリも用意できないようなプアな環境のならmallocやreallocする設計から見直さねばならない 見直すべき >>427 意味わからん スレッドなんて関係ないだろ >>429 ヒープメモリはスレッドで共有される もしヒープメモリを使う他のスレッドが一切無いなら realloc()でサイズ拡大してもコピーは生じない(後ろに領域伸ばせるから この説明でまだ疑念が渦巻くのならプログラミング言語Cをきちんと読み直した砲が良い (あのmalloc()実装例がmalloc()実装の全てとは言わんが基本 >>430 断片化って知ってる? > 後ろに領域伸ばせるから これ常にできるわけじゃないよ > この説明でまだ疑念が渦巻くのならプログラミング言語Cをきちんと読み直した砲が良い お前がなw 特にこの場合はgzipを使うからね アウトプット用のメモリを確保した上でgzipを実行するわけだけど gzipが内部で動的にメモリを確保するかしないかは知らんけど、多分するでしょ そうすると新たに論理アドレス空間が使われるから 連続したメモリ空間を後ろに拡張できるかって言われるとね >>431-433 んまーそれはそうやったorz あと今回のgzip展開ルーチン呼び出し前にmallocした領域がたまたま後ろに居る可能性もあるな! しかし>>428-428 は断片化が生じないと言っているのではないし主目的のgzip読み込みに関しては 断片化による影響を受けにくくしているのだから大枠問題無い 良い良い、良いではないか 色々とご意見ありがとうございます。 どなたかの役にたてばと思い僕が調べた内容をお知らせします。 gzip展開後に5GBくらいになるデータでテストしてみました。 @time ./a.outで簡易的に時間取得 Arealloc方式の場合 >>415 の下記部分でコピーが何回発生しているかをカウントしてみる // アドレスが変化した場合 if( data != data_new ){ // free(data); // 元オブジェクトは解放済みのため不要 data = data_new; copy +=1; // コピーした回数をカウント }else{ not_copy +=1; // コピーせずに拡張できた回数をカウント } 結果は以下のようになりました。 強力なサーバでメモリが潤沢にあるためか、コピーがほとんど発生しないようで realloc方式が早かったです。 本日祝日でサーバ使用者が少なく、よりコピー回数が減っていると思います。 個人PCでchromeにメモリ食われたりするとコピーが増えて逆転するかもしれないですね。 環境に合わせて変えようと思います。 # 2パス方式(約27秒) ./a.out 25.12s user 1.27s system 99% cpu 26.479 total # realloc方式(約15秒) ./a.out 12.73s user 1.46s system 99% cpu 14.263 total -> コピー 1 -> notコピー 636 malloc()されたりrealloc()されたりするヒープメモリは仮想アドレス空間に対応した普通のOSならプロセス毎に別空間だから 他のプロセス(他のサーバ利用者が居る or chrome)があってもヒープメモリの断片化に関係しないはず… さらに、2パス方式の時間が1パス方式の倍になるのはメモリコピーよりもgzip展開を2回もやることが利いているでケテーイ すみません、また疑問が出てきたので相談させてください。 今読み込んだバイナリファイルの解析をしています。 ある一部の8バイトがビッグエンディアン形式で下記になっていて、これが少数点の数値で「2.500000e-04」となるようです。 3e 10 62 4d d2 f1 a9 fc 次に下記URLを参考に調べると今使っているサーバはリトルエンディアンでした。 (CPUはintel) ttps://qiita.com/ryuichi1208/items/31442f9e8a7a7c94aeec このため ビックエンディアン→リトルエンディアン の変換が必要と思うので下記のようにしました。 unsigned char t[8]; double little; for (int i = 0; i < 8; i++) { t[i] = data[7-i]; // バイトオーダーの変換 printf("%02x ", t[i]); } printf("\n"); memcpy(&little, t, 8); printf(" %e\n", little); ---結果--- fc a9 f1 d2 4d 62 10 3e 9.536743e-10 ---------- ちゃんと反転できていますが、結果は期待値「2.500000e-04」ではありませんでした。 >>続きます 次に実際の値を16進数表示したときの確認として下記を実行したところ、結果は以下のようになりました。 int main(){ double data = 2.500000e-04; unsigned char *p; int i; p = (unsigned char *)&data; for (i = 0; i < 8; i++) { printf(" %02X", p[i]); } printf("\n"); printf("%e\n", data); return 1; } ---結果--- FC A9 F1 D2 4D 62 30 3F 2.500000e-04 ---------- 比較すると、最初の6バイトは同じですが最後の2バイトが違いました。 どうやったらバイナリデータに入っている 「3e 10 62 4d d2 f1 a9 fc」 を 「2.500000e-04」 に変換できるかわかりますでしょうか? ビッグエンディアン→リトルエンディアン の変換時にもうひと工夫いるのでしょうか? 2.500000e-04のIEEE754表現は3f30624dd2f1a9fcだぞ 元のバイナリの解釈間違ってんだろ >>426 開発っつーか本当にどうしようもないバグの場合は使う。 遅いって言っても5〜10倍くらいだろ。 2.500000e-04/9.536743e-10≒262144=2^18だからどっかで誰かが18ビットシフトしてないか調べろ あとはそのバイナリ作った野郎に聞け decimal64だったりして サーバのCPUは何? >>440 ,442 データの方が違うんですかね。。 今調べてますがまだわかりません。 >>443 xeonです。 decimal64というのはまだ調べていませんがまたちょっと違う変換になるんですかね? サーバじゃないか もとデータ生成したビッグエンディアンのCPUは何かと 同じサーバで生成されました。 生成したソフトは販売されているものなので問題はないと思うし、 他のソフトで読み取ってもちゃんと 2.5e-04 が出てくるのでデータに問題はなさそうです。 なぜそう読めるのか不思議です。。 Big Endian だし IBM フォーマットとか? >>446 > 生成したソフトは販売されているものなので問題はないと思うし、 なぜそのソフトの名前を書かないの? > 他のソフトで読み取ってもちゃんと 2.5e-04 が出てくるのでデータに問題はなさそうです。 他のソフトって何よ? みんなエスパーじゃないんだから出せる情報は出しなよ >>448 すみません、calmaという大昔のもので今はもう販売されていません。 Calmaでググるとこれがヒットするけどこれかな? https://en.m.wikipedia.org/wiki/Calma これだとかなり古いソフトウェアだから浮動小数点のフォーマットが違うような気がする >>450 数値をバイナリ変換していそうなコードを今見つけました。 ただのビッグエンディアン表記ではなさそうです。 もう少し調べて見ます。 下記で数値からバイナリへの変換ができましたが、何の計算をしているのかさっぱりわかりません…… 逆変換できるのでしょうか? http://codepad.org/oSvOJP1p ---結果--- 変換前の値:0.000250 変換後の値:3e 10 62 4d d2 f1 a9 fc ---------- 浮動小数の正規化っぽいけど ( A < 0.0625 ) || ( A >= 1.0 ) ってのが特殊だと思う 何かそういう事情があったんでしょう 浮動小数の正規化ってのは検索すればわかる 別環境でデコードするだけならたぶん気にしなくて大丈夫 確かに、IBM方式ってやつっぽい 気にしないといかんわw 無駄なこと書いてごめんね >>453-455 ありがとうございます。 今 IBMフォーマット や IBM方式 でググってますが中々それらしいものが出てきません。 かなりマイナーなものなのでしょうか? こんな感じかな?保証はせん uint64_t ibm = 0x3e10624dd2f1a9fcULL if (ibm == 0x0) { return 0.0; } uint64_t sign = ibm >> 63; uint64_t ibmexp = (ibm >> 56) & 0x7f; uint64_t ibmfrac = ibm & 0x00ff'ffff'ffff'ffffULL; if (ibmexp == 0x0) { return std::numeric_limits<double>::quiet_NaN(); } //てきとう uint64_t ieeeexp = (ibmexp - 64) * 4 + 1023; uint64_t ieeefrac = ibmfrac; while(ieeefrac & 0x0100'0000'0000'0000) { ieeefrac <<=1; --ieeeexp; } ieeefrac ^= 0x0100'0000'0000'0000; ieeefrac >>= 1; uint64_t ieee = (sign << 63) | (ieeeexp << 55) | ieeefrac; return *reinterpret_cast<double*>(&ieee); というか指数部のビット長勘違いしてたわ 459は捨ててください恥ずかしい ieee形式は自前で変換せずにdoubleで計算してしまえばいいんでは? frexpとldexpでやっちゃう方が間違えにくくていいのかな エクセス64か 半導体とかで使われるGDSIIの実数がそれなんだよね。 自力で実装したわー。 4bitを16進数一桁として考えてて、指数部は16^xで表現されててケチ表現なし。 じゃあどっかにライブラリでもあるんじゃねえの 探したら出てくるパターンだろこれ >>457-466 コメントやサンプルコードありがとうございます。 こんな複雑なコードになるんですね。。 何やってるのかさっぱりわかりませんが、上記コードを参考に勉強してみます。 しかしエクセス64で検索してもそんなに記事が出てこないですね。 かなりの難易度の予感…… これか? GitHub - enthought/ibm2ieee: Cross-project library for converting IBM-format hexadecimal floating-point to IEEE format binary floating-point. https://github.com/enthought/ibm2ieee 日本語だと情報が少なかったので英語圏も検索してみたところ、下記を見つけました。 ここのexcess64_to_ieee754が変換できるものかもしれません。 これから調べてみます。 ttps://github.com/ulfgri/gdsii-toolbox/blob/de8deaa5972c1449aacc3eea5dda86472ef721a8/Basic/gdsio/convert_float_generic.h >>469 かぶりました。 探していただきありがとうございます。 それも調べてみたいと思います。 >>467 フォーマットは>>458 のリンク先に書いてある 3e 10 62 4d d2 f1 a9 fc の最初の1バイト(3e)は符号ビットと指数 0x3e = (0 0111110) で最初の0は符号(正) 残りの0111110が指数で10進では62 指数は64の時に0と解釈するので62 - 64 = -2 IBM形式では16の指数なので16^(-2) = 1/256 一方仮数部は 1: 1/16 0: 0/256 6: 6/4096 2: 2/65536 : 計 0.064 なので結果は0.064*(1/256) = 0.00025 = 2.5e-4 >>472 わかりやすい解説ありがとうございます。 仮数部の計算がまだいまいち理解できていませんが、符号ビットと指数のところは理解できました。 なんとかプログラム作れそうです。 とても勉強になりました。ありがとうございました。 >>472 仮数部の計算も理解できました。 ネットで浮動小数点を解説している記事を見るとどこも2進数で書かれていましたが、 >>472 はこのスレで会話に出しているバイト単位(16進数)で計算してもらってるんですね。 この辺の話になるとこのスレの趣旨から外れてきているのでこの辺にしておきます。 以上、お礼を兼ねての書き込みでした。ありがとうございました。 bit単位でもいいんだけど元の値との対応が取りにくいから16進の1文字(4bitなのでByteじゃなくてNibbleって言う)単位で計算してる そうでした。4bitでした。 今回バイナリ読みで初めてどっぷり16進数を扱ってますがバイトとニブル?がすぐわからなくなります。。 ttp://www7b.biglobe.ne.jp/~robe/cpphtml/html02/cpp02007.html 上記URLで ・クラスの宣言はヘッダファイルにする ・クラスの実装部はソースファイルにする ・そのクラスを使いたいときはヘッダファイルのみインクルード とありますが、これが一般的なのでしょうか? なるべく基本にのっとった書き方に慣れることで、他の人が書いているプログラムもある程度読めるようになれたら調べるときに助かりそうだと思っています。 だからさ、そういう疑問を持つってことは お前なりに考えた別のやり方があるんだろ? それを書けよ どういう意味や効果があってそうしてるかじゃなくて「一般的」かどうかばかり気にしてるあたりがプログラマ向きの性格じゃなさそう iOSのC++の勉強アプリ何個か試してみたんだけど、未だにC++03時代の事までしか教えてないのね。 でも付属の簡易コンパイラはC++17の機能が使えたりする... 初心者のうちから shared_ptrやunique_ptr を積極的に使うようにしてほしい。 いくら便利なものがあるといってもさすがにC++をナマポや自前RAIIの知識なしで使うのは不可能だから、 初心者は最初はメモリ破壊で苦しんだ方がいいと思うわ https://ideone.com/10xlAn ギャグなんですけど、 これファイル間またいで定義したい時って何か特別な事しないといけなかったでしたっけ? 「日本語C++」書いてみたい人生だった。 >>491 検証ありがとう。自分はVCなんだけどね。書き忘れてごめん。 VCも無理かな。 最近プリプロセッサは、すたれる流れのようなのでメンテされてないのかなぁ・・・。 マクロは名前空間に閉じ込めることができないからしょうがない VCはソースを全てBOM付きのutf8にすれば通るんじゃないかな。 #define 違うなら else これは もしくは の方がいいんじゃねえか? もし i == 0 なら printf(">>497 はちょっと頭悪い"); もしくは printf(">>497 はちょっと頭弱い"); …なるほど正しいかも ってそんなわけ無いだろw >>80 >Pythonは「CPythonの実装が規格だ」だし それrubyと勘違いしてないか? 明文化されていない仕様なんてそんなに残っていないと思うが。 あと、MATLABはアカデミック分野では少なくともRやOctaveなんかより 信用されていると思うよ。 make環境を作ると更新ファイルだけコンパイルしてくれたり、色々便利そうなので コンパイルコマンド直たたきからmake環境に移行しようと考えています。 下記で正常動作しているので、これでmake環境を作りたいと考えていますが 「c++ make」で検索してもあまり情報がないため苦戦しています。 どのように書けば良いかわかりますか?もしくは参考のURLなどあれば教えていただけないでしょうか。 #!/bin/sh - export CC=~local/bin/gcc export CXX=~local/bin/g++ g++ -c -g -Wall -pthread -std=c++11 ./Func.cpp -lm -lz -Wextra -o Func.o && g++ -c -g -Wall -pthread -std=c++11 ./Main.cpp -lm -lz -Wextra -o Main.o && g++ Main.o Func.o -o main.exe -lz >>501 簡単に言えばMakefileに 作ってほしいファイル名: そのファイルを作るのに必要なファイル (タブ(なぜか空白はダメ))作るためのコマンド をズラズラ書いておけばいい なのでその例だと Func.o: Func.cpp g++ -c -g -Wall -pthread -std=c++11 ./Func.cpp -lm -lz -Wextra -o Func.o Main.o: Main.cpp g++ -c -g -Wall -pthread -std=c++11 ./Main.cpp -lm -lz -Wextra -o Main.o Main.exe: Main.o Func.m g++ Main.o Func.o -o main.exe -lz って書いておいて(わかると思うがg++の前はタブな) make Main.exe ってやればいい 毎回Main.exeを指定するのが面倒なら Main.exe: Main.o Func.m g++ Main.o Func.o -o main.exe -lz の行を一番上に持って行けば make だけで作成できる (makeは指定がないと最初に見つけた作りたいファイルを作ろうとする) >>501 以下の文献とオライリーのGNUmake読んで、あとは自分で考えるのが良い。 http://aegis.sourceforge.net/auug97.pdf この辺り、まともに理解してる奴が本当に少ないから。 だからconstexprとかboostとかクソみたいなものをありがたがるんだろうなと思う。 ビルドツール選びの時にC++の言語機能をたたく理由がわからない。 >>506 ビルドと言語機能は綿密に絡み合ってるから。 c++使っててこれだけ当たり前の話を理解できないというのが理解できない。 > ビルドと言語機能は綿密に絡み合ってるから。 具体例の1つも出せないクズ乙 >>508 505の内容見て具体例に思えないようならもう話すことはないな。 > タブ(なぜか空白はダメ) こういうところがクソ Makeは古い AntかMavenかGradle使え、 いや知らんけど 素のMakefileは最終的なオブジェクトファイルとヘッダファイルの依存関係を書き下すのが大変に面倒臭い なぜなら、 Target: Dependencies1 Dependencies2 ... (TAB)Command という記述において、Commandが具体的にTargetお生成しないと事実上立ち行かないので、 インクルードファイルAがインクルードファイルB、Cをインクルードしているという状況を A: B C (TAB)echo Hello World! などと書くわけには逝かず、あくまで foo.obj : foo.cc A B C (TAB)gcc foo.cc 式に.objなターゲットに対して関連付けねばならない ファイルがあるだけで勝手にヘッダファイルの依存関係を解決させることは GNU Makeの昨日とシェルコマンドを組み合わせてできた気がするが(忘れた たかがこれだけのためになんでそんな糞面倒なことをせねばならんのじゃ、というキモス ※ 個人の感想です Ruby のRake, Thor などのタスクランナーで、コンパイル出来ないのか? Webpack, Gulp とか ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる