1

在那儿MulDiv

WINBASEAPI
int
WINAPI
MulDiv(
    _In_ int nNumber,
    _In_ int nNumerator,
    _In_ int nDenominator
    );

在 C# 中还是等效的?

还是我应该实施它?

编辑:没有 PInvoking !

4

4 回答 4

7

这是对 Hans Passant 建议的增强,但根据 MSDN 文档包括 +0.5 舍入:

public static int MulDiv(int number, int numerator, int denominator)
{
    return (int)(((long)number * numerator + (denominator >> 1)) / denominator);
}

注意:此代码使用右移运算符来获得最佳性能。

于 2014-07-31T17:39:34.390 回答
5

此 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关键字。

于 2012-06-12T20:42:59.000 回答
1

不,这不是开箱即用的。你需要做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));
于 2012-06-12T19:29:56.780 回答
0

如果您想明确表示您将竭尽全力处理两个 32 位整数可能产生大于 32 位整数的值的情况,您可以使用 Math.BigMul,然后将结果相除并将其转换回整数。我看到,正如其他答案所述,.NET 对 64 位整数的支持显然提供了 MulDiv 以前需要的所有好处(然后是一些)。

int result = unchecked((int)(System.Math.BigMul(nNumber, nNumerator) / nDenominator));
于 2013-10-14T16:38:03.447 回答