[英]Floating Point Representation in Debugger in C vs C++(CLI)
一點背景 :我正在使用C++/CLI
中間層進行從C
到C#
的一些數據轉換,我注意到調試器顯示floats
和doubles
的方式的特殊性,具體取決於代碼執行的dll(參見代碼)和圖片如下)。 起初我認為它與托管/非托管差異有關,但后來我意識到如果我完全離開C#
層並且只使用非托管數據類型,則表現出相同的行為。
測試用例 :為了進一步探討這個問題,我創建了一個獨立的測試用例,以清楚地識別出奇怪的行為。 我假設任何可能正在測試此代碼的人都已經設置了一個有效的解決方案和dllimport
/ dllexport
/ 宏 。 我叫做DLL_EXPORT
。 如果您需要最小的工作頭文件,請告訴我。 這里的主要應用程序是C
並從C++/CLI
dll調用函數。 我使用的是Visual Studio 2015 ,兩個程序集都是32 bit
。
我有點擔心,因為我不確定這是否是我需要擔心的事情,或者它只是調試器正在做的事情(我傾向於后者)。 說實話,我對這里發生的事情完全好奇。
問題:任何人都可以解釋觀察到的行為或者至少指出我正確的方向嗎?
C - 調用函數
void floatTest()
{
float floatValC = 42.42f;
double doubleValC = 42.42;
//even if passing the address, behaviour is same as all others.
float retFloat = 42.42f;
double retDouble = 42.42;
int sizeOfFloatC = sizeof(float);
int sizeOfDoubleC = sizeof(double);
floatTestCPP(floatValC, doubleValC, &retFloat, &retDouble);
//do some dummy math to make compiler happy (i.e. no unsused variable warnings)
sizeOfFloatC = sizeOfFloatC + sizeOfDoubleC;//break point here
}
C ++ / CLI標頭
DLL_EXPORT void floatTestCPP(float floatVal, double doubleVal,
float *floatRet, double *doubleRet);
C ++ / CLI源代碼
//as you can see, there are no managed types in this function
void floatTestCPP(float floatVal, double doubleVal, float *floatRet, double *doubleRet)
{
float floatLocal = floatVal;
double doubleLocal = doubleVal;
int sizeOfFloatCPP = sizeof(float);
int sizeOfDoubleCPP = sizeof(double);
*floatRet = 42.42f;
*doubleRet = 42.42;
//do some dummy math to make compiler happy (no warnings)
floatLocal = (float)doubleLocal;//break point here
sizeOfDoubleCPP = sizeOfFloatCPP;
}
C中的調試器 - floatTest()
最后一行的floatTest()
C ++ / CLI中的調試器 - floatTestCPP()
倒數第二行的floatTestCPP()
考慮C ++ / CLI中的調試器本身不一定用C,C#或C ++編碼。
MS庫支持“R”格式 :可以往返於相同數字的字符串。 我懷疑使用了這種或g
格式。
沒有MS源代碼,以下只是一個很好的假設:
調試輸出足以區分double
與其他附近的double
。 所以代碼不需要打印"42.420000000000002"
,但"42.42"
就足夠了 - 無論使用什么格式。
作為IEEE double
42.42約為42.4200000000000017053025658242404460906982...
並且調試器當然不需要打印確切的值。
潛在; 類似的C代碼
int main(void) {
puts("12.34567890123456");
double d = 42.42;
printf("%.16g\n", nextafter(d,0));
printf("%.16g\n", d);
printf("%.17g\n", d);
printf("%.16g\n", nextafter(d,2*d));
d = 1 / 3.0f;
printf("%.9g\n", nextafterf(d,0));
printf("%.9g\n", d);
printf("%.9g\n", nextafterf(d,2*d));
d = 1 / 3.0f;
printf("%.16g\n", nextafter(d,0));
printf("%.16g\n", d);
printf("%.16g\n", nextafter(d,2*d));
}
產量
12.34567890123456
42.41999999999999
42.42
42.420000000000002 // this level of precision not needed.
42.42000000000001
0.333333313
0.333333343
0.333333373
0.3333333432674407
0.3333333432674408
0.3333333432674409
對於您的代碼,將double
轉換為具有足夠文本精度的文本並返回double
以“往返”該數字,請參閱Printf寬度說明符以保持浮點值的精度 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.