MsgBox(0, '计算结果', _BigNum_Div(1981678876449912983, 7))
Func _BigNum_Div($sX, $sY, $iD = -1)
If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
Local $iNeg = __BigNum_CheckNegative($sX, $sY), $sNeg = ''
If $iD = -1 Then $iD = StringLen($sX) + StringLen($sY)
Local $iDec = __BigNum_StringIsDecimal($sX, $sY), $sMod
If $sX = 0 Or $sY = 0 Then Return '0'
If $sY = '1' Then Return $sNeg & $sX
While StringLeft($sX, 1) = '0'
$sX = StringTrimLeft($sX, 1)
$iDec += 1
WEnd
While StringLeft($sY, 1) = '0'
$sY = StringTrimLeft($sY, 1)
$iDec += 1
WEnd
Local $sRet = '', $iLnX = StringLen($sX), $iLnY = StringLen($sY), $iTmp, $iCnt, $sTmp, $iDe1 = 0
If $iD > 0 Then $iDe1 += $iD
If $iNeg = 1 Or $iNeg = 2 Then $sNeg = '-'
$iTmp = _BigNum_Compare($sX, $sY)
If $iTmp = -1 Then
For $iCnt = $iLnX To $iLnY
$sX &= 0
$iDe1 += 1
Next
EndIf
If $iTmp = 0 Then Return $sNeg & '1'
If $iD = -1 Then $iD = $iDec * 2
For $iCnt = 1 To $iD
$sX &= '0'
Next
If $iLnY > 14 Then
$sRet = __BigNum_Div_DivisorGreater14($sX, $sY, $sMod)
Else
$sRet = __BigNum_Div_DivisorMaxLen14($sX, $sY, $sMod)
EndIf
If $iDe1 > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDe1, $iD)
If $sRet = '0' Then
Return '0'
Else
Return $sNeg & $sRet
EndIf
EndFunc ;==>_BigNum_Div
Func _BigNum_Compare($sX, $sY)
Local $iNeg = __BigNum_CheckNegative($sX, $sY)
Switch $iNeg
Case 1
Return -1
Case 2
Return 1
Case 3
__BigNum_Swap($sX, $sY)
EndSwitch
__BigNum_CompEqualizeLength($sX, $sY)
Return StringCompare($sX, $sY)
EndFunc ;==>_BigNum_Compare
Func __BigNum_CompEqualizeLength(ByRef $sX, ByRef $sY)
Local $iXDotPos = StringInStr($sX, '.')
Local $iYDotPos = StringInStr($sY, '.')
Local $iXLen = StringLen($sX)
Local $iYLen = StringLen($sY)
Local $iLeading, $iTrailing
If $iXDotPos == 0 And $iYDotPos <> 0 Then
$iLeading = $iXLen - ($iYDotPos - 1)
$iTrailing = -1 * ($iYLen - $iYDotPos)
$sX &= '.'
ElseIf $iXDotPos <> 0 And $iYDotPos == 0 Then
$iLeading = ($iXDotPos - 1) - $iYLen
$iTrailing = $iXLen - $iXDotPos
$sY &= '.'
ElseIf $iXDotPos == 0 And $iYDotPos == 0 Then
$iLeading = $iXLen - $iYLen
Else
$iLeading = $iXDotPos - $iYDotPos
$iTrailing = ($iXLen - $iXDotPos) - ($iYLen - $iYDotPos)
EndIf
If $iLeading < 0 Then
$sX = __BigNum_CompStringAddZeroes($sX, -1 * $iLeading, 0, 0)
ElseIf $iLeading > 0 Then
$sY = __BigNum_CompStringAddZeroes($sY, $iLeading, 0, 0)
EndIf
If $iTrailing < 0 Then
$sX = __BigNum_CompStringAddZeroes($sX, -1 * $iTrailing, 1, 0)
ElseIf $iTrailing > 0 Then
$sY = __BigNum_CompStringAddZeroes($sY, $iTrailing, 1, 0)
EndIf
EndFunc ;==>__BigNum_CompEqualizeLength
Func __BigNum_CompStringAddZeroes($sString, $iCount, $bTrailing = 0, $bToLength = 1)
If $bToLength Then
$iCount -= StringLen($sString)
EndIf
Local $i = 0
Local $s = ''
While $i < $iCount
$s &= '0'
$i += 1
WEnd
If $bTrailing Then
Return $sString & $s
EndIf
Return $s & $sString
EndFunc ;==>__BigNum_CompStringAddZeroes
Func __BigNum_Swap(ByRef $sX, ByRef $sY)
Local $sSwap = $sX
$sX = $sY
$sY = $sSwap
Return True
EndFunc ;==>__BigNum_Swap
Func __BigNum_Div_DivisorGreater14($sX, $sY, ByRef $sM)
$sM = '0'
If $sY = '1' Then Return $sX
If $sX = '0' Or $sY = '0' Or $sX = '' Or $sY = '' Then Return '0'
Local $iLnY = StringLen($sY), $bRed = False
Local $sRet = '', $sRem = StringLeft($sX, $iLnY), $sTmp = '', $sTm2 = '', $iCnt, $iLen = 1
$sX = StringTrimLeft($sX, $iLnY)
Do
If __BigNum_DivComp($sRem, $sY) = -1 Then
$sTmp = StringLeft($sX, 1)
$sRem &= $sTmp
$sX = StringTrimLeft($sX, 1)
If StringLen($sTmp) > 0 Then $iLen += 1
EndIf
$sTmp = $sY
$sTm2 = '0'
If __BigNum_DivComp($sRem, $sY) >= 0 Then
For $iCnt = 1 To 9
$sTm2 = $sTmp
$sTmp = __BigNum_DivAdd($sTmp, $sY)
If __BigNum_DivComp($sRem, $sTmp) < 0 Then ExitLoop
Next
Else
$iCnt = 0
EndIf
If StringLen($sX) = 0 Then $bRed = True
$sM = $sRem
$sRem = __BigNum_DivSub($sRem, $sTm2)
If $iCnt > 0 Then $sM = $sRem
$sRet &= StringFormat('%0' & String($iLen) & 'u', $iCnt)
$iTrm = $iLnY - StringLen($sRem)
$sTmp = StringLeft($sX, $iTrm)
$sX = StringTrimLeft($sX, $iTrm)
$iLen = StringLen($sTmp)
$sRem &= $sTmp
Until $bRed
$sM = StringRegExpReplace($sM, '^0+([^0]|0$)', '\1', 1)
Return StringRegExpReplace($sRet, '^0+([^0]|0$)', '\1', 1)
EndFunc ;==>__BigNum_Div_DivisorGreater14
Func __BigNum_Div_DivisorMaxLen14($sX, $sY, ByRef $sM)
$sM = '0'
If $sY = '1' Then Return $sX
If $sX = '0' Or $sY = '0' Or $sX = '' Or $sY = '' Then Return '0'
Local $sRet = '', $iRem = StringLeft($sX, 15), $iTmp = 0, $iTrm = 6, $iLen
$sX = StringTrimLeft($sX, 15)
$iTmp = Floor($iRem / $sY)
$sRet &= $iTmp
$iRem -= $iTmp * $sY
While StringLen($sX) > 0
$iTrm = 15 - StringLen($iRem)
$iTmp = StringLeft($sX, $iTrm)
$iLen = StringLen($iTmp)
$iRem &= $iTmp
$sX = StringTrimLeft($sX, $iTrm)
$iTmp = Floor($iRem / $sY)
$iTmp = StringRight('000000000000000' & $iTmp, $iLen)
$sRet &= $iTmp
$iRem -= $iTmp * $sY
WEnd
$sM = String($iRem)
Return StringRegExpReplace($sRet, '^0+([^0]|0$)', '\1', 1)
EndFunc ;==>__BigNum_Div_DivisorMaxLen14
Func __BigNum_DivComp($sX, $sY)
$sX = StringRegExpReplace($sX, '^0+([^0]|0$)', '\1', 1)
$sY = StringRegExpReplace($sY, '^0+([^0]|0$)', '\1', 1)
Local $iLnX = StringLen($sX), $iLnY = StringLen($sY)
If $iLnX < $iLnY Then
Return -1
ElseIf $iLnX > $iLnY Then
Return 1
Else
If $sX < $sY Then
Return -1
ElseIf $sX > $sY Then
Return 1
Else
Return 0
EndIf
EndIf
EndFunc ;==>__BigNum_DivComp
Func __BigNum_DivAdd($sX, $sY)
Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ''
If $iLen < $iTmp Then $iLen = $iTmp
For $i = 1 To $iLen Step 18
$iTmp = Int(StringRight($sX, 18)) + Int(StringRight($sY, 18)) + $iCar
$sX = StringTrimRight($sX, 18)
$sY = StringTrimRight($sY, 18)
If ($iTmp > 999999999999999999) Then
$sRet = StringRight($iTmp, 18) & $sRet
$iCar = 1
Else
$iTmp = StringRight('000000000000000000' & $iTmp, 18)
$sRet = $iTmp & $sRet
$iCar = 0
EndIf
Next
$sRet = StringRegExpReplace($iCar & $sRet, '^0+([^0]|0$)', '\1', 1)
Return $sRet
EndFunc ;==>__BigNum_DivAdd
Func __BigNum_DivSub($sX, $sY)
Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ''
If $iLen < $iTmp Then $iLen = $iTmp
For $i = 1 To $iLen Step 18
$iTmp = Int(StringRight($sX, 18)) - Int(StringRight($sY, 18)) - $iCar
$sX = StringTrimRight($sX, 18)
$sY = StringTrimRight($sY, 18)
If $iTmp < 0 Then
$iTmp = 1000000000000000000 + $iTmp
$iCar = 1
Else
$iCar = 0
EndIf
$sRet = StringRight('0000000000000000000' & $iTmp, 18) & $sRet
Next
$sRet = StringRegExpReplace($iCar & $sRet, '^0+([^0]|0$)', '\1', 1)
Return $sRet
EndFunc ;==>__BigNum_DivSub
Func __BigNum_IsValid($sX, $sY)
If StringRegExp($sX, '[^0-9.-]') Or StringRegExp($sY, '[^0-9.-]') Then Return False
Return True
EndFunc ;==>__BigNum_IsValid
Func __BigNum_InsertDecimalSeparator($sX, $iDec, $iD = 18)
If $iD = 0 And $iDec = 0 Then Return $sX
Local $sRet = StringRegExpReplace(StringRight(StringFormat('%0' & String($iDec) & 'u', '') & $sX, $iDec), '0+$', '\1', 1)
$sX = StringTrimRight($sX, $iDec)
If $sX = '' Then $sX = '0'
$sRet = StringLeft($sRet, $iD)
If $sRet = '' Or $sRet = '0' Then Return $sX
Return $sX & '.' & $sRet
EndFunc ;==>__BigNum_InsertDecimalSeparator
Func __BigNum_StringIsDecimal(ByRef $sX, ByRef $sY)
If StringLeft($sX, 1) = '.' Then $sX = '0' & $sX
If StringLeft($sY, 1) = '.' Then $sY = '0' & $sY
Local $iPsX = StringInStr($sX, '.', 0, 1) - 1, $iPsY = StringInStr($sY, '.', 0, 1) - 1
$sX = StringRegExpReplace($sX, '\D', '')
$sY = StringRegExpReplace($sY, '\D', '')
Local $iLnX = StringLen($sX), $iLnY = StringLen($sY)
If $iPsX <= 0 Then $iPsX = $iLnX
If $iPsY <= 0 Then $iPsY = $iLnY
If $iLnX - $iPsX > $iLnY - $iPsY Then
For $iCnt = $iLnY - $iPsY To $iLnX - $iPsX - 1
$sY &= '0'
Next
Return $iLnX - $iPsX
ElseIf $iLnX - $iPsX < $iLnY - $iPsY Then
For $iCnt = $iLnX - $iPsX To $iLnY - $iPsY - 1
$sX &= '0'
Next
Return $iLnY - $iPsY
EndIf
Return $iLnX - $iPsX
EndFunc ;==>__BigNum_StringIsDecimal
Func __BigNum_CheckNegative(ByRef $sX, ByRef $sY)
Local $bNgX = False, $bNgY = False
While StringLeft($sX, 1) = '-'
$bNgX = Not $bNgX
$sX = StringTrimLeft($sX, 1)
WEnd
While StringLeft($sY, 1) = '-'
$bNgY = Not $bNgY
$sY = StringTrimLeft($sY, 1)
WEnd
$sX = StringRegExpReplace($sX, '^0+([^0]|0$)', '\1', 1)
$sY = StringRegExpReplace($sY, '^0+([^0]|0$)', '\1', 1)
If $sX = '' Then $sX = '0'
If $sY = '' Then $sY = '0'
If $bNgX = True And $bNgY = True Then
Return 3
ElseIf $bNgX = True And $bNgY = False Then
Return 1
ElseIf $bNgX = False And $bNgY = True Then
Return 2
Else
Return 0
EndIf
EndFunc ;==>__BigNum_CheckNegative