浅谈 BigIntegerWord文档格式.docx
- 文档编号:21068754
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:21
- 大小:24.67KB
浅谈 BigIntegerWord文档格式.docx
《浅谈 BigIntegerWord文档格式.docx》由会员分享,可在线阅读,更多相关《浅谈 BigIntegerWord文档格式.docx(21页珍藏版)》请在冰豆网上搜索。
8//
9}
根据第7行的internalsbyte[]__bits;
猜想java.math.BigInteger的内部实现是基于28进制的。
ChewBigInteger就是ChewKeongTAN在CodeProject中的C#BigIntegerClass。
这是个很有名的C#Biginteger类,它写于2002年8月到9月,已经有很久的历史了。
但是她有个致命的缺点,就是不能自动增长,需要事先指定最大允许有多大的数,如果在运算过程中产生超过你事先指定大小的数,就会引发异常。
她的部分源程序代码如下所示:
1namespaceChewKeongTAN
2{
3/*public*/classBigInteger
4{
5//maximumlengthoftheBigIntegerinuint(4bytes)
6//changethistosuittherequiredlevelofprecision.
7
8privateconstintmaxLength=26591;
//==Math.Ceiling(digits/log10(2^32))
9
10privateuint[]data=null;
//storesbytesfromtheBigInteger
11publicintdataLength;
//numberofactualcharsused
12
13//
14
15}
16}
她内部使用一个uint[]来存储,是基于232≈4.3x109进制的。
需要事先设定maxLength的值(程序中第8行),用以指定最多允许多少个232进制的数字,换算用的公式是:
maxLength=Math.Ceiling(digits/log10(232))≈digits/9.6
上式中digits表示十进制数字的个数。
Fcl35Biginteger就是.NETFramework3.5BaseClassLibrary中的System.Numeric.BigInteger,她在System.Core.dll中。
注意,她是一个internalstruct。
首先,她是一个struct,不是一个class,也就是说她是值类型而不是引用类型。
其次,致命的是,她是internal的,而不是public的,也就是说,她就在那里,但是你就是不能使用她。
实际上,在.NETFramework3.5的Beta和latestCTP版本中,她还是public的,只不过是在.NETFramework3.5正式发布时变成了internal的。
这里有一篇BCLTeam的MelittaAndersen于2008年1月4日发表的Blog:
WheredidBigIntegergo?
谈到这件事,要点是:
SowhywasBigIntegercut?
ThebasicrationalebehindmakingBigIntegerinternalwasthatitjustwasn'
treadytoship.WethoughtourimplementationmettheneedsforaBigIntegertype.Butthenwehadsomeotherteamstakealookatitandtheypointedoutsomeperformanceandcompatibilityissuesthatwejustdidn'
thavetimetofixbeforeweshipped.
于是,.NETReflector又上场了,用她打开C:
\Windows\assembly\GAC_MSIL\System.Core\3.5.0.0__b77a5c561934e089\System.Core.dll文件,找到System.Numeric.BigInteger,在Disassembler窗口中,点击最下方的ExpandMethods,然后把源程序代码全部复制到VisualStudio2008的IDE窗口(注意,目标Framework设定为.NETFramework2.0)中。
按下编译按钮,天啊,出现了好多错误。
于是,就开始修改源程序代码:
实现两个空的sealedclass:
ImmutableAttribute和PureAttribute。
(前一个好理解,后一个不知是什么东东。
当然,实际上她们不应该是空的)
实现一个staticclass:
Contract,其中包括两个重载的publicstaticvoidRequires方法。
(当然,实际上的Contract.Requires应该更复杂)
Res,其中包括若干个publicstaticreadonlystring字段。
(当然,实际上Res应该从资源文件中获得本地化的数据)
将程序中出现的某些常数值还原为privateconst字段。
注意,这不是必须的,只是为了使程序更容易看懂。
如果不做这一步,就可以将程序中所有的privateconst字段全部删除。
修改程序中某些变量的名称。
注意,这也不是必须的,也只是为了使程序更容易看懂。
然后,再次编译,耶,通过了。
但是,还是高兴得太早了一点,运行一些测试,发现答案根本不对。
经检查,发现是.NETReflector在反汇编为C#代码时会丢失一些强制类型转换,这在我的上一篇随笔浅谈Math.BigMul方法中已经提到过了:
她把Math.BigMul方法中的唯一的语句return(long)a*b;
错误地反汇编为return(a*b);
了,但是反汇编为IL代码是正确的。
于是,只好逐条语句检查,如果需要进行强制类型转换,就自己加上,同时还去掉一些不必要的强制类型转换和括号,以便使源程序代码更易读。
真是一个很烦人和困难和工作,热切盼望.NETReflector能够尽快修复这个BUG。
:
)
好了,经过调试,程序终于运行正常了。
下面就是修改后的部分源程序代码:
1namespaceFcl35.Numeric
3[Serializable,StructLayout(LayoutKind.Sequential),Immutable,ComVisible(false)]
4public/*internal*/structBigInteger:
IFormattable,
5IEquatable<
BigInteger>
IComparable<
IComparable
6{
7privateconstulongBase=uint.MaxValue+1UL;
//0x100000000L;
8privatereadonlyshort_sign;
9privatereadonlyuint[]_data;
10privateint_length;
11//
12}
13}
和ChewKeongTAN.BigInteger类一样,Fcl35.Numberic.BigInteger结构内部也使用一个uint[]来存储,同样也是基于232≈4.3x109进制的。
但是,最重要的一点,Fcl35.Numberic.BigInteger结构是动态增长的,不需要事先指定最大允许有多大的数。
现在来讨论我最近写的一个Skyiv.Numeric.BigInteger类,她是从我在做ACM题时写的极简单的如下所示的BigInteger类发展而来的:
1sealedclassBigInteger
2{
3int[]digits=newint[1800];
4//
5}
这个极简单的BigInteger类的全部源程序代码可以在本随笔开头给出的URL中找到,只有五十多行。
她是基于10进制的,内部使用一个int[]来存储,需要事先指定该数组的大小,不能动态增长,而且只能表示非负整数。
下面是Skyiv.Numeric.BigInteger的源程序代码,非常短小精悍,只有区区335行,该有的功能基本上都有了。
实现了基本的算术运算和逻辑运算,还实现了Pow和Sqrt方法。
1usingSystem;
2usingSystem.Text;
3usingSystem.Collections.Generic;
4
5namespaceSkyiv.Numeric
7sealedclassBigInteger:
IEquatable<
8{
9staticreadonlyintLen=9;
//int.MaxValue=2,147,483,647
10staticreadonlyintBase=(int)Math.Pow(10,Len);
11
12intsign;
13List<
int>
data;
14
复制代码
她内部使用一个List<
来存储(程序中第13行),是动态增长的,基于109进制(第9和10行)。
15BigInteger(longx)
16{
17sign=(x==0)?
0:
((x>
0)?
1:
-1);
18data=newList<
();
19for(ulongz=Abs(x);
z!
=0;
z/=(ulong)Base)data.Add((int)(z%(ulong)Base));
20}
21
22BigInteger(BigIntegerx)
23{
24sign=x.sign;
//x!
=null
25data=newList<
(x.data);
26}
27
28publicstaticimplicitoperatorBigInteger(longx)
29{
30returnnewBigInteger(x);
31}
32
她只有两个构造函数,而且都是private的。
要获得该类的实例,主要途径之一是通过从long、int等类型隐式转换(第28到31行)而来,例如BigIntegera=2;
语句。
33publicstaticBigIntegerParse(strings)
34{
35if(s==null)returnnull;
36s=s.Trim().Replace("
"
null);
37if(s.Length==0)return0;
38BigIntegerz=0;
39z.sign=(s[0]=='
-'
)?
-1:
1;
40if(s[0]=='
||s[0]=='
+'
)s=s.Substring
(1);
41intr=s.Length%Len;
42z.data=newList<
(newint[s.Length/Len+((r!
=0)?
0)]);
43inti=z.data.Count-1;
44if(r!
=0)z.data[i--]=int.Parse(s.Substring(0,r));
45for(;
i>
i--,r+=Len)z.data[i]=int.Parse(s.Substring(r,Len));
46z.Shrink();
47returnz;
48}
49
获得该类的实例的主要途径之二是调用静态的Parse方法,例如:
vara=BigInteger.Parse("
-123,456,789"
);
50publicstaticvoidSwap(refBigIntegerx,refBigIntegery)
51{
52BigIntegerz=x;
53x=y;
54y=z;
55}
56
57publicstaticulongAbs(longx)
58{
59return(x<
(ulong)-x:
(ulong)x;
60}
61
62publicstaticBigIntegerAbs(BigIntegerx)
63{
64if(x==null)returnnull;
65BigIntegerz=newBigInteger(x);
66z.sign=Math.Abs(x.sign);
67returnz;
68}
69
上面三个静态的公共方法都很简单,主要是为了方便,如果不提供这些方法也没关系。
要注意的是第二个Abs(long)方法返回ulong类型,而且从不抛出异常。
而Math.Abs(long)返回long类型,而且当参数为long.MinValue时会抛出异常。
70publicstaticBigIntegerPow(BigIntegerx,inty)
71{
72if(x==null)returnnull;
73BigIntegerz=1,n=x;
74for(;
y>
0;
>
=1,n*=n)if((y&
1)!
=0)z*=n;
75returnz;
76}
77
78publicstaticBigIntegeroperator+(BigIntegerx)
79{
80if(x==null)returnnull;
81returnnewBigInteger(x);
82}
83
84publicstaticBigIntegeroperator-(BigIntegerx)
85{
86if(x==null)returnnull;
87BigIntegerz=newBigInteger(x);
88z.sign=-x.sign;
89returnz;
90}
91
注意,重载的单目+操作符不仅是为了和重载的单目-操作符对应,而且可以用于克隆。
BigIntegerx=+y;
和BigIntegerx=y;
语句是完全不同的,前者为克隆一份新的对象,后者只是直接引用同一对象。
之所以不实现IClone接口,是因为该接口的Clone方法的返回类型是object,使用起来很不方便:
varx=y.Clone()asBigInteger;
需要一次强制类型转换。
如果FCL中有泛型版本的IClone<
T>
接口就好了。
92publicstaticBigIntegeroperator++(BigIntegerx)
93{
94returnx+1;
95}
96
97publicstaticBigIntegeroperator--(BigIntegerx)
98{
99returnx-1;
100}
101
在C#语言中重载++和--运算符比在C++语言中容易,C#编译器会处理好前缀和后缀的情况。
102publicstaticBigIntegeroperator+(BigIntegerx,BigIntegery)
103{
104if(x==null||y==null)returnnull;
105if(x.AbsCompareTo(y)<
0)Swap(refx,refy);
106BigIntegerz=newBigInteger(x);
107if(x.sign*y.sign==-1)z.AbsSubtract(y);
108elsez.AbsAdd(y);
109returnz;
110}
111
112publicstaticBigIntegeroperator-(BigIntegerx,BigIntegery)
113{
114if(x==null||y==null)returnnull;
115returnx+(-y);
116}
117
118publicstaticBigIntegeroperator*(BigIntegerx,BigIntegery)
119{
120if(x==null||y==null)returnnull;
121BigIntegerz=0;
122z.sign=x.sign*y.sign;
123z.data=newList<
(newint[x.data.Count+y.data.Count]);
124for(inti=x.data.Count-1;
i--)
125for(intj=y.data.Count-1;
j>
j--)
126{
127longn=Math.BigMul(x.data[i],y.data[j]);
128z.data[i+j]+=(int)(n%Base);
129z.CarryUp(i+j);
130z.data[i+j+1]+=(int)(n/Base);
131z.CarryUp(i+j+1);
132}
133z.Shrink();
134returnz;
135}
136
137publicstaticBigIntegeroperator/(BigIntegerdividend,BigIntegerdivisor)
138{
139BigIntegerremainder;
140returnDivRem(dividend,divisor,outremainder);
141}
142
143publicstaticBigIntegeroperator%(BigIntegerdividend,BigIntegerdivisor)
144{
145BigIntegerremainder;
146DivRem(dividend,divisor,outremainder);
147returnremainder;
148}
149
在C#中重载加减乘除等运算符,C#编译器也会自动添上相应的赋值运算符(+=,-=,...)。
150publicstaticBigIntegerDivRem(BigIntegerdividend,BigIntegerdivisor,outBigIntegerremainder)
151{
152remainder=null;
153if(dividend==null||divisor==null)returnnull;
154if(divisor.sign==0)thrownewException("
divisionbyzero"
155if(dividend.AbsC
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 浅谈 BigInteger