Visual Studio 2010 Part21
2022スレ立ってるけど
もうバージョンでスレ分ける意味なんてないだろ
しかもワッチョイだし VisualStudio2010のC#で作成した2つのアプリ(A,Bとする)と1つのDLL(C.dllとする)
があって、C.dll内の関数のfloatやdoubleを使った計算が、Aから呼び出した場合とBから呼び出した場合
で異なる(誤差が出る)んだけど、何が原因なんだろう?ターゲットプラットフォームの
問題かと考えてAとBをx86にそろえたけど変わらない。 AとBでDLL呼び出すための宣言が違ってるんじゃないか? >>239
早速の返信ありがとうございます。
ビンゴかもしれません!
今、条件を変えて調査中です・・ 238です。
宣言は確かに異なっていたのですが、合わせてみても結果はかわりませんでした。 誤差の出る部分を絞り込むと、math.sqrtに行き当たりました。
こんな感じです。
A:Math.sqrt(14) = 3.74165749549866
B:Math.sqrt(14) = 3.74165738677394 >>243
ほんそれ
>AとBをx86にそろえたけど
とか言ってるから x86 の DLL と x64 の DLL がありそうだし >>246
>>247
ありがとうございます。ヒントになりそうなので、こちらの方向で調べてみます。 >>246、>>247のヒントで、C.dll内にあるMath.Pow, Math.Sqrt, Math.Ceilingなど、
floatからdoubleにキャストされてしまう関数を再度floatにキャストしたり、小数部の
誤差を切り捨てるで、誤差を減らせることがわかりました。(なかったことにするとも言う)
最悪これでいきます。
AとBのアプリからC.dllの同じ関数を同じ引数で呼んでいるのに、なぜ戻り値が
異なるのかはわかっていません。そこがわかればスッキリ直せそうなのですが。 どっかで型変換しちゃってるんでしょ
面倒なことせずにABC全部doubleで統一したらいいよw どこかで型変換してしまっているんですかねぇ。。
お伝えできていませんでしたが、A、BからC.dllへ渡す引数はすべてInt型です。
C.dll内の数値計算でfloat,doubleが使われています。C.dll内で型変換を
してしまっているのなら、A,Bどちらからも条件は同じはずなのに・・
私としてはVisualStudioの設定の問題かと思ってこちらに書き込みましたが、
スレチな可能性が出てきましたので、この辺でおいとましようかと思います。 >AとBのアプリからC.dllの同じ関数を同じ引数で呼んでいる
あやCすぎる ABはこのどちらかの問題があるはず
・dllに同じ値を渡してるつもりだけど、実は異なる値を渡してる
・dllから異なる値が返ってきてるつもりだけど、実は同じ値を受け取ってから異なる値にしてしまってる
Cは小数点の計算誤差を拡大してる状態だろうからそこも修正すべきだけど、とりあえず今回の問題とは無関係
まぁABCの全ソースをうpするぐらいじゃないとわからないな(一部ソースにするとたいていそこに問題あるから全ソースじゃないとダメ) ABから完全に同一条件で同一のメソッドを呼んでいるかが最初に確認すべきことだと思うんだけど
そこを誰も聞かないのが凄いねw なにを期待してるんか知らんけど
そもそも真面目に答える義務なんて無いから
ノイズだらけの問題にまともな答えが来ると思ってる方が可笑しい 質問主です。
いいえ、皆さんの意見は参考になっています。ありがとうございます。
ソースコード全部は難しいので、現象を簡略化してみました。
C.dllに次の関数を用意し、A、Bから呼び出しました。
public static int test()
{
string tmpStr = "";
tmpStr += "Math.sqrt(2f) = " + System.Math.Sqrt(2.0f).ToString() + "\n";
tmpStr += "Math.sqrt(2d) = " + System.Math.Sqrt(2.0d).ToString() + "\n";
string tmpFileName = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "debug.txt");
System.IO.File.WriteAllText(tmpFileName, tmpStr);
return 1;
}
結果は次の通りです。
A:
Math.sqrt(2f) = 1.41421353816986
Math.sqrt(2d) = 1.41421353816986
B:
Math.sqrt(2f) = 1.4142135623731
Math.sqrt(2d) = 1.4142135623731
A、Bと引数、結果のやり取りをしていないので、無意識の型変換はされていないと思うのですが、
見逃している点があるのでしょうか。 A は import Mathf
B は import Math
というオチとか 綺麗にAがfloat、Bがdoubleになってるな
省略した部分に問題があるよ MathF、Aの結果がfloat、いろいろご助言ありがとうございます。
MathFについては、私も調べてみたのですが、.NETのVer.5から追加されており、
今使っているVS2010の.NET Ver.4では実装されていないようです。
とはいえ核心に近づいていると感じますので、同様の問題に引っかかっていないか、
調べています。 呼び出し方については、下記まで簡略化しました。
A,Bとも(BはFormAとFormBと読み替え)
namespace WindowsApplication1
{
public partial class FormA:Form
{
public FormA()
{
InitializeComponent();
tlib.tcls.test();
}
}
}
C.dllは
namespace tlib
{
public static class tcls
{
public static int test()
{
>>257と同じ
}
}
}
A、BともC.dllをソリューションエクスプローラーの「参照設定」から追加しました。 簡略した形式でいいから誰でも再現できるようにABC全ソース(プロジェクト一式)をzipでかためてどっかにうpしろって
>>262は言葉にしたら「ACとABは同じソースコードなのに結果が変わる」だからな。それはあり得ないんだよ 実は C.dll が2個あるとかは?
A と B の置き場所カレントディレクトリを一緒にして C.dll もそこに置いて確認はしたか 全ソースを準備している途中で、どこかの段階でAの結果がBと一致するようになりました。
ありがとうございます。ここまでくれば徐々にAを戻していって、自力で原因に
たどり着けそうです。皆様の助言のおかげです。 やっぱりここで言ってるのとは違って実際には「違うことやってるから違う結果が出た」だけの話だよねw
最初からそうだと思ったよ。
プロジェクトの設定にMath.Sqrtとかの結果に影響を与えるようなオプションなんて存在しないしw コンパイルオプションで常にdoubleをfloatで計算するようなのあったっけ 質問主です。
原因は、ネットから落として来たフリーのDirectX関係のライブラリでした。
このライブラリの初期化前に実行するとSystem.Math.Sqrtは正しい(doubleの)
答えを返します。回避策としてSystem.Math.Powを使えそうです。
このライブラリがSystem.Mathに影響を与えるはずがない、と思い込んでいた私が
間違っておりました。
皆様のご助言、大変助かりました。 なるほど
>フリーのDirectX関係のライブラリ
kwsk >>269
責任転嫁のために必死で考えたんだろうから、
あまり突っ込んでやるなよw 標準ライブラリの置き換えはわりとやるぞ
例えばPCのシステムタイム変更したくない/できないからkernel32のGetTimeZoneInformationの動作変えるとかさ
math.sqrtが置換できるのかは知らないけどdirectx系ならやりたくなってもおかしくない 質問主です。
ライブラリの作者の方に相談したところ、これはDirect3D 9の仕様であり、計算速度を稼ぐために
CPUの浮動小数点演算の精度をfloatに変更するのがデフォルトになっているとのことでした。
それを無効化するオプションの設定方法を教えていただき、無事解決しました。 >Direct3D 9の仕様
ほう
オプション描けよ DirectXの初期化時にD3DCREATE_FPU_PRESERVEというフラグをセットすること
により、回避できるそうです。 https://docs.microsoft.com/ja-jp/windows/win32/direct3d9/d3dcreate
Direct3D 浮動小数点演算の精度を、呼び出し元のスレッドで使用される有効桁数に設定します。
このフラグを指定しない場合、Direct3D では、次の2つの理由により、
既定で単精度のラウンドツーニアモードが使用されます。
倍精度モードでは、Direct3D のパフォーマンスが低下します。
Direct3D の部分は、浮動小数点単位の例外がマスクされることを想定しています。
これらの例外をマスク解除と、未定義の動作が発生する可能性があります。
なるほど最近のバージョンでも起こり得るのかな Dirext3D内部の設定がSystem.Mathに影響を与えるってこと?w
よく知らんがFPU自体が演算精度の設定を持ってて、
プロセス全体の演算精度がそれに影響されるってこと?
聞いたことないけどマジならヤバいねw デバッグ時にのみ環境変数を設定したいのですが
プロジェクト→プロパティ構成プロパティ→デバッグ→環境
で設定しようとしても1つしか設定出来ません
hoge1=a
hoge2=b
のようにしてもhoge1のみしか有効になりません
解決策あるでしょうか? pathを複数設定するときに複数行で書けず1行にしないといけなくて困ったことあるけど、それもだめなのかよ。なんとかしてもらいたいな
ソースコード中で#ifdef DEBUGとか使って設定したら? yotube-dlってVC2010を使ってるけど脆弱性とか大丈夫? 使っているのはexe化しているpy2exeだから、
心配なら最新のPython上で動かせばいい。