我在使用delphi舍入时遇到了一些严重的问题(当从c#项目中使用时)并且当值似乎落在.5括号内时它的结果是一致的,即它是向上还是向下舍入???
我创建了一个执行许多操作的delphi DLL。其中一项行动的关键是(例如)
double := Round(double1 * double2);
其中double1 = 1.9且double2 = 225(从文件中获取的值从中读取)
我的计算器上的结果显示它应该是427.5。 delphi DLL中的结果是427.四舍五入,根据Round()
的delphi文档都很好这些计算的值存储在代表表格的Delphi(我相信的类)中。在上面的情况下像这样
property SRDairy : Double read FSRDairy write FSRDairy;
这个属性属于一堆类,并且像这样被序列化到Delphi DLL中的缓冲区(AOvrFarm是包含所有要序列化的项目的父项,包括我的SRDairy)
procedure GetResultString(AOvrFarm: TdataV6; outputStringBuffer: PChar; var
bufLen: Integer);
var
MyStrings : TStringList;
resultString : string;
begin
MyStrings := TStringList.Create;
try
AOvrFarm.SavetoStrings(MyStrings);
resultString := MyStrings.Text;
if outputStringBuffer = nil then
begin
bufLen := Length(resultString) + 1;
end
else
begin
StrLCopy(outputStringBuffer, PChar(resultString), bufLen - 1);
end;
finally
MyStrings.Free;
end;
end;
在此DLL中有许多其他属性,表单(类)等。结束时,此文件被序列化为一个字符串,该字符串返回给调用者(c#)应用程序,refoutputStringBuffer使用类似(在delphi中)填充:
StrLCopy(outputStringBuffer, PChar(resultString), bufLen - 1);
我的问题是当我从c#应用程序调用此DLL时。我得到的结果不是427,它是428.圆满!!!!
德尔福签名:
function ConvertString(fileContents:PChar; fileExt:PChar; var outputStringBuffer: PChar类型; var outputStringBufferSize:Integer; var errorMsgBuffer:PChar; VAR errorMsgBufferSize:Integer):WordBool; STDCALL;出口;
我使用c#中的DLL,如:
[DllImport("OvrFileImport.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern bool
ConvertString(
string fileContents,
string fileExt,
ref string refputStringBuffer,
ref int outputStringBufferSize,
ref string errorMsgBuffer,
ref int errorMsgBufferSize);
转换字符串调用一次以获取缓冲区大小,然后再次调用填充缓冲区。这是第二次电话,我注意到了差异。当从Test Delphi项目使用相同的DLL时,我得到427(而不是c#428)。
我已经尝试针对任何CPU构建我的c#而只是x86因为我的PC是64位机器而出现了某种cpu 64位问题。
有没有人遇到过这种事情,如果有的话,他们有什么办法吗?
编辑 - 答案
正如David Heffernan所提到的,从c#调用DLL时使用的控制字与从另一个Delphi应用程序调用时使用的控制字不同。从c#调用时使用的控制字实际上是639美元。
不幸的是,将控制字设置为$ 1372会导致我的c#app在调试时出现问题,即它导致本地监视窗口显示“由于堆栈溢出状态而无法评估”所有变量的异常。我找到了article - strange floating point results来讨论这个问题,因此改为$ 133F(这解决了浮点差异和c#调试问题)。
代码:
begin
cw := Get8087CW;
Set8087CW($133F);
....
finally
Set8087CW(cw);
答案 0 :(得分:2)
1.9在浮点中不能完全表示,而225则完全可以表示。
目前尚不清楚输入数字的来源,但IEEE754算法根本不可能完全执行产品1.9 * 225。您看到的行为与舍入无关,实际上是关于可表示性的。如果您需要完全执行此计算,则需要使用十进制算术而不是浮点。这意味着在Delphi中使用货币类型或在C#中使用小数。
您的不同行为的来源可能是控制浮点寄存器的8087控制字。当您的DLL执行时,从C#调用,控制字将与默认的Delphi设置不同。在DLL的入口点调用Set8087CW($ 1372)以使用默认的Delphi控制字。请记住在从DLL返回之前恢复它。