c# - 双字结果的高​​效长乘法

标签 c# .net

我正在尝试优化 31.32 fixed-point math library written in C# 的乘法代码.

(不正确的)伪代码是: 长结果 = (a * b) >> 32;

问题当然是 a * b 在被下移之前的潜在溢出。即使(a * b) >> 32(乘法的最终结果)在long的取值范围内,中间值a * b 可能不是。

通常的解决方案是将ab分别拆分为低位和高位,并在乘法步骤之前对高位进行移位操作。这避免了中间值的溢出,但使代码更加复杂:

var xl = x.m_rawValue;
var yl = y.m_rawValue;

var xlo = (ulong)(xl & 0x00000000FFFFFFFF);
var xhi = xl >> FRACTIONAL_PLACES;
var ylo = (ulong)(yl & 0x00000000FFFFFFFF);
var yhi = yl >> FRACTIONAL_PLACES;

var lolo = xlo * ylo;
var lohi = (long)xlo * yhi;
var hilo = xhi * (long)ylo;
var hihi = xhi * yhi;

var loResult = lolo >> FRACTIONAL_PLACES;
var midResult1 = lohi;
var midResult2 = hilo;
var hiResult = hihi << FRACTIONAL_PLACES;

var sum = (long)loResult + midResult1 + midResult2 + hiResult;

生成的机器代码同样复杂。

x86 imul 指令可以在一条指令中的两个寄存器中返回一个双字结果,但我不知道如何编写编译器可以优化使用它的 C# 代码。

有什么想法吗?

最佳答案

Core 3.0 添加了对您正在寻找的 imul x64 CPU 指令的支持:

ulong lo64Bits;
ulong hi64Bits= System.Runtime.Intrinsics.X86.Bmi2.X64.MultiplyNoFlags(a, b, &lo);

(当然仅限于x86 arch)

关于c# - 双字结果的高​​效长乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49008086/

相关文章:

c# - Entity Framework : best practice to filter data inside multiple "one-to-many" relationships

c# - 使用 System.Uri 删除多余的斜线

c# - 类常量JAVA到C#的实现

c# - 使用注释和自定义属性时的验证顺序

c# - 应用程序在处理所有事件之前退出 - 基于事件的异步模式

C# ConvertTimeFromUtc 时髦

.net - 如何使用 EPPlus for .NET 将 Excel 工作表从一个文件复制到另一个文件

c#通用转换器

.net - 无法打开已被我的另一个应用程序打开的文件

c# - MemoryCache OutOfMemoryException