浅谈 Math.BigMul 方法

偶然在 MSDN 上看到 Math.BigMul 方法:

Math.BigMul 方法

生成两个 32 位数字的完整乘积。

命名空间:System

程序集: mscorlib(在 mscorlib.dll 中)

语法:

public static long BigMul(int a, int b)

参数:

a  类型:System.Int32,第一个乘数。

b  类型:System.Int32,第二个乘数。

返回值:

类型:System.Int64

包含指定数字乘积的 Int64。

我就想,为什么 .NET Base Class Library 要提供这么一个方法?她的功能不就是等价于 (long)a * b 吗?

那么,首先想到的就是用 .NET Reflector 这个 .NET 程序员必备的工具看看 Math.BigMul 的源程序代码:

1 public static long BigMul(int a, int b)

2 {

3     return (a * b);

4 }

咦,上面的代码好像有点不对。第 3 行应该是

return (long)a * b;

才对呀。于是,再看 IL 代码:

1 .method public hidebysig static int64 BigMul(int32 a, int32 b) cil managed

2 {

3     .maxstack 8

4     L_0000: ldarg.0

5     L_0001: conv.i8

6     L_0002: ldarg.1

7     L_0003: conv.i8

8     L_0004: mul

9     L_0005: ret

10 }

这下对了,第 5 行和第 7 行的 conv.i8 指令将两个 int 参数转换为 long 类型,然后再调用 mul 指令(第 8 行)进行乘法运算。

不过,这样一来,Math.BigMul 方法不就完全没有存在的必要吗?调用她还不如我们自己写 (long)a * b 语句来代替她,还省了一次方法调用的开销。我原来以为 IL 语言中有什么指令可以直接将两个 int 类型的操作数相乘得到 long 类型的结果呢,而 Math.BigMul 方法就直接调用该指令。

于是,我就写了以下的程序来比较 Math.BigMul 方法和 (long)a * b 的效率:

1 using System;

2 using System.Diagnostics;

3

4 namespace Skyiv.Ben

5 {

6   sealed class TestBigMul

7   {

8     static void Main()

9     {

10       for (int i = 0; i < 5; i++) Console.WriteLine(BigMultiply(i) == LongMultiply(i));

11     }

12

13     static long BigMultiply(int n)

14     {

15       long k = 0;

16       var watch = Stopwatch.StartNew();

17       for (int i = int.MaxValue; i > 0; i--) k += Math.BigMul(i, n - i);

18       watch.Stop();

19       Console.WriteLine("Math.BigMul(): " + watch.Elapsed);

20       return k;

21     }

22

23     static long LongMultiply(int n)

24     {

25       long k = 0;

26       var watch = Stopwatch.StartNew();

27       for (int i = int.MaxValue; i > 0; i--) k += (long)i * (n - i);

28       watch.Stop();

29       Console.WriteLine("long multiply: " + watch.Elapsed);

30       return k;

31     }

32   }

33 }

这个程序关键部分的 IL 代码如下:

BigMultiply LongMultiply
IL_0008:  stloc.1

IL_0009:  ldc.i4      0x7fffffff

IL_000e:  stloc.2

IL_000f:  br.s         IL_0021

IL_0011:  ldloc.0

IL_0012:  ldloc.2

IL_0013:  ldarg.0

IL_0014:  ldloc.2

IL_0015:  sub

IL_0016:  call  int64 [mscorlib]

System.Math::BigMul

(int32, int32)

IL_001b:  add

IL_001c:  stloc.0

IL_001d:  ldloc.2

IL_001e:  ldc.i4.1

IL_001f:  sub

IL_0020:  stloc.2

IL_0021:  ldloc.2

IL_0022:  ldc.i4.0

IL_0023:  bgt.s      IL_0011

IL_0025:  ldloc.1

IL_0008:  stloc.1

IL_0009:  ldc.i4     0x7fffffff

IL_000e:  stloc.2

IL_000f:  br.s       IL_001f

IL_0011:  ldloc.0

IL_0012:  ldloc.2

IL_0013:  conv.i8

IL_0014:  ldarg.0

IL_0015:  ldloc.2

IL_0016:  sub

IL_0017:  conv.i8

IL_0018:  mul

IL_0019:  add

IL_001a:  stloc.0

IL_001b:  ldloc.2

IL_001c:  ldc.i4.1

IL_001d:  sub

IL_001e:  stloc.2

IL_001f:  ldloc.2

IL_0020:  ldc.i4.0

IL_0021:  bgt.s      IL_0011

IL_0023:  ldloc.1

上表中的 IL 代码和我们预计的一样。在 BigMultiply 方法中就是直接调用 Math.BigMul 方法,而在 LongMultiply 方法中先用两个 conv.i8 指令将两个 int 类型的操作数转换为 long 类型,然后再使用 mul 指令进行乘法运算。而 Math.BigMul 方法内部也是这么做的。那么,这是不是说 BigMultiply 方法就一定比 LongMultiply 方法慢呢?还是让我们来看看这个程序的实际运行情况吧:

Math.BigMul(): 00:00:06.7050475
long multiply: 00:00:06.6712870
True
Math.BigMul(): 00:00:06.6946425
long multiply: 00:00:06.6873783
True
Math.BigMul(): 00:00:06.6640827
long multiply: 00:00:06.6910634
True
Math.BigMul(): 00:00:06.6726273
long multiply: 00:00:06.6743329
True
Math.BigMul(): 00:00:06.6601853
long multiply: 00:00:06.6685163
True

可以看出,这两种方法的运行时间是一样的。

这样看来,在 C# 语言中,方法调用的时间几乎可以忽略不计。因为在 BigMultiply 方法中比 LongMultiply 方法中多了二十多亿次(准确地说,是 2,147,483,647次) Math.BigMul 方法调用。但她们的运行时间差不多。

在 MSDN 论坛上有一篇关于 Math.BigMul 的有趣的帖子

Andrew Shapira [loc] - Posted 于 2008年3月26日 3:47:24

What purpose does Math.BigMul serve, and why was Math.BigMul included in the BCL when a*(long)b achieves the same thing as Math.BigMul(a,b), for Int32 a and b?

(And why does the name ‘BigMul‘ violate the guideline of not abbreviating names, e.g., wouldn‘t it have been better to call the method ‘BigMultiply‘?)

Philippe Leybaert [loc] - Posted 于 2008年3月26日 4:50:04Math.BigMul() is just a convenience method, so you wouldn‘t need to cast the values you‘re multiplying (it also makes sure you don‘t forget to
cast, because if you do, the results will be not what you expect)

Regarding your second question, I‘ll leave that to the .NET Framework designers 

BinaryCoder [loc] - Posted 于 2008年3月26日 6:36:55

I‘m sure there is a really good story about why this method was put in .NET!

Notice that in the documentation it says:

Supported in: 3.0, 2.0, 1.1

This means that BigMul was not originally in 1.0 but was added later... Interesting.

这个帖子中说到 Math.BigMul 方法是为了防止程序员在做乘法时忘记了把 int 类型转换为 long 类型。我想,作为一个熟练的程序员,应该不会犯这个错误。相反,不知道有 Math.BigMul 方法的程序员可能会更多一些。

版权声明:本文为博主http://www.zuiniusn.com 原创文章,未经博主允许不得转载。

时间: 2024-08-06 15:42:37

浅谈 Math.BigMul 方法的相关文章

浅谈 JSON.stringify 方法

用过 json 的应该都知道,把一个对象通过 stringify 之后提交给后台或者存储在 Storage 里是很常用的手段.但是 IE6-7 下没有 JSON 对象,所以要借助 json2.js 来实现. 今天我们来简单介绍下 stringify 方法的一些正确使用姿势吧.当然,让高手们贱笑了,本文只是分享一些方法给新手朋友们. var data = [ {name: "王尼玛", sex:1, age: 30}, {name: "王尼美", sex:0, age

Unity iOS打开AppStore评星页面,浅谈Application.OpenURL()方法。

http://fairwoodgame.com/blog/?p=38 Unity iOS打开AppStore评星页面,浅谈Application.OpenURL()方法. Posted in  Unity on August 6, 2013Comments: 暂无评论 太简单了.我们知道iOS里有个URL Scheme的东西(这个我还没深究,希望有大神帮我贴个教程,十分感谢~另外Android也有),可以通过打开一个URL来进入iOS的某些应用.比如下面这个链接在iOS里点击就可以直接进入爱掼蛋

浅谈数据初始化方法

浅谈数据初始化方法 在定制开发的信息化项目实施过程中,我们发现衡量一个项目成功与否,关键看以下三个指标: v人: 系统的利益相关人的需求是否都得到了满足: v系统:软件本身是否可用.易用.稳定.有效率: v数据:数据是否准确.可靠.稳定支持业务的运作: 从这个角度来说,数据在信息系统项目实施过程中有着举足轻重的地位,特别是数据初始化的成功与否是源头和决定因素.下面将数据初始化的过程分解为八个步骤,以确保数据初始化过程的严谨性和科学性. 步骤一:系统数据库表的分析:对信息系统数据库表进行分析,了解

浅谈Arrays.asList()方法的使用

首先,该方法是将数组转化为list.有以下几点需要注意: (1)该方法不适用于基本数据类型(byte,short,int,long,float,double,boolean) (2)该方法将数组与列表链接起来,当更新其中之一时,另一个自动更新 (3)不支持add和remove方法 上代码: 1 package com.hdu.test; 2 3 import java.util.Arrays; 4 import java.util.List; 5 6 abstract public class

浅谈webshell检测方法 寒龙博客转载

一  什么是webshell"web"的含义是显然需要服务器开放web服务,"shell"的含义是取得对服务器某种程度上操作权限.webshell常常被称为匿名用户(入侵者)通过网站端口对网站服务器的某种程度上操作的权限.简单理解:webshell就是一个web的页面,但是它的功能非常强大可以获得一些管理员不希望你获得的权限,比如执行系统命令.删除web页面.修改主页等.webshell中由于需要完成一些特殊的功能就不可避免的用到一些特殊的函数,我们也就可以对着特征

浅谈两种方法实现浏览器内多个标签页之间的通信

调用localstorge.cookies等本地存储方式. 方法一: localstorge在一个标签页里被添加.修改或删除时,都会触发一个storage事件,通过在另一个标签页里监听storage事件,即可得到localstorge存储的值,实现不同标签页之间的通信. <input id="name"> <input type="button" id="btn" value="提交"> <scr

Python进阶之浅谈内置方法

目录 有序or无序和可变or不可变 数字类型内置方法 整形 浮点型 字符串类型内置方法 有序or无序和可变or不可变 有序:有索引 无序:无索引 可变:变量值变,id不变 不可变:变量值变,id也变 数字类型内置方法 整形 1.作用 描述年龄,id,身高 2.定义方式 x=10 x=int('10') 3.内置方法 没有内置方法,只有算术运算和比较运算 4.存在一个值还是多个值 一个值 5.有序or无序 整形没有这一说法 6.可变or不可变 整形是不可变的 浮点型 1.作用 描述薪资等 2.定义

浅谈 JSON.stringify 方法【转】

但是 IE6-7 下没有 JSON 对象,所以要借助json2.js来实现. 今天我们来简单介绍下stringify方法的一些正确使用姿势吧. 当然,让高手们贱笑了,本文只是分享一些方法给新手朋友们. var data = [ {name: "王尼玛", sex:1, age: 30}, {name: "王尼美", sex:0, age: 20}, {name: "王大锤", sex:1, age: 30} ]; var str_json = J

菜鸟浅谈github使用方法--之创建仓库

上一个小节呢,就是讲了一下github的基本概念什么的. 下面讲讲如何创建仓库吧. 1.建立仓库 在创建仓库之前,建议先去https://github.com官网上注册一个github账户吧.注册完之后登录,新建new repository 2.安装Git客户端 github是服务器端,git是客户端,我的git客户端是百度里直接下载的 下载完之后在本地创建ssh key,运行git-bash.exe $ ssh-keygen -t rsa -C "[email protected]"