在那儿MulDiv
WINBASEAPI
int
WINAPI
MulDiv(
_In_ int nNumber,
_In_ int nNumerator,
_In_ int nDenominator
);
在 C# 中还是等效的?
还是我应该实施它?
编辑:没有 PInvoking !
在那儿MulDiv
WINBASEAPI
int
WINAPI
MulDiv(
_In_ int nNumber,
_In_ int nNumerator,
_In_ int nDenominator
);
在 C# 中还是等效的?
还是我应该实施它?
编辑:没有 PInvoking !
这是对 Hans Passant 建议的增强,但根据 MSDN 文档包括 +0.5 舍入:
public static int MulDiv(int number, int numerator, int denominator)
{
return (int)(((long)number * numerator + (denominator >> 1)) / denominator);
}
注意:此代码使用右移运算符来获得最佳性能。
此 api 函数可以追溯到 Windows 版本 3,即 Windows 的 16 位版本。很可能以前,我还不够老。让 C 编译器将两个 16 位数字(两个整数)相乘,得到一个 32 位中间结果并除以一个 16 位数字以获得 16 位结果有点困难。该操作很常见,例如计算字体大小。
微软的一大负担是,一旦他们发布了一个 api 函数,他们就必须永远维护它,除非它与操作系统中的必要更改完全不兼容。MulDiv() 没什么大不了的,但是int参数确实自动提升到 32 位,这使得该函数几乎完全没有必要。但是为 Win3 编写的程序仍然可以编译,反向兼容是神圣的。
让 api 负担这个有点错误,但动机很强烈,很难将窗口系统塞进 640 KB。公开已经存在的东西,因为操作系统需要它确实有助于减少字节。其他类似的 api 函数是 wprintf()、lstrcpyXxx() 等。Core C 运行时函数,今天仍然可用,甚至通过切换到 Unicode 来维护。窗户的考古记录。
pinvoking 没有任何意义,C# 可以毫无困难地做到这一点:
public static int MulDiv(int number, int numerator, int denominator) {
return (int)(((long)number * numerator) / denominator);
}
如果您想要溢出异常,请使用checked关键字。
不,这不是开箱即用的。你需要做PInvoke。
你当然可以自己实现它:
//truncation is unnecessary if you want to continue using a long
//the truncation can never overflow so it is unchecked
var result = unchecked((int)(nNumber * (long)nNumerator / nDenominator));
如果您想明确表示您将竭尽全力处理两个 32 位整数可能产生大于 32 位整数的值的情况,您可以使用 Math.BigMul,然后将结果相除并将其转换回整数。我看到,正如其他答案所述,.NET 对 64 位整数的支持显然提供了 MulDiv 以前需要的所有好处(然后是一些)。
int result = unchecked((int)(System.Math.BigMul(nNumber, nNumerator) / nDenominator));