C++ VBA 浮点差异中的 .NET COM 组件
C++ .NET COM component in VBA floating point differences
我写了一个可以从VBA调用的C++.NET组件。该组件计算了一个非常大的数字数组(给定一些输入(,并将该数组写入二进制文件。
我注意到,如果我使用通过 VBA 调用组件的完全相同的设置生成文件,我每次都会得到不同的结果。在十六进制编辑器中打开二进制文件时,我可以看到字节的差异。但是,如果我做同样的事情,但通过在 C++.NET 或 C#.NET 可执行文件中调用组件,我根本不会得到任何差异 - 使用相同的设置生成的文件每次以这种方式生成时都是相同的。
差异很小,只是浮点差异。但是,我想找出为什么会发生这种情况。为什么通过 VBA 调用它时会出现差异,而不是通过 C++.NET 或 C#.NET 调用它?
作为记录 - 我在这里的 32 位机器上运行 64 位 Excel(用于 VBA((如果这有什么区别......
对此的任何想法将不胜感激。
@Terry - 我想我能够证明这种情况正在发生。首先让我解释一下问题是什么(或者至少我认为是合理的解释(。
为什么 C# 可执行文件会给 Excel 不同的结果?
任何应用程序都可以将浮点状态设置为所需的任何状态。事实上,这是一种很好的做法,因此您可以确保应用程序中的特定精度(如果重要的话(。
从 C# 可执行文件运行时,使用的浮点设置是编译器决定的任何设置。但是,当您在 Excel 中运行它时,Excel 会将浮点设置更改为所需的任何设置,这可能与可执行文件不同。这就是为什么你会有所作为。
为什么在 Excel 中运行每次可能会给出不同的结果?
Excel 将浮点设置更改为所需的任何设置。但是,它仅在需要使用的线程上执行此操作。因此,如果 Excel 需要 N 个线程,它将在这 N 个线程上设置浮点设置。任何新生成的线程上的浮点设置都不会从"主"线程复制。因此,如果加载项中的进程需要 M> N 个线程,则生成 M-N 个线程,这些线程的浮点设置与 Excel 设置的 N 个浮点设置不同。所以现在你有 M 个线程,它们有两组不同的浮点设置。由于并行编程中使用的线程不是确定性的,因此每次在 Excel 中运行时,可能会得到不同的结果。
我是如何解决的?
我通过在用于确保它始终相同的每个线程上显式设置浮点设置来解决此问题。我介绍了以下例程。它在C++中,但你也应该能够让它在 C# 中工作。
[DllImport("msvcrt.dll")] int _controlfp(int IN_New, int IN_Mask);
void FixFPU()
{
_controlfp(_MCW_DN, _DN_SAVE);
_controlfp(_MCW_EM, _EM_INVALID);
_controlfp(_MCW_RC, _RC_CHOP);
_controlfp(_MCW_PC, _PC_53);
}
我在 Parallel.For 循环中调用了这个例程。这可确保 Parallel.For 循环使用的每个线程都具有相同的浮点设置。通过显式指定浮点状态,可以在例程从外接程序运行时覆盖这些线程上的 Excel 浮点设置。我还在进程开始时调用了此例程,以确保启动时使用的单个线程也运行相同的浮点设置。这可确保在到达 Parallel.For 循环之前完成的任何计算都以与 Parallel.For 循环内相同的精度执行。
这是该例程中的最后一条语句,它会产生最大的差异,因为这设置了精度。
我希望这可以帮助您解决问题。
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 将指向COM接口指针的指针从托管c++传递到.NET c#
- 合并 c 可执行文件、托管 COM dll 和 .Net GUI
- 在 .NET 中调用 COM 枚举器的正确方法是什么?
- 如何从com库中打印到主机,并从.NET代码召唤激活器
- 如何从C++和通过COM互操作性访问.NET类的属性
- 无法在.net中创建com对象实例
- 通过 .net 互操作类调试到 COM C++代码
- 如何将 void* 放入 COM 变体中,以便它被 COM-Interop 编组为 IntPtr,到 .NET
- 应用程序在 的协同创建实例期间挂起.基于 NET 的 COM 对象
- 一个C++客户端无法使用我们新的 COM 注册的 .NET .dll加载,另一个客户端可以正常工作
- CoCreateInstance:创建在 .NET 库中定义的 COM 实例
- 将本机dll或.NET程序集嵌入COM
- C++ VBA 浮点差异中的 .NET COM 组件
- 调试.NET应用程序创建的COM对象
- . net实现的c++接口,暴露于COM
- 如何从c# /创建回调.. NET通过COM转换为c++
- 从.net应用程序中销毁COM对象
- 使用 C/C++学习 COM 会帮助我更好地理解 .NET 吗?
- 用VB重写的c++ out-proc COM服务器.. NET和跨c++ EXE共享