C++相談室 part145

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん
垢版 |
2019/09/13(金) 17:13:24.60ID:/ygW08Jq
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。

前スレ
C++相談室 part144
https://mevius.5ch.net/test/read.cgi/tech/1563769115/

このスレもよろしくね。
【初心者歓迎】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/ (日本語)

----- テンプレ ここまで -----
2019/10/01(火) 23:39:09.19ID:84uW7JaU
速さ計測すればいいじゃん
逆アセンブル見ればいいじゃん
2019/10/01(火) 23:40:49.69ID:3zNRBOOL
>>262
1個のプログラムの中に一個か二個の float しか使わなくても、 double の場合より速くなるのですか?
そもそもイントリンシックを書かないのに SIMD のコードが出力されるのですか?
2019/10/01(火) 23:44:09.36ID:sOAgszt0
そもそもx64ではFPUは無かったことにされている
doubleやfloatの計算したかったらSIMDで1レーンだけ使って計算する仕組み
2019/10/01(火) 23:54:05.20ID:5ranOfZi
>1個のプログラムの中に一個か二個の float しか使わなくても、 double の場合より速く
その条件だとどっちを使っても良い大して変わらん

やっぱループアンローリングできるぐらいループリッチな課題でないと意味が無い
https://www.isus.jp/products/c-compilers/compiler_part2/
https://cpplover.blogspot.com/2015/03/blog-post_30.html
2019/10/02(水) 00:10:27.89ID:eo8nmuYy
しかしコンパイラの最適化はイマイチっぽい
https://www.isus.jp/products/c-compilers/compiler_part4/
2019/10/02(水) 07:48:44.41ID:BafSfR+Q
>>265
いいえ x64 でも fpu コードは使えますよ、嘘はやめて!
2019/10/02(水) 07:54:44.99ID:Y2eIpMbX
>>228
こういうやつって何かしらソフト完成させたこともない初心者のクセしてイキってるんだろ
マジ邪魔だから消えて欲しい
テンプレート使ったコードで遅くなるというのがわからんならboostのspiritとか使ってみたらいいわ
言ってる意味わかるから
2019/10/02(水) 07:59:03.00ID:Y2eIpMbX
あ、もちろんデバッグビルドの話な
最適化ありならspiritは当然速い
2019/10/02(水) 08:01:33.95ID:sddCZQNP
C++を使わないと言っているやつに、どうぞご勝手にということと何の関係が?
2019/10/02(水) 08:22:40.25ID:QmwKmz4W
>>268
でもアセンブラで直接使わないと無かったことにされるだろ
2019/10/02(水) 08:29:18.29ID:0zoKeqvU
>>261
amd64でfpuコード吐かせるほうが手間じゃwwww
2019/10/02(水) 08:30:44.39ID:0zoKeqvU
そもそもプログラム中に一個か二個の浮動小数点演算なんて最適化ポイントちゃうがなwwww
自説を通すためにバカな例を仮定するアホに絡むだけ無駄やなw
2019/10/02(水) 11:21:30.36ID:iITLzrzf
>>272
プロジェクトの設定でfpも選べるよ
既定だとsse使われると思うけど
2019/10/02(水) 22:05:22.14ID:VK3sSC9+
コンパイラの種類変わったら算術演算ぶん回す場合は結構差が出るだろうけど、同じコンパイラでバージョンかわると最適化とかの進化で結構かわるのかな?
gccの3と4、msvcの2005と2017とかそういう違いで
2019/10/03(木) 04:57:05.82ID:vAL7lUst
質問です
既にクラスHogeとAがあり
クラスAとは別に新たにクラスBを追加することになった
BはA専用の関数が無く呼び出す必要も無いし逆のことは無い
その場合BにA専用の関数と同じ名前の空の関数を用意するか、呼び出されているHoge内で切り分けるかどちらの方が良いですか?
なおAは絶対に継承しなければならないし改変することもできない

class Hoge : A か class Hoge : Bをプリプロセッサかテンプレートで切り分ける

これを
void Hpge::func() {
  A_func(); //Bは持っていない
}

プリプロセッサで切り分けるのが良いのか
void Hpge::func() {
#if defined(USE_A)
  A_func();
#endif
}


それとも空の関数を書いた方が良いのか
class Hoge : B {
  A_func() {}
}

詳しい方がいたら教えていただきたいです
これ以外の賢いやり方があればそれでも大丈夫です
2019/10/03(木) 07:04:32.42ID:damPur2/
絶対に、の理由が知りたいところだけど、普通はA_funcを仮想関数にしてBは空関数でオーバーライド。
2019/10/03(木) 07:05:22.94ID:OJdSM3QH
c++17以降ならif constexprとstd::is_sameでできるんじゃない?
template < typename T >
class Hoge : T{
void func() {
  if constexpr(std::is_same<T,A>){ //基底クラスTがAであればA_func()を実行する
    A_func();
  }
}
}
2019/10/03(木) 07:12:55.92ID:OJdSM3QH
std::is_same<T,A> じゃなくて std::is_same_v<T,A> か
2019/10/03(木) 07:31:04.45ID:5EMHpFEj
>>278
HogeがAかBを継承するんだからそれじゃだめやろ
ただ設計見直したいところだけどそういうわけにもいかんのかね
2019/10/03(木) 07:54:23.64ID:r73Y/293
c++17が使えなくて、Bの定義を関係ないAのために汚染したくないなら一層増やせばいい

template<typename T>
class HogeBase;

template<>
class HogeBase<A> : A {}

template<>
class HogeBase<B> : B { A_func(){} }

template<typename T>
class Hoge : HogeBase<T> { /*...*/ }
2019/10/03(木) 09:13:02.91ID:r91xqmRv
>>281
なにか問題起きる?
2019/10/03(木) 11:57:14.92ID:z1c5xmGq
>>277
基底クラスを切替たいってこと?
しかも片方の基底クラスにしかないメソッドを派生クラス側で呼出すとかどんな状況なんだろう…
まあ、やっつけでやるなら素直にB側に空のメソッド追加しとけばいいと思うよ
どう見てもまともな設計じゃなさそうだし、かと言って設計を見直すこともできなさそうだしね
プリプロセッサなんて愚の骨頂にしかならん
285281
垢版 |
2019/10/03(木) 12:22:59.66ID:GJuckdYX
>>283
A_funcを持つものを継承するならオーバーライドが理想的だろうけど、基底がAかBってことだから無理っしょ
しかもAは書き換えられないときてる

すでに言われてるようにテンプレートで基底を指定させるか単純に空のA_funcを書くか、プリプロセッサか

でもそもそも利用者側がAを使うのかBを使うのか決めるのなら、クラス側で対処せずに利用者がプリプロセッサで分けた方がいいと思う(でないとぐちゃぐちゃになりそう)

それだと修正箇所が多すぎるのかもしれんけど
2019/10/03(木) 13:00:06.78ID:t4NBMq8s
こんなマトモじゃないケースに
ベストな解答なんかないわな
287デフォルトの名無しさん
垢版 |
2019/10/03(木) 13:00:33.56ID:YSTER/9m
>>284
Qtをdisってんの
2019/10/03(木) 15:51:04.04ID:z1c5xmGq
まさかと思うがQtを盲信してるのか?w
289デフォルトの名無しさん
垢版 |
2019/10/03(木) 16:04:15.58ID:LjcEi/T6
ちょとっ猛進
2019/10/03(木) 16:37:32.38ID:vAL7lUst
回答ありがとうございます
プリプロセッサまみれになるより空の関数生やした方が見通しよさそうですね
2019/10/03(木) 18:04:25.67ID:SL8wP/0a
>>288
え、qt便利じゃん
2019/10/03(木) 19:00:51.01ID:BEqWQnsI
旧版は知らんけどQt5はかなり良いと思う
不満に思うのはベンチ厨くらいでは
2019/10/03(木) 19:22:01.27ID:z1c5xmGq
>>291
便利かどうかなんて言ってないのにいきなりどうした?w
2019/10/03(木) 21:53:13.09ID:Uq6PP8Ux
コンパイル通らないので助けてください。
メンバテンプレートを持つクラスを継承して、派生先からメソッドが呼べません。
一見問題なさそうにはみえるのですが・・・

template<typename _T1>
class A{

public :

template<typename _T2> _T2 get() { return _T2(); };

};

template<typename _T3>
class B : public A<_T3> {
std::string hogehoge() { return A<_T3>::get<std::string>();}
};
2019/10/03(木) 21:59:37.34ID:A/fPHEZe
>>294 エラーメッセージとか出てないの?
2019/10/03(木) 22:06:09.67ID:BrhogHgJ
>>294
clangさんが教えてくれた
std::string hogehoge() { return A<_T3>::template get<std::string>();}
2019/10/03(木) 22:13:42.78ID:Uq6PP8Ux
ありがとうございました。
通りました。

つか、そんなtemplate文の使い方初めて知った・・
2019/10/03(木) 22:31:15.90ID:zkquM/gX
この場合Aがテンプレートなので、Aの先のgetが何者かコンパイラは判断つかないので
"<" が比較演算なのかテンプレートのかっこなのか判断つかないから
らしい
clangは教えてくれるんだから判断ついてるわけだが・・・
まったく醜い文法を持った言語だよ
2019/10/03(木) 22:49:50.59ID:BrhogHgJ
この場合のエラーメッセージ、GCCはほんとに何言ってるのか分からないのを出すのでclang様様
2019/10/04(金) 01:11:35.70ID:gSpEwnzq
C++テンプレートのプログラミングでのエラーを読み解く訓練をしているうちに
実世界での初心者が投げてくる質問へのエスパー力がやしなわれる
これ豆
2019/10/04(金) 02:30:32.92ID:gpJXYiEy
そのうちエラーメッセージを見ずにエラーを修正できるようになる
2019/10/04(金) 02:54:08.89ID:P4b1n6up
ちなVC2015か2017か忘れたけど、一時期までのVCは
その場合のtemplateを書くと逆にエラーにされてた
303デフォルトの名無しさん
垢版 |
2019/10/04(金) 03:18:41.39ID:I4catYuR
goで変数用いて
*******
*****
***
*
***
*****
*******
って出力するにはどうすりゃいいのっと
304デフォルトの名無しさん
垢版 |
2019/10/04(金) 03:19:28.61ID:I4catYuR
あ、↑のは砂時計みたいな形にしたい
2019/10/04(金) 04:12:53.14ID:NaWoGk/Z
>>303
二重のループか仮想画面
2019/10/04(金) 04:19:18.14ID:I4catYuR
>>305
申し訳ないが初心者ゆえ、数字の二重ループはできるけどそれを文字列にする仕方がわからず
2019/10/04(金) 05:45:45.52ID:jwb6jSs+
goスレ行け
2019/10/04(金) 08:20:48.47ID:FzFdUbJu
>>298
なぜか偶然ですが、このスレを見る前から昨日からその辺に関係するパーサーを
作っていて悩んでいたところなんですが、
多くの言語では、+,-,*,/,<,> などの演算子が混ざったいわゆる「数式」は文脈に依存せずに
上位のコンパイル作業に入る前に、いったん「数式ツリー」に直すことが出来ます。
ここで「文脈に依存せず」というのは、変数名、関数名、型名などの宣言情報を
調べなくても済むという(いわゆる意味解析の結果の情報を必要としないと言う
)ことです。
ところが、template機能が入った後のC++では、A<B と書いたとき、
< がテンプレートの記号なのか比較演算子なのかは A がテンプレート名であるか
どうかによって決まります。
Bが型名であることが明確な場合には文脈によらず < はテンプレート記号だと断定
できます。ところが、Bに 1, 456, 3.1415 のような数値や、"Hello" などの文字列
が来ている場合には、(その場では)判断が付きません。
文脈に依存せずに判断を付けたいなら、もっと先まで呼んで、< に対応する >
があるかどうかを調べるといける可能性があります。

1. "<"に対応する">"が存在するかどうか調べれば、これまでの宣言情報を使わなくても
 トークン・ツリーを作ることが出来る。トークン・ツリーと言ったのは、数式とは
 限らないからです。例えば、A<B> x[100]; などとすることがありますが、A<B>
 は型名であり、数式では有りません。ただし、他の多くの言語では数式ツリーは
 作ることが多いのですが、トークン・ツリーはまず作りません。
2. 1の方法を使わないなら、宣言情報を調べて、Aがtemplate名であるかどうかを調べる
 必要がある。ところが、Q::A<B> などのような場合があるので、そんなに
 単純な作業でく、Q::A が型名なのか、変数名なのかはちゃんと調べる必要がある。
2019/10/04(金) 08:25:56.64ID:FzFdUbJu
>>308
補足
「Bが型名であることが明確な場合には文脈によらず < はテンプレート記号だと断定
できます。」
の部分ですが、B<CPerson(実引数列) などとした場合、CPersonは型名ですが、
CPerson(実引数列) 全体は、型名ではなくCPersonクラスの引数つき
コンストラクタを呼び出した結果の「一時オブジェクト」です。なので、
Bが変数名の場合は、< は比較演算子の可能性があります。
2019/10/04(金) 08:33:37.62ID:FzFdUbJu
>>308
誤:なぜか偶然ですが、このスレを見る前から昨日からその辺に関係するパーサーを
正:なぜか偶然ですが、このスレを見る前の昨日からその辺に関係するパーサーを

誤:文脈に依存せずに判断を付けたいなら、もっと先まで呼んで、< に対応する >
正:文脈に依存せずに判断を付けたいなら、もっと先まで読んで、< に対応する >

誤:単純な作業でく、Q::A が型名なのか、変数名なのかはちゃんと調べる必要がある。
正:単純な作業ではなく、Q::A がtemplate名なのか、変数名なのかはちゃんと調べる必要がある。
2019/10/04(金) 08:37:14.54ID:P4b1n6up
>>225
>>224=228や>>226=219みたいなどうみても初心者なヤツにプロが敬語使う必要ないと思うよ
C++スゲー=俺スゲーみたいな明らかにプログラミングに向いてない精神構造のクソバカが多く居るからねここ
2019/10/04(金) 08:41:34.48ID:FzFdUbJu
>>306
一般論として、文字列の長さを len として、文字列型の変数を str としたとき、
for ( len 回のループ ) {
 str = str + "*"
}
で行けます。
2019/10/04(金) 09:33:34.23ID:8yIxxMU3
>>311
ようクソバカ
2019/10/04(金) 09:41:54.97ID:P4b1n6up
>>313
すまんな図星だったか?
邪魔だから出てけよ
2019/10/04(金) 11:43:51.24ID:FzFdUbJu
>>308
C++言語をパースする方法として、結論的には、2.ではダメで、1.でなくてはならないようです。例として、A<実引数列>::B の場合を考えると、template は実体化する
際の実引数によって展開される内容は大幅に変わりますので、
A<int>::B とした場合には、B は template 名で、
A<string>::B とした場合には、B は変数名であることもありえます。すると、
A<int>::B<C> の場合の B<C> は template 実体化ですが、
A<string>::B < C の場合は、変数B と変数 Cに対しての比較演算となります。
なので、もし、>>308 の 2.のやり方でパース使用とすると、Aがtemplate名であると
分かっただけでは B が「何なのか」を結論付けるには不十分で、A<実引数列>の
実引数列をほとんど完全に調べ上げてから、その方名に応じた template A の
定義を探して template の overload 解決をしてから、A<実引数列> 部分(のclass)を
完全に「特定」する必要があります。ここまでやるとなると、コンパイラの層分けが
上手く出来ないことになります。
2019/10/04(金) 12:03:58.19ID:FzFdUbJu
>>315
A::B くらいの場合なら、意味解析の情報だけを元に、Bが何なのかを特定をすることは
可能です。ところが、A<1+2,decltype(x*y)>::B の様な場合、x, y の意味論的な型
を調べた後、x*yに適応可能な operator*() 関数が定義されて言うかどうかも調べ、
定義されていれば、その戻り値の型を調べてx*y の型として、A<・・・> の部分が
結局何なのかを特定しなくてはなりません。今述べた x*y の部分の処理は、
トークン解析層(?)より上位のコンパイル層で行う処理です。なのでこのやり方
だと、コンパイラ内部の「層」の切り分けが難しくなります(技術的に不可能な
わけではありませんが。)。
2019/10/04(金) 12:07:27.45ID:FzFdUbJu
>>315
誤:なので、もし、>>308 の 2.のやり方でパース使用とすると、Aがtemplate名であると
正:なので、もし、>>308 の 2.のやり方でパースしようとすると、Aがtemplate名であると

誤:実引数列をほとんど完全に調べ上げてから、その方名に応じた template A の
正:実引数列をほとんど完全に調べ上げてから、その型名に応じた template A の

>>316
誤:を調べた後、x*yに適応可能な operator*() 関数が定義されて言うかどうかも調べ、
正:を調べた後、x*yに適応可能な operator*() 関数が定義されているかどうかも調べ、
2019/10/04(金) 12:36:35.66ID:cK/f4a5x
>>312
ありがとうございます!
やってみます
2019/10/04(金) 12:41:17.15ID:G1/ISgxb
c++って文法に曖昧さがないことどうやって保証してんだろ
形式的なアプローチ無理だと思うんだが
2019/10/04(金) 13:05:22.64ID:MVQV/kgg
いや、そんな保証は端っから諦めてるだろ
引数なしの関数宣言とデフォコン呼び出しの曖昧さなんか
長年放置してたのをC++11でようやく対応したし
関数ポインタにキャストするoperatorはtypedef使えとか
言語としての完全性なんか重視してない
2019/10/04(金) 13:28:40.80ID:FzFdUbJu
>>319
曖昧さはあるといわれています。例えば、CPersonというクラスがあったとき、関数内で
CPerson person();
と書いた場合、person という名前で、戻り値の型が CPerson の関数のプロトタイプ宣言なのか、
CPerson クラスの person という変数名(オブジェクト名)の定義なのかの曖昧さがあります。
後者は、CPerson person("name", 25, MALE); などと同じ系統で、実引数が全く無い場合
に相当します。
また、template class の場合に、
A<B<・・・>>
と書くと、>> が右シフト演算子に解釈されてしまうので、回避するために空白を1つ入れて
A<B<・・・> >
としなければならなかった(過去形)時代も有ります。
しかし、パーサーを作る側からすれば、">>" を ">" 2個 だと解釈するのはかなり大変な
労力が必要でです。

また、x < y を比較演算のつもりで A< x < y > などと書くと、A<・・・>
の中に x という template class 名に対しての x<y> が入っていると解釈
されてしまい、> が足りないというエラーになるかもしれません。
回避するには、
A< (x < y) >
と書くと良いと思われます。
2019/10/04(金) 14:48:30.02ID:D8qarNFk
C++というより3Dプログラミングの質問で申し訳ないのだけど、
行列ライブラリglmの以下のコードがbugってる気がするので詳しい人がいたら確認して欲しい。

template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER qua<T, Q> rotate(qua<T, Q> const& q, T const& angle, vec<3, T, Q> const& v)
{
vec<3, T, Q> Tmp = v;

// Axis of rotation must be normalised
T len = glm::length(Tmp);
if(abs(len - static_cast<T>(1)) > static_cast<T>(0.001))
{
T oneOverLen = static_cast<T>(1) / len;
Tmp.x *= oneOverLen;
Tmp.y *= oneOverLen;
Tmp.z *= oneOverLen;
}

T const AngleRad(angle);
T const Sin = sin(AngleRad * static_cast<T>(0.5));

return q * qua<T, Q>(cos(AngleRad * static_cast<T>(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin);
}

クオータニオンqをベクタ軸v周りにAngleRad回転させる関数のソースらしいんだが、
最後の行掛け算の順番が逆のような気がする。
qua<T,Q>(...) * qが正解だと思うんだ。

glmはファイル構成がバージョン間で結構派手に変更されてるんで、
最近のバージョンではext/quaternion_transform.inlに上のコードが含まれてる。
古いバージョンではgtx/quaternion.inlにあったような気がする。
2019/10/04(金) 14:55:11.92ID:FzFdUbJu
>>322
あるライブラリでのq1 * q2 という書き方が、q2 * q1
がどういう意味に解釈されるかは、
2019/10/04(金) 15:01:05.28ID:FzFdUbJu
>>322
(>>323 は誤投です。)
あるライブラリでの q1 * q2 という書き方が、別のライブラリでは
q2 * q1 と等価なことが有り得て、それはベクトルや行列計算全般に
言える記法の違いなのでこのソースだけではなんとも言えない。
ベクトルの場合、成分表示を1列の縦行列と考えるか1行の横行列
と考えるかによって、賭け全の左右が逆さまになる。
その結果、成分表示で書かない表記も、左右どちらかで書くかは
好みの問題となる。
特に Quaternion の場合も同様。
2019/10/04(金) 15:02:02.33ID:FzFdUbJu
>>324
誤:と考えるかによって、賭け全の左右が逆さまになる。
正:と考えるかによって、掛け算の左右が逆さまになる。
2019/10/04(金) 15:45:42.88ID:P4b1n6up
OpenGL系は縦ベクトルだね
D3Dを前提にしたライブラリとは逆になる(行列も転置
2019/10/04(金) 15:58:00.91ID:FzFdUbJu
>>326
数学や物理学では縦ベクトルが多いが、D3Dはそれに従ってない。
328デフォルトの名無しさん
垢版 |
2019/10/04(金) 16:08:07.51ID:JXWhYfPM
テンプレが糞だと思う瞬間はいくつもあるが
その一つはネストしてるときの閉じ括弧
>> じゃだめで > > ってわざわざ分けないといかんうざい
2019/10/04(金) 16:08:35.30ID:P4b1n6up
>数学や物理学では縦ベクトルが多いが、D3Dはそれに従ってない。
みたいだね
D3Dからそれ以外に移るとみんなここで引っかかるけど
実は行列周りは(大文字は行列として)
OpenGLに合わせるとA*B*C*xとなるのを
D3Dではx*C*B*Aと書けた方が、左からの計算が全部結果がベクトルなので計算量が減るというメリットはある
MSはC++での書きやすさと効率を考えたのかもしれない
330デフォルトの名無しさん
垢版 |
2019/10/04(金) 16:09:02.58ID:JXWhYfPM
>>326-327
縦横ってより右から掛けるか左から掛けるかだと思ってた
意味は一緒なんだろうけど
2019/10/04(金) 16:11:58.82ID:P4b1n6up
>>328
C++11からは連続して書けるようになったで
2019/10/04(金) 16:14:31.61ID:MVQV/kgg
C++03いやC++98?のまま更新止まってるやつ
俺が想像するより遙かに多いのかもしかして

もうC++11でさえ要注意な旧規格になってるんだが
333デフォルトの名無しさん
垢版 |
2019/10/04(金) 16:16:30.52ID:JXWhYfPM
>>329
メモリ上の順序も変わるぞ
SIMDとかで計算されるときの効率にも影響する
必ずしもD3D(横ベクトル方式)が高速化に都合が良いとは言えないんじゃないか

行列の各要素のメモリ上の並びって
glの行列AとD3Dの行列A'はいちいち転置しなくても結局同じになるんだっけ
2019/10/04(金) 16:22:07.03ID:P4b1n6up
ああ確かにメモリの中身は同じだった
格納方式も違うから結果的に同じになるんだよね
そこが余計ややこしい
2019/10/04(金) 16:29:39.34ID:FzFdUbJu
>>329
行列計算は、縦ベクトル方式、横ベクトル方式でも、(それぞれで)「結合則」があるので、
A*B*C*x = A*(B*(C*x))
でもあり、
A*B*C*x = ((A*B)*C)*x)
でもあり、どっちで計算しても結果は同じになる。

また、3D計算の場合、点の座標がいくつあっても、行列を一度計算しておくと、
使いまわしできるので、先に行列の方を計算しておいて、最後に座標の変換
を行うと、点が2個以上あるときには効率が高い。
2019/10/04(金) 16:31:49.50ID:FzFdUbJu
>>332
C++98くらいから、実際問題上使いたくない機能ばかりが追加されるような
傾向があったのに、Upgrade 版は適用外になったりしたりして買う機を逃した。
2019/10/04(金) 16:38:53.10ID:FzFdUbJu
>>329
>MSはC++での書きやすさと効率を考えたのかもしれない
>>335 に既に書いたけど、OpenGL 形式でも、右結合でも、
左結合でも、好きな方で計算は出来る。だから、行列部分を
先に計算しても良いし、座標部分から計算しても良い。
座標部分から計算していくと一見計算量が減るように思える
かも知れないが、点の個数が多くなると、一度だけ行列部分の
積を予め計算しておいて、その結果を全ての点の変換部分に
遣うと効率が劇的に向上するので、むしろ、効率が良いのは逆。
2019/10/04(金) 16:40:53.55ID:P4b1n6up
>>335
確かに(OpenGLでも上で書いたような式が使えるライブラリ使うとして)括弧でくくったりして優先順位変えればいいし
言う通り行列はまとめればいいんだけど
どちらにもメリットデメリットあると言いたかった
2019/10/04(金) 16:51:20.07ID:FzFdUbJu
>>338
実は、アメリカで有名な 3D Graphics の本が、横ベクトル方式を採用していた
事が関係しているかもしれない。要はその本が数学や物理の標準とは何故か
逆の記法を採用していたということ。
340デフォルトの名無しさん
垢版 |
2019/10/04(金) 17:00:49.77ID:FW+Y/3wm
>>337
GL
(A*B*C)*(x0(縦),x1(縦),x2(縦),x3(縦), ... , xN(縦))(横)
D3D
(x0(横),x1(横),x2(横),x3(横), ... , xN(横))(縦)*(C*B*A)
が最速やね
2019/10/04(金) 19:54:25.76ID:5CiM54x6
>>335
行列って結合則は約束されてましたっけ?
2019/10/04(金) 20:17:27.71ID:gZky9oRw
当たり前だろ。
そんなレベルの知識しかないからフォントライブラリ書けないんだよ
2019/10/04(金) 20:27:59.81ID:5CiM54x6
>>342
では証明してください(キリッ)
2019/10/04(金) 21:24:32.75ID:FzFdUbJu
>>343
ベクトル部分はおいておくとして、まず正方行列の部分だけに限定すれば
A(BC)=(AB)C  ・・・(1)
が証明できれば どんな場合でも結合側が成り立つことが数学的帰納法で
証明できます。なので、A,B,C が正方行列の時に(1)を証明すれば全体の証明が
ほぼ終わります。
【(1)の証明】
行列の積の定義により
 (AB)ij=Σ_{k=1}^n A_{ik} B_{kj}  ・・・(2)
です。なので、
{(AB)C}mn = Σ_l(AB)_{ml}C_{ln}
     = Σ_k Σ_l A_{mk} B_{kl} C_{ln} ・・・(3)
です。全く同様に、
{A(BC)}mn = Σ_k A_{mk} (BC)_{kn}
     = Σ_k A_{mk} Σ_l B_{kl} C_{ln}
     = Σ_k Σ_l A_{mk} B_{kl} C_{ln} ・・・(4)
となり、(3), (4) が一致することから、
 {A(BC)}mn = {(AB)C}mn
が言えます。これが (1) に他なりません。    (Q.E.D)

次に、このように3つの行列の場合ではなく、一般の個数の行列の場合、
最初に書いたように数学的帰納法を使います。それは、あなた自身で
お考えください。考える力の練習になります。
2019/10/04(金) 22:10:52.87ID:cDY60lSZ
doubleの値を++aした時にaの値は+1と規定されてる?
2019/10/04(金) 23:19:26.96ID:FzFdUbJu
>>345
boolen型以外では、++x は正確に x+=1 と等価です。
x+=1 は、正確に x = x + 1 と等価です。x がポインタ型の場合は、
BYTE 単位で見ると object size 単位で増加しますが、double/float/int/short/char
などの「算術型」の場合は、単純に 1 が足されるだけです。


https://en.cppreference.com/w/cpp/language/operator_incdec
For non-boolean operands, the expression ++x is exactly equivalent to x += 1, and the expression --x is exactly equivalent to x -= 1, that is, the prefix increment or decrement is an lvalue expression that identifies the modified operand.
347デフォルトの名無しさん
垢版 |
2019/10/04(金) 23:36:52.32ID:NJj/Utu/
>>346
ありがとうございます。
という事はキャストの時におかしくなっているのかな?

aの値は0.0〜100.0程度
for(double i = a; i < 1000.0; ++i){
std::cout << (int)i << "," << std::endl;
}
期待している結果: 1,2,3,4,5...と連番になる
たまに起こる結果: 1,2,3,5,6...と歯抜けになる
2019/10/04(金) 23:42:33.92ID:8yIxxMU3
丸められただけでは
2019/10/04(金) 23:55:23.10ID:YWySipM2
>>341-344
また5ch名物のしょーもない煽り煽られの流れかとおもったら
ちゃんと勉強になる流れでワロタ
2019/10/05(土) 00:03:15.79ID:bnoeYdBm
行列の結合則なんて高校で習っただろ
線形代数わからないプログラマって生き残れないと思うわ
2019/10/05(土) 00:05:26.41ID:KADe2ROY
>>347
・そのコードは、完全に上記の通りですか?

例えば、ループ回数が1000回より遥かに多くなると、
誤差の都合でそうなることがあるかもしれませんが、1000回くらい
だと、正しい処理系ではその現象は起きないはずです。
2019/10/05(土) 01:17:38.13ID:d5aP5JOP
キャストする前にlround呼んだらええんちゃうん。
2019/10/05(土) 01:44:04.24ID:VkhEKreX
(0.2+0.3)+0.4 == 0.2+(0.3+0.4)の結果がfalseになるのは正しいの?
2019/10/05(土) 01:54:00.97ID:Lbi5NeET
浮動小数点を勉強しておいで
2019/10/05(土) 02:07:17.64ID:5hJZ4CgN
有効数字1桁の計算で誤差は生じない
2019/10/05(土) 07:04:22.03ID:UfPJq4d2
10進の0.1を2進表現すると循環小数定期

>>355
バカ乙
2019/10/05(土) 08:03:13.32ID:9T2eUTn8
>>336
本当、人って色々だな
俺はC++98は未完成感があまりに強くて続きはまだかと待ちかねていた
具体的には例えば右辺値参照だ
一時オブジェクトにいちいちconstがつくのがイヤでイヤで待望のやつがやっと来た
2019/10/05(土) 08:28:45.86ID:iS4eZEWC
>>337, >>340
ちょっと誤解招くのでやっぱ突っ込んでおくけど、
多数のベクトルを変換するのに行列をまとめておかないと無駄になるのはどっちの方式でも同じだよ
俺が言ったのは(少なくとも同一の行列が)一度限りしか出てこない場合の話
まぁそれを最適化する必要があるのか、またそういう処理を大量にループするなら最適化の方法は他にあるだろうけど
>>333
GL方式でも列優先だから結局d3dと同じ無駄はあるんやで
最近のは知らんけど
2019/10/05(土) 08:49:33.11ID:KADe2ROY
>>353
計算誤差です。
(0.2+0.3)+0.4 == 0.2+(0.3+0.4) が偽になっても
(0.2+0.3)+0.4 == (0.2+0.3)+0.4 や
0.2+(0.3+0.4) == 0.2+(0.3+0.4)
は必ず真になることが保障されています。
2019/10/05(土) 08:55:38.66ID:KADe2ROY
>>359
コンピュータにおける浮動小数点は、内部表現は10進数ではなく2進数
で表現されており、有効桁数は 10 進数で 8 桁や 15桁などではなく
2進数で xx BIT という風になっています。
0.2, 0.3, 0.4 は、10進数だと、有効桁数が1桁でも完全に区切れが
よく表現できていますが、2進数の表現だと厳密には無限小数になってしまい、
どんなに有効桁数を長くしても厳密には表現できません。そのため計算誤差
が生じるのです。0.5 や 0.25 や 0.125 は 2 進数でも区切れ良く表現できるため、
 (0.125+0.25)+0.5 == 0.125+(0.25+0.5)
は誤差が生じることがないため、必ず真になるはずです。
2019/10/05(土) 10:06:32.18ID:e1uvrqu3
>>360
浮動小数の計算誤差を考慮して比較する時にstd::abs(a-b) < std::numeric_limit<double>::epsilon()というふうにするのはどう思う?
2019/10/05(土) 11:34:20.93ID:KADe2ROY
>>361
誤差の量が計算の順序や書き方によって変わってくるので、
そのようなヘッダに書かれているような誤差定数を使うことは
余り意味がありません。
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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