BigNum UDF


SUBMITTED BY: Guest

DATE: May 30, 2013, 7:46 a.m.

FORMAT: Text only

SIZE: 30.8 kB

HITS: 2222

  1. #include-once
  2. ; #INDEX# =======================================================================================================================
  3. ; Title .........: BigNum
  4. ; AutoIt Version : 3.2.12.1
  5. ; Language ......: English
  6. ; Description ...: Perform calculations with big numbers
  7. ; ===============================================================================================================================
  8. ; #CURRENT# =====================================================================================================================
  9. ;_BigNum_Parse
  10. ;_BigNum_Add
  11. ;_BigNum_Sub
  12. ;_BigNum_Mul
  13. ;_BigNum_Div
  14. ;_BigNum_Pow
  15. ;_BigNum_SQRT
  16. ;_BigNum_n_Root
  17. ;_BigNum_Mod
  18. ;_BigNum_Round
  19. ;_BigNum_Compare
  20. ; ===============================================================================================================================
  21. ; #INTERNAL_USE_ONLY#============================================================================================================
  22. ;__BigNum_Swap
  23. ;__BigNum_CheckNegative
  24. ;__BigNum_DivAdd
  25. ;__BigNum_DivComp
  26. ;__BigNum_DivSub
  27. ;__BigNum_Div_DivisorGreater14
  28. ;__BigNum_Div_DivisorMaxLen14
  29. ;__BigNum_InsertDecimalSeparator
  30. ;__BigNum_StringIsDecimal
  31. ;__BigNum_IsValid
  32. ; ===============================================================================================================================
  33. ; #FUNCTION# ;====================================================================================
  34. ; Name...........: _BigNum_Parse
  35. ; Description ...: Parses a line using bigNums
  36. ; Syntax.........: _BigNum_Parse($sLine)
  37. ; Parameters ....: $sLine - e.g. "-1-(2-4*3^(2*5))/(-2.5)"
  38. ; ^ : Power
  39. ; % : Mod
  40. ; / : Div
  41. ; * : Mul
  42. ; + : Add
  43. ; - : Sub
  44. ; Return values .: Success - Result
  45. ; Failure - ?
  46. ; Remarks .......:
  47. ; Author ........: eukalyptus
  48. ; ;===============================================================================================
  49. Func _BigNum_Parse($sLine)
  50. $sLine = StringStripWS($sLine, 8)
  51. $sLine = StringRegExpReplace($sLine, "([\^%/*+-])", "$1#")
  52. Local $aReg = StringRegExp($sLine, "\(([^()]+)\)", 3)
  53. If IsArray($aReg) Then
  54. $sLine = StringRegExpReplace($sLine, "\([^()]+\)", Chr(1))
  55. For $i = 0 To UBound($aReg) - 1
  56. $sLine = StringReplace($sLine, Chr(1), _BigNum_Parse($aReg[$i]), 1)
  57. Next
  58. $sLine = _BigNum_Parse($sLine)
  59. EndIf
  60. Local $aOp[6][2] = [["\^", "_BigNum_Pow"],["%", "_BigNum_Mod"],["/", "_BigNum_Div"],["\*", "_BigNum_Mul"],["\+", "_BigNum_Add"],["-", "_BigNum_Sub"]]
  61. Local $iCnt = 0
  62. While $iCnt < 6
  63. $aReg = StringRegExp($sLine, "(-*[0-9.]+)\#*" & $aOp[$iCnt][0] & "\#*(-*[0-9.]+)", 1)
  64. If IsArray($aReg) Then
  65. $sLine = StringRegExpReplace($sLine, "-*[0-9.]+\#*" & $aOp[$iCnt][0] & "\#*-*[0-9.]+", Call($aOp[$iCnt][1], $aReg[0], $aReg[1]), 1)
  66. Else
  67. $iCnt += 1
  68. EndIf
  69. WEnd
  70. $sLine = StringReplace($sLine, "#", "")
  71. $sLine = StringReplace($sLine, "--", "+")
  72. If StringRegExp($sLine, "^\+[0-9.]+$") Then $sLine = StringReplace($sLine, "+", "")
  73. Return $sLine
  74. EndFunc ;==>_BigNum_Parse
  75. ; #FUNCTION# ;====================================================================================
  76. ;
  77. ; Name...........: _BigNum_Add
  78. ; Description ...: Addition $sX + $sY
  79. ; Syntax.........: _BigNum_Add($sX, $sY)
  80. ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  81. ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  82. ; Return values .: Success - Result $sX + $sY
  83. ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
  84. ; Author ........: Eukalyptus www.autoit.de
  85. ;
  86. ; ;===============================================================================================
  87. Func _BigNum_Add($sX, $sY)
  88. If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
  89. Local $iNeg = __BigNum_CheckNegative($sX, $sY), $sNeg = ""
  90. Switch $iNeg
  91. Case 3
  92. $sNeg = "-"
  93. Case 1
  94. Return _BigNum_Sub($sY, $sX)
  95. Case 2
  96. Return _BigNum_Sub($sX, $sY)
  97. EndSwitch
  98. Local $iDec = __BigNum_StringIsDecimal($sX, $sY)
  99. Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ""
  100. If $iLen < $iTmp Then $iLen = $iTmp
  101. For $i = 1 To $iLen Step 18
  102. $iTmp = Int(StringRight($sX, 18)) + Int(StringRight($sY, 18)) + $iCar
  103. $sX = StringTrimRight($sX, 18)
  104. $sY = StringTrimRight($sY, 18)
  105. If ($iTmp > 999999999999999999) Then
  106. $iTmp = StringRight($iTmp, 18)
  107. $sRet = $iTmp & $sRet
  108. $iCar = 1
  109. Else
  110. $iTmp = StringRight("000000000000000000" & $iTmp, 18)
  111. $sRet = $iTmp & $sRet
  112. $iCar = 0
  113. EndIf
  114. Next
  115. $sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1)
  116. If $iDec > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDec, $iDec)
  117. If $sRet = "0" Then $sNeg = ""
  118. Return $sNeg & $sRet
  119. EndFunc ;==>_BigNum_Add
  120. ; #FUNCTION# ;====================================================================================
  121. ;
  122. ; Name...........: _BigNum_Sub
  123. ; Description ...: Subtraction $sX - $sY
  124. ; Syntax.........: _BigNum_Sub($sX, $sY)
  125. ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  126. ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  127. ; Return values .: Success - Result $sX - $sY
  128. ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
  129. ; Author ........: Eukalyptus www.autoit.de
  130. ;
  131. ; ;===============================================================================================
  132. Func _BigNum_Sub($sX, $sY)
  133. If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
  134. Local $iNeg = __BigNum_CheckNegative($sX, $sY), $bNeg = False
  135. Switch $iNeg
  136. Case 3
  137. Return _BigNum_Add("-" & $sX, $sY)
  138. Case 1
  139. Return "-" & _BigNum_Add($sX, $sY)
  140. Case 2
  141. Return _BigNum_Add($sX, $sY)
  142. EndSwitch
  143. Local $iDec = __BigNum_StringIsDecimal($sX, $sY)
  144. If _BigNum_Compare($sX, $sY) = -1 Then $bNeg = __BigNum_Swap($sX, $sY)
  145. Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ""
  146. If $iLen < $iTmp Then $iLen = $iTmp
  147. For $i = 1 To $iLen Step 18
  148. $iTmp = Int(StringRight($sX, 18)) - Int(StringRight($sY, 18)) - $iCar
  149. $sX = StringTrimRight($sX, 18)
  150. $sY = StringTrimRight($sY, 18)
  151. If $iTmp < 0 Then
  152. $iTmp = 1000000000000000000 + $iTmp
  153. $iCar = 1
  154. Else
  155. $iCar = 0
  156. EndIf
  157. $sRet = StringRight("0000000000000000000" & $iTmp, 18) & $sRet
  158. Next
  159. $sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1)
  160. If $iDec > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDec, $iDec)
  161. If $bNeg = True And $sRet <> "0" Then
  162. Return "-" & $sRet
  163. Else
  164. Return $sRet
  165. EndIf
  166. EndFunc ;==>_BigNum_Sub
  167. ; #FUNCTION# ;====================================================================================
  168. ;
  169. ; Name...........: _BigNum_Mul
  170. ; Description ...: Multiplication $sX * $sY
  171. ; Syntax.........: _BigNum_Mul($sX, $sY)
  172. ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  173. ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  174. ; Return values .: Success - Result $sX * $sY
  175. ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
  176. ; Author ........: Eukalyptus www.autoit.de
  177. ;
  178. ; ;===============================================================================================
  179. Func _BigNum_Mul($sX, $sY)
  180. If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
  181. Local $iNeg = __BigNum_CheckNegative($sX, $sY), $sNeg = ""
  182. Local $iDec = __BigNum_StringIsDecimal($sX, $sY)
  183. Local $aX = StringRegExp($sX, '\A.{' & 6 - (Ceiling(StringLen($sX) / 6) * 6 - StringLen($sX)) & '}|.{6}+', 3)
  184. Local $aY = StringRegExp($sY, '\A.{' & 6 - (Ceiling(StringLen($sY) / 6) * 6 - StringLen($sY)) & '}|.{6}+', 3)
  185. Local $aRet[UBound($aX) + UBound($aY) - 1]
  186. For $j = 0 To UBound($aX) - 1
  187. For $i = 0 To UBound($aY) - 1
  188. $aRet[$j + $i] += $aX[$j] * $aY[$i]
  189. Next
  190. Next
  191. Local $sRet = "", $iCar = 0, $iTmp
  192. For $i = UBound($aRet) - 1 To 0 Step -1
  193. $aRet[$i] += $iCar
  194. $iCar = Floor($aRet[$i] / 1000000)
  195. $iTmp = Mod($aRet[$i], 1000000)
  196. If $iTmp <= 1000000 Then $iTmp = StringRight("000000" & $iTmp, 6)
  197. $sRet = $iTmp & $sRet
  198. Next
  199. If $iCar > 0 Then $sRet = $iCar & $sRet
  200. $sRet = StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)
  201. If ($iNeg = 1 Or $iNeg = 2) And $sRet <> "0" Then $sNeg = "-"
  202. If $iDec > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDec * 2, $iDec * 2)
  203. Return $sNeg & $sRet
  204. EndFunc ;==>_BigNum_Mul
  205. ; #FUNCTION# ;====================================================================================
  206. ;
  207. ; Name...........: _BigNum_Div
  208. ; Description ...: Division $sX / $sY
  209. ; Syntax.........: _BigNum_Div($sX, $sY, [$iD = 0])
  210. ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  211. ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  212. ; $iD [optional] - Number of Decimalplaces; if -1 then $iD = StringLen($sX) + StringLen($sY)
  213. ; Return values .: Success - Result $sX / $sY
  214. ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
  215. ; Author ........: Eukalyptus www.autoit.de
  216. ;
  217. ; ;===============================================================================================
  218. Func _BigNum_Div($sX, $sY, $iD = -1)
  219. If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
  220. Local $iNeg = __BigNum_CheckNegative($sX, $sY), $sNeg = ""
  221. If $iD = -1 Then $iD = StringLen($sX) + StringLen($sY)
  222. Local $iDec = __BigNum_StringIsDecimal($sX, $sY), $sMod
  223. If $sX = 0 Or $sY = 0 Then Return "0"
  224. If $sY = "1" Then Return $sNeg & $sX
  225. While StringLeft($sX, 1) = "0"
  226. $sX = StringTrimLeft($sX, 1)
  227. $iDec += 1
  228. WEnd
  229. While StringLeft($sY, 1) = "0"
  230. $sY = StringTrimLeft($sY, 1)
  231. $iDec += 1
  232. WEnd
  233. Local $sRet = "", $iLnX = StringLen($sX), $iLnY = StringLen($sY), $iTmp, $iCnt, $sTmp, $iDe1 = 0
  234. If $iD > 0 Then $iDe1 += $iD
  235. If $iNeg = 1 Or $iNeg = 2 Then $sNeg = "-"
  236. $iTmp = _BigNum_Compare($sX, $sY)
  237. If $iTmp = -1 Then
  238. For $iCnt = $iLnX To $iLnY
  239. $sX &= 0
  240. $iDe1 += 1
  241. Next
  242. EndIf
  243. If $iTmp = 0 Then Return $sNeg & "1"
  244. If $iD = -1 Then $iD = $iDec * 2
  245. For $iCnt = 1 To $iD
  246. $sX &= "0"
  247. Next
  248. If $iLnY > 14 Then
  249. $sRet = __BigNum_Div_DivisorGreater14($sX, $sY, $sMod)
  250. Else
  251. $sRet = __BigNum_Div_DivisorMaxLen14($sX, $sY, $sMod)
  252. EndIf
  253. If $iDe1 > 0 Then $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDe1, $iD)
  254. If $sRet = "0" Then
  255. Return "0"
  256. Else
  257. Return $sNeg & $sRet
  258. EndIf
  259. EndFunc ;==>_BigNum_Div
  260. ; #FUNCTION# ;====================================================================================
  261. ;
  262. ; Name...........: _BigNum_Pow
  263. ; Description ...: Exponentiation $n^$e
  264. ; Syntax.........: _BigNum_Pow($n [, $e = 2])
  265. ; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  266. ; $e [optional] - Exponent (must be a positive 64-bit signed integer)
  267. ; Default: $e = 2 means result = $n²
  268. ; Return values .: Success - Result $n^$e
  269. ; Failure - -1, sets @error to 1 if $n not valid StringNumber
  270. ; -1, sets @error to 2 if $e is not a positive Integer
  271. ; Author ........: jennicoattminusonlinedotde
  272. ; Date ..........: 9.12.09
  273. ; Remarks .......: Fractional exponents not allowed - use BigNum_n_root instead.
  274. ; _BigNum_Pow() offers a drastically better efficiency than looping _BigNum_Mul()
  275. ; Reference .....: http://en.wikipedia.org/wiki/Exponentiation_by_squaring
  276. ; ;===============================================================================================
  277. Func _BigNum_Pow($n, $e = 2)
  278. $e = Number($e)
  279. If IsInt($e) = 0 Or $e < 0 Then Return SetError(2, 0, -1)
  280. ;If $e < -2147483648 Or $e > 2147483647 Then Return SetError(-2, 0, -1)
  281. If Not __BigNum_IsValid($n, $n) Then Return SetError(1, 0, -1)
  282. Local $res = 1
  283. While $e
  284. ;If BitAND($e, 1) Then ; bitoperation is not faster !
  285. If Mod($e, 2) Then
  286. $res = _BigNum_Mul($res, $n)
  287. $e -= 1
  288. EndIf
  289. $n = _BigNum_Mul($n, $n)
  290. ;$e = BitShift($e, 1) ; bitoperation is not faster !
  291. $e /= 2
  292. WEnd
  293. Return $res
  294. EndFunc ;==>_BigNum_Pow
  295. ; #FUNCTION# ;====================================================================================
  296. ;
  297. ; Name...........: _BigNum_SQRT
  298. ; Description ...: Square Root (BigNum)
  299. ; Syntax.........: _BigNum_SQRT($n [, $p = -1])
  300. ; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  301. ; $p [optional] - Precision (Number of Decimalplaces) (must be positive Integer)
  302. ; Default: $p = -1 means automatic precision (stringlen of integer part of $n)
  303. ; Return values .: Success - Result SQRT($n)
  304. ; @extended = Precicion of result (if $p set to automatic precision)
  305. ; @error = Number of Iterations
  306. ; Failure - -1, sets @error to -1 if $n not valid StringNumber
  307. ; -1, sets @error to -2 if $p is out of valid range
  308. ; -1, sets @error to -3 if time-out (>100 iterations)
  309. ; Author ........: jennicoattminusonlinedotde
  310. ; Date ..........: 8.12.09
  311. ; Remarks .......: use Precision param when u want to obtain the square root of a small number with the desired decimal places.
  312. ; References ....: http://www.merriampark.com/bigsqrt.htm
  313. ; "Newton's Method" - before: Heron of Alexandria
  314. ; ;===============================================================================================
  315. Func _BigNum_SQRT($n, $p = -1)
  316. If Not __BigNum_IsValid($n, $n) Then Return SetError(-1, 0, -1)
  317. $p = Number($p)
  318. If IsInt($p) = 0 Or $p < -1 Then Return SetError(-2, 0, -1)
  319. Local $l = StringInStr($n, ".") - 1
  320. If $l = -1 Then $l = StringLen($n)
  321. If $p < 0 Then $p = $l
  322. Local $g = 1, $last
  323. For $i = 3 To $l Step 2
  324. $g = _BigNum_Mul($g, 10)
  325. Next
  326. For $i = 1 To 100
  327. $last = $g
  328. $g = _BigNum_Div(_BigNum_Add(_BigNum_Div($n, $g, $p), $g), 2, $p)
  329. If $last = $g Then Return SetError($i, $p, $g)
  330. Next
  331. Return SetError(-3, 0, -1)
  332. EndFunc ;==>_BigNum_SQRT
  333. ; #FUNCTION# ;====================================================================================
  334. ;
  335. ; Name...........: _BigNum_n_Root
  336. ; Description ...: $e-th Root of $n
  337. ; Syntax.........: _n_Root($n [, $e=2])
  338. ; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  339. ; $e - [optional] Multiplicity of root (power, exponent) (must be a positive 64-bit signed integer > 0)
  340. ; Default: $e = 2 (=SQRT)
  341. ; $p - [optional] Precision (Number of desired Decimalplaces) (must be positive Integer)
  342. ; Default: $p = -1 means automatic precision (stringlen of integer part of $n)
  343. ; Return values .: Success - Result $e-root($n)
  344. ; @extended = Number of Iterations
  345. ; Failure - -1 and sets @error to 1 if $n not valid StringNumber
  346. ; -1 and sets @error to 2 if $e out of valid range
  347. ; -1 and sets @error to 3 if $p out of valid range
  348. ; Author ........: jennicoattminusonlinedotde
  349. ; Date ..........: 9.12.09
  350. ; References ....: derived from "Newton's Method"
  351. ; ;===============================================================================================
  352. Func _BigNum_n_Root($n, $e = 2, $p = -1)
  353. If Not __BigNum_IsValid($n, $n) Then Return SetError(1, 0, -1)
  354. $e = Number($e)
  355. If IsInt($e) = 0 Or $e < 1 Then Return SetError(2, 0, -1)
  356. $p = Number($p)
  357. If IsInt($p) = 0 Or $p < -1 Then Return SetError(3, 0, -1)
  358. Local $l = StringInStr($n, ".") - 1
  359. If $l = -1 Then $l = StringLen($n)
  360. If $p < 0 Then $p = $l
  361. Local $g = 1, $last, $i = 0
  362. For $i = 3 To $l Step 2
  363. $g = _BigNum_Mul($g, 10)
  364. Next
  365. While 1
  366. $i += 1
  367. $last = $g
  368. $g = _BigNum_Div(_BigNum_Add(_BigNum_Div($n, _BigNum_Pow($g, $e - 1), $p), _BigNum_Mul($g, $e - 1)), $e, $p)
  369. If $last = $g Then Return SetExtended($i, $g)
  370. WEnd
  371. EndFunc ;==>_BigNum_n_Root
  372. ; #FUNCTION# ;====================================================================================
  373. ;
  374. ; Name...........: _BigNum_Mod
  375. ; Description ...: Modulo Mod($sX, $sY)
  376. ; Syntax.........: _BigNum_Mod($sX, $sY)
  377. ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  378. ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  379. ; Return values .: Success - Result Mod($sX, $sY)
  380. ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber
  381. ; Author ........: Eukalyptus www.autoit.de
  382. ;
  383. ; ;===============================================================================================
  384. Func _BigNum_Mod($sX, $sY)
  385. If Not __BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0)
  386. If $sY = 0 Or $sY = 1 Then Return "0"
  387. Local $sRes = $sX
  388. Local $iNeg = __BigNum_CheckNegative($sX, $sY)
  389. Local $iDec = __BigNum_StringIsDecimal($sX, $sY)
  390. If _BigNum_Compare($sX, $sY) < 0 Then Return $sRes
  391. Local $sRet = "", $iLnX = StringLen($sX), $iLnY = StringLen($sY)
  392. If $iLnY > 14 Then
  393. __BigNum_Div_DivisorGreater14($sX, $sY, $sRet)
  394. Else
  395. __BigNum_Div_DivisorMaxLen14($sX, $sY, $sRet)
  396. EndIf
  397. $sRet = __BigNum_InsertDecimalSeparator($sRet, $iDec, StringLen($sRet))
  398. If ($iNeg = 3 Or $iNeg = 1) And $sRet <> "0" Then $sRet = "-" & $sRet
  399. Return $sRet
  400. EndFunc ;==>_BigNum_Mod
  401. ; #FUNCTION# ;====================================================================================
  402. ;
  403. ; Name...........: _BigNum_Round
  404. ; Description ...: Round $sX to $iD Decimalplaces
  405. ; Syntax.........: _BigNum_Round($sX, $iD)
  406. ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  407. ; $iD - Number of Decimalplaces
  408. ; Return values .: Success - Result Round($sX, $iD)
  409. ; Failure - 0, sets @error to 1 if $sX not valid StringNumber
  410. ; Author ........: Eukalyptus www.autoit.de
  411. ;
  412. ; ;===============================================================================================
  413. Func _BigNum_Round($sX, $iD)
  414. If Not __BigNum_IsValid($sX, $sX) Then Return SetError(1, 0, 0)
  415. Local $sTmp = 0, $sRet, $sRes = $sX
  416. Local $iNeg = __BigNum_CheckNegative($sX, $sTmp)
  417. Local $iDec = __BigNum_StringIsDecimal($sX, $sTmp)
  418. If $iD > $iDec Or $iDec = 0 Then Return $sRes
  419. $sTmp = StringLeft(StringRight($sX, $iDec - $iD), 1)
  420. $sRet = StringTrimRight($sRes, $iDec - $iD)
  421. If $sTmp >= 5 And $iD > 0 Then
  422. If $iNeg = 1 Then
  423. $sRet = _BigNum_Add($sRet, "-0." & StringFormat("%0" & String($iD) & "u", "1"))
  424. Else
  425. $sRet = _BigNum_Add($sRet, "0." & StringFormat("%0" & String($iD) & "u", "1"))
  426. EndIf
  427. ElseIf $sTmp >= 5 And $iD = 0 Then
  428. If $iNeg = 1 Then
  429. $sRet = _BigNum_Add($sRet, "-1")
  430. Else
  431. $sRet = _BigNum_Add($sRet, "1")
  432. EndIf
  433. Else
  434. If StringRight($sRet, 1) = "." Then $sRet = StringTrimRight($sRet, 1)
  435. EndIf
  436. Return $sRet
  437. EndFunc ;==>_BigNum_Round
  438. ; #FUNCTION# ;====================================================================================
  439. ;
  440. ; Name...........: _BigNum_Compare
  441. ; Description ...: Compares $sX $sY
  442. ; Syntax.........: _BigNum_Compare($sX, $sY)
  443. ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  444. ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345")
  445. ; Return values .: Success - Return:
  446. ; |0 - $sX and $sY are equal
  447. ; |1 - $sX is greater than $sY
  448. ; |-1 - $sX is less than $sY
  449. ; Failure - sets @error to 1 if $sX/$sY not valid StringNumber
  450. ; Author ........: eXirrah
  451. ;
  452. ; ;===============================================================================================
  453. Func _BigNum_Compare($sX, $sY) ;Algorithm No.2
  454. Local $iNeg = __BigNum_CheckNegative($sX, $sY)
  455. Switch $iNeg
  456. Case 1 ; sX = negative
  457. Return -1
  458. Case 2 ; sY = negative
  459. Return 1
  460. Case 3 ; both negative
  461. __BigNum_Swap($sX, $sY)
  462. EndSwitch
  463. __BigNum_CompEqualizeLength($sX, $sY)
  464. Return StringCompare($sX, $sY)
  465. EndFunc ;==>_BigNum_Compare
  466. ; #INTERNAL_USE_ONLY#============================================================================================================
  467. #Region Internal Functions
  468. Func __BigNum_CompEqualizeLength(ByRef $sX, ByRef $sY)
  469. Local $iXDotPos = StringInStr($sX, ".")
  470. Local $iYDotPos = StringInStr($sY, ".")
  471. Local $iXLen = StringLen($sX)
  472. Local $iYLen = StringLen($sY)
  473. Local $iLeading, $iTrailing
  474. ;Calculation leading and trailing zeroes
  475. If $iXDotPos == 0 And $iYDotPos <> 0 Then
  476. $iLeading = $iXLen - ($iYDotPos - 1)
  477. $iTrailing = -1 * ($iYLen - $iYDotPos)
  478. $sX &= "."
  479. ElseIf $iXDotPos <> 0 And $iYDotPos == 0 Then
  480. $iLeading = ($iXDotPos - 1) - $iYLen
  481. $iTrailing = $iXLen - $iXDotPos
  482. $sY &= "."
  483. ElseIf $iXDotPos == 0 And $iYDotPos == 0 Then
  484. $iLeading = $iXLen - $iYLen
  485. Else
  486. $iLeading = $iXDotPos - $iYDotPos
  487. $iTrailing = ($iXLen - $iXDotPos) - ($iYLen - $iYDotPos)
  488. EndIf
  489. ;adding leading and trailing zeroes
  490. If $iLeading < 0 Then
  491. $sX = __BigNum_CompStringAddZeroes($sX, -1 * $iLeading, 0, 0)
  492. ElseIf $iLeading > 0 Then
  493. $sY = __BigNum_CompStringAddZeroes($sY, $iLeading, 0, 0)
  494. EndIf
  495. If $iTrailing < 0 Then
  496. $sX = __BigNum_CompStringAddZeroes($sX, -1 * $iTrailing, 1, 0)
  497. ElseIf $iTrailing > 0 Then
  498. $sY = __BigNum_CompStringAddZeroes($sY, $iTrailing, 1, 0)
  499. EndIf
  500. EndFunc ;==>__BigNum_CompEqualizeLength
  501. Func __BigNum_CompStringAddZeroes($sString, $iCount, $bTrailing = 0, $bToLength = 1)
  502. ;$bToLength is set when the user wants to add the nescessary amount
  503. ;of zeroes to the string so it is with length $iCount (Default)
  504. If $bToLength Then
  505. $iCount -= StringLen($sString)
  506. EndIf
  507. Local $i = 0
  508. Local $s = ""
  509. While $i < $iCount
  510. $s &= "0"
  511. $i += 1
  512. WEnd
  513. ;$bTrailing is set when the user wants the zeroes to be added at the
  514. ;right side of the string. By defaut zeroes are added at the left side of the string
  515. If $bTrailing Then
  516. Return $sString & $s
  517. EndIf
  518. Return $s & $sString
  519. EndFunc ;==>__BigNum_CompStringAddZeroes
  520. Func __BigNum_Swap(ByRef $sX, ByRef $sY)
  521. Local $sSwap = $sX
  522. $sX = $sY
  523. $sY = $sSwap
  524. Return True
  525. EndFunc ;==>__BigNum_Swap
  526. Func __BigNum_Div_DivisorGreater14($sX, $sY, ByRef $sM)
  527. $sM = "0"
  528. If $sY = "1" Then Return $sX
  529. If $sX = "0" Or $sY = "0" Or $sX = "" Or $sY = "" Then Return "0"
  530. Local $iLnY = StringLen($sY), $bRed = False
  531. Local $sRet = "", $sRem = StringLeft($sX, $iLnY), $sTmp = "", $sTm2 = "", $iCnt, $iLen = 1
  532. $sX = StringTrimLeft($sX, $iLnY)
  533. Do
  534. If __BigNum_DivComp($sRem, $sY) = -1 Then
  535. $sTmp = StringLeft($sX, 1)
  536. $sRem &= $sTmp
  537. $sX = StringTrimLeft($sX, 1)
  538. If StringLen($sTmp) > 0 Then $iLen += 1
  539. EndIf
  540. $sTmp = $sY
  541. $sTm2 = "0"
  542. If __BigNum_DivComp($sRem, $sY) >= 0 Then
  543. For $iCnt = 1 To 9
  544. $sTm2 = $sTmp
  545. $sTmp = __BigNum_DivAdd($sTmp, $sY)
  546. If __BigNum_DivComp($sRem, $sTmp) < 0 Then ExitLoop
  547. Next
  548. Else
  549. $iCnt = 0
  550. EndIf
  551. If StringLen($sX) = 0 Then $bRed = True
  552. $sM = $sRem
  553. $sRem = __BigNum_DivSub($sRem, $sTm2)
  554. If $iCnt > 0 Then $sM = $sRem
  555. $sRet &= StringFormat("%0" & String($iLen) & "u", $iCnt)
  556. $iTrm = $iLnY - StringLen($sRem)
  557. $sTmp = StringLeft($sX, $iTrm)
  558. $sX = StringTrimLeft($sX, $iTrm)
  559. $iLen = StringLen($sTmp)
  560. $sRem &= $sTmp
  561. Until $bRed
  562. $sM = StringRegExpReplace($sM, "^0+([^0]|0$)", "\1", 1)
  563. Return StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)
  564. EndFunc ;==>__BigNum_Div_DivisorGreater14
  565. Func __BigNum_Div_DivisorMaxLen14($sX, $sY, ByRef $sM)
  566. $sM = "0"
  567. If $sY = "1" Then Return $sX
  568. If $sX = "0" Or $sY = "0" Or $sX = "" Or $sY = "" Then Return "0"
  569. Local $sRet = "", $iRem = StringLeft($sX, 15), $iTmp = 0, $iTrm = 6, $iLen
  570. $sX = StringTrimLeft($sX, 15)
  571. $iTmp = Floor($iRem / $sY)
  572. $sRet &= $iTmp
  573. $iRem -= $iTmp * $sY
  574. While StringLen($sX) > 0
  575. $iTrm = 15 - StringLen($iRem)
  576. $iTmp = StringLeft($sX, $iTrm)
  577. $iLen = StringLen($iTmp)
  578. $iRem &= $iTmp
  579. $sX = StringTrimLeft($sX, $iTrm)
  580. $iTmp = Floor($iRem / $sY)
  581. $iTmp = StringRight("000000000000000" & $iTmp, $iLen)
  582. $sRet &= $iTmp
  583. $iRem -= $iTmp * $sY
  584. WEnd
  585. $sM = String($iRem)
  586. Return StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)
  587. EndFunc ;==>__BigNum_Div_DivisorMaxLen14
  588. Func __BigNum_DivComp($sX, $sY)
  589. $sX = StringRegExpReplace($sX, "^0+([^0]|0$)", "\1", 1)
  590. $sY = StringRegExpReplace($sY, "^0+([^0]|0$)", "\1", 1)
  591. Local $iLnX = StringLen($sX), $iLnY = StringLen($sY)
  592. If $iLnX < $iLnY Then
  593. Return -1
  594. ElseIf $iLnX > $iLnY Then
  595. Return 1
  596. Else
  597. If $sX < $sY Then
  598. Return -1
  599. ElseIf $sX > $sY Then
  600. Return 1
  601. Else
  602. Return 0
  603. EndIf
  604. EndIf
  605. EndFunc ;==>__BigNum_DivComp
  606. Func __BigNum_DivAdd($sX, $sY)
  607. Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ""
  608. If $iLen < $iTmp Then $iLen = $iTmp
  609. For $i = 1 To $iLen Step 18
  610. $iTmp = Int(StringRight($sX, 18)) + Int(StringRight($sY, 18)) + $iCar
  611. $sX = StringTrimRight($sX, 18)
  612. $sY = StringTrimRight($sY, 18)
  613. If ($iTmp > 999999999999999999) Then
  614. $sRet = StringRight($iTmp, 18) & $sRet
  615. $iCar = 1
  616. Else
  617. $iTmp = StringRight("000000000000000000" & $iTmp, 18)
  618. $sRet = $iTmp & $sRet
  619. $iCar = 0
  620. EndIf
  621. Next
  622. $sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1)
  623. Return $sRet
  624. EndFunc ;==>__BigNum_DivAdd
  625. Func __BigNum_DivSub($sX, $sY)
  626. Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = ""
  627. If $iLen < $iTmp Then $iLen = $iTmp
  628. For $i = 1 To $iLen Step 18
  629. $iTmp = Int(StringRight($sX, 18)) - Int(StringRight($sY, 18)) - $iCar
  630. $sX = StringTrimRight($sX, 18)
  631. $sY = StringTrimRight($sY, 18)
  632. If $iTmp < 0 Then
  633. $iTmp = 1000000000000000000 + $iTmp
  634. $iCar = 1
  635. Else
  636. $iCar = 0
  637. EndIf
  638. $sRet = StringRight("0000000000000000000" & $iTmp, 18) & $sRet
  639. Next
  640. $sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1)
  641. Return $sRet
  642. EndFunc ;==>__BigNum_DivSub
  643. Func __BigNum_IsValid($sX, $sY)
  644. If StringRegExp($sX, "[^0-9.-]") Or StringRegExp($sY, "[^0-9.-]") Then Return False
  645. Return True
  646. EndFunc ;==>__BigNum_IsValid
  647. Func __BigNum_InsertDecimalSeparator($sX, $iDec, $iD = 18)
  648. If $iD = 0 And $iDec = 0 Then Return $sX
  649. Local $sRet = StringRegExpReplace(StringRight(StringFormat("%0" & String($iDec) & "u", "") & $sX, $iDec), "0+$", "\1", 1)
  650. $sX = StringTrimRight($sX, $iDec)
  651. If $sX = "" Then $sX = "0"
  652. $sRet = StringLeft($sRet, $iD)
  653. If $sRet = "" Or $sRet = "0" Then Return $sX
  654. Return $sX & "." & $sRet
  655. EndFunc ;==>__BigNum_InsertDecimalSeparator
  656. Func __BigNum_StringIsDecimal(ByRef $sX, ByRef $sY)
  657. If StringLeft($sX, 1) = "." Then $sX = "0" & $sX
  658. If StringLeft($sY, 1) = "." Then $sY = "0" & $sY
  659. Local $iPsX = StringInStr($sX, ".", 0, 1) - 1, $iPsY = StringInStr($sY, ".", 0, 1) - 1
  660. $sX = StringRegExpReplace($sX, "\D", "")
  661. $sY = StringRegExpReplace($sY, "\D", "")
  662. Local $iLnX = StringLen($sX), $iLnY = StringLen($sY)
  663. If $iPsX <= 0 Then $iPsX = $iLnX
  664. If $iPsY <= 0 Then $iPsY = $iLnY
  665. If $iLnX - $iPsX > $iLnY - $iPsY Then
  666. For $iCnt = $iLnY - $iPsY To $iLnX - $iPsX - 1
  667. $sY &= "0"
  668. Next
  669. Return $iLnX - $iPsX
  670. ElseIf $iLnX - $iPsX < $iLnY - $iPsY Then
  671. For $iCnt = $iLnX - $iPsX To $iLnY - $iPsY - 1
  672. $sX &= "0"
  673. Next
  674. Return $iLnY - $iPsY
  675. EndIf
  676. Return $iLnX - $iPsX
  677. EndFunc ;==>__BigNum_StringIsDecimal
  678. Func __BigNum_CheckNegative(ByRef $sX, ByRef $sY)
  679. Local $bNgX = False, $bNgY = False
  680. While StringLeft($sX, 1) = "-"
  681. $bNgX = Not $bNgX
  682. $sX = StringTrimLeft($sX, 1)
  683. WEnd
  684. While StringLeft($sY, 1) = "-"
  685. $bNgY = Not $bNgY
  686. $sY = StringTrimLeft($sY, 1)
  687. WEnd
  688. $sX = StringRegExpReplace($sX, "^0+([^0]|0$)", "\1", 1)
  689. $sY = StringRegExpReplace($sY, "^0+([^0]|0$)", "\1", 1)
  690. If $sX = "" Then $sX = "0"
  691. If $sY = "" Then $sY = "0"
  692. If $bNgX = True And $bNgY = True Then
  693. Return 3
  694. ElseIf $bNgX = True And $bNgY = False Then
  695. Return 1
  696. ElseIf $bNgX = False And $bNgY = True Then
  697. Return 2
  698. Else
  699. Return 0
  700. EndIf
  701. EndFunc ;==>__BigNum_CheckNegative
  702. #EndRegion Internal Functions

comments powered by Disqus