質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

6回答

2134閲覧

(どの言語にもいえる)プログラムについて質問です

TestMen

総合スコア1

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2020/08/13 12:19

例としてUnityのShader風に記載します。

float a = "変数" + 0.5;
return a * a;

のようなものがあった場合、以下と結果は変わらないと思いますが、

return ("変数"+0.5) * ("変数"+0.5);

負荷的には、前者のほうが軽いのでしょうか。わからないでいるのは、"a"には計算結果だけが格納されるのか、計算式そのものが格納されているのか、です。
「計算結果」だけが格納されているのであれば前者のほうが軽いと思いますし、「計算式」が格納されていてaを使うと中身が展開されるような形なら両者とも負荷は変わらないと思うんです。どっちなのでしょうか

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/08/13 12:35 編集

C# の場合は型が float なので計算結果が代入されます。Func<float> なら計算式が代入されます。 Unity もオブジェクト指向も関係ありません。 言語によって違うことがあるので、このような質問をする場合は言語を決めてください。でないと回答がブレます。
guest

回答6

0

解決済みですが、質問文に「(どの言語にもいえる)」と書いてあるので、C#以外の言語について補足しておきたいと思います。

この回答には、参照透過など関数型プログラミングの用語や最適化にまつわる定数式などの用語が含まれているため、理解にはある程度の知識が必要なことをあらかじめご了承ください。


まず、言語によって式の評価の仕方、および、最適化の仕方はかなり異なります。ですので、C#での動作がどの言語でも同じとは言えません。

まず、Haskellのような純粋関数型言語の場合、遅延評価という動作になります。

Haskell

1a = x + 0.5 2b = a * a 3x = 0.1 4 5main = print b

a = x + 0.5の時点でaがどんな式の結果なのかが定義されるだけで、評価されません。そもそもxが不明なので評価できません。続くbでも評価はされません。最後のmainbの評価値が必要となって、bの定義の式を評価しようとします。さらにaの評価値が必要となって、aの定義の式を評価しようとします。aではxがちゃんと定義されていますので、0.6が評価値になるでしょう。最初のaはこれで定まったのでbの定義の評価の続きをしようと2盤面のaを評価しようとします。このとき、aの定義の式を再度評価するのかというと、aは参照透過であるため、再度評価しても結果は同じなので、ほとんどの場合はキャッシュが使われます(キャッシュが使われるかどうかは実行環境の実装次第なので、必ず使われるわけはありません)。

つまり、遅延評価が前提のような場合は、aの結果ではなくaの式がそこに置かれているとみなすことができます。言わば、質問の前者と後者はあまり違いが無いと言うことです。これは、C#のような正格評価の言語とは全く異なることに注意してください。

次に最適化についてです。

先程のHaskellの例ではaは参照透過と言いましたが、このように参照透過であることが保証されていれば、キャシュを使う、または、2回計算しないような処理に最適化される場合があります。これは変数に入れた場合に限りません。質問の後者の場合であっても、("変数"+0.5)が参照透過であれば、二つ目の式は一つ目の式の結果を使う場合があると言うことです。

この、参照透過であるというのはかなり複雑です。"変数"がどうなっているかによって違います。例えばobj.nameと言ったプロパティアクセスの場合、C#では参照透過ではない可能性がある(プロパティの読み込みアクセスは副作用ありにできる)ため、処理のキャッシュを使うと言うことができません。優秀なコンパイラやJITエンジンはこれらを自動的に判別して、「どちらであっても確実に結果がわからない」場合のみキャッシュを使用するような動作になります。

最適化はまだあります。前者で使われた変数aですが、その変数が他の場所で使われていない場合は、変数がなかったかのように処理される場合があります。つまり、変数ようにメモリが確保されるわけではなく、aを計算した結果がレジスタにあるうちにそのままa * aを求めると言うことです。C/C++での最適化では度々この処理が行われます。(他で使われた瞬間に最適化から外れるので、確認するのは難しいです。)

最適化についてもう一つです。それは定数式です。もし、"変数"部分が定数式なら、aは定数式でしょう。そうなるとa * aも定数式です。言語やコンパイラによって異なりますが、定数式の場合、コンパイル時にその値に置き換わります。実行時に計算しても常に結果が同じだから、コンパイル時に計算して置き換えておこうという物です。この場合、前者も後者もコンパイル後は一つの「値」に置き換わっているため、全く同じ動作になるでしょう。


プログラミング言語は似たような言語では同じような動作をすることも多いですが、細部を見ると千差万別です。他の方はC#を念頭に回答していると思われますが、C#以外の言語でも全く同じになるとは限らないと言うことだけが、伝わっていれば幸いです。

投稿2020/08/14 02:46

編集2020/08/14 02:47
raccy

総合スコア21739

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2020/08/14 11:38

> 他の方はC#を念頭に回答している タグに C# とありますので。
guest

0

"変数" とはなんでしょうか? メソッド内での変数? それとも外部定義? それによっても(若干)異なると思いますが、、

aは、floatとして宣言されているので、式ではなく、値(計算結果)が格納されます。(少なくとも、C#とかでは)
ただ、どちらが実際の処理として軽い(速い)かは、単純には分かりません。最近のコンパイラは、最適化が行われるので、コンパイルした結果で見る必要があります。
(まあ、一旦、 aに結果を格納した方が速いとは思いますが)

なお、"変数"が外部定義で、マルチタスクとかで参照されている場合、結果が異なる事があるので注意が必要。

投稿2020/08/13 12:32

pepperleaf

総合スコア6385

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こういう形式で書かれる機能であれば、値が保存されます。

計算負荷としては最適化されて両者同一というケースもあれば、同一でないケースもあります。

値でなく処理自体を変数に代入して、後でその処理を呼び出して実行するという機能を備えた言語も多いです。が、質問文のコードのような書き方にはならないです。

投稿2020/08/13 12:30

otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

この程度の違いならばコンパイル時に自動修正されるでしょう。

インタプリタ言語だとすればケースバイケースです。

投稿2020/08/13 12:40

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/08/13 12:42

C# ではされませんでした。
HogeAnimalLover

2020/08/14 12:06

お。そうでしたか、それは失礼しました。ただ、いずれにしてもこの程度では「どちらのほうが優れているか」という議論はできないと思います。
guest

0

ベストアンサー

a には計算結果が格納されます

最初の例では、足し算一回と、掛け算一回(と変数の代入一回)の動作ですが、
あとの例では、足し算2回と掛け算一回の動作となります

まあ、最近のCPUでは、計算1回より、メモリ(変数)のアクセスのほうが実行時間がかかる事が多いため、どちらかと言うとあとのほうが軽くなったりしますね

投稿2020/08/13 12:28

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/08/13 12:47

重い軽いの差は出ないと思います。誤差の方が大きいでしょう。差が出るほど変数を使うならどのみちメモリを使います。
guest

0

言語の実装によって異なりますが計算式が格納される場合はほとんどないと思われます。
CベースのUnityの場合には
aはfloatのデータが入る領域をメモリ上に確保し、
右辺の式の結果をその領域に書き込んでいます。
そのため、式が書き込まれるわけではなく、値が書き込まれていると考えられます。
そのため、どちらが軽いかという疑問に関しましては質問者様のお考え通り、
計算回数が一度で済む、前者という事になるかと思われます。

投稿2020/08/13 12:26

shibukazu

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問