[過去ログ] Visual Studio 2008 Part 22 (314レス)
1-

このスレッドは過去ログ倉庫に格納されています。
次スレ検索 歴削→次スレ 栞削→次スレ 過去ログメニュー
188: 2018/09/15(土)17:18 ID:heijdb7v(7/7) AAS
>>183
>揚げ足取りだけどLSBを「最も価値が小さい」って直訳はいかがなものかなw
>普通に最下位ビットじゃないの?

整数の場合は、「最下位ビット」というと、本当にBITの位置が一番右にあるようなイメージもある。

一方、浮動小数点数の場合は、右にあるとかより、仮数部において、一番価値の小さいビット、というニュアンスを使えたかった。

IEEEでは、それは確かに一番右にあるビットであって、マシン語レベルの表現では、BIT0ではあるのだが。

ニュアンス的に。
189: 2018/09/15(土)17:29 ID:aC3C7hdp(2/2) AAS
>>186
それは俺も思ったけど、それならsignificandの方も複数じゃないとおかしいような...
190
(1): 2018/09/15(土)20:35 ID:UR1d6CKz(2/5) AAS
同様の症状を再現出来るようになったので上げる。
完全再現は出来てないが、使い物にはなるはず。興味がある人はよろしく。

症状:
単独で起動した場合と、IDEから起動した場合で、結果が異なる。

環境:
VS++2008ExpressEdition

再現方法:
1. 新規プロジェクトを作成。(CLRコンソールアプリケーション。オプション等は全てデフォのまま)
2. mainを以下ソースと差し替える。
3. Releaseビルドで実行する。(Debugビルドでは再現しなかったので注意)
省15
191
(14): 2018/09/15(土)20:37 ID:UR1d6CKz(3/5) AAS
ソース:
#include "stdafx.h"
#include <math.h>
using namespace System;

template<typename T> static double calc_norm_and_regulate(int num, T* r, bool regulate){ // <float> for debug.
double norm = 0;
for (int i=0;i<num;i++) norm += (double)r[i] * (double)r[i];
norm = sqrt(norm);
if (regulate) for (int i=0;i<num;i++) r[i] = (T)(r[i]/norm);
return norm;
省17
192
(1): 2018/09/15(土)20:42 ID:UR1d6CKz(4/5) AAS
オプション等(コマンドライン):(全てデフォのままのはずだが一応)
C/C++:
 /GL /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /FD /EHa /MD /Yu"stdafx.h"
/Fp"Release\test_floating_error4.pch" /Fo"Release\\" /Fd"Release\vc90.pdb"
/W3 /nologo /c /Zi /clr /TP /errorReport:prompt /FU "c:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll"
/FU "c:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll"
/FU "c:\Windows\Microsoft.NET\Framework\v2.0.50727\System.XML.dll"
リンカ:
/OUT:"MYPATH\test_floating_error4\Release\test_floating_error4.exe"
/INCREMENTAL:NO /NOLOGO /MANIFEST
省6
193: 2018/09/15(土)20:43 ID:UR1d6CKz(5/5) AAS
備考2:
なおこの方法で見える calc_norm_and_regulate 関数の『逆アセンブル』結果は
俺の環境での物とコールアドレス以外は一致していることを確認している。
一応、diff結果は以下。
8c8
< 0000000c cmp dword ptr ds:[00752E14h],0
---
> 0000000c cmp dword ptr ds:[007D2E14h],0
10c10
< 00000015 call 676F58B9
省6
194
(3): 2018/09/16(日)02:47 ID:wIV2HUNW(1/4) AAS
>>190
C++/CLR では、.Net を使っているから、起動方法が違うだけでも、
fpu control word の値や、使うCPU命令がx87 FPUなのか、SSE
なのかが違ってくる可能性があるかもしれない。

fpu control word は、main()関数に入る前の start up codeの中で
初期化される。
195
(1): 2018/09/16(日)03:19 ID:wIV2HUNW(2/4) AAS
>>191
// Release build
// 0.000000, 0x1ff68ddfb62221dd from IDE
// 0.000000, 0x1ff68ddfb62221de from command prompt

それにしても、随分小さな値だね。ちなみに、浮動小数点表示
の場合の有効数字の桁数を上げたら、どのようになる?
1.xxxe-yy
表示にして。
196
(2): 2018/09/16(日)03:40 ID:wIV2HUNW(3/4) AAS
>>191
試しに、ソースの冒頭に
#include <stdio.h>
を追加してから、

Console::Write(String::Format("{0:F6}, 0x{1:x16}\r\n",norm, *(__int64*)&norm));
の部分を、

printf( "%30.30e, 0x%016X\n", norm, *(__int64*)&norm) );

としてみるとどうなる?
197: 2018/09/16(日)03:42 ID:wIV2HUNW(4/4) AAS
>>196
誤: printf( "%30.30e, 0x%016X\n", norm, *(__int64*)&norm) );
正: printf( "%30.30e, 0x%016X\n", norm, *(__int64*)&norm );
198
(5): 2018/09/16(日)07:27 ID:SOVIz+sV(1/15) AAS
> 0x1ff68ddfb62221dd(Debug)
> 0x1ff68ddfb62221de(Release)

VS 2010 VC++ Express でも再現した
199
(1): 2018/09/16(日)07:38 ID:SOVIz+sV(2/15) AAS
↓このループを抜けたあと、すでにReleaseビルドとDebugビルドでは
 normの値に差異が発生してることが確認できた
for (int i=0;i<num;i++) norm += (double)r[i] * (double)r[i];

↓この下に(ループ内に)fprintf文を入れるだけで
 ReleaseビルドとDebugビルドが同じ実行結果になることが確認できた
norm += (double)r[i] * (double)r[i];

とりあえずまずこれだけは分かったから
低学歴知恵遅れが書いたウンココードの問題箇所を限定する
200
(8): 2018/09/16(日)07:51 ID:SOVIz+sV(3/15) AAS
AA省
201
(1): 2018/09/16(日)07:51 ID:SOVIz+sV(4/15) AAS
?-1 デフォルト設定(Release)

↓このコードの逆アセンブルコード
外部リンク:ideone.com

【実行結果】

0x0007F2C44DFFF8F2:1.1053482540585106e-308
202
(3): 2018/09/16(日)07:53 ID:SOVIz+sV(5/15) AAS
AA省
203
(2): 2018/09/16(日)08:02 ID:SOVIz+sV(6/15) AAS
?-2 デフォルト設定(Release)

↓このコードの逆アセンブルコード
外部リンク:ideone.com

【実行結果】

↓実行結果を書き込めないからこっちに書き込んどいた
外部リンク:ideone.com

0x0007F2C44DFFF8F1:1.1053482540585101e-308
204: 2018/09/16(日)08:05 ID:SOVIz+sV(7/15) AAS
?-1 最適化無効 (/Od)(Release)

※ コードは?-1(>>200)と同じ

↓このコードの逆アセンブルコード
外部リンク:ideone.com

【実行結果】

0x0007F2C44DFFF8F1:1.1053482540585101e-308
205: 2018/09/16(日)08:09 ID:SOVIz+sV(8/15) AAS
?-2 最適化無効 (/Od)(Release)

※ コードは?-2(>>202)と同じ

↓このコードの逆アセンブルコード
外部リンク:ideone.com

【実行結果】

※ ?-2(>>203)と同じ
省1
206
(1): 2018/09/16(日)08:20 ID:SOVIz+sV(9/15) AAS
?-1、?-2の逆アセンブルの出力結果を比較すると原型をとどめてないぐらいグチョグチョに違う(最適化のせいと考えられる)
?-1、?-2の逆アセンブルの出力結果を比較すると差異はほとんどない(?は両方ともまったく最適化されてないから当然)

?-1と?-1の逆アセンブルの出力結果を比較すると原型をとどめてないぐらいグチョグチョに違う(?-1のコード(>>200)ははげしくウンコ最適化されてると考えられる)
?-2と?-2の逆アセンブルの出力結果を比較すると差異はほとんどない(?-2のコード(>>202)はあまり最適化されてないと考えられる)

はっきりいって、これ以上見る気もしないしテキトーだが
ウンコみたいな最適化で演算の順序が入れ替わったせいで、誤差が発生しているものと考えられる
207: 2018/09/16(日)08:28 ID:zL1WUjLu(1/27) AAS
>>198以降、
すまん、入れ替わりになるかもしれんが後で確認する。
まず>>194その他について回答する。

>>194
SSEは /arch:SSE または /arch:SSE2 でないと出ないことになっており、勿論設定はしていない。
また、逆アセンブル結果では x87 命令のみであるのも確認している。
ただ今回の問題は、本当にReleaseビルドのバイナリを逆アセンブルしているか怪しい事だが。

>>195
小さい値なのは偶々だ。
辿って行ってそれが1回目にヒットする入力データだっただけのこと。
省10
208
(1): 2018/09/16(日)08:29 ID:zL1WUjLu(2/27) AAS
>>194
FPU control registor については何故か安定した結果を得られていない。
インラインアセンブラは以下の通りで、

#pragma unmanaged
inline void fpu_getcw(unsigned short* cw) {
__asm{
fnstcw [cw];
}
}
#pragma managed
省14
209
(3): 2018/09/16(日)08:29 ID:zL1WUjLu(3/27) AAS
>>194
直後のみに配置:
0x027F (倍精度) = Debug(IDE起動)のIDE内表示、Release(IDE起動)のIDE内表示、
0x03a5 (拡張倍精度) = Debug(IDE起動)、Release(IDE起動)、
0x3fdc (拡張倍精度) = Debug(コマンドプロンプト)、
0xf280, 0xf290, 0xf160, 0xf010等、不安定 = Release(コマンドプロンプト)

直前のみに配置:
直後のみと同じ結果。(つまり『何故か』安定している)
Release(コマンドプロンプト)は不安定なのも同じ。

直前と直後に配置:
省11
210: 2018/09/16(日)12:52 ID:haV9TZ8e(1/12) AAS
>>209
興味深い結果だ。
211
(1): 2018/09/16(日)13:21 ID:haV9TZ8e(2/12) AAS
>>209
>命令自体は rdtsc と同じで非同期に実行されている雰囲気だが、
>rdtsc命令の注意書きにある「シリアル化命令ではない」という但し書きが無く、状況は不明。
>正直、正しく読み出せているか怪しい。(あてにならない)

インラインアセンブラを使わずに、

_control87(), _controlfp() : Get and set the floating-point control word.

unsigned int _control87( unsigned int new, unsigned int mask );
unsigned int _controlfp( unsigned int new, unsigned int mask );

を使ってみたらどうなる?
212
(1): 2018/09/16(日)13:31 ID:Q5j4SiHR(1/2) AAS
win32コンソールなら結果が同じ。 もう理由は分かったのに何が問題なんだ?こんなの何の影響もないだろう。
213
(1): 2018/09/16(日)13:33 ID:zL1WUjLu(4/27) AAS
>>198
再現実験ありがとう。
しかし色々問題がある。

1. 俺は起動方法による違いについてフォーカスしているが、
 君はRelease/Debugの違いにフォーカスしている。
2. VC++2008では再現しない。(VC++2010では再現する)
3. ソース改変しすぎ。それでは意味がない。
4. >>206の結論は間違い。

まず問題なのはソースの改変だ。
ループ回数を16回と決め打ちしたことで 8*2 に展開されている。
省14
214: 2018/09/16(日)13:33 ID:zL1WUjLu(5/27) AAS
>>198
問題は、俺の環境で俺が提供したコード>>191だと、
同様に展開されないにも関わらず、『起動方法によって』結果が異なってしまう点だ。
俺の環境でのRelease/Debugの逆アセンブル結果のdiffは以下。
17c17
< 0000000c cmp dword ptr ds:[001C2E14h],0
---
> 0000000c cmp dword ptr ds:[00702E14h],0
19c19
< 00000015 call 68302BA9
省21
215: 2018/09/16(日)13:53 ID:haV9TZ8e(3/12) AAS
>>213
なるほど、全く別の2つの理由で、精度が変わっている可能性(というより多分、確実)があると。

それは以下の2つ:

1. Debug版とRelease版では、最適化の結果、x87 FPU命令の使われ方が変わる。
  x87では、メモリに書き戻さずに st(0)〜st(7)レジスタに入っている途中では、
 拡張倍精度の80BITで計算されるが、書き戻すとdoubleの場合でも64BITに丸め
 られる。なるべくメモリに書き戻さずにレジスタった方が高速なので、Release版
 では、80BITで計算される「期間」が多くなる。そのため、Debug版とRelese版では
 結果が僅かに違ってくる。

2. fpu control word が違っていて、st(0)〜st(7)に入っていても、計算が
省5
216: 2018/09/16(日)13:58 ID:haV9TZ8e(4/12) AAS
まず、
__asm{
 fnstcw [cw];
}
ではなく、_control87() を使ってみて欲しい。

インラインアセンブラは、独立した *.asm で書くより危険な場合が
あるかも知れないので。特にC関数の引数、今の場合は、「cw」を
インライン・アセンブラで用いた場合、正しいコードが出ているかどうか
は注意が必要。
217: 2018/09/16(日)14:05 ID:haV9TZ8e(5/12) AAS
>>208
よく見ると、それは、かなり複雑な事情が絡みそうなコード。
以下のようにした方が安心。なお、「cw」という短すぎる引数名
も長年のプログラミング経験からすると、インラインアセンブラでは
怖い。また、

TTTT reg,引数名

TTTT 引数名
は大丈夫でも、
TTTT reg,[引数名]
省14
1-
あと 97 レスあります
スレ情報 赤レス抽出 画像レス抽出 歴の未読スレ AAサムネイル

ぬこの手 ぬこTOP 0.039s