.net - 在 .NET 中模拟 VBA 算术

标签 .net vb.net vba math

免责声明:我知道 0.025 无法在 IEEE 浮点变量中精确表示,因此舍入可能不会返回预期的结果。这不是我的问题!

<小时/>

是否可以在.NET 中模拟 VBA 算术运算符的行为?

例如,在 VBA 中,以下表达式生成 3:

Dim myInt32 As Long
myInt32 = CLng(0.025 * 100)      ' yields 3

但是,在 VB.NET 中,以下表达式会生成 2:

Dim myInt32 As Integer
myInt32 = CInt(0.025 * 100)      ' yields 2

根据规范,两者应该返回相同的值:

  • Long (VBA) 和 Integer (VB.NET) 是 32 位整数类型。
  • 根据the VBA specification 、CLng对Long进行Let-强制转换,数字类型之间的Let-强制使用Banker的舍入。 The same is true对于 VB.NET 的 CInt。
  • 0.025 在这两种情况下都是 double IEEE 浮点常量。

因此,浮点乘法运算符或整数转换运算符的一些实现细节发生了变化。但是,出于与旧版 VBA 系统兼容性的原因,我需要在 .NET 应用程序中复制 VBA 的数学行为(无论它可能有多么错误)。

有什么办法可以做到这一点吗?有人编写了 Microsoft.VBA.Math 库吗?或者是否在某处记录了精确 VBA 算法,以便我可以自己完成?

最佳答案

VBA 和 VB.NET 的行为不同,因为 VBA 使用 80-bit "extended" precision用于中间浮点计算(即使 Double 是 64 位类型),而 VB.NET 始终使用 64 位精度。使用 80 位精度时,0.025 * 100 的值略大于 2.5,因此 CLng(0.025 * 100) 向上舍入为 3。

不幸的是,VB.NET 似乎不提供 80 位精度的算术。作为解决方法,您可以使用 Visual C++ 创建 native Win32 DLL 并通过 P/Invoke 调用它。例如:

#include <cmath>
#include <float.h>

#pragma comment(linker, "/EXPORT:MultiplyAndRound=_MultiplyAndRound@16")

extern "C" __int64 __stdcall MultiplyAndRound(double x, double y)
{
    unsigned int cw = _controlfp(0, 0);
    _controlfp(_PC_64, _MCW_PC); // use 80-bit precision (64-bit significand)
    double result = floor(x * y + 0.5);
    if (result - (x * y + 0.5) == 0 && fmod(result, 2))
        result -= 1.0; // round down to even if halfway between even and odd
    _controlfp(cw, _MCW_PC); // restore original precision
    return (__int64)result;
}

在 VB.NET 中:

Declare Function MultiplyAndRound Lib "FPLib.dll" (ByVal x As Double, ByVal y As Double) As Long

Console.WriteLine(MultiplyAndRound(2.5, 1))       ' 2
Console.WriteLine(MultiplyAndRound(0.25, 10))     ' 2
Console.WriteLine(MultiplyAndRound(0.025, 100))   ' 3
Console.WriteLine(MultiplyAndRound(0.0025, 1000)) ' 3

关于.net - 在 .NET 中模拟 VBA 算术,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19498346/

相关文章:

c# - RGB/十六进制颜色到十进制值

asp.net - 创建过期的 ASP.NET session 值

excel - IF 在 VBA 中具有多个 OR 和 AND

vba - 未定义用户定义类型 - 从 Excel 控制 Word

vba - 用于打开 Access 数据库、运行宏和持久化 Access 实例的脚本

.net - VS2017 .Net Core(完整框架)项目的构建后事件获取 $(ConfigurationName) 的空字符串

c# - 如何导航到粘贴的堆栈跟踪 visual-studio

javascript - 关于从 ASP .NET 用户控件迁移到 .NET 3.5 母版页技术的问题

c# - 是否可以在迭代 ICollection 时确定当前位置?

c# - 如何在 PropertyGrid 中显示静态(共享)对象的属性?