.NET中的BigDecimal超过28位 [英] BigDecimal in .NET with more than 28 digits
问题描述
您好,
我需要一个BigDecimal-Class来计算超过28位的数字。
我试图使用W3bSine-Project并导入J#-BigDecimal-Type。
这两个方法都没有让我开心。原因W3bSine似乎有错误并且没有支持。
在.NET 4中有一个BigInteger - 但没有BigDecimal!
有谁知道一个很好的.NET库/类?
可以是商业的。
谢谢,
Mike
< blockquote>如果 BigDecimal
存在(并且可以创建这样的类型),它将不是真正的数字类型。术语十进制与数字以人类可读形式编写的形式有关,而与数值属性(如值,算术运算等)无关。这就是编程语言中不存在十进制类型的原因。然而,在这种类型中存在某种(小)意义:然后可以使用逐位数计算技术用作固定精度整数类型 - 就像传统的计算器一样。我认为这项技术已经走到了尽头。
如果你有 BigInteger
- 你有你所需要的一切,只学会使用它。
目前尚不清楚,你想要整数还是小数。如果你需要一个固定精度的小数 - 这实际上是相同的 BigInteger
,但实现基于 BigInteger
需要一些认真的工作。原则上是可行的。
请在此处查看我的回答和讨论:
我想使用c#制作windows计算器,应该使用什么类型 [ ^ ]。
我写了这个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
IfBigDecimal
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 haveBigInteger
— 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 isBigInteger
, but implementing floating-point based onBigInteger
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屋!