我正在使用Delphi 7,现在FloatToStr(64)
返回
64,0000017441
在使用Direct3D代码的同一进程中加载不同的模块时。
返回值为
64
正如预期的那样,当其他模块在此过程中未处于活动状态时。
为什么FloatToStr()的输出会根据执行的其他不相关代码而改变,以及如何始终获得浮点值的可靠且一致的字符串表示形式?
FloatToStr()的行为差异可以在以下示例代码中看到:
{$APPTYPE CONSOLE}
program Project1;
uses
SysUtils;
begin
Writeln('FloatToStr(64) = ', FloatToStr(64));
Set8087CW(Get8087CW and $FCFF);
Writeln('FloatToStr(64) = ', FloatToStr(64));
end.
答案 0 :(得分:5)
提供一个简单的控制台应用程序,复制您所看到的行为,以及更详细的解释:
{$APPTYPE CONSOLE}
program Project1;
uses
SysUtils;
begin
Set8087CW(Get8087CW and $FCFF);
Writeln('FloatToStr(64) = ', FloatToStr(64));
end.
输出:
FloatToStr(64) = 64.000001744411
单步执行调试器,将64
转换为十进制表示的代码最终调用
function _Pow10(val: Extended; Power: Integer): Extended;
使用val = 64
,Power = 16
来计算64 * 10**16
。然后将其转换为整数640000000000000000
,从中提取十进制数字,并在其中放置小数点。这在默认的FPU模式下会很好,它会精确地生成640000000000000000
,但是在这里使用的FPU模式中,可用的精度较低,表示该数字的精度不够。它会向上舍入到最接近的可表示数字,并且后续的正确提取小数的代码会看到最后的数字不是 0
。
此问题是2004年未解决的QC报告的主题:QC#7275。
答案 1 :(得分:4)
在外国插件代码中,在" display.cpp"在代码中
hr = d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_NOWINDOWCHANGES | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,
&d3dpp, &d3ddev );
添加标志" D3DCREATE_FPU_PRESERVE"所以代码是:
hr = d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_NOWINDOWCHANGES | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
&d3dpp, &d3ddev );
如果省略此代码,Direct 3D会更改FPU用于当前线程的精度,您将看到不太精确的值。
另见http://blogs.msdn.com/b/tmiller/archive/2004/06/01/145596.aspx
备选方案(当您无法或不想更改其他插件代码时)是在显示浮点值时使用显式格式化。
使用
s:= FormatFloat('0.##', x);
而不是
s:= FloatToStr(X);
这将始终将值四舍五入到小数点后两位,并且在小数点分隔符后不显示尾随零。当两个最高位数为0时,它不会显示任何小数分隔符。
另一种方法是让你的代码在一个单独的线程中运行,因为FPU精度设置是每个线程。
另一种选择是执行
Reset8087CW;
在调用FloatToStr()之前,在代码中。但是,这可能会使Direct3D混乱并在那里产生错误。