.NET中的BigDecimal超过28位 [英] BigDecimal in .NET with more than 28 digits

查看:134
本文介绍了.NET中的BigDecimal超过28位的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,



我需要一个BigDecimal-Class来计算超过28位的数字。

我试图使用W3bSine-Project并导入J#-BigDecimal-Type。

这两个方法都没有让我开心。原因W3bSine似乎有错误并且没有支持。



在.NET 4中有一个BigInteger - 但没有BigDecimal!



有谁知道一个很好的.NET库/类?

可以是商业的。



谢谢,



Mike

解决方案

< blockquote>如果 BigDecimal 存在(并且可以创建这样的类型),它将不是真正的数字类型。术语十进制与数字以人类可读形式编写的形式有关,而与数值属性(如值,算术运算等)无关。这就是编程语言中不存在十进制类型的原因。然而,在这种类型中存在某种(小)意义:然后可以使用逐位数计算技术用作固定精度整数类型 - 就像传统的计算器一样。我认为这项技术已经走到了尽头。



如果你有 BigInteger - 你有你所需要的一切,只学会使用它。



目前尚不清楚,你想要整数还是小数。如果你需要一个固定精度的小数 - 这实际上是相同的 BigInteger ,但实现基于 BigInteger 需要一些认真的工作。原则上是可行的。

请在此处查看我的回答和讨论:

我想使用c#制作windows计算器,应该使用什么类型 [ ^ ]。



-SA


我写了这个BigInt的VB实现,我喜欢它,所以认为它可能会有所帮助。它无法处理真正巨大的数字,如格雷厄姆的数字,但它可以在大约3毫秒内计算普朗克长度(+/- 1)的宇宙体积,因此似乎适合大多数实际的大数字应用。它对加法,减法,乘法,积分除法,Log2和移位都是准确的。示例位于顶部,您可以随意以任何方式重复使用此代码。如果你喜欢它,并且你为Googol工作,请雇用我:)







公共结构BigInt 
公共共享函数U()As BigInt'计划长度中的宇宙体积
Dim lRet As BigInt = New BigInt(10)^ 35'Planck-lengths per meter
lRet =(lRet * 30000000)* 13700000 *(60 * 60 * 24 * 365)'可观察宇宙的直径在普朗克长度
lRet = BigInt.TimesPi((lRet ^ 3)* 4)\\ \\ 3'普朗克的宇宙体积 - 长度
返回lRet
结束函数
公共共享函数TimesPi(pBigInt As BigInt)As BigInt
Dim lOp As BigInt
'只是一个方便的理性近似Pi,十六进制为性能
Dim lSignificantDigits =(pBigInt.Log2 \ 4)+ 3
'lOp = BigInt.FromBase10(19018707285669230606090143944714770339621590768313546397192526115562704339680963564320007808107929370299752345187688835741387003036853 361285671158059867702399073227994426905220194699766118756059055619036488502928002591)
'Debug.Print(Multiple =& BigInt.ToBase16(LOP))
LOP = BigInt.FromBase16(左( 5845B0A4C43FF041EE3CB64FE4AC283EC160121098D69A6E811E20511E3AE9B57DF4090D8855B3DC8BD649FA3756935283A0022779248D97ADD33C6B0BEAC74973DC124A3E1F0DBD6937F0E9E6975FF3C1C556B02A38ED94CE1F,lSignificantDigits))
尺寸LRET作为BigInt有= pBigInt * LOP
LOP = BigInt.FromBase10( 605384255146420326102361023215940531716391478150345020739231253172134740688232476946000058713774549796561447468267746412874022717544100946587144148739626803435133473281606663121381125761746030151344353855924025288111\" )
'Debug.Print( 多路= &安培; BigInt.ToBase16(LOP))
LOP = BigInt.FromBase16(左( 1C1911716363228A62BB598F0ACD9C1565D39E10D84CE34459AF8E7B7C871CF668B48356882A8239FC1FD6523E3B273E5232C420D9CB5564A5A2D1E571BD2D4ED25995EB9B7B06A9721C4929034443808B4F399D6714F9F1E5AF,lSignificantDigits))
' 调试.Print(Dividend =& BigInt.ToBase16(lOp))
lRet = lRet \ lOp
返回lRet
结束函数
公共共享函数TestTimesPi(pReps As Integer)As Double
Dim lOp As BigInt
Dim lBigInt BigInt = U()
Dim lEnd As Double
Dim lRet As BigInt
Dim lStart As Double = Microsoft.VisualBasic.Timer
For i As Integer = 1 to pReps
lRet = TimesPi(lBigInt)
Next i
lEnd = Microsoft.VisualBasic.Timer
Debug.Print(lEnd - lStart& 秒为& pReps& pi计算)
返回lEnd - lStart
结束函数
私有mBytes作为列表(Byte)
私有mIsNegative作为Boolean
公共函数IsEven()As Boolean
返回非IsOdd()
结束函数
公共函数IsOdd()As Boolean
如果IsZero()则返回False Else返回mBytes(0)和1
结束函数
公共函数Abs()As BigInt
Dim lRet As New BigInt
lRet.mBytes = New List(Of Byte)
lRet.mBytes.AddRange(mBytes)
lRet.Normalize()
返回lRet
结束函数
Public Sub Normalize()
如果mBytes为Nothing那么
mIsNegative = False
退出Sub
结束如果
如果mBytes.Count> 0然后
而mBytes(mBytes.Count - 1)= 0
mBytes.RemoveAt(mBytes.Count - 1)
结束时
结束如果
If(mBytes .Count = 0)然后
mIsNegative = False
结束如果
结束子
公共子新(pVal为长)
如果pVal< 0然后
mIsNegative = True
pVal = -pVal
结束如果
mBytes =新列表(字节数)
虽然pVal> 0
Dim lByte As Byte = pVal和255
mBytes.Add(lByte)
pVal = pVal>> 8
结束时
'无需规范化此
结束子
公共子新(pBigInt As BigInt)
mBytes =新列表(字节数)
mBytes.AddRange(pBigInt.mBytes.ToArray)
mIsNegative = pBigInt.mIsNegative
Normalize()
End Sub
公共共享运算符 - (ByVal class1 As BigInt)As BigInt
Dim lRet As New BigInt(class1)
lRet.mIsNegative = Not lRet.mIsNegative
lRet.Normalize()
返回lRet
结束运算符
公共共享函数比较(ByVal class1 As BigInt,ByVal class2 As BigInt)As Integer
class1.Normalize()
class2.Normalize()
If class1.IsZero Then
If class2.IsZero然后
返回0
ElseIf class2.mIsNegative然后
返回1
否则
返回-1
结束如果
ElseIf class2。 IsZero然后
如果class1.mIsNegative然后
返回-1
否则
返回1
结束如果
ElseIf class1.mIsNegative然后
如果class2 .mIsNegative然后
返回-Compare(-class1,-class2)
否则
返回-1
结束如果
ElseIf class2.mIsNegative然后
返回1
结束如果
'处理正阳性比较这里
Dim iLeft As Integer = class1.mBytes.Count - 1
Dim iRight As Integer = class2.mBytes.Count - 1
虽然iLeft> iRight
如果class1.mBytes(iLeft)<> 0然后
返回1
结束如果
iLeft - = 1
结束时
虽然iRight> iLeft
如果class2.mBytes(iRight)<> 0然后
返回-1
结束如果
iRight - = 1
结束时
虽然iLeft> = 0
如果class1.mBytes(iLeft) < class2.mBytes(iLeft)然后
返回-1
ElseIf class1.mBytes(iLeft)> class2.mBytes(iLeft)然后
返回1
结束如果
iLeft - = 1
结束时
返回0
结束函数
公开共享运算符<(ByVal class1 As BigInt,ByVal class2 As BigInt)As Boolean
Select Case Compare(class1,class2)
Case -1
返回True
Case Else
返回False
结束选择
结束运算符
公共共享运算符>(ByVal class1 As BigInt,ByVal class2 As BigInt)As Boolean
Select Case Compare(class1,class2)
案例1
返回True
案例Else
返回False
结束选择
结束运算符
公共共享运算符< =(ByVal class1 As BigInt,ByVal class2 As BigInt)As Boolean
Select Case Compare(class1,class2)
Case 0,-1
返回True
Case Else
返回False
结束选择
结束运算符
公共共享运算符> =(ByVal class1 As BigInt,ByVal class2 As BigInt)As Boolean
选择案例比较(class1,class2)
案例0,1
返回True
案例Else
返回False
结束选择
结束运算符
公共共享运算符=(ByVal class1 As BigInt,ByVal class2 As BigInt)As Boolean
Select Case Compare(class1,class2)
Case 0
返回True
Case Else
返回False
结束选择
结束运算符
公共共享运算符<>(ByVal class1 As BigInt,ByVal class2 As BigInt)As Boolean
Select Case Compare(class1, class2)
Case 0
返回False
Case Else
返回True
结束选择
结束运算符
公共函数IsZero()As Boolean
如果mBytes为Nothing则返回True
如果mBytes.Count = 0则返回True
For Each lByte以mBytes
如果lByte<> 0然后返回False
下一个
返回True
结束函数
公共共享运算符+(ByVal class1 As BigInt,ByVal class2 As Long)As BigInt
返回class1 + New BigInt(class2)
结束运算符
公共共享运算符+(ByVal class1 As BigInt,ByVal class2 As BigInt)As BigInt
如果class1.mBytes Is Nothing则返回class2
如果class2 .mBytes Is Nothing Then返回class1
Dim lBytes1 As Integer = class1.mBytes.Count
Dim lBytes2 As Integer = class2.mBytes.Count
Dim lBytes As New List(Of Byte)
Dim lRemainder As Byte = 0
Dim i As Integer = 0
Dim lZeros As Integer = 0
While(i< lBytes1)Or(i< lBytes2)Or(l< lBytes2)Or(lRemainder< ;> 0)
Dim lByte1 As Integer = 0
Dim lByte2 As Integer = 0
Dim lTemp As Integer = 0
如果i< lBytes1然后lByte1 = class1.mBytes(i)
如果i< lBytes2然后lByte2 = class2.mBytes(i)
lTemp = lByte1 + lByte2 + lRemainder
lRemainder = 0
如果lTemp> 255然后
lRemainder = lTemp \ 256
lTemp - = 256 * lRemainder
结束如果
lBytes.Add(lTemp)
如果lTemp = 0那么lZeros + = 1 Else lZeros = 0
i + = 1
结束时
虽然lZeros> 0
lBytes.RemoveAt(lBytes.Count - 1)
lZeros - = 1
结束时
Dim lRet As New BigInt
lRet.mBytes = lBytes
返回lRet
结束运算符
公共共享运算符 - (ByVal class1 As BigInt,ByVal class2 As Long)As BigInt
返回class1 - 新BigInt(class2)
结束运算符
公共共享的运营商 - (BYVAL class1的作为BigInt有,BYVAL Class2中作为BigInt有)作为BigInt有
尺寸lResultIsNegative作为布尔值
尺寸lLeft作为BigInt有
尺寸lRight作为BigInt有
class1.Normalize ()
class2.Normalize()
如果class1.mIsNegative那么
如果class2.mIsNegative那么
返回 - (class1.Abs + class2.Abs)
否则
返回class1.Abs + class2
结束如果
ElseIf class2.mIsNegative然后
返回class1 + class2.Abs
结束如果
Select Case Compare(class1,class2)
Case 0
返回New BigInt(0)
Case -1
lResultIsNegative = True
lLeft = class2
lRight = class1
Case 1
lResultIsNegative = False
lLeft = class1
lRight = class2
Case Else
抛出新的InvalidOperationException(BigInt.vb遇到无效比较数字时的结果。)
结束选择

'左边大于右边,如果指示
Dim lBorrow As Integer = 0
Dim lRet As New BigInt(0)
For i As Integer = 0 to lLeft.mBytes.Count - 1
Dim iLeft As Integer
Dim iRight As Byte
iLeft = lLeft.mBytes (i) - lBorrow
如果i> = lRight.mBytes.Count那么
iRight = 0
否则
iRight = lRight.mBytes(i)
结束如果
lBorrow = 0
虽然iLeft< iRight
lBorrow + = 1
iLeft + = 256
End
lRet.mBytes.Add(iLeft - iRight)
Next
lRet.mIsNegative = lResultIsNegative
lRet.Normalize()
返回LRET
结束操作
公共共享功能GrahamNotation(PBASE为整数,pArrows作为整数,pHeight作为整数)作为BigInt有
返回GrahamNotation(新BigInt有(PBASE),pArrows,新BigInt有(pHeight))
端功能
公共共享功能GrahamNotation(PBASE作为BigInt有,pArrows作为整数,pHeight作为BigInt有)作为BigInt有
。如果pArrows> 1然后
返回GrahamNotation(pBase,pArrows - 1,GrahamNotation(pBase,1,pHeight))
结束如果
Dim lRet As BigInt = pBase
lRet = pBase ^ pHeight

'lRet = lRet ^(pHeight - 1)
返回lRet
结束函数
公共共享运算符*(ByVal class1 As BigInt,pByte As Byte)As BigInt
Dim lBytes1 As Integer = class1.mBytes.Count

Dim lOutBytes As New List(Of Byte)
Dim lCarry As Long = 0
For i = 0 To lBytes1 - 1
Dim lTemp As Long =(CLng(class1.mBytes(i))* pByte)+ lCarry
lCarry = 0
如果lTemp> 255然后
lCarry = lTemp \ 256
lTemp = lTemp Mod 256
结束如果
lOutBytes.Add(CByte(lTemp))
下一个
'而lCarry> 255
如果lCarry> 255然后
lOutBytes.Add(CByte(lCarry Mod 256))
lCarry = lCarry \ 256
结束如果
'结束而
如果lCarry> 0然后lOutBytes.Add(CByte(lCarry))
Dim lRet As New BigInt
lRet.mBytes = lOutBytes
lRet.mIsNegative = class1.mIsNegative
返回lRet
结束运算符
公共共享运算符^(ByVal class1 As BigInt,class2 As BigInt)As BigInt
class2.Normalize()
If class2.IsZero Then Return New BigInt(1)
如果class2 = New BigInt(1)那么返回class1
Dim lIsNegative As Boolean = False
如果class1.mIsNegative AndAlso(class2.mBytes(0)和1)那么lIsNegative = True
Dim lPow作为New BigInt(class2)
Dim lBase As New BigInt(class1)
Dim l1 As New BigInt(1)
Dim lSuperpow As New BigInt(l1)
Dim lMultiplier As New BigInt(l1)
Dim l2 As New BigInt(2)
而lPow> l2
如果lPow.IsOdd那么
lPow - = l1
lMultiplier = lMultiplier *(lBase ^ lSuperpow)
Else
lPow = lPow>> 1
lSuperpow = lSuperpow<< 1
结束如果
结束而
lBase = lBase ^ lSuperpow
如果lPow = l2那么lMultiplier = lMultiplier * lBase
lBase = lBase * lMultiplier
'如果lSuperpow> l1然后lBase = lBase ^ lSuperpow
返回lBase
结束运算符

公共共享运算符^(ByVal class1 As BigInt,class2 As Integer)As BigInt
返回class1 ^新BigInt(class2)
结束运营商
公共共享运营商*(ByVal class1 As BigInt,class2 As Long)As BigInt
返回class1 * New BigInt(class2)
End Operator

公共共享运营商*(ByVal class1 As BigInt,class2 As BigInt)As BigInt
Dim lTop As BigInt
Dim lBottom As BigInt
class1.Normalize()
class2.Normalize()
如果class1.IsZero或class2.IsZero然后返回New BigInt(0)
Dim lResultIsNegative As Boolean = class1.mIsNegative Xor class2.mIsNegative
If class1.mBytes .Count< class2.mBytes.Count然后
lTop = class2
lBottom = class1
否则
lTop = class1
lBottom = class2
结束如果

Dim lRunningTotal As New BigInt
For i = 0 To lBottom.mBytes.Count - 1
Dim lAdditive As BigInt = lTop * CByte(lBottom.mBytes(i))
for j = 1至I
lAdditive.mBytes.Insert(0,CByte(0))
下一
lRunningTotal + = lAdditive
下一
lRunningTotal.mIsNegative = lResultIsNegative
lRunningTotal.Normalize()
返回lRunningTotal
结束运算符
公共共享函数PowerOf2(pPower As Integer)As BigInt
Dim lRet As BigInt = New BigInt(1)< < (pPower - 1)
返回lRet
结束函数
私有共享mPowersOf10 As Dictionary(Of Integer,BigInt)

公共共享函数ClearCachedPowers()
如果mPowersOf10 IsNot Nothing那么
mPowersOf10.Clear()
结束如果
结束函数
公共共享函数PowerOf10(pPower As Integer)As BigInt
如果pPower = 0那么
返回New BigInt(1)
ElseIf pPower = 1然后
返回New BigInt(10)
ElseIf mPowersOf10.ContainsKey(pPower)然后
返回New BigInt(mPowersOf10 (pPower))
Else
mPowersOf10(pPower)= New BigInt(10)^ pPower
返回New BigInt(mPowersOf10(pPower))
结束如果
结束函数
公共共享运营商\(ByVal class1 As BigInt,class2 As BigInt)As BigInt
Dim lResult As BigInt = New BigInt(0)
Divide(class1,class2, lResult,New BigInt(0))
返回lResult
结束运算符
公共共享运算符/(ByVal class1 As BigInt,class2 As Long)As BigDecimal1
'Dim lResult As BigDecimal =新BigInt(0)
'除以(class1,New BigInt(class2),lResult,New BigInt(0))
'返回lResult
结束运营商
公共共享运营商/( ByVal class1 As BigInt,class2 As BigInt)As BigDecimal1
'Dim lResult As BigInt = New BigInt(0)
'Divide(class1,New BigInt(class2),lResult,New BigInt(0))
'返回lResult
结束运算符
公共共享运算符\(ByVal class1 As BigInt,class2 As Long)As BigInt
Dim lResult As BigInt = New BigInt(0)
除以(class1,New BigInt(class2),lResult,New BigInt(0))
返回lResult
结束运算符
公共共享运算符Mod(ByVal class1 As BigInt,class2 As BigInt)As BigInt
Dim lResult As BigInt = New BigInt(0)
除以(class1,class2,New BigInt(0),lResult)
返回lResult
结束运算符
公共共享运算符Mod(ByVal class1 As BigInt ,class2 As Long)As BigInt
Dim lResult BigInt = New BigInt(0)
除以(class1,New BigInt(class2),New BigInt(0),lResult)
返回lResult
结束运算符
公共函数ToByte()As Byte
Normalize()
如果IsZero()则返回0
返回mBytes(0)
结束函数

Public Shared Sub SquareTest(pPower As Integer)
Dim lRet As BigInt =(New BigInt(1)<< pPower) - New BigInt(1)
Debug.Print(lRet.ToString)
End Sub


Public Shared Sub SpeedTest2()
Dim lBigNum作为BigInt = New BigInt(10)
Dim lTime1 As Double = Microsoft.VisualBasic.Timer
lBigNum = lBigNum ^ 1000
Dim lTime2 As Double = Microsoft.VisualBasic.Timer
Debug .Print((lTime2 - lTime1)&秒来计算Googol ^ 10)
lTime1 = Microsoft.VisualBasic.Timer
lBigNum = lBigNum ^ 50
lTime2 = Microsoft.VisualBasic.Timer
Debug.Print((lTime2 - lTime1)&秒将其提升到50次幂)
Debug.Print(结果是& lBigNum.Log2&位长。 )
Debug.Print(转换为十进制......)
lTime1 = Microsoft.VisualBasic.Timer
Debug.Print(lBigNum.ToString)
lTime2 = Microsoft。 VisualBasic.Timer
Debug.Print(转换为十进制&am磷; (lTime2 - lTime1)& 秒。)
结束Sub
公共共享Sub SpeedTest3()
Debug.Print(生成3(箭头)3)
Dim lTime1 As Double = Microsoft.VisualBasic .Timer
Dim lBigInt = BigInt.GrahamNotation(3,1,3)
Dim lTime2 As Double = Microsoft.VisualBasic.Timer
Debug.Print(Time elapsed:&(lTime2 - lTime1))
Debug.Print(lBigInt.ToString)

Debug.Print(Generating 3(double-arrow)3)
lTime1 = Microsoft.VisualBasic.Timer
lBigInt = BigInt.GrahamNotation(3,2,3)
lTime2 = Microsoft.VisualBasic.Timer
Debug.Print(Time elapsed:&(lTime2 - lTime1))
Debug.Print(lBigInt.ToString)

退出Sub

Debug.Print(lBigInt.mBytes.Count&bytes)
Debug.Print (生成3(三箭头)2)
lTime1 = Microsoft.VisualBasic.Timer
lBigInt = BigInt.GrahamNotation(3,3, 2)
lTime2 = Microsoft.VisualBasic.Timer
Debug.Print(Time elapsed:& (lTime2 - lTime1))
Debug.Print(lBigInt.ToString)
Debug.Print(lBigInt.mBytes.Count&bytes)
Debug.Print(Generating 3(triple) -arrow)3)
lTime1 = Microsoft.VisualBasic.Timer
lBigInt = BigInt.GrahamNotation(3,3,3)
lTime2 = Microsoft.VisualBasic.Timer
Debug。打印(已过去的时间:&(lTime2 - lTime1))
Debug.Print(lBigInt.ToString)
Debug.Print(lBigInt.mBytes.Count&bytes)
End Sub
Public Shared Sub SpeedTest4()
Dim lBigInt As BigInt = GrahamNotation(2,4,2)
Debug.Print(lBigInt.ToString)
End Sub


公共共享Sub SpeedTest()
Dim lTime1 As Double = Microsoft.VisualBasic.Timer
Dim j As Integer
For i = 1 To 1000000
j = j + 1
下一个
Dim lTime2 As Double = Microsoft.VisualBasic.Timer
Debug.Print(整数:& (lTime2 - lTime1))
Dim k As New BigInt(0)
Dim l1 As New BigInt(1)
For i = 1 To 10000
k = k + l1
下一个
lTime1 = Microsoft.VisualBasic.Timer
Debug.Print(BigInt:&(lTime1 - lTime2))
End Sub

公共函数ToInt16()As Int16
Dim lRet As Int16
If IsZero()然后返回0
如果mBytes.Count> 1然后lRet = lRet +(CLng(mBytes(1)和127)<< 8)
如果mBytes.Count> 0然后lRet = lRet + mBytes(0)
如果mIsNegative然后返回-lRet Else返回lRet
结束函数
公共函数ToInt32()As Int32
Dim lRet As Int32
如果IsZero()则返回0
如果mBytes.Count> 3然后lRet = lRet +(CLng(mBytes(3)和127)<< 24)
如果mBytes.Count> 2然后lRet = lRet +(CLng(mBytes(2))<< 16)
如果mBytes.Count> 1然后lRet = lRet +(CLng(mBytes(1))<< 8)
如果mBytes.Count> 0然后lRet = lRet + mBytes(0)
如果mIsNegative然后返回-lRet Else返回lRet
结束函数

私有共享子除(pDividend作为BigInt,pDivisor作为BigInt, ByRef pResult As BigInt,ByRef pModulus As BigInt)
pDivisor.Normalize()
如果pDivisor.IsZero然后抛出新DivideByZeroException
pDividend.Normalize()
如果pDividend.IsZero那么
pResult = New BigInt(0)
pModulus = New BigInt(0)
退出Sub
结束如果
Dim lResultIsNegative As Boolean = pDividend.mIsNegative Xor pDivisor.mIsNegative
Dim lDividend As BigInt = pDividend.Abs
Dim lDivisor As BigInt = pDivisor.Abs
Select Case Compare(lDividend,lDivisor)
Case -1
pResult = New BigInt (0)
pModulus =新BigInt(lDividend)
退出Sub
案例0
pResult = New BigInt(1)
pModulus = New BigInt(0)
退出Sub
结束选择
'红利大于除数
'将红利乘以256而

Dim lShift As Integer
Dim lRunningTotal As New BigInt(0)
而不是lDividend.IsZero
如果lDividend< lDivisor然后
pModulus = lDividend
pResult = lRunningTotal
退出小组
结束如果
LSHIFT = Math.Truncate(lDividend.Log2_Dbl - lDivisor.Log2_Dbl)
'lShift = Math.Truncate(lDividend.Log2 - lDivisor.Log2)
Dim lTestDivisor As BigInt = lDivisor<< lShift
如果lTestDivisor> lDividend然后
lTestDivisor = lTestDivisor>> 1
lShift - = 1
结束如果

lRunningTotal + =(New BigInt(1)<< lShift)
lDividend - = lTestDivisor
结束时

pResult = lRunningTotal
pModulus = New BigInt(0)
退出Sub
End Sub

公共共享运营商<< ;(pBigInt As BigInt,pBits As Integer)As BigInt
Dim lRet As New BigInt(pBigInt)
Dim lBits As Integer = pBits
pBigInt.Normalize()
if lBits> ; = 8然后
Dim lInsertBytes((pBits \ 8) - 1)As Byte
lRet.mBytes.InsertRange(0,lInsertBytes)
lBits = lBits Mod 8
End如果
如果lBits = 0那么
lRet.Normalize()
返回lRet
结束如果
Dim lMostSignificantBit As Byte = Log2(lRet.mBytes(lRet.mBytes。计数 - 1))
Dim lAvailableBits As Byte = 8 - lMostSi gnificantBit
如果lAvailableBits< lBits然后lRet.mBytes.Add(0)
Dim lMaskLeft As Byte =(1<<(lBits + 1)) - 1
Dim lMaskRight As Byte = Not lMaskLeft
For i = 1Ret.mBytes.Count - 1到1步-1
lRet.mBytes(i)=((1Ret.mBytes(i)<< lBits)或(lRet.mBytes(i-1)> >(8 - lBits)))和255
下一个
lRet.mBytes(0)=(lRet.mBytes(0)<< lBits)和255
返回lRet
结束运算符
公共共享运算符>>(pBigInt作为BigInt,pBits作为整数)作为BigInt
Dim lRet作为新BigInt(pBigInt)
Dim lBits As Integer = pBits
pBigInt.Normalize()
如果lBits> = 8那么
lRet.mBytes.RemoveRange(0,pBits = 8)
lBits = lBits Mod 8
结束如果
如果lBits = 0那么
lRet.Normalize()
返回lRet
结束如果

Dim lMostSignificantBit As Byte = Log2(lRet.mBytes(l Ret.mBytes.Count - 1))
Dim lAvailableBits As Byte = 8 - lMostSignificantBit
如果lAvailableBits< lBits然后lRet.mBytes.Add(0)
Dim lMaskLeft As Byte =(1<<(lBits + 1)) - 1
Dim lMaskRight As Byte = Not lMaskLeft
For i = 0到lRet.mBytes.Count - 2
lRet.mBytes(i)=((lRet.mBytes(i)>> lBits)或(lRet.mBytes(i + 1)<<( 8 - lBits))) And 255
Next
lRet.mBytes(lRet.mBytes.Count - 1) = (lRet.mBytes(lRet.mBytes.Count - 1) >> lBits) And 255
Return lRet

End Operator
Public Function Log2() As Long
Normalize()
If IsZero() Then Return 0
Return ((mBytes.Count - 1) * 8) + Log2(mBytes(mBytes.Count - 1))
End Function

Public Function Log2_Dbl() As Double
Normalize ()
If IsZero() Then Return 0
Dim lBits As Integer = (mBytes.Count - 1) * 8
Dim lDivisor As Double = 1
Dim lRunningTotal As Double = lBits + Log2_Dbl(mBytes(mBytes.Count - 1 ))
For i = mBytes.Count - 2 To Math.Max(mBytes.Count - 8, 0) Step -1
lDivisor = lDivisor * 256
lRunningTotal += (CDbl(Log2_Dbl(mBytes(i))) / lDivisor)
Next
Return lRunningTotal
End Function

Public Overrides Function ToString() As String
Return BigInt.ToBase10(Me)
End Function

Public Shared Function ToBaseX(pBigInt As BigInt, pBase As Byte) As String
If pBase < 2 Then Throw New ArgumentException(\"Cannot display as base less than 2\")
If pBase > 2 Then Throw New ArgumentException(\"Cannot display as base greater than 16\")
pBigInt.Normalize()
If pBigInt.IsZero Then Return \"0\"
Dim aChars() As Char = {\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\"}

Dim lRet As New System.Text.StringBuilder()
If pBigInt.mIsNegative Then lRet.Append(\"-\")
lRet.Append(\"&(\" & pBase & \")\")

Dim lByte As Byte = (pBigInt Mod pBase).ToByte
If lByte And &HF0 Then
lRet.Append(aChars(lByte))
End If
If lByte And &HF Then
lRet.Append(aChars(lByte And &HF))
End If
For i = pBigInt.mBytes.Count - 2 To 0 Step -1
lByte = pBigInt.mBytes(i)
lRet.Append(aChars(lByte >> 4) & aChars(lByte And 15))
Next
Return lRet.ToString
End Function

Public Shared Function ToBase16(pBigInt As BigInt) As String
pBigInt.Normalize()
If pBigInt.IsZero Then Return \"0\"
Dim aChars() As Char = {\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\"}

Dim lRet As New System.Text.StringBuilder()
If pBigInt.mIsNegative Then lRet.Append(\"-\")
lRet.Append(\"&H\")
Dim lByte As Byte = pBigInt.mBytes(pBigInt.mBytes.Count - 1)
If lByte And &HF0 Then
lRet.Append(aChars(lByte >> 4))
End If
If lByte And &HF Then
lRet.Append(aChars(lByte And &HF))
End If
For i = pBigInt.mBytes.Count - 2 To 0 Step -1
lByte = pBigInt.mBytes(i)
lRet.Append(aChars(lByte >> 4) & aChars(lByte And 15))
Next
Return lRet.ToString
End Function

Public Function ToBase16() As String
Return BigInt.ToBase16(Me)
End Function

Public Shared Function FromBase10(pSource As String) As BigInt
Dim lMode As Byte = 1
Dim lIsNegative As Boolean
Dim lNB As New System.Text.StringBuilder
Dim lDec As Integer = -1
Dim lShiftDirection As Char
Dim lShiftAmt As String
For Each lChar In pSource
Select Case lMode
Case 1
Select Case lChar
Case \" \", \"+\"
Case \"-\"
lIsNegative = True
lMode = 2
Case \"0\" ’ignore leading zeros
Case \"1\" To \"9\"
lNB.Append(lChar)
lMode = 2
Case \".\"
lDec = lNB.Length
lMode = 3
Case Else
Throw New InvalidCastException
End Select
Case 2
Select Case lChar
Case \",\"
Case \"0\" To \"9\"
lNB.Append(lChar)
Case \".\"
lDec = lNB.Length
lMode = 3
Case \"E\"
lMode = 4
Case Else
Throw New InvalidCastException
End Select
Case 3
Select Case lChar
Case \",\"
Case \"0\" To \"9\"
lNB.Append(lChar)
Case \"E\"
lMode = 4
lShiftDirection = \"+\"
Case Else
Throw New InvalidCastException
End Select
Case 4
Select Case lChar
Case \"+\", \"-\"
lShiftDirection = lChar
lM ode = 5
Case \"0\"
Case \"1\" To \"9\"
lShiftAmt = lShiftAmt & lChar
lMode = 6
Case Else
Throw New InvalidCastException
End Select
Case 5
Select Case lChar
Case \"0\"
Case \"1\" To \"9\"
lShiftAmt = lShiftAmt & lChar
lMode = 6
Case Else
Throw New InvalidCastException
End Select
Case 6
Select Case lChar
Case \"0\" To \"9\"
lShiftAmt = lShiftAmt & lChar
lMode = 6
Case Else
Throw New InvalidCastException
End Select
End Select
Next
If lDec = -1 Then lDec = lNB.Length + 1
Dim lAsDecimal As String
If lShiftAmt = \"\" Then
lAsDecimal = lNB.ToString
ElseIf lShiftDirection = \"+\" Then
lDec = lDec + Val(lShiftAmt)
If lDec > (lNB.Length + 1) Then
lAsDecimal = lNB.ToString & New String(\"0\", (lDec - lNB.Length) - 1)
Else
lAsDecimal = lNB.ToString.Substring(0, lDec - 1)
End If
ElseIf lShiftDirection = \"-\" Then
lDec = lDec - Val(lShiftAmt)
If lDec < 1 Then
Return New BigInt(0)
Else
lAsDecimal = lNB.ToString.Substring(0, lDec - 1)
End If
End If
’lAsDecimal is now a clean, unsigned decimal with scientific notation expanded
Dim l10 As BigInt = New BigInt(10)
Dim lTens As BigInt = New BigInt(1)
Dim lRet As BigInt = New BigInt(0)
For i = lAsDecimal.Length - 1 To 0 Step -1
Dim lAdditive As BigInt = lTens * New BigInt(Asc(lAsDecimal.Substring(i, 1)) - 48)
lRet += lAdditive
lTens = lTens * l10
Next
lRet.mIsNegative = lIsNegative
lRet.Normalize()
Return lRet
End Function


Public Shared Function FromBase16(pSource As String) As BigInt
Dim lProc As New Stack(Of Byte)
Dim lTemp As String = \"\"
Dim lRet As New BigInt(0) $b$ b For i = 0 To pSource.Length - 1
Dim lChar As Char = pSource.Substring(i, 1)
Dim lAsc As Integer = Asc(lChar)
Select Case lAsc
Case 48 To 57
lTemp = lTemp & lChar
Case 65 To 70
lTemp = lTemp & lChar
End Select
If Len(lTemp) = 2 Then
Dim lByte As Byte = 0
lAsc = Asc(lTemp.Substring(0, 1))
Select Case lAsc
Case 48 To 57
lByte = (lAsc - 48) << 4
Case 65 To 70
lByte = (lAsc - 55) << 4
End Select
lAsc = Asc(lTemp.Substring(1, 1))
Select Case lAsc
Case 48 To 57
lByte = lByte + (lAsc - 48)
Case 65 To 70
lByte = lByte + (lAsc - 55)
End Select

lTemp = \"\"
lRet.mBytes.Insert(0, lByte)
End If
Next
If lTemp <> \"\" Then
Select Case Asc(lTemp)
Case 48 To 57
lRet = lRet << 4
lRet += New BigInt(Asc(lTemp) - 48)
Case 65 To 70
lRet = lRet << 4
lRet += New BigInt(Asc(lTemp) - 55)
End Select
End If
lRet.Normalize()
Return lRet
End Function

Public Shared Function ToBase10(pBigInt As BigInt) As String
Dim lRemaining As BigInt = pBigInt
Dim lStack As New Stack(Of Char)
Dim lMod As BigInt = Nothing
Dim lDigit As Byte
Dim l10 As New BigInt(10)
Dim l10K As New BigInt(10000)
Dim l1B As New BigInt(1000000000)
Dim l1Googol As BigInt = New BigInt(0)
If pBigInt.Log2 >= 332 Then l1Googol = New BigInt(10000) ^ 25
Dim l1GoogolE10 As BigInt = New BigInt(0)
If pBigInt.Log2 >= 3321 Then l1GoogolE10 = l1Googol ^ 10
pBigInt.Normalize()
If pBigInt.IsZero Then Return \"0\"
Dim lLastUpdate As Double = Microsoft.VisualBasic.Timer
Dim lStartTime As D ateTime = Now
Dim lStartDigits As Integer = lRemaining.Log2
Dim lStackSize As Long = 0
Do
If (Not l1GoogolE10.IsZero) AndAlso (lRemaining > l1GoogolE10) Then
Divide(lRemaining, l1GoogolE10, lRemaining, lMod)
Dim lText As String = lMod.ToString.PadLeft(1000, \"0\")
For i = lText.Length - 1 To 0 Step -1
lStack.Push(lText.Substring(i, 1))
Next
lStackSize += lText.Length
ElseIf (Not l1Googol.IsZero) AndAlso (lRemaining > l1Googol) Then
Divide(lRemaining, l1Googol, lRemaining, lMod)
Dim lText As String = lMod.ToString.PadLeft(100, \"0\")
For i = lText.Length - 1 To 0 Step -1
lStack.Push(lText.Substring(i, 1))
Next
lStackSize += lText.Length
ElseIf lRemaining > l1B Then
Divide(lRemaining, l1B, lRemaining, lMod)
Dim lText As String = Format(lMod.ToInt32, \"000000000\")
For i = lText.Length - 1 To 0 Step -1
lStack.Push(lText.Substring(i, 1))
Next
lStackSize += lText.Length
ElseIf lRemaining > l10K Then
Divide(lRemaining, l10K, lRemaining, lMod)
Dim lText As String = Format(lMod.ToInt16, \"0000\")
For i = lText.Length - 1 To 0 Step -1
lStack.Push(lText.Substring(i, 1))
Next
lStackSize += lText.Length
Else
Divide(lRemaining, l10, lRemaining, lMod)
lStack.Push(CStr(lMod.ToByte))
lStackSize += 1
End If
If (Microsoft.VisualBasic.Timer - lLastUpdate) > 10 Then
Dim lLog2 As Integer = lRemaining.Log2
If lLog2 < lStartDigits Then
Debug.Print(lLog2 & \" significant digits remaining.\")
Dim lTimeSpent As TimeSpan = Now.Subtract(lStartTime)
Dim lUnitTime As Double = lTimeSpent.TotalSeconds / (lStartDigits - lLog2)
Dim lCompletion As DateTime = Now.AddSeconds(lUnitTime * lLog2 * (lLog2 / lStartDigits) / 3)
Debug.Print(\"Estimated Completion: \" & Format(lCompletion, \"M/d/yyyy HH:mm:ss\"))
Dim lDigitRatio As Double = lStackSize / (lStartDigits - lLog2)
Debug.Print(\"Estimated Output Digits: \" & (lStackSize + CInt(lDigitRatio * lLog2)))
lLastUpdate = Microsoft.VisualBasic.Timer
End If
End If
Loop Until lRemaining.IsZero
If pBigInt.mIsNegative Then lStack.Push(\"-\")
Dim lRet As New System.Text.StringBuilder
Whi le lStack.Count
lRet.Append(lStack.Pop)
End While
If Now - lStartTime > New TimeSpan(0, 1, 0) Then
Using lwriter As New IO.StreamWriter(\"c:\temp\Calculation.txt\", False)
lwriter.WriteLine(lRet.ToString)
lwriter.Close()
lwriter.Dispose()
End Using
End If
Return lRet.ToString
End Function

Public Shared Function Log2(pByte As Byte) As Byte
Dim lRet As Byte
While pByte <> 0
lRet += 1
pByte = pByte >> 1
End While
Return lRet
End Function
Public Shared Function Log2(pInteger As Integer) As Byte
Dim lRet As Byte
If pInteger < 0 Then Throw New InvalidOperationException(\"BigInt cannot take the logarithm of a negative number.\")
While pInteger <> 0
lRet += 1
pInteger = pInteger >> 1
End While
Return lRet
End Function
Public Shared Function Log2_Dbl(pByte As Byte) As Double
Dim lRet As Double = 8
If pByte = 0 Then Return 0
While (pByte And &H80) = 0
lRet -= 1
pByte = pByte << 1
End While
pByte = pByte << 1
Dim lDivisor As Integer = 2
While pByte <> 0
If pByte And &H80 Then
lRet = lRet + 1 / lDivisor
End If
lDivisor *= 2
pByte = pByte << 1
End While
Return lRet
End Function
Public Shared Function Log2_Dbl(pInteger As Integer) As Double
Dim lRet As Double = 8
If pInteger = 0 Then Return 0
While (pInteger And &H8000) = 0
lRet -= 1
pInteger = pInteger << 1
End While
pInteger = pInteger << 1
Dim lDivisor As Integer = 2
While pInteger <> 0
If pInteger And &H8000 Then
lRet = lRet + 1 / lDivisor
End If
lDivisor *= 2
pInteger = pInteger << 1
End While
Return lRet
End Function
End Structure


Hello,

I need a BigDecimal-Class for calculating with numbers with more than 28 digits.
I tried to use the W3bSine-Project and to import the J#-BigDecimal-Type.
Both approched didn't make me happy. Cause W3bSine seems to be buggy and there is no support.

In .NET 4 there is a BigInteger - but no BigDecimal!

Does anyone knows a good Library / Class for .NET?
Could be comercial.

Thanks,

Mike

解决方案

If BigDecimal existed (and it is possible to create such type), it would not be a real numeric type. The term "decimal" is related to the form a numeric is written in human readable form, not to the numeric properties like value, arithmetic operations, etc. That's why such things as "decimal" types do not exist in programming languages. Nevertheless, there is certain (little) sense in such type: then could be used as fixed-precision integer type using the technology of calculation "digit-by-digit" — like in traditional calculators. I think this technology is rendered a dead end.

If you have BigInteger — you have all you need, only learn to use it.

It is not clear, do you want integer or fractional number. If you need a fixed-precision fractional — this is practically the same is BigInteger, but implementing floating-point based on BigInteger will need some serious work. Is is in principle possible.
Please see my past Answer and discussion here:
I would like to use c # to make the windows calculator, what type should be used[^].

—SA


I wrote this VB implementation of BigInt, and I like it, so thought it might be helpful. It can't handle truly gigantic numbers like graham's number, but it can calculate the volume of the universe in planck-lengths (+/- 1) in about 3 milliseconds, and thus seems suitable for most practical big-number applications. It's accurate for addition, subtraction, multiplication, integral division, Log2, and Shifting. Examples are at the top, feel free to reuse this code in any way you please. If you like it, and you work for Googol, hire me :)



Public Structure BigInt
    Public Shared Function U() As BigInt 'Volume of the universe in planck-lengths
        Dim lRet As BigInt = New BigInt(10) ^ 35 'Planck-lengths per meter
        lRet = (lRet * 30000000) * 13700000 * (60 * 60 * 24 * 365) ' Diameter of Observable Universe in planck-lengths
        lRet = BigInt.TimesPi((lRet ^ 3) * 4) \ 3 ' Volume of the universe in Plank-lengths
        Return lRet
    End Function
    Public Shared Function TimesPi(pBigInt As BigInt) As BigInt
        Dim lOp As BigInt
        'Just a handy rational approximation of Pi, in hex for performance
        Dim lSignificantDigits = (pBigInt.Log2 \ 4) + 3
        'lOp = BigInt.FromBase10("1901870728566923076090143944714770339621590768313546337192526115562704339680963564320007808107929370299752345187688835741387003036853361285671158059867702399073227994426905220194699766118756059055619036488502928002591")
        'Debug.Print("Multiple=" & BigInt.ToBase16(lOp))
        lOp = BigInt.FromBase16(Left("5845B0A4C43FF041EE3CB64FE4AC283EC160121098D69A6E811E20511E3AE9B57DF4090D8855B3DC8BD649FA3756935283A0022779248D97ADD33C6B0BEAC74973DC124A3E1F0DBD6937F0E9E6975FF3C1C556B02A38ED94CE1F", lSignificantDigits))
        Dim lRet As BigInt = pBigInt * lOp
        'lOp = BigInt.FromBase10("605384255146420326102361023215940531716391478150345020739231253172134740688232476946000058713774549796561447468267746412874022717544100946587144148739626803435133473281606663121381125761746030151344353855924025288111")
        'Debug.Print("Multiple=" & BigInt.ToBase16(lOp))
        lOp = BigInt.FromBase16(Left("1C1911716363228A62BB598F0ACD9C1565D39E10D84CE34459AF8E7B7C871CF668B48356882A8239FC1FD6523E3B273E5232C420D9CB5564A5A2D1E571BD2D4ED25995EB9B7B06A9721C4929034443808B4F399D6714F9F1E5AF", lSignificantDigits))
        'Debug.Print("Dividend=" & BigInt.ToBase16(lOp))
        lRet = lRet \ lOp
        Return lRet
    End Function
    Public Shared Function TestTimesPi(pReps As Integer) As Double
        Dim lOp As BigInt
        Dim lBigInt As BigInt = U()
        Dim lEnd As Double
        Dim lRet As BigInt
        Dim lStart As Double = Microsoft.VisualBasic.Timer
        For i As Integer = 1 To pReps
            lRet = TimesPi(lBigInt)
        Next i
        lEnd = Microsoft.VisualBasic.Timer
        Debug.Print(lEnd - lStart & " seconds for " & pReps & " pi calculations")
        Return lEnd - lStart
    End Function
    Private mBytes As List(Of Byte)
    Private mIsNegative As Boolean
    Public Function IsEven() As Boolean
        Return Not IsOdd()
    End Function
    Public Function IsOdd() As Boolean
        If IsZero() Then Return False Else Return mBytes(0) And 1
    End Function
    Public Function Abs() As BigInt
        Dim lRet As New BigInt
        lRet.mBytes = New List(Of Byte)
        lRet.mBytes.AddRange(mBytes)
        lRet.Normalize()
        Return lRet
    End Function
    Public Sub Normalize()
        If mBytes Is Nothing Then
            mIsNegative = False
            Exit Sub
        End If
        If mBytes.Count > 0 Then
            While mBytes(mBytes.Count - 1) = 0
                mBytes.RemoveAt(mBytes.Count - 1)
            End While
        End If
        If (mBytes.Count = 0) Then
            mIsNegative = False
        End If
    End Sub
    Public Sub New(pVal As Long)
        If pVal < 0 Then
            mIsNegative = True
            pVal = -pVal
        End If
        mBytes = New List(Of Byte)
        While pVal > 0
            Dim lByte As Byte = pVal And 255
            mBytes.Add(lByte)
            pVal = pVal >> 8
        End While
        'No need to normalize this
    End Sub
    Public Sub New(pBigInt As BigInt)
        mBytes = New List(Of Byte)
        mBytes.AddRange(pBigInt.mBytes.ToArray)
        mIsNegative = pBigInt.mIsNegative
        Normalize()
    End Sub
    Public Shared Operator -(ByVal class1 As BigInt) As BigInt
        Dim lRet As New BigInt(class1)
        lRet.mIsNegative = Not lRet.mIsNegative
        lRet.Normalize()
        Return lRet
    End Operator
    Public Shared Function Compare(ByVal class1 As BigInt, ByVal class2 As BigInt) As Integer
        class1.Normalize()
        class2.Normalize()
        If class1.IsZero Then
            If class2.IsZero Then
                Return 0
            ElseIf class2.mIsNegative Then
                Return 1
            Else
                Return -1
            End If
        ElseIf class2.IsZero Then
            If class1.mIsNegative Then
                Return -1
            Else
                Return 1
            End If
        ElseIf class1.mIsNegative Then
            If class2.mIsNegative Then
                Return -Compare(-class1, -class2)
            Else
                Return -1
            End If
        ElseIf class2.mIsNegative Then
            Return 1
        End If
        'Handle positive-positive comparison here
        Dim iLeft As Integer = class1.mBytes.Count - 1
        Dim iRight As Integer = class2.mBytes.Count - 1
        While iLeft > iRight
            If class1.mBytes(iLeft) <> 0 Then
                Return 1
            End If
            iLeft -= 1
        End While
        While iRight > iLeft
            If class2.mBytes(iRight) <> 0 Then
                Return -1
            End If
            iRight -= 1
        End While
        While iLeft >= 0
            If class1.mBytes(iLeft) < class2.mBytes(iLeft) Then
                Return -1
            ElseIf class1.mBytes(iLeft) > class2.mBytes(iLeft) Then
                Return 1
            End If
            iLeft -= 1
        End While
        Return 0
    End Function
    Public Shared Operator <(ByVal class1 As BigInt, ByVal class2 As BigInt) As Boolean
        Select Case Compare(class1, class2)
            Case -1
                Return True
            Case Else
                Return False
        End Select
    End Operator
    Public Shared Operator >(ByVal class1 As BigInt, ByVal class2 As BigInt) As Boolean
        Select Case Compare(class1, class2)
            Case 1
                Return True
            Case Else
                Return False
        End Select
    End Operator
    Public Shared Operator <=(ByVal class1 As BigInt, ByVal class2 As BigInt) As Boolean
        Select Case Compare(class1, class2)
            Case 0, -1
                Return True
            Case Else
                Return False
        End Select
    End Operator
    Public Shared Operator >=(ByVal class1 As BigInt, ByVal class2 As BigInt) As Boolean
        Select Case Compare(class1, class2)
            Case 0, 1
                Return True
            Case Else
                Return False
        End Select
    End Operator
    Public Shared Operator =(ByVal class1 As BigInt, ByVal class2 As BigInt) As Boolean
        Select Case Compare(class1, class2)
            Case 0
                Return True
            Case Else
                Return False
        End Select
    End Operator
    Public Shared Operator <>(ByVal class1 As BigInt, ByVal class2 As BigInt) As Boolean
        Select Case Compare(class1, class2)
            Case 0
                Return False
            Case Else
                Return True
        End Select
    End Operator
    Public Function IsZero() As Boolean
        If mBytes Is Nothing Then Return True
        If mBytes.Count = 0 Then Return True
        For Each lByte In mBytes
            If lByte <> 0 Then Return False
        Next
        Return True
    End Function
    Public Shared Operator +(ByVal class1 As BigInt, ByVal class2 As Long) As BigInt
        Return class1 + New BigInt(class2)
    End Operator
    Public Shared Operator +(ByVal class1 As BigInt, ByVal class2 As BigInt) As BigInt
        If class1.mBytes Is Nothing Then Return class2
        If class2.mBytes Is Nothing Then Return class1
        Dim lBytes1 As Integer = class1.mBytes.Count
        Dim lBytes2 As Integer = class2.mBytes.Count
        Dim lBytes As New List(Of Byte)
        Dim lRemainder As Byte = 0
        Dim i As Integer = 0
        Dim lZeros As Integer = 0
        While (i < lBytes1) Or (i < lBytes2) Or (lRemainder <> 0)
            Dim lByte1 As Integer = 0
            Dim lByte2 As Integer = 0
            Dim lTemp As Integer = 0
            If i < lBytes1 Then lByte1 = class1.mBytes(i)
            If i < lBytes2 Then lByte2 = class2.mBytes(i)
            lTemp = lByte1 + lByte2 + lRemainder
            lRemainder = 0
            If lTemp > 255 Then
                lRemainder = lTemp \ 256
                lTemp -= 256 * lRemainder
            End If
            lBytes.Add(lTemp)
            If lTemp = 0 Then lZeros += 1 Else lZeros = 0
            i += 1
        End While
        While lZeros > 0
            lBytes.RemoveAt(lBytes.Count - 1)
            lZeros -= 1
        End While
        Dim lRet As New BigInt
        lRet.mBytes = lBytes
        Return lRet
    End Operator
    Public Shared Operator -(ByVal class1 As BigInt, ByVal class2 As Long) As BigInt
        Return class1 - New BigInt(class2)
    End Operator
    Public Shared Operator -(ByVal class1 As BigInt, ByVal class2 As BigInt) As BigInt
        Dim lResultIsNegative As Boolean
        Dim lLeft As BigInt
        Dim lRight As BigInt
        class1.Normalize()
        class2.Normalize()
        If class1.mIsNegative Then
            If class2.mIsNegative Then
                Return -(class1.Abs + class2.Abs)
            Else
                Return class1.Abs + class2
            End If
        ElseIf class2.mIsNegative Then
            Return class1 + class2.Abs
        End If
        Select Case Compare(class1, class2)
            Case 0
                Return New BigInt(0)
            Case -1
                lResultIsNegative = True
                lLeft = class2
                lRight = class1
            Case 1
                lResultIsNegative = False
                lLeft = class1
                lRight = class2
            Case Else
                Throw New InvalidOperationException("BigInt.vb encountered an invalid result when comparing numbers.")
        End Select

        'Left is bigger than right, switch sign at the end if indicated
        Dim lBorrow As Integer = 0
        Dim lRet As New BigInt(0)
        For i As Integer = 0 To lLeft.mBytes.Count - 1
            Dim iLeft As Integer
            Dim iRight As Byte
            iLeft = lLeft.mBytes(i) - lBorrow
            If i >= lRight.mBytes.Count Then
                iRight = 0
            Else
                iRight = lRight.mBytes(i)
            End If
            lBorrow = 0
            While iLeft < iRight
                lBorrow += 1
                iLeft += 256
            End While
            lRet.mBytes.Add(iLeft - iRight)
        Next
        lRet.mIsNegative = lResultIsNegative
        lRet.Normalize()
        Return lRet
    End Operator
    Public Shared Function GrahamNotation(pBase As Integer, pArrows As Integer, pHeight As Integer) As BigInt
        Return GrahamNotation(New BigInt(pBase), pArrows, New BigInt(pHeight))
    End Function
    Public Shared Function GrahamNotation(pBase As BigInt, pArrows As Integer, pHeight As BigInt) As BigInt
        If pArrows > 1 Then
            Return GrahamNotation(pBase, pArrows - 1, GrahamNotation(pBase, 1, pHeight))
        End If
        Dim lRet As BigInt = pBase
        lRet = pBase ^ pHeight

        'lRet = lRet ^ (pHeight - 1)
        Return lRet
    End Function
    Public Shared Operator *(ByVal class1 As BigInt, pByte As Byte) As BigInt
        Dim lBytes1 As Integer = class1.mBytes.Count

        Dim lOutBytes As New List(Of Byte)
        Dim lCarry As Long = 0
        For i = 0 To lBytes1 - 1
            Dim lTemp As Long = (CLng(class1.mBytes(i)) * pByte) + lCarry
            lCarry = 0
            If lTemp > 255 Then
                lCarry = lTemp \ 256
                lTemp = lTemp Mod 256
            End If
            lOutBytes.Add(CByte(lTemp))
        Next
        'While lCarry > 255
        If lCarry > 255 Then
            lOutBytes.Add(CByte(lCarry Mod 256))
            lCarry = lCarry \ 256
        End If
        'End While
        If lCarry > 0 Then lOutBytes.Add(CByte(lCarry))
        Dim lRet As New BigInt
        lRet.mBytes = lOutBytes
        lRet.mIsNegative = class1.mIsNegative
        Return lRet
    End Operator
    Public Shared Operator ^(ByVal class1 As BigInt, class2 As BigInt) As BigInt
        class2.Normalize()
        If class2.IsZero Then Return New BigInt(1)
        If class2 = New BigInt(1) Then Return class1
        Dim lIsNegative As Boolean = False
        If class1.mIsNegative AndAlso (class2.mBytes(0) And 1) Then lIsNegative = True
        Dim lPow As New BigInt(class2)
        Dim lBase As New BigInt(class1)
        Dim l1 As New BigInt(1)
        Dim lSuperpow As New BigInt(l1)
        Dim lMultiplier As New BigInt(l1)
        Dim l2 As New BigInt(2)
        While lPow > l2
            If lPow.IsOdd Then
                lPow -= l1
                lMultiplier = lMultiplier * (lBase ^ lSuperpow)
            Else
                lPow = lPow >> 1
                lSuperpow = lSuperpow << 1
            End If
        End While
        lBase = lBase ^ lSuperpow
        If lPow = l2 Then lMultiplier = lMultiplier * lBase
        lBase = lBase * lMultiplier
        'If lSuperpow > l1 Then lBase = lBase ^ lSuperpow
        Return lBase
    End Operator

    Public Shared Operator ^(ByVal class1 As BigInt, class2 As Integer) As BigInt
        Return class1 ^ New BigInt(class2)
    End Operator
    Public Shared Operator *(ByVal class1 As BigInt, class2 As Long) As BigInt
        Return class1 * New BigInt(class2)
    End Operator

    Public Shared Operator *(ByVal class1 As BigInt, class2 As BigInt) As BigInt
        Dim lTop As BigInt
        Dim lBottom As BigInt
        class1.Normalize()
        class2.Normalize()
        If class1.IsZero Or class2.IsZero Then Return New BigInt(0)
        Dim lResultIsNegative As Boolean = class1.mIsNegative Xor class2.mIsNegative
        If class1.mBytes.Count < class2.mBytes.Count Then
            lTop = class2
            lBottom = class1
        Else
            lTop = class1
            lBottom = class2
        End If

        Dim lRunningTotal As New BigInt
        For i = 0 To lBottom.mBytes.Count - 1
            Dim lAdditive As BigInt = lTop * CByte(lBottom.mBytes(i))
            For j = 1 To i
                lAdditive.mBytes.Insert(0, CByte(0))
            Next
            lRunningTotal += lAdditive
        Next
        lRunningTotal.mIsNegative = lResultIsNegative
        lRunningTotal.Normalize()
        Return lRunningTotal
    End Operator
    Public Shared Function PowerOf2(pPower As Integer) As BigInt
        Dim lRet As BigInt = New BigInt(1) << (pPower - 1)
        Return lRet
    End Function
    Private Shared mPowersOf10 As Dictionary(Of Integer, BigInt)

    Public Shared Function ClearCachedPowers()
        If mPowersOf10 IsNot Nothing Then
            mPowersOf10.Clear()
        End If
    End Function
    Public Shared Function PowerOf10(pPower As Integer) As BigInt
        If pPower = 0 Then
            Return New BigInt(1)
        ElseIf pPower = 1 Then
            Return New BigInt(10)
        ElseIf mPowersOf10.ContainsKey(pPower) Then
            Return New BigInt(mPowersOf10(pPower))
        Else
            mPowersOf10(pPower) = New BigInt(10) ^ pPower
            Return New BigInt(mPowersOf10(pPower))
        End If
    End Function
    Public Shared Operator \(ByVal class1 As BigInt, class2 As BigInt) As BigInt
        Dim lResult As BigInt = New BigInt(0)
        Divide(class1, class2, lResult, New BigInt(0))
        Return lResult
    End Operator
    Public Shared Operator /(ByVal class1 As BigInt, class2 As Long) As BigDecimal1
        'Dim lResult As BigDecimal = New BigInt(0)
        'Divide(class1, New BigInt(class2), lResult, New BigInt(0))
        'Return lResult
    End Operator
    Public Shared Operator /(ByVal class1 As BigInt, class2 As BigInt) As BigDecimal1
        'Dim lResult As BigInt = New BigInt(0)
        'Divide(class1, New BigInt(class2), lResult, New BigInt(0))
        'Return lResult
    End Operator
    Public Shared Operator \(ByVal class1 As BigInt, class2 As Long) As BigInt
        Dim lResult As BigInt = New BigInt(0)
        Divide(class1, New BigInt(class2), lResult, New BigInt(0))
        Return lResult
    End Operator
    Public Shared Operator Mod(ByVal class1 As BigInt, class2 As BigInt) As BigInt
        Dim lResult As BigInt = New BigInt(0)
        Divide(class1, class2, New BigInt(0), lResult)
        Return lResult
    End Operator
    Public Shared Operator Mod(ByVal class1 As BigInt, class2 As Long) As BigInt
        Dim lResult As BigInt = New BigInt(0)
        Divide(class1, New BigInt(class2), New BigInt(0), lResult)
        Return lResult
    End Operator
    Public Function ToByte() As Byte
        Normalize()
        If IsZero() Then Return 0
        Return mBytes(0)
    End Function

    Public Shared Sub SquareTest(pPower As Integer)
        Dim lRet As BigInt = (New BigInt(1) << pPower) - New BigInt(1)
        Debug.Print(lRet.ToString)
    End Sub


    Public Shared Sub SpeedTest2()
        Dim lBigNum As BigInt = New BigInt(10)
        Dim lTime1 As Double = Microsoft.VisualBasic.Timer
        lBigNum = lBigNum ^ 1000
        Dim lTime2 As Double = Microsoft.VisualBasic.Timer
        Debug.Print((lTime2 - lTime1) & " seconds to calculate Googol^10")
        lTime1 = Microsoft.VisualBasic.Timer
        lBigNum = lBigNum ^ 50
        lTime2 = Microsoft.VisualBasic.Timer
        Debug.Print((lTime2 - lTime1) & " seconds to raise that to the 50th power")
        Debug.Print("The result is " & lBigNum.Log2 & " bits long.")
        Debug.Print("Converting to decimal...")
        lTime1 = Microsoft.VisualBasic.Timer
        Debug.Print(lBigNum.ToString)
        lTime2 = Microsoft.VisualBasic.Timer
        Debug.Print("Converting to decimal took " & (lTime2 - lTime1) & " seconds.")
    End Sub
    Public Shared Sub SpeedTest3()
        Debug.Print("Generating 3 (arrow) 3")
        Dim lTime1 As Double = Microsoft.VisualBasic.Timer
        Dim lBigInt = BigInt.GrahamNotation(3, 1, 3)
        Dim lTime2 As Double = Microsoft.VisualBasic.Timer
        Debug.Print("Time elapsed: " & (lTime2 - lTime1))
        Debug.Print(lBigInt.ToString)

        Debug.Print("Generating 3 (double-arrow) 3")
        lTime1 = Microsoft.VisualBasic.Timer
        lBigInt = BigInt.GrahamNotation(3, 2, 3)
        lTime2 = Microsoft.VisualBasic.Timer
        Debug.Print("Time elapsed: " & (lTime2 - lTime1))
        Debug.Print(lBigInt.ToString)

        Exit Sub

        Debug.Print(lBigInt.mBytes.Count & " bytes")
        Debug.Print("Generating 3 (triple-arrow) 2")
        lTime1 = Microsoft.VisualBasic.Timer
        lBigInt = BigInt.GrahamNotation(3, 3, 2)
        lTime2 = Microsoft.VisualBasic.Timer
        Debug.Print("Time elapsed: " & (lTime2 - lTime1))
        Debug.Print(lBigInt.ToString)
        Debug.Print(lBigInt.mBytes.Count & " bytes")
        Debug.Print("Generating 3 (triple-arrow) 3")
        lTime1 = Microsoft.VisualBasic.Timer
        lBigInt = BigInt.GrahamNotation(3, 3, 3)
        lTime2 = Microsoft.VisualBasic.Timer
        Debug.Print("Time elapsed: " & (lTime2 - lTime1))
        Debug.Print(lBigInt.ToString)
        Debug.Print(lBigInt.mBytes.Count & " bytes")
    End Sub
    Public Shared Sub SpeedTest4()
        Dim lBigInt As BigInt = GrahamNotation(2, 4, 2)
        Debug.Print(lBigInt.ToString)
    End Sub


    Public Shared Sub SpeedTest()
        Dim lTime1 As Double = Microsoft.VisualBasic.Timer
        Dim j As Integer
        For i = 1 To 1000000
            j = j + 1
        Next
        Dim lTime2 As Double = Microsoft.VisualBasic.Timer
        Debug.Print("Integer: " & (lTime2 - lTime1))
        Dim k As New BigInt(0)
        Dim l1 As New BigInt(1)
        For i = 1 To 10000
            k = k + l1
        Next
        lTime1 = Microsoft.VisualBasic.Timer
        Debug.Print("BigInt: " & (lTime1 - lTime2))
    End Sub

    Public Function ToInt16() As Int16
        Dim lRet As Int16
        If IsZero() Then Return 0
        If mBytes.Count > 1 Then lRet = lRet + (CLng(mBytes(1) And 127) << 8)
        If mBytes.Count > 0 Then lRet = lRet + mBytes(0)
        If mIsNegative Then Return -lRet Else Return lRet
    End Function
    Public Function ToInt32() As Int32
        Dim lRet As Int32
        If IsZero() Then Return 0
        If mBytes.Count > 3 Then lRet = lRet + (CLng(mBytes(3) And 127) << 24)
        If mBytes.Count > 2 Then lRet = lRet + (CLng(mBytes(2)) << 16)
        If mBytes.Count > 1 Then lRet = lRet + (CLng(mBytes(1)) << 8)
        If mBytes.Count > 0 Then lRet = lRet + mBytes(0)
        If mIsNegative Then Return -lRet Else Return lRet
    End Function

    Private Shared Sub Divide(pDividend As BigInt, pDivisor As BigInt, ByRef pResult As BigInt, ByRef pModulus As BigInt)
        pDivisor.Normalize()
        If pDivisor.IsZero Then Throw New DivideByZeroException
        pDividend.Normalize()
        If pDividend.IsZero Then
            pResult = New BigInt(0)
            pModulus = New BigInt(0)
            Exit Sub
        End If
        Dim lResultIsNegative As Boolean = pDividend.mIsNegative Xor pDivisor.mIsNegative
        Dim lDividend As BigInt = pDividend.Abs
        Dim lDivisor As BigInt = pDivisor.Abs
        Select Case Compare(lDividend, lDivisor)
            Case -1
                pResult = New BigInt(0)
                pModulus = New BigInt(lDividend)
                Exit Sub
            Case 0
                pResult = New BigInt(1)
                pModulus = New BigInt(0)
                Exit Sub
        End Select
        ' Dividend is greater than divisor
        ' Multiply the dividend by 256 while

        Dim lShift As Integer
        Dim lRunningTotal As New BigInt(0)
        While Not lDividend.IsZero
            If lDividend < lDivisor Then
                pModulus = lDividend
                pResult = lRunningTotal
                Exit Sub
            End If
            lShift = Math.Truncate(lDividend.Log2_Dbl - lDivisor.Log2_Dbl)
            'lShift = Math.Truncate(lDividend.Log2 - lDivisor.Log2)
            Dim lTestDivisor As BigInt = lDivisor << lShift
            If lTestDivisor > lDividend Then
                lTestDivisor = lTestDivisor >> 1
                lShift -= 1
            End If

            lRunningTotal += (New BigInt(1) << lShift)
            lDividend -= lTestDivisor
        End While

        pResult = lRunningTotal
        pModulus = New BigInt(0)
        Exit Sub
    End Sub

    Public Shared Operator <<(pBigInt As BigInt, pBits As Integer) As BigInt
        Dim lRet As New BigInt(pBigInt)
        Dim lBits As Integer = pBits
        pBigInt.Normalize()
        If lBits >= 8 Then
            Dim lInsertBytes((pBits \ 8) - 1) As Byte
            lRet.mBytes.InsertRange(0, lInsertBytes)
            lBits = lBits Mod 8
        End If
        If lBits = 0 Then
            lRet.Normalize()
            Return lRet
        End If
        Dim lMostSignificantBit As Byte = Log2(lRet.mBytes(lRet.mBytes.Count - 1))
        Dim lAvailableBits As Byte = 8 - lMostSignificantBit
        If lAvailableBits < lBits Then lRet.mBytes.Add(0)
        Dim lMaskLeft As Byte = (1 << (lBits + 1)) - 1
        Dim lMaskRight As Byte = Not lMaskLeft
        For i = lRet.mBytes.Count - 1 To 1 Step -1
            lRet.mBytes(i) = ((lRet.mBytes(i) << lBits) Or (lRet.mBytes(i - 1) >> (8 - lBits))) And 255
        Next
        lRet.mBytes(0) = (lRet.mBytes(0) << lBits) And 255
        Return lRet
    End Operator
    Public Shared Operator >>(pBigInt As BigInt, pBits As Integer) As BigInt
        Dim lRet As New BigInt(pBigInt)
        Dim lBits As Integer = pBits
        pBigInt.Normalize()
        If lBits >= 8 Then
            lRet.mBytes.RemoveRange(0, pBits = 8)
            lBits = lBits Mod 8
        End If
        If lBits = 0 Then
            lRet.Normalize()
            Return lRet
        End If

        Dim lMostSignificantBit As Byte = Log2(lRet.mBytes(lRet.mBytes.Count - 1))
        Dim lAvailableBits As Byte = 8 - lMostSignificantBit
        If lAvailableBits < lBits Then lRet.mBytes.Add(0)
        Dim lMaskLeft As Byte = (1 << (lBits + 1)) - 1
        Dim lMaskRight As Byte = Not lMaskLeft
        For i = 0 To lRet.mBytes.Count - 2
            lRet.mBytes(i) = ((lRet.mBytes(i) >> lBits) Or (lRet.mBytes(i + 1) << (8 - lBits))) And 255
        Next
        lRet.mBytes(lRet.mBytes.Count - 1) = (lRet.mBytes(lRet.mBytes.Count - 1) >> lBits) And 255
        Return lRet

    End Operator
    Public Function Log2() As Long
        Normalize()
        If IsZero() Then Return 0
        Return ((mBytes.Count - 1) * 8) + Log2(mBytes(mBytes.Count - 1))
    End Function

    Public Function Log2_Dbl() As Double
        Normalize()
        If IsZero() Then Return 0
        Dim lBits As Integer = (mBytes.Count - 1) * 8
        Dim lDivisor As Double = 1
        Dim lRunningTotal As Double = lBits + Log2_Dbl(mBytes(mBytes.Count - 1))
        For i = mBytes.Count - 2 To Math.Max(mBytes.Count - 8, 0) Step -1
            lDivisor = lDivisor * 256
            lRunningTotal += (CDbl(Log2_Dbl(mBytes(i))) / lDivisor)
        Next
        Return lRunningTotal
    End Function

    Public Overrides Function ToString() As String
        Return BigInt.ToBase10(Me)
    End Function

    Public Shared Function ToBaseX(pBigInt As BigInt, pBase As Byte) As String
        If pBase < 2 Then Throw New ArgumentException("Cannot display as base less than 2")
        If pBase > 2 Then Throw New ArgumentException("Cannot display as base greater than 16")
        pBigInt.Normalize()
        If pBigInt.IsZero Then Return "0"
        Dim aChars() As Char = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}

        Dim lRet As New System.Text.StringBuilder()
        If pBigInt.mIsNegative Then lRet.Append("-")
        lRet.Append("&(" & pBase & ")")

        Dim lByte As Byte = (pBigInt Mod pBase).ToByte
        If lByte And &HF0 Then
            lRet.Append(aChars(lByte))
        End If
        If lByte And &HF Then
            lRet.Append(aChars(lByte And &HF))
        End If
        For i = pBigInt.mBytes.Count - 2 To 0 Step -1
            lByte = pBigInt.mBytes(i)
            lRet.Append(aChars(lByte >> 4) & aChars(lByte And 15))
        Next
        Return lRet.ToString
    End Function

    Public Shared Function ToBase16(pBigInt As BigInt) As String
        pBigInt.Normalize()
        If pBigInt.IsZero Then Return "0"
        Dim aChars() As Char = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}

        Dim lRet As New System.Text.StringBuilder()
        If pBigInt.mIsNegative Then lRet.Append("-")
        lRet.Append("&H")
        Dim lByte As Byte = pBigInt.mBytes(pBigInt.mBytes.Count - 1)
        If lByte And &HF0 Then
            lRet.Append(aChars(lByte >> 4))
        End If
        If lByte And &HF Then
            lRet.Append(aChars(lByte And &HF))
        End If
        For i = pBigInt.mBytes.Count - 2 To 0 Step -1
            lByte = pBigInt.mBytes(i)
            lRet.Append(aChars(lByte >> 4) & aChars(lByte And 15))
        Next
        Return lRet.ToString
    End Function

    Public Function ToBase16() As String
        Return BigInt.ToBase16(Me)
    End Function

    Public Shared Function FromBase10(pSource As String) As BigInt
        Dim lMode As Byte = 1
        Dim lIsNegative As Boolean
        Dim lNB As New System.Text.StringBuilder
        Dim lDec As Integer = -1
        Dim lShiftDirection As Char
        Dim lShiftAmt As String
        For Each lChar In pSource
            Select Case lMode
                Case 1
                    Select Case lChar
                        Case " ", "+"
                        Case "-"
                            lIsNegative = True
                            lMode = 2
                        Case "0" 'ignore leading zeros
                        Case "1" To "9"
                            lNB.Append(lChar)
                            lMode = 2
                        Case "."
                            lDec = lNB.Length
                            lMode = 3
                        Case Else
                            Throw New InvalidCastException
                    End Select
                Case 2
                    Select Case lChar
                        Case ","
                        Case "0" To "9"
                            lNB.Append(lChar)
                        Case "."
                            lDec = lNB.Length
                            lMode = 3
                        Case "E"
                            lMode = 4
                        Case Else
                            Throw New InvalidCastException
                    End Select
                Case 3
                    Select Case lChar
                        Case ","
                        Case "0" To "9"
                            lNB.Append(lChar)
                        Case "E"
                            lMode = 4
                            lShiftDirection = "+"
                        Case Else
                            Throw New InvalidCastException
                    End Select
                Case 4
                    Select Case lChar
                        Case "+", "-"
                            lShiftDirection = lChar
                            lMode = 5
                        Case "0"
                        Case "1" To "9"
                            lShiftAmt = lShiftAmt & lChar
                            lMode = 6
                        Case Else
                            Throw New InvalidCastException
                    End Select
                Case 5
                    Select Case lChar
                        Case "0"
                        Case "1" To "9"
                            lShiftAmt = lShiftAmt & lChar
                            lMode = 6
                        Case Else
                            Throw New InvalidCastException
                    End Select
                Case 6
                    Select Case lChar
                        Case "0" To "9"
                            lShiftAmt = lShiftAmt & lChar
                            lMode = 6
                        Case Else
                            Throw New InvalidCastException
                    End Select
            End Select
        Next
        If lDec = -1 Then lDec = lNB.Length + 1
        Dim lAsDecimal As String
        If lShiftAmt = "" Then
            lAsDecimal = lNB.ToString
        ElseIf lShiftDirection = "+" Then
            lDec = lDec + Val(lShiftAmt)
            If lDec > (lNB.Length + 1) Then
                lAsDecimal = lNB.ToString & New String("0", (lDec - lNB.Length) - 1)
            Else
                lAsDecimal = lNB.ToString.Substring(0, lDec - 1)
            End If
        ElseIf lShiftDirection = "-" Then
            lDec = lDec - Val(lShiftAmt)
            If lDec < 1 Then
                Return New BigInt(0)
            Else
                lAsDecimal = lNB.ToString.Substring(0, lDec - 1)
            End If
        End If
        'lAsDecimal is now a clean, unsigned decimal with scientific notation expanded
        Dim l10 As BigInt = New BigInt(10)
        Dim lTens As BigInt = New BigInt(1)
        Dim lRet As BigInt = New BigInt(0)
        For i = lAsDecimal.Length - 1 To 0 Step -1
            Dim lAdditive As BigInt = lTens * New BigInt(Asc(lAsDecimal.Substring(i, 1)) - 48)
            lRet += lAdditive
            lTens = lTens * l10
        Next
        lRet.mIsNegative = lIsNegative
        lRet.Normalize()
        Return lRet
    End Function


    Public Shared Function FromBase16(pSource As String) As BigInt
        Dim lProc As New Stack(Of Byte)
        Dim lTemp As String = ""
        Dim lRet As New BigInt(0)
        For i = 0 To pSource.Length - 1
            Dim lChar As Char = pSource.Substring(i, 1)
            Dim lAsc As Integer = Asc(lChar)
            Select Case lAsc
                Case 48 To 57
                    lTemp = lTemp & lChar
                Case 65 To 70
                    lTemp = lTemp & lChar
            End Select
            If Len(lTemp) = 2 Then
                Dim lByte As Byte = 0
                lAsc = Asc(lTemp.Substring(0, 1))
                Select Case lAsc
                    Case 48 To 57
                        lByte = (lAsc - 48) << 4
                    Case 65 To 70
                        lByte = (lAsc - 55) << 4
                End Select
                lAsc = Asc(lTemp.Substring(1, 1))
                Select Case lAsc
                    Case 48 To 57
                        lByte = lByte + (lAsc - 48)
                    Case 65 To 70
                        lByte = lByte + (lAsc - 55)
                End Select

                lTemp = ""
                lRet.mBytes.Insert(0, lByte)
            End If
        Next
        If lTemp <> "" Then
            Select Case Asc(lTemp)
                Case 48 To 57
                    lRet = lRet << 4
                    lRet += New BigInt(Asc(lTemp) - 48)
                Case 65 To 70
                    lRet = lRet << 4
                    lRet += New BigInt(Asc(lTemp) - 55)
            End Select
        End If
        lRet.Normalize()
        Return lRet
    End Function

    Public Shared Function ToBase10(pBigInt As BigInt) As String
        Dim lRemaining As BigInt = pBigInt
        Dim lStack As New Stack(Of Char)
        Dim lMod As BigInt = Nothing
        Dim lDigit As Byte
        Dim l10 As New BigInt(10)
        Dim l10K As New BigInt(10000)
        Dim l1B As New BigInt(1000000000)
        Dim l1Googol As BigInt = New BigInt(0)
        If pBigInt.Log2 >= 332 Then l1Googol = New BigInt(10000) ^ 25
        Dim l1GoogolE10 As BigInt = New BigInt(0)
        If pBigInt.Log2 >= 3321 Then l1GoogolE10 = l1Googol ^ 10
        pBigInt.Normalize()
        If pBigInt.IsZero Then Return "0"
        Dim lLastUpdate As Double = Microsoft.VisualBasic.Timer
        Dim lStartTime As DateTime = Now
        Dim lStartDigits As Integer = lRemaining.Log2
        Dim lStackSize As Long = 0
        Do
            If (Not l1GoogolE10.IsZero) AndAlso (lRemaining > l1GoogolE10) Then
                Divide(lRemaining, l1GoogolE10, lRemaining, lMod)
                Dim lText As String = lMod.ToString.PadLeft(1000, "0")
                For i = lText.Length - 1 To 0 Step -1
                    lStack.Push(lText.Substring(i, 1))
                Next
                lStackSize += lText.Length
            ElseIf (Not l1Googol.IsZero) AndAlso (lRemaining > l1Googol) Then
                Divide(lRemaining, l1Googol, lRemaining, lMod)
                Dim lText As String = lMod.ToString.PadLeft(100, "0")
                For i = lText.Length - 1 To 0 Step -1
                    lStack.Push(lText.Substring(i, 1))
                Next
                lStackSize += lText.Length
            ElseIf lRemaining > l1B Then
                Divide(lRemaining, l1B, lRemaining, lMod)
                Dim lText As String = Format(lMod.ToInt32, "000000000")
                For i = lText.Length - 1 To 0 Step -1
                    lStack.Push(lText.Substring(i, 1))
                Next
                lStackSize += lText.Length
            ElseIf lRemaining > l10K Then
                Divide(lRemaining, l10K, lRemaining, lMod)
                Dim lText As String = Format(lMod.ToInt16, "0000")
                For i = lText.Length - 1 To 0 Step -1
                    lStack.Push(lText.Substring(i, 1))
                Next
                lStackSize += lText.Length
            Else
                Divide(lRemaining, l10, lRemaining, lMod)
                lStack.Push(CStr(lMod.ToByte))
                lStackSize += 1
            End If
            If (Microsoft.VisualBasic.Timer - lLastUpdate) > 10 Then
                Dim lLog2 As Integer = lRemaining.Log2
                If lLog2 < lStartDigits Then
                    Debug.Print(lLog2 & " significant digits remaining.")
                    Dim lTimeSpent As TimeSpan = Now.Subtract(lStartTime)
                    Dim lUnitTime As Double = lTimeSpent.TotalSeconds / (lStartDigits - lLog2)
                    Dim lCompletion As DateTime = Now.AddSeconds(lUnitTime * lLog2 * (lLog2 / lStartDigits) / 3)
                    Debug.Print("Estimated Completion: " & Format(lCompletion, "M/d/yyyy HH:mm:ss"))
                    Dim lDigitRatio As Double = lStackSize / (lStartDigits - lLog2)
                    Debug.Print("Estimated Output Digits: " & (lStackSize + CInt(lDigitRatio * lLog2)))
                    lLastUpdate = Microsoft.VisualBasic.Timer
                End If
            End If
        Loop Until lRemaining.IsZero
        If pBigInt.mIsNegative Then lStack.Push("-")
        Dim lRet As New System.Text.StringBuilder
        While lStack.Count
            lRet.Append(lStack.Pop)
        End While
        If Now - lStartTime > New TimeSpan(0, 1, 0) Then
            Using lwriter As New IO.StreamWriter("c:\temp\Calculation.txt", False)
                lwriter.WriteLine(lRet.ToString)
                lwriter.Close()
                lwriter.Dispose()
            End Using
        End If
        Return lRet.ToString
    End Function

    Public Shared Function Log2(pByte As Byte) As Byte
        Dim lRet As Byte
        While pByte <> 0
            lRet += 1
            pByte = pByte >> 1
        End While
        Return lRet
    End Function
    Public Shared Function Log2(pInteger As Integer) As Byte
        Dim lRet As Byte
        If pInteger < 0 Then Throw New InvalidOperationException("BigInt cannot take the logarithm of a negative number.")
        While pInteger <> 0
            lRet += 1
            pInteger = pInteger >> 1
        End While
        Return lRet
    End Function
    Public Shared Function Log2_Dbl(pByte As Byte) As Double
        Dim lRet As Double = 8
        If pByte = 0 Then Return 0
        While (pByte And &H80) = 0
            lRet -= 1
            pByte = pByte << 1
        End While
        pByte = pByte << 1
        Dim lDivisor As Integer = 2
        While pByte <> 0
            If pByte And &H80 Then
                lRet = lRet + 1 / lDivisor
            End If
            lDivisor *= 2
            pByte = pByte << 1
        End While
        Return lRet
    End Function
    Public Shared Function Log2_Dbl(pInteger As Integer) As Double
        Dim lRet As Double = 8
        If pInteger = 0 Then Return 0
        While (pInteger And &H8000) = 0
            lRet -= 1
            pInteger = pInteger << 1
        End While
        pInteger = pInteger << 1
        Dim lDivisor As Integer = 2
        While pInteger <> 0
            If pInteger And &H8000 Then
                lRet = lRet + 1 / lDivisor
            End If
            lDivisor *= 2
            pInteger = pInteger << 1
        End While
        Return lRet
    End Function
End Structure


这篇关于.NET中的BigDecimal超过28位的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆