1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
|
'---------------------------------------------------------------------------------------
' http://fordom.free.fr/
'---------------------------------------------------------------------------------------
Option Explicit
Function AGN(ByVal Nb1 As String, ByVal Nb2 As String) As String
'ADDITION SIGNEE DE 2 GRANDS NOMBRES
'Info sur les longueurs des termes
Dim L1 As Long, L2 As Long
L1 = Len(Nb1): L2 = Len(Nb2)
'Recherche des signes et conversion en nombre positif
Dim S1 As Long, S2 As Long
S1 = 1: S2 = 1
If Left$(Nb1, 1) = "-" Then S1 = -1: Nb1 = Right$(Nb1, L1 - 1): L1 = L1 - 1
If Left$(Nb2, 1) = "-" Then S2 = -1: Nb2 = Right$(Nb2, L2 - 1): L2 = L2 - 1
'Recherche de la décimale et conversion en entier
Dim P1 As Long, P2 As Long, virgule As Long, PS1 As Long, PS2 As Long
Dim Z As String 'optimisation pour les string$ qui suivent
Z = "0"
'Recherche emplacement de la virgule
P1 = InStr(1, Nb1, ",") + InStr(1, Nb1, ".")
P2 = InStr(1, Nb2, ",") + InStr(1, Nb2, ".")
'Recompose en entier
Dim Nb1Prov As String, Nb2Prov As String
PS1 = 0: PS2 = 0
If P1 > 0 Then
PS1 = L1 - P1
Nb1Prov = Left$(Nb1, P1 - 1)
End If
If P2 > 0 Then
PS2 = L2 - P2
Nb2Prov = Left$(Nb2, P2 - 1)
End If
If PS1 > PS2 Then
Nb1 = Nb1Prov & Right$(Nb1, L1 - P1)
Nb2 = Nb2Prov & Right$(Nb2, L2 - P2) & String$(PS1 - PS2, Z)
ElseIf PS1 < PS2 Then
Nb1 = Nb1Prov & Right$(Nb1, L1 - P1) & String$(PS2 - PS1, Z)
Nb2 = Nb2Prov & Right$(Nb2, L2 - P2)
Else
Nb1 = Nb1Prov & Right$(Nb1, L1 - P1) & String$(PS2 - PS1, Z)
Nb2 = Nb2Prov & Right$(Nb2, L2 - P2) & String$(PS1 - PS2, Z)
End If
'Retrouve les bonnes longueurs
L1 = Len(Nb1): L2 = Len(Nb2)
'Trouve la bonne position de la décimale du résultat
virgule = IIf(PS2 > PS1, PS2, PS1)
'Comparaison des termes si soustraction
If S1 <> S2 Then
Dim Pgdd As Long, Lmax As Long
'Renvoi 1 si Nb1>Nb2, sinon -1 ou Revoi 0 si égalité avec Nb1 et Nb2 >=0
Lmax = L1
If L1 < L2 Then Lmax = L2
Pgdd = StrComp(String$(Lmax - L1, Z) & Nb1, String$(Lmax - L2, Z) & Nb2)
If Pgdd = 0 Then AGN = "0": Exit Function 'égalité
End If
'Transformation en longueur multiple de Multiple
Dim Multiple As Long
Multiple = 14
Dim lgmul As Long
lgmul = (IIf(L1 < L2, L2, L1) \ Multiple + 1) * Multiple
Nb1 = String$(lgmul - L1, Z) & Nb1
Nb2 = String$(lgmul - L2, Z) & Nb2
'Variables
Dim Total As String
Dim T As Long
Dim v1 As Double, v2 As Double, R As Double, Ret As Long
Dim lr As Long
Dim ln10 As Double
ln10 = Log(10)
'Déclare le résultat à la longueur maxi
Total = String$(lgmul, Z)
'Fait l'opération puis met en forme
If S1 = S2 Then
'Addition
For T = lgmul - Multiple + 1 To 1 Step -Multiple
v1 = Mid$(Nb1, T, Multiple)
v2 = Mid$(Nb2, T, Multiple)
R = v1 + v2 + Ret
lr = Fix(Log(R + 0.11) / ln10) + 1
If lr = Multiple + 1 Then Ret = 1 Else Ret = 0
Mid$(Total, T - lr + Multiple, lr) = CStr(R)
Next T
'Replacement de la virgule
If virgule <> 0 Then Total = Left$(Total, Len(Total) - virgule) & "," & Right$(Total, virgule)
'Mise en forme
AGN = ZeroGN(Total)
'Règle des signes
If S1 = -1 And AGN <> "0" Then AGN = "-" & AGN
Else
'Soustraction
Dim base As Double
base = 10 ^ (Multiple + 1)
For T = lgmul - Multiple + 1 To 1 Step -Multiple
v1 = Mid$(Nb1, T, Multiple)
v2 = Mid$(Nb2, T, Multiple)
R = v1 - v2 + Ret
Ret = 0
If Sgn(R) <> Pgdd And R <> 0 Then
R = Pgdd * base + R
Ret = -Pgdd
End If
lr = Fix(Log(Abs(R) + 0.11) / ln10) + 1
Mid$(Total, T - lr + Multiple, lr) = CStr(Abs(R))
Next T
'Replacement de la virgule
If virgule <> 0 Then Total = Left$(Total, Len(Total) - virgule) & "," & Right$(Total, virgule)
'Mise en forme
AGN = ZeroGN(Total)
'Règle des signes
If Pgdd * S1 = -1 Then AGN = "-" & AGN
End If
End Function
'=========================
Function ZeroGN(ByVal Term1 As String) As String
'RETIRE LES ZEROS INUTILES
'Boucle de recherche des zéros inutiles dans la partie entière
Dim i As Long
For i = 1 To Len(Term1)
If Mid$(Term1, i, 1) <> "0" Then Exit For
Next i
Term1 = Mid$(Term1, i)
If Term1 = vbNullString Then Term1 = "0" 'traite le cas d'un nombre nul
'Recherche si virgule
Dim v As Long
v = InStr(1, Term1, ",") + InStr(1, Term1, ".")
'Recherche si Term1<1, si oui remet un zéro devant la virgule
If v = 1 Then Term1 = "0" & Term1: v = 2
'Boucle de recherche des zéros inutiles dans partie décimale
If v > 0 Then
For i = Len(Term1) To v - 1 Step -1
If Mid$(Term1, i, 1) <> "0" Then Exit For
Next i
Term1 = Left$(Term1, i)
End If
'Recherche si dernier=virgule, si oui=supprime
If v = Len(Term1) Then Term1 = Left$(Term1, v - 1)
'Renvoi
ZeroGN = Term1
End Function
'=========================
Function FactGN(ByVal a As Long, Optional b As Variant = 2) As String
'CALCUL FACTORIELLE
'Traitement option : B=1er nb de départ
b = CLng(b)
'Traitement des cas triviaux
If a < 0 Then FactGN = "#VALEUR!": Exit Function
If a = 0 Then FactGN = 1: Exit Function
'Variables
Dim base As Double, P As Double, Q As Double
Dim N As Long, j As Long, i As Long
Dim Expo As Long
'Base dynamique optimisée
Expo = 15 - Len(Trim(Str$(a))) 'évite P>10^15 et donc le formattage exponentiel (1E15) !!
'Base de calcul
base = 10 ^ Expo
'Nombre d'indice dans la base
N = Int((0.92 + (a + 0.5) * Log(a) - a) / Log(10)) + 1 'nb chiffre de A!
N = Int(N / Expo) + 1
'Déclaration des indices
ReDim T(N) As Double
T(0) = 1
'Algorithme factorielle
For j = b To a
For i = 0 To N
P = T(i) * j + Q
Q = Int(P / base)
T(i) = P - Q * base
Next i
Next j
'Rajoute les zeros devant les indices moins long que expo
Dim Z As String 'optimisation string$
Z = "0"
Dim ln10 As Double
ln10 = Log(10)
For i = N To 0 Step -1
FactGN = FactGN & String$(Expo - 1 - Fix(Log(T(i) + 0.11) / ln10), Z) & T(i)
Next i
'Supprime les zeros inutiles du début
FactGN = ZeroGN(FactGN)
End Function
'========================
Function ArrangGN(ByVal N As Long, ByVal P As Long) As String
'ARRANGEMENT de P objets avec N objets au total
If P > N Then ArrangGN = "#NOMBRE!": Exit Function
P = N - P + 1 'dernier indice dans l'algo factorielle
If P < 0 Then ArrangGN = "#VALEUR!": Exit Function
ArrangGN = FactGN(N, P)
End Function
'=========================
Function PGN(ByVal Nb1 As String, ByVal Nb2 As String) As String
'PRODUIT GRANDS NOMBRES
'Info sur les longueurs des termes
Dim L1 As Long, L2 As Long
L1 = Len(Nb1): L2 = Len(Nb2)
'Recherche des signes et conversion en nombre positif
Dim S1 As Long, S2 As Long
S1 = 1: S2 = 1
If Left$(Nb1, 1) = "-" Then S1 = -1: Nb1 = Right$(Nb1, L1 - 1): L1 = L1 - 1
If Left$(Nb2, 1) = "-" Then S2 = -1: Nb2 = Right$(Nb2, L2 - 1): L2 = L2 - 1
'Recherche de la décimale et conversion en entier
Dim P1 As Long, P2 As Long, virgule As Long
'Recherche emplacement de la virgule
P1 = InStr(1, Nb1, ",") + InStr(1, Nb1, ".")
P2 = InStr(1, Nb2, ",") + InStr(1, Nb2, ".")
'Recompose en entier
If P1 > 0 Then
Nb1 = Left$(Nb1, P1 - 1) & Right$(Nb1, L1 - P1)
virgule = L1 - P1
L1 = L1 - 1
End If
If P2 > 0 Then
Nb2 = Left$(Nb2, P2 - 1) & Right$(Nb2, L2 - P2)
virgule = virgule + L2 - P2
L2 = L2 - 1
End If
'Découpage en tranche
Dim K1 As Long, K2 As Long, Kt As Long
K1 = L1 \ 7 + 1: K2 = L2 \ 7 + 1: Kt = K1 + K2
'Tableaux de stockage des tranches
ReDim a(K1) As Double, b(K2) As Double
'Remplissage tableau
Dim i As Long, j As Long
For i = 0 To K1 - 2
a(i) = Mid$(Nb1, L1 - 6 - i * 7, 7)
Next i
a(K1 - 1) = 0
If L1 Mod 7 <> 0 Then a(K1 - 1) = Left$(Nb1, L1 Mod 7)
For i = 0 To K2 - 2
b(i) = Mid$(Nb2, L2 - 6 - i * 7, 7)
Next i
b(K2 - 1) = 0
If L2 Mod 7 <> 0 Then b(K2 - 1) = Left$(Nb2, L2 Mod 7)
'Base de calcul
Dim base As Long
base = 10 ^ 7
'Déclaration des indices
ReDim T(Kt + 1) As Double
'Algo multiplication
Dim P As Double, Q As Double, k As Long, Saut As Long, l As Double
Saut = 90
For j = 0 To K1
l = a(j)
If j = Saut Then Saut = Saut + 90: GoSub Recalcul
For i = 0 To K2
T(i + j) = l * b(i) + T(i + j)
Next i
Next j
GoSub Recalcul
GoTo Suite:
Recalcul: 'recalculs des indices t() dans la Base avant dépassement de capacité
P = 0
For k = 0 To K2 + j
Q = Int((T(k) + P) / base)
T(k) = T(k) + P - Q * base
P = Q
Next k
Return
Suite:
'Rajoute les zeros dans les indices moins long que 7 chiffres
Dim Z As String 'optimisation string$
Z = "0"
Dim ln10 As Double
ln10 = Log(10)
For i = Kt To 0 Step -1
PGN = PGN & String$(6 - Fix(Log(T(i) + 0.11) / ln10), Z) & T(i)
Next i
'Supprime les zeros inutiles
PGN = ZeroGN(PGN)
'Replacement de la virgule
Dim PS As Long
If virgule <> 0 Then
PS = Len(PGN) - virgule
If PS < 0 Then PGN = String$(-PS, Z) & PGN
PGN = Left$(PGN, Len(PGN) - virgule) & "," & Right$(PGN, virgule)
End If
'Mise en forme
PGN = ZeroGN(PGN)
'Règle des signes
If S1 * S2 = -1 And PGN <> "0" Then PGN = "-" & PGN
End Function
'===============================
Function PuissanceGN(ByVal Nb1 As String, ByVal Expo As Long) As String
'PUISSANCE ENTIERE D'UN GRAND NOMBRE (décimal ou entier)
If Expo = 0 Then PuissanceGN = 1: Exit Function
If Expo = 1 Then PuissanceGN = Nb1: Exit Function
PuissanceGN = "1"
Do
If Expo And 1 Then PuissanceGN = PGN(PuissanceGN, Nb1)
Expo = Expo \ 2
Nb1 = PGN(Nb1, Nb1)
Loop While Expo > 1
PuissanceGN = PGN(PuissanceGN, Nb1)
End Function
'===============================
Function AbsGN(ByVal nb As String) As String
'Equivalent à ABS()
If Left$(nb, 1) = "-" Then AbsGN = Mid$(nb, 2) Else AbsGN = nb
End Function
'===============================
Function SgnGN(ByVal nb As String) As Long
'Equivalent à SGN()
nb = ZeroGN(nb)
If nb = "0" Then SgnGN = 0: Exit Function
Dim premier As String * 1
premier = Left$(nb, 1)
Select Case premier
Case "-"
SgnGN = -1
Case Else
SgnGN = 1
End Select
End Function
'===============================
Function IntGN(ByVal nb As String) As String
'Equivalent à INT()
nb = ZeroGN(nb)
Dim P As Long, Signe As Long
P = InStr(nb, ",") + InStr(nb, ".")
If P = 0 Then IntGN = nb: Exit Function
Signe = SgnGN(nb)
Select Case Signe
Case -1
IntGN = AGN(Left$(nb, P - 1), "-1")
Case Else
IntGN = Left$(nb, P - 1)
End Select
End Function
'===============================
Function FixGN(ByVal nb As String) As String
'Equivalent à FIX()
nb = ZeroGN(nb)
Dim P As Long
P = InStr(nb, ",") + InStr(nb, ".")
If P = 0 Then FixGN = nb: Exit Function
FixGN = Left$(nb, P - 1)
End Function
'=========================
Function CompGN(ByVal Nb1 As String, ByVal Nb2 As String) As Long
'Renvoie 1 si Nb1>Nb2,
'Renvoie -1 si Nb1<Nb2
'Renvoi 0 si égalité
'format sans zero inutile
Nb1 = ZeroGN(Nb1): Nb2 = ZeroGN(Nb2)
'Regarde le signe
Dim Signe1 As String * 1, Signe2 As String * 1, Inverse As Long
Signe1 = Left$(Nb1, 1): Signe2 = Left$(Nb2, 1): Inverse = 1
If Signe1 = "-" And Signe2 <> "-" Then CompGN = "-1": Exit Function
If Signe1 <> "-" And Signe2 = "-" Then CompGN = "1": Exit Function
If Signe1 = "-" And Signe2 = "-" Then Nb1 = AbsGN(Nb1): Nb2 = AbsGN(Nb2): Inverse = -1
'Définitions
Dim P1 As Long, P2 As Long, PS1 As Long, PS2 As Long
Dim Z As String 'optimisation pour les string$ qui suivent
Z = "0"
'Info sur les longueurs des termes
Dim L1 As Long, L2 As Long
L1 = Len(Nb1): L2 = Len(Nb2)
'Recherche emplacement de la virgule
P1 = InStr(1, Nb1, ",") + InStr(1, Nb1, ".")
P2 = InStr(1, Nb2, ",") + InStr(1, Nb2, ".")
'Recompose en entier
Dim Nb1Prov As String, Nb2Prov As String
PS1 = 0: PS2 = 0
If P1 > 0 Then
PS1 = L1 - P1
Nb1Prov = Left$(Nb1, P1 - 1)
End If
If P2 > 0 Then
PS2 = L2 - P2
Nb2Prov = Left$(Nb2, P2 - 1)
End If
If PS1 > PS2 Then
Nb1 = Nb1Prov & Right$(Nb1, L1 - P1)
Nb2 = Nb2Prov & Right$(Nb2, L2 - P2) & String$(PS1 - PS2, Z)
ElseIf PS1 < PS2 Then
Nb1 = Nb1Prov & Right$(Nb1, L1 - P1) & String$(PS2 - PS1, Z)
Nb2 = Nb2Prov & Right$(Nb2, L2 - P2)
Else
Nb1 = Nb1Prov & Right$(Nb1, L1 - P1) & String$(PS2 - PS1, Z)
Nb2 = Nb2Prov & Right$(Nb2, L2 - P2) & String$(PS1 - PS2, Z)
End If
'Retrouve les bonnes longueurs
L1 = Len(Nb1): L2 = Len(Nb2)
'Le maxi
Dim Lmax As Long
Lmax = L1
If L1 < L2 Then Lmax = L2
'Comparaison
CompGN = Inverse * StrComp(String$(Lmax - L1, Z) & Nb1, String$(Lmax - L2, Z) & Nb2)
End Function
'=========================
Function MinGN(ByVal Nb1 As String, ByVal Nb2 As String) As String
'Renvoi le nb mini
If CompGN(Nb1, Nb2) = -1 Then
MinGN = Nb1
Else
MinGN = Nb2
End If
End Function
'=========================
Function MaxGN(ByVal Nb1 As String, ByVal Nb2 As String) As String
'Renvoi le nb maxi
If CompGN(Nb1, Nb2) = 1 Then
MaxGN = Nb1
Else
MaxGN = Nb2
End If
End Function
'=========================
Function ArrondiGN(ByVal nb As String, Optional ByVal Pos As Variant = 16) As String
'ARRONDI(nombre;no_chiffres)
'Equivalent à ARRONDI d'Excel
'supprime les zeros inutiles
nb = ZeroGN(nb)
'Recherche emplacement de la virgule
Dim P As Long
P = InStr(1, nb, ",") + InStr(1, nb, ".")
'Si entier alors rajoute une virgule
If P = 0 Then P = Len(nb) + 1: nb = nb & ",0"
'vérifie que partie entière assez long
If -Pos >= P Then ArrondiGN = "0": Exit Function
'transforme en nb sans virgule
If P > 0 Then nb = Left$(nb, P - 1) & Right$(nb, Len(nb) - P)
'dernier chiffre à retenir pour arrondi
Dim C As Long, a As String
C = Val(Mid$(nb, P + Pos, 1))
a = Str$(SgnGN(nb))
'coupe nb
nb = Left$(nb, P + Pos - 1)
'arrondi
If C >= 5 Then
Dim ZeroDeb As String 'traite le cas du zero devant qui sera supprimé par AGN
ZeroDeb = Left$(nb, 1)
nb = AGN(nb, a)
If ZeroDeb = "0" Then nb = "0" & nb
End If
'reconstruit le nb
If Len(nb) >= P Then
ArrondiGN = Left$(nb, P - 1) & "," & Right$(nb, Len(nb) - P + 1)
Else
Dim enplus As Long
enplus = 0
If -Pos = P - 1 And SgnGN(nb) = 1 Then enplus = 1
If -Pos = P - 2 And SgnGN(nb) = -1 Then enplus = 1
ArrondiGN = nb & String$(P - Len(nb) - 1 + enplus, "0")
End If
'supprime les zeros inutiles
ArrondiGN = ZeroGN(ArrondiGN)
End Function
'=========================
Function RndGN(Optional ByVal Deci As Variant = 16) As String
'Equivalent à Rnd + Randomize : renvoi nb dans [0;1[
'Traitement option
Deci = CLng(Deci)
'Initialisation série
Randomize Timer
'Déclaration
Dim bfin As Long, T As Long, NbRnd As String, base As Double, nb As String
base = 10 ^ 15
'Complète par série de 15 chiffres entiers aléatoires
bfin = Deci \ 15
NbRnd = Space$((bfin + 1) * 15)
'Fabrique le nb
For T = 0 To bfin
nb = Trim$(Str$(Int(Rnd * base)))
Mid$(NbRnd, T * 15 + 1, 15) = String$(15 - Len(nb), "0") & nb
Next T
RndGN = "0," & NbRnd
'Arrondi à Deci et met en forme
RndGN = ZeroGN(ArrondiGN(RndGN, Deci))
End Function
'=========================
Function RndBorneGN(ByVal Borne1 As String, Borne2 As String, Optional ByVal Deci As Variant = 16) As String
'Renvoi un nb décimal entre deux bornes
'Traitement option
Deci = CLng(Deci)
'Fabrique un nb : RNDGN()*(b-a)+a
RndBorneGN = ArrondiGN(AGN(PGN(AGN(Borne2, InverseGN(Borne1)), RndGN(Deci + Len(Borne1) + Len(Borne2))), Borne1), Deci)
End Function
'=========================
Function InverseGN(ByVal nb As String) As String
'Inverse le signe d'un nb
If Left$(nb, 1) = "-" Then
InverseGN = AbsGN(nb)
Exit Function
Else
InverseGN = "-" & nb
End If
End Function |
Partager