Delphi 当FPU控制字更改时,FloatToStr返回不精确的值

Delphi 当FPU控制字更改时,FloatToStr返回不精确的值,delphi,floating-point,Delphi,Floating Point,我正在使用Delphi7,现在FloatToStr(64)返回 640000017441 在使用Direct3D代码的同一进程中加载不同模块时 返回值为 六十四 正如预期的那样,当另一个模块在此过程中未处于活动状态时 为什么FloatToStr()的输出会根据执行的其他无关代码而改变,以及如何始终获得浮点值的可靠和一致的字符串表示形式 FloatToStr()的行为差异可以在以下示例代码中看到: {$APPTYPE CONSOLE} program Project1; uses SysUti

我正在使用Delphi7,现在
FloatToStr(64)
返回

640000017441

在使用Direct3D代码的同一进程中加载不同模块时

返回值为

六十四

正如预期的那样,当另一个模块在此过程中未处于活动状态时

为什么FloatToStr()的输出会根据执行的其他无关代码而改变,以及如何始终获得浮点值的可靠和一致的字符串表示形式

FloatToStr()的行为差异可以在以下示例代码中看到:

{$APPTYPE CONSOLE}
program Project1;
uses
  SysUtils;
begin
  Writeln('FloatToStr(64) = ', FloatToStr(64));
  Set8087CW(Get8087CW and $FCFF);
  Writeln('FloatToStr(64) = ', FloatToStr(64));
end.

在外文插件代码中,在“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对当前线程使用的精度,您将看到精度较低的值

另见

另一种选择(当您不能或不想更改其他插件代码时)是在显示浮点值时使用显式格式

使用

而不是

   s:= FloatToStr(X);
这将始终将值四舍五入到两位小数,并且在小数分隔符后不显示尾随的零。当两个最高数字为0时,它将不显示任何十进制分隔符

另一种选择是让代码在单独的线程中运行,因为FPU精度设置是每个线程的

另一种选择是执行

 Reset8087CW;

在调用FloatToStr()之前,请在代码中输入。但是,这可能会干扰Direct3D并在那里产生错误。

在外部插件代码中,在代码中的“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对当前线程使用的精度,您将看到精度较低的值

另见

另一种选择(当您不能或不想更改其他插件代码时)是在显示浮点值时使用显式格式

使用

而不是

   s:= FloatToStr(X);
这将始终将值四舍五入到两位小数,并且在小数分隔符后不显示尾随的零。当两个最高数字为0时,它将不显示任何十进制分隔符

另一种选择是让代码在单独的线程中运行,因为FPU精度设置是每个线程的

另一种选择是执行

 Reset8087CW;

在调用FloatToStr()之前,请在代码中输入。但是,这可能会弄乱Direct3D并在那里产生错误。

要提供一个简单的控制台应用程序来复制您看到的行为,并提供一些更详细的解释:

{$APPTYPE CONSOLE}
program Project1;
uses
  SysUtils;
begin
  Set8087CW(Get8087CW and $FCFF);
  Writeln('FloatToStr(64) = ', FloatToStr(64));
end.
输出:

FloatToStr(64) = 64.000001744411 使用
val=64
Power=16
计算
64*10**16
。然后将其转换为整数
640000000000000000
,从中提取十进制数字,并在其中放置小数点。在默认FPU模式下,这将很好,在默认FPU模式下,它将准确地生成
640000000000000000
,但在这里使用的FPU模式下,可用的精度较低,不足以表示该数字。它被四舍五入到最近的可表示数字,随后提取小数的代码正确地看到最后的数字不是
0


此问题是2004年未解决的QC报告的主题:。

提供一个简单的控制台应用程序,复制您看到的行为,并提供一些更详细的解释:

{$APPTYPE CONSOLE}
program Project1;
uses
  SysUtils;
begin
  Set8087CW(Get8087CW and $FCFF);
  Writeln('FloatToStr(64) = ', FloatToStr(64));
end.
输出:

FloatToStr(64) = 64.000001744411 使用
val=64
Power=16
计算
64*10**16
。然后将其转换为整数
640000000000000000
,从中提取十进制数字,并在其中放置小数点。在默认FPU模式下,这将很好,在默认FPU模式下,它将准确地生成
640000000000000000
,但在这里使用的FPU模式下,可用的精度较低,不足以表示该数字。它被四舍五入到最近的可表示数字,随后提取小数的代码正确地看到最后的数字不是
0


这个问题是2004年未解决的质量控制报告的主题:。

那么你的问题到底是什么?什么是“早期”,您是否更改了版本?如果没有此攻击,则可以正常工作,使用FloatToStr返回长值。无论如何,永远不要发布代码的图像。它很难读取,无法复制和粘贴以进行测试,并且无法从大多数移动设备读取。作为图片发布也比仅仅选择、复制和粘贴到问题中要困难得多。所以说清楚,永远,永远不要把你的代码作为iimage发布。那么你的问题到底是什么?什么是“早期”,您是否更改了版本?如果没有此攻击,则可以正常工作,使用FloatToStr返回长值。无论如何,永远不要发布代码的图像。它很难读取,无法复制和粘贴以进行测试,并且无法从大多数移动设备读取。作为图片发布也比仅仅选择、复制和粘贴到问题中要困难得多。所以说清楚一点,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远,永远?我甚至不是一个程序员,也永远不会对我说“但说真的,这让我很沮丧,你没有足够的关心来理解这一点”吗?我甚至不是一个程序员,也永远不会。请注意:这在当前版本(2.6.4)的免费Pascal中不会发生。想知道Delphi的哪个版本有这个问题是很有意思的。更像是这样。我希望现代德尔福能做到这一点。你在换什么?精确吗?谢谢。真令人沮丧,现代德尔菲也是如此。更糟糕的是,在x64上从文本到浮点的转换调用
InternalTextToExtended
,然后调用
SetMXCSR
,这不是线程安全的。s