Accueil > > > BIGINT! UNE STRUCTURE POUR SURCHARGER LES ENTIERS (LONG) SANS LIMITE DE TAILLE. SURCHARGE DES OPÉRATIONS ET COMPARAISONS DE BASE
BIGINT! UNE STRUCTURE POUR SURCHARGER LES ENTIERS (LONG) SANS LIMITE DE TAILLE. SURCHARGE DES OPÉRATIONS ET COMPARAISONS DE BASE
Information sur la source
Description
Plus de risque de OverFlow avec cette classe, vous pouvez enfin calculer 350! (factorielle 350, le résultat fais 741 chiffres, en moins de 2 secondes) les opérations + - * / ainsi que les comparaisons = <> > < ... et la puissance sont déjà disponibles. On peut également multiplier un BigInt par un Long ou autre type de base (simple mais il fallait l'implémenter aussi) Cerise sur le gateau: j'ai joint au zip la classe complexe modifiée pour utiliser des BigInt en partie réelle et partie imaginaire! les complexes décomplexés, sans limite de taille (mais aussi sans décimale du coup...)
Source
- Public Structure BigInt
- Implements IComparable, IEquatable(Of BigInt), IEquatable(Of Long), IComparable(Of Long), IComparable(Of BigInt)
-
- Private mNumber As String ' nombre SANS le signe
- Private mSign As Int16 ' -1 0 ou 1
- Private mLength As Int16 ' longueur avec le signe (si négatif)
- Private Const BASE_NOMBRE As Int16 = 10
-
-
- #Region "Constructeurs"
-
- ''' <summary>
- ''' constructeurs de BigInt à partir d'un String, ou bien Long, ou bien Double (3 surcharges)
- ''' </summary>
- ''' <param name="initVal">valeur initiale (nombre et un signe - facultatif)</param>
- Public Sub New(ByVal initVal As String)
- ' signe
- If initVal.Substring(0, 1) = "-" Then mSign = -1 ' négatif
- mNumber = ""
- For i As Int16 = 0 To initVal.Length - 1
- If IsNumeric(initVal(i)) Then
- mNumber = mNumber & initVal(i)
- ElseIf i <> 0 Or initVal(i) <> "-" Then
- Throw New System.Exception("Ceci n'est pas un chiffre correctement identifié! 1 seul séparateur décimal (.) 1 signe (-) au début, le reste n'est que des chiffres")
- End If
- Next
- While mNumber <> "" AndAlso mNumber(0) = "0" ' supprimer les zéro redondants
- mNumber = mNumber.Remove(0, 1)
- End While
- If mNumber = "" Then
- mNumber = 0
- mSign = 0
- Else
- mLength = mNumber.Length
- If mSign <> -1 Then mSign = 1 Else mLength += 1
- End If
- End Sub
-
- Public Sub New(ByVal initVal As Long)
- mSign = Math.Sign(initVal)
- mNumber = CType(Math.Abs(initVal), String)
- mLength = mNumber.Length
- End Sub
-
- Public Sub New(ByVal initVal As Double)
- mSign = Math.Sign(initVal)
- mNumber = CType(Math.Abs(Int(initVal)), String)
- mLength = mNumber.Length
- End Sub
-
- Public Sub New(ByVal initVal As Decimal)
- mSign = Math.Sign(initVal)
- mNumber = CType(Math.Abs(initVal), String)
- mLength = mNumber.Length
- End Sub
-
- Public Shared ReadOnly Empty As BigInt = New BigInt("0")
-
- #End Region
-
- #Region "Surcharge des opérateurs + - * / "
-
- #Region "Opérateurs Principaux (BigInt, BigInt) + - * / "
- ''' <summary>
- ''' surcharge principale des opérateurs habituels + - * / avec 2 nombres BigInt
- ''' </summary>
- ''' <param name="A">1er opérande BigInt</param>
- ''' <param name="B">2eme opérande BigInt</param>
- ''' <returns>somme / soustraction / multiplication / division entière</returns>
- ''' <remarks>la division est entière</remarks>
- Public Shared Operator +(ByVal A As BigInt, ByVal B As BigInt) As BigInt
- ' cas triviaux:
- If A.Sign = 0 Then
- Return B
- ElseIf B.Sign = 0 Then
- Return A
- ElseIf A.Sign <> B.Sign Then ' soustraction
- Return A - B
- End If
-
- ' plus grande longueur+1 pour la retenue
- Dim longChiffre As Long = IIf(A.Length > B.Length, A.Length, B.Length)
- Dim arrAddTable(longChiffre, 2) As Long
- Dim lLength As Long
- Dim lresult As String = ""
-
- ' remplir les 2 tableaux d'entrée
- lLength = A.Abs.Length
- For i As Integer = 0 To lLength - 1
- arrAddTable(i, 0) = Val(A.Abs(lLength - i - 1))
- Next
- lLength = B.Abs.Length
- For i As Integer = 0 To lLength - 1
- arrAddTable(i, 1) = Val(B.Abs(lLength - i - 1))
- Next
-
- For i As Integer = 0 To longChiffre
- arrAddTable(i, 2) += arrAddTable(i, 0) + arrAddTable(i, 1)
- If arrAddTable(i, 2) >= BASE_NOMBRE Then ' retenue
- ' j'enlève 10 et je retiens 1
- arrAddTable(i + 1, 2) += 1
- arrAddTable(i, 2) = arrAddTable(i, 2) - BASE_NOMBRE
- End If
- lresult = arrAddTable(i, 2) & lresult
- Next
-
- If B.Sign = -1 Then ' A<0 aussi: -(A+B)
- Return -New BigInt(lresult)
- Else
- Return New BigInt(lresult)
- End If
- End Operator
-
- Public Shared Operator -(ByVal A As BigInt, ByVal B As BigInt) As BigInt ' A-B
- ' cas triviaux: écartés, pour se ramener à A-B avec A>0 et B>0
- If A.Sign = 0 Then
- Return -B
- ElseIf B.Sign = 0 Then
- Return A
- ElseIf A.Sign <> B.Sign Then ' addition!
- If A.Sign = 1 Then Return A + (-B) Else Return (-A) + B
- ElseIf B.Sign = -1 Then ' A>0, B<0
- Return A + B
- ElseIf A < B Then
- Return -(B - A) ' = A-B
- End If
-
- ' longueur du résultat
- Dim longChiffre As Long = IIf(A.Length > B.Length, A.Length, B.Length)
- Dim arrSousTable(longChiffre, 2) As Long
- Dim lLength As Long
- Dim lresult As String = ""
-
- lLength = A.Length
- For i As Integer = 0 To lLength - 1
- arrSousTable(i, 0) = Val(A.Abs(lLength - i - 1))
- Next
- lLength = B.Length
- For i As Integer = 0 To lLength - 1
- arrSousTable(i, 1) = Val(B.Abs(lLength - i - 1))
- Next
-
- For i As Integer = 0 To (longChiffre - 1)
- If arrSousTable(i, 0) < arrSousTable(i, 1) Then
- 'trop petite quantité! j'ajoute 10 et j'enlèverais 1 unité au prochain tour
- arrSousTable(i, 0) += BASE_NOMBRE
- arrSousTable(i + 1, 1) += 1
- End If
- arrSousTable(i, 2) = arrSousTable(i, 0) - arrSousTable(i, 1)
- lresult = arrSousTable(i, 2) & lresult
- Next
-
- Return New BigInt(lresult)
- End Operator
-
- 'Multiplication (TODO : algorithme de KARATSUBA? )
- Public Shared Operator *(ByVal A As BigInt, ByVal B As BigInt) As BigInt
- Dim result As String = "", BigIntResultat As New BigInt(0)
- Dim lLength As Int16, strTemp(BASE_NOMBRE) As String, lngNumber As Int16
-
- If A.Sign = 0 OrElse B.Sign = 0 Then Return New BigInt("0")
-
- ' boucle sur les chiffres de B pour multiplier A
- lLength = B.Abs.Length
- For i As Integer = lLength - 1 To 0 Step -1
- lngNumber = Val(B.Abs(i))
- If lngNumber <> 0 Then
- ' enregistrer dans un tableau les calculs intermédiaires
- If strTemp(lngNumber) Is Nothing Then strTemp(lngNumber) = (A * lngNumber).Value
- BigIntResultat += New BigInt(strTemp(lngNumber) & "".PadRight(lLength - i - 1, "0"))
- End If
- Next
-
- If A.Sign = B.Sign Then
- Return BigIntResultat
- Else
- Return -BigIntResultat
- End If
- End Operator
-
- ' division : A = dividende, B = diviseur
- Public Shared Operator /(ByVal A As BigInt, ByVal B As BigInt) As BigInt
-
- If A.Sign = 0 Then
- Return New BigInt("0")
- ElseIf B.Sign = 0 Then
- Throw New Exception("Erreur! Division par 0")
- End If
-
- Dim N As Short = B.Abs.Length
- Dim biMinor As New BigInt(B.Abs), biReste As New BigInt(A.Abs)
- Dim i As Long, lResult As String = ""
-
- Do Until biMinor > A ' recherche du plus grand multiple de B*10 minorant A
- ' multiplication par 10 = décalage d'une unité, ajouter un 0 à droite
- N = N + 1
- biMinor = New BigInt(B.Abs.PadRight(N, "0")) ' B x BASE ^ N
- Loop
-
- N = N - 1
-
- For k As Long = 0 To N - B.Abs.Length
- ' décalage à gauche pour le diviseur
- biMinor = New BigInt(biMinor.Abs.Remove(N - k, 1))
- For i = 0 To BASE_NOMBRE - 1
- If (i + 1) * biMinor > biReste Then Exit For
- Next i
- ' i => ajouté au résultat
- lResult = lResult & i.ToString
- ' calcul du reste
- biReste = biReste - i * biMinor
-
- Next k
-
- If A.Sign = B.Sign Then
- Return New BigInt(lResult)
- Else
- Return New BigInt("-" & lResult)
- End If
-
- End Operator
-
- #End Region
-
- #Region "Surcharge autres opérateurs - négation, Puissance(BigInt ^Long), modulo"
-
- ''' <summary>
- ''' A puissance B (soyons raisonable, dans A ^ B le B ne sera pas un BigInt!)
- ''' </summary>
- ''' <param name="A">BigInt</param>
- ''' <param name="B">Long</param>
- ''' <returns>A ^ B BigInt</returns>
- Public Shared Operator ^(ByVal A As BigInt, ByVal B As Long) As BigInt
- Dim biTmp As New BigInt(1)
-
- If B = 0 Then
- Return New BigInt(1)
- ElseIf B = 1 Then
- Return A
- ElseIf B < 0 Then ' le résultat ne sera pas un entier /!\
- Return New BigInt(0)
- Else
- Do ' calcul des puissances par mod 2
- If B And 1 Then biTmp = biTmp * A
- B = B \ 2
- A = A * A
- Loop While B > 1
-
- Return biTmp * A
- End If
- End Operator
-
- ''' <summary>
- ''' opérateur négation unaire
- ''' </summary>
- ''' <param name="nbr1">BigInt à inverser</param>
- ''' <returns>- nbr1</returns>
- Public Shared Operator -(ByVal nbr1 As BigInt) As BigInt
- nbr1.Sign = -nbr1.Sign
- Return nbr1
- End Operator
-
- ''' <summary>
- ''' Modulo : reste de la division entière A / B
- ''' </summary>
- ''' <param name="A">BigInt</param>
- ''' <param name="B">BigInt</param>
- ''' <returns>reste de A/B</returns>
- Public Shared Operator Mod(ByVal A As BigInt, ByVal B As BigInt) As BigInt
- If A.Sign = 0 Then
- Return New BigInt("0")
- ElseIf B.Sign = 0 Then
- Throw New Exception("Erreur! Division par 0")
- End If
-
- Dim N As Short = B.Abs.Length
- Dim biMinor As New BigInt(B.Abs), biReste As New BigInt(A.Abs)
- Dim i As Long, lResult As String = ""
-
- Do Until biMinor > A ' recherche du plus grand multiple de B*10 minorant A
- ' multiplication par 10 = décalage d'une unité, ajouter un 0 à droite
- N = N + 1
- biMinor = New BigInt(B.Abs.PadRight(N, "0")) ' B x BASE ^ N
- Loop
-
- N = N - 1
- For k As Long = 0 To N - B.Abs.Length
- ' décalage à gauche pour le diviseur
- biMinor = New BigInt(biMinor.Abs.Remove(N - k, 1))
- For i = 0 To BASE_NOMBRE - 1
- If (i + 1) * biMinor > biReste Then Exit For
- Next i
- ' i => ajouté au résultat
- lResult = lResult & i.ToString
- ' calcul du reste
- biReste = biReste - i * biMinor
-
- Next k
-
- If A.Sign = B.Sign Then
- Return biReste
- Else
- Return -biReste
- End If
- End Operator
-
- ''' <summary>
- ''' Multiplication (BigInt * Long)
- ''' </summary>
- ''' <param name="A">BigInt</param>
- ''' <param name="B">Long</param>
- ''' <returns>A * B BigInt</returns>
- ''' <remarks>plus simple que BigInt * BinInt et nécessaire pour l'opérateur *</remarks>
- Public Shared Operator *(ByVal A As BigInt, ByVal B As Long) As BigInt
- ' une petite optimisation est possible ici
- Dim lresult As String = ""
- Dim lLength As Long = A.Abs.Length
- Dim loperation As Long
- Dim lretenue As Long = 0
-
- For i As Long = lLength - 1 To 0 Step -1
- loperation = Val(A.Abs(i)) * B + lretenue
- ' retenue pour le tour suivant
- lretenue = loperation \ BASE_NOMBRE
- ' ôter le chiffre des dizaines
- loperation = loperation Mod BASE_NOMBRE
- lresult = loperation & lresult
- Next
- If lretenue <> 0 Then lresult = lretenue & lresult
- Return New BigInt(lresult)
- End Operator
-
- #End Region
-
- #End Region
-
- #Region "Surcharge des opérateurs de comparaison = <> < > <= >="
-
- ''' <summary>
- ''' égalité ( l'opérateur = implique l'opérateur <> (différent) )
- ''' </summary>
- ''' <param name="a">A BigInt</param>
- ''' <param name="b">B bigInt</param>
- ''' <returns>True si A=B, False sinon</returns>
- Public Shared Operator =(ByVal a As BigInt, ByVal b As BigInt) As Boolean
- Return a.Sign = b.Sign AndAlso a.Abs = b.Abs
- End Operator
- Public Shared Operator <>(ByVal a As BigInt, ByVal b As BigInt) As Boolean
- Return Not a = b
- End Operator
-
- ''' <summary>
- ''' opérateurs de comparaison surchargé sur 2 objets de type BigInt ( > < >= <= )
- ''' </summary>
- ''' <param name="a">BigInt</param>
- ''' <param name="b">BigInt</param>
- ''' <returns>True ou False selon la comparaison de A et B</returns>
- ''' <remarks>Seul l'opérateur > est 'calculé', les autres sont déduit de celui ci.</remarks>
- Public Shared Operator >(ByVal a As BigInt, ByVal b As BigInt) As Boolean
- If a.Sign <> b.Sign Then
- Return a.Sign > b.Sign
- ElseIf a.Length <> b.Length Then ' a et b de même signe, comparer leur longueur
- Return a.Length > b.Length ' le + long est le + grand
- Else
- Return a.Abs > b.Abs
- End If
- End Operator
- Public Shared Operator <(ByVal a As BigInt, ByVal b As BigInt) As Boolean
- Return Not (a > b OrElse a = b)
- End Operator
- Public Shared Operator >=(ByVal a As BigInt, ByVal b As BigInt) As Boolean
- Return a > b OrElse a = b
- End Operator
- Public Shared Operator <=(ByVal a As BigInt, ByVal b As BigInt) As Boolean
- Return Not a > b
- End Operator
-
- #End Region
-
- #Region "Propriétés usuelles"
- ''' <summary>
- ''' calcul par itérations de la racine carrée.
- ''' </summary>
- ''' <param name="P">BigInt</param>
- ''' <returns>BigInt</returns>
- ''' <remarks>le résultat est une valeur approchée entière BigInt</remarks>
- Public Function Sqr(Optional ByVal P As Double = 1) As BigInt
- ' racine carrée, algo par itérations
- Dim X, Y As BigInt
-
- Y = (Me + 1) / 2
- X = Me / Y
- Do While Y - X > P
- Y = (X + Y) / 2
- X = Me / Y
- Loop
- Return (X + Y) / 2
- End Function
-
- ''' <summary>
- ''' Valeur du BigInt, c.à.d sa représentatino littérale
- ''' </summary>
- ''' <remarks>concaténation du signe (-) si besoin et du chiffre</remarks>
- Public ReadOnly Property Value() As String
- Get
- Select Case Me.mSign
- Case 1
- Return Me.mNumber
- Case -1
- Return "-" & mNumber
- Case Else
- Return "0"
- End Select
- End Get
- End Property
-
- ''' <summary>
- ''' Longueur du nombre
- ''' </summary>
- ''' <value></value>
- ''' <returns></returns>
- ''' <remarks>nombre de chiffres +1 si négatif</remarks>
- Public ReadOnly Property Length() As Int16
- Get
- Return mLength
- End Get
- End Property
-
- ''' <summary>
- ''' signe du nombre -1 si <0, +1 si >0, 0 si =0
- ''' </summary>
- ''' <value></value>
- ''' <returns></returns>
- ''' <remarks>propriété lecture/écriture: on peut inverser un nombre par ce moyen</remarks>
- Public Property Sign() As Int16
- Get
- Return mSign
- End Get
- ' on peut changer de signe simplement
- Set(ByVal value As Int16)
- If value = 1 Or value = -1 Then mSign = value
- End Set
- End Property
-
- ''' <summary>
- ''' Valeur absolue du nombre
- ''' </summary>
- ''' <value></value>
- ''' <returns></returns>
- Public ReadOnly Property Abs() As String
- Get
- Return mNumber
- End Get
- End Property
-
- ''' <summary>
- ''' exposant de 10 (base) = simple décalage, on ajoute ou supprime des zéros
- ''' </summary>
- ''' <param name="exposant">nombre de puissances de 10 à ajouter/supprimer</param>
- ''' <value></value>
- ''' <returns>Me * 10^exposant</returns>
- Public ReadOnly Property Exp(ByVal exposant As Long) As BigInt
- Get
- If exposant > 0 Then ' ajouter n zéros
- If Me.Sign > 0 Then
- Return New BigInt(Me.Abs.PadRight(Me.Length + exposant, "0"))
- ElseIf Me.Sign < 0 Then
- Return -New BigInt(Me.Abs.PadRight(Me.Abs.Length + exposant, "0"))
- Else
- Return New BigInt(0)
- End If
- ElseIf exposant < 0 Then ' supprimer des zéros (ou pas) = arrondi /!\
- If Me.Abs.Length > -exposant Then
- If Me.Sign > 0 Then
- Return New BigInt(Me.Abs.Remove(Me.Length + exposant, -exposant))
- ElseIf Me.Sign < 0 Then
- Return -New BigInt(Me.Abs.Remove(Me.Abs.Length + exposant, -exposant))
- Else
- Return New BigInt(0)
- End If
- Else
- Return New BigInt(0)
- End If
- Else
- Return Me
- End If
- End Get
- End Property
-
- ''' <summary>
- ''' surcharges pour l'implémentation de l'interface IComparable
- ''' </summary>
- ''' <param name="other"></param>
- ''' <returns></returns>
- ''' <remarks>surcharges sur Object, Long, BigInt</remarks>
- Public Overloads Function CompareTo(ByVal other As Object) As Integer Implements IComparable.CompareTo
- If TypeOf other Is Long Then
- Return Me.CompareTo(New BigInt(CType(other, Long)))
- ElseIf TypeOf other Is Integer Then
- Return Me.CompareTo(New BigInt(CType(other, Integer)))
- ElseIf TypeOf other Is BigInt Then
- Return Me.CompareTo(CType(other, BigInt))
- End If
-
- Throw New ArgumentException("Impossible de convertir l'objet en BigInt")
- End Function
- Public Overloads Function CompareTo(ByVal other As Long) As Integer Implements IComparable(Of Long).CompareTo
- Return Me.CompareTo(New BigInt(other))
- End Function
- Public Overloads Function CompareTo(ByVal other As BigInt) As Integer Implements IComparable(Of BigInt).CompareTo
- If other = Me Then
- Return 0
- ElseIf other < Me Then
- Return -1
- Else
- Return 1
- End If
- End Function
-
- ''' <summary>
- ''' Surcharges pour l'implémentation de l'interface IEquatable
- ''' </summary>
- ''' <param name="other"></param>
- ''' <returns></returns>
- ''' <remarks>surcharges sur Long, BigInt</remarks>
- Public Overloads Function EqualsTo(ByVal other As BigInt) As Boolean Implements IEquatable(Of BigInt).Equals
- Return other.Sign = Me.Sign AndAlso other.Abs = Me.Abs
- End Function
- Public Overloads Function EqualsTo(ByVal other As Long) As Boolean Implements IEquatable(Of Long).Equals
- Dim a As New BigInt(other)
- Return a.Sign = Me.Sign AndAlso a.Abs = Me.Abs
- End Function
-
- #End Region
-
- #Region "Conversions explicites et implicites"
-
- ''' <summary>
- ''' conversion implicite, Long ou Double ou String => BigInt, automatique et sans perte de données
- ''' </summary>
- ''' <param name="a"></param>
- ''' <returns></returns>
- Public Shared Widening Operator CType(ByVal a As Long) As BigInt
- Return New BigInt(a)
- End Operator
- ' conversion implicite, Double => BigInt, automatique et sans perte de données
- Public Shared Widening Operator CType(ByVal a As Double) As BigInt
- Return New BigInt(a)
- End Operator
- ' conversion implicite String => BigInt !
- Public Shared Widening Operator CType(ByVal a As String) As BigInt
- Return New BigInt(a)
- End Operator
-
- ''' <summary>
- ''' conversion implicite BigInt => String
- ''' </summary>
- ''' <param name="c"></param>
- ''' <returns></returns>
- Public Shared Widening Operator CType(ByVal c As BigInt) As String
- Return c.Value
- End Operator
-
- #End Region
-
- End Structure
Public Structure BigInt
Implements IComparable, IEquatable(Of BigInt), IEquatable(Of Long), IComparable(Of Long), IComparable(Of BigInt)
Private mNumber As String ' nombre SANS le signe
Private mSign As Int16 ' -1 0 ou 1
Private mLength As Int16 ' longueur avec le signe (si négatif)
Private Const BASE_NOMBRE As Int16 = 10
#Region "Constructeurs"
''' <summary>
''' constructeurs de BigInt à partir d'un String, ou bien Long, ou bien Double (3 surcharges)
''' </summary>
''' <param name="initVal">valeur initiale (nombre et un signe - facultatif)</param>
Public Sub New(ByVal initVal As String)
' signe
If initVal.Substring(0, 1) = "-" Then mSign = -1 ' négatif
mNumber = ""
For i As Int16 = 0 To initVal.Length - 1
If IsNumeric(initVal(i)) Then
mNumber = mNumber & initVal(i)
ElseIf i <> 0 Or initVal(i) <> "-" Then
Throw New System.Exception("Ceci n'est pas un chiffre correctement identifié! 1 seul séparateur décimal (.) 1 signe (-) au début, le reste n'est que des chiffres")
End If
Next
While mNumber <> "" AndAlso mNumber(0) = "0" ' supprimer les zéro redondants
mNumber = mNumber.Remove(0, 1)
End While
If mNumber = "" Then
mNumber = 0
mSign = 0
Else
mLength = mNumber.Length
If mSign <> -1 Then mSign = 1 Else mLength += 1
End If
End Sub
Public Sub New(ByVal initVal As Long)
mSign = Math.Sign(initVal)
mNumber = CType(Math.Abs(initVal), String)
mLength = mNumber.Length
End Sub
Public Sub New(ByVal initVal As Double)
mSign = Math.Sign(initVal)
mNumber = CType(Math.Abs(Int(initVal)), String)
mLength = mNumber.Length
End Sub
Public Sub New(ByVal initVal As Decimal)
mSign = Math.Sign(initVal)
mNumber = CType(Math.Abs(initVal), String)
mLength = mNumber.Length
End Sub
Public Shared ReadOnly Empty As BigInt = New BigInt("0")
#End Region
#Region "Surcharge des opérateurs + - * / "
#Region "Opérateurs Principaux (BigInt, BigInt) + - * / "
''' <summary>
''' surcharge principale des opérateurs habituels + - * / avec 2 nombres BigInt
''' </summary>
''' <param name="A">1er opérande BigInt</param>
''' <param name="B">2eme opérande BigInt</param>
''' <returns>somme / soustraction / multiplication / division entière</returns>
''' <remarks>la division est entière</remarks>
Public Shared Operator +(ByVal A As BigInt, ByVal B As BigInt) As BigInt
' cas triviaux:
If A.Sign = 0 Then
Return B
ElseIf B.Sign = 0 Then
Return A
ElseIf A.Sign <> B.Sign Then ' soustraction
Return A - B
End If
' plus grande longueur+1 pour la retenue
Dim longChiffre As Long = IIf(A.Length > B.Length, A.Length, B.Length)
Dim arrAddTable(longChiffre, 2) As Long
Dim lLength As Long
Dim lresult As String = ""
' remplir les 2 tableaux d'entrée
lLength = A.Abs.Length
For i As Integer = 0 To lLength - 1
arrAddTable(i, 0) = Val(A.Abs(lLength - i - 1))
Next
lLength = B.Abs.Length
For i As Integer = 0 To lLength - 1
arrAddTable(i, 1) = Val(B.Abs(lLength - i - 1))
Next
For i As Integer = 0 To longChiffre
arrAddTable(i, 2) += arrAddTable(i, 0) + arrAddTable(i, 1)
If arrAddTable(i, 2) >= BASE_NOMBRE Then ' retenue
' j'enlève 10 et je retiens 1
arrAddTable(i + 1, 2) += 1
arrAddTable(i, 2) = arrAddTable(i, 2) - BASE_NOMBRE
End If
lresult = arrAddTable(i, 2) & lresult
Next
If B.Sign = -1 Then ' A<0 aussi: -(A+B)
Return -New BigInt(lresult)
Else
Return New BigInt(lresult)
End If
End Operator
Public Shared Operator -(ByVal A As BigInt, ByVal B As BigInt) As BigInt ' A-B
' cas triviaux: écartés, pour se ramener à A-B avec A>0 et B>0
If A.Sign = 0 Then
Return -B
ElseIf B.Sign = 0 Then
Return A
ElseIf A.Sign <> B.Sign Then ' addition!
If A.Sign = 1 Then Return A + (-B) Else Return (-A) + B
ElseIf B.Sign = -1 Then ' A>0, B<0
Return A + B
ElseIf A < B Then
Return -(B - A) ' = A-B
End If
' longueur du résultat
Dim longChiffre As Long = IIf(A.Length > B.Length, A.Length, B.Length)
Dim arrSousTable(longChiffre, 2) As Long
Dim lLength As Long
Dim lresult As String = ""
lLength = A.Length
For i As Integer = 0 To lLength - 1
arrSousTable(i, 0) = Val(A.Abs(lLength - i - 1))
Next
lLength = B.Length
For i As Integer = 0 To lLength - 1
arrSousTable(i, 1) = Val(B.Abs(lLength - i - 1))
Next
For i As Integer = 0 To (longChiffre - 1)
If arrSousTable(i, 0) < arrSousTable(i, 1) Then
'trop petite quantité! j'ajoute 10 et j'enlèverais 1 unité au prochain tour
arrSousTable(i, 0) += BASE_NOMBRE
arrSousTable(i + 1, 1) += 1
End If
arrSousTable(i, 2) = arrSousTable(i, 0) - arrSousTable(i, 1)
lresult = arrSousTable(i, 2) & lresult
Next
Return New BigInt(lresult)
End Operator
'Multiplication (TODO : algorithme de KARATSUBA? )
Public Shared Operator *(ByVal A As BigInt, ByVal B As BigInt) As BigInt
Dim result As String = "", BigIntResultat As New BigInt(0)
Dim lLength As Int16, strTemp(BASE_NOMBRE) As String, lngNumber As Int16
If A.Sign = 0 OrElse B.Sign = 0 Then Return New BigInt("0")
' boucle sur les chiffres de B pour multiplier A
lLength = B.Abs.Length
For i As Integer = lLength - 1 To 0 Step -1
lngNumber = Val(B.Abs(i))
If lngNumber <> 0 Then
' enregistrer dans un tableau les calculs intermédiaires
If strTemp(lngNumber) Is Nothing Then strTemp(lngNumber) = (A * lngNumber).Value
BigIntResultat += New BigInt(strTemp(lngNumber) & "".PadRight(lLength - i - 1, "0"))
End If
Next
If A.Sign = B.Sign Then
Return BigIntResultat
Else
Return -BigIntResultat
End If
End Operator
' division : A = dividende, B = diviseur
Public Shared Operator /(ByVal A As BigInt, ByVal B As BigInt) As BigInt
If A.Sign = 0 Then
Return New BigInt("0")
ElseIf B.Sign = 0 Then
Throw New Exception("Erreur! Division par 0")
End If
Dim N As Short = B.Abs.Length
Dim biMinor As New BigInt(B.Abs), biReste As New BigInt(A.Abs)
Dim i As Long, lResult As String = ""
Do Until biMinor > A ' recherche du plus grand multiple de B*10 minorant A
' multiplication par 10 = décalage d'une unité, ajouter un 0 à droite
N = N + 1
biMinor = New BigInt(B.Abs.PadRight(N, "0")) ' B x BASE ^ N
Loop
N = N - 1
For k As Long = 0 To N - B.Abs.Length
' décalage à gauche pour le diviseur
biMinor = New BigInt(biMinor.Abs.Remove(N - k, 1))
For i = 0 To BASE_NOMBRE - 1
If (i + 1) * biMinor > biReste Then Exit For
Next i
' i => ajouté au résultat
lResult = lResult & i.ToString
' calcul du reste
biReste = biReste - i * biMinor
Next k
If A.Sign = B.Sign Then
Return New BigInt(lResult)
Else
Return New BigInt("-" & lResult)
End If
End Operator
#End Region
#Region "Surcharge autres opérateurs - négation, Puissance(BigInt ^Long), modulo"
''' <summary>
''' A puissance B (soyons raisonable, dans A ^ B le B ne sera pas un BigInt!)
''' </summary>
''' <param name="A">BigInt</param>
''' <param name="B">Long</param>
''' <returns>A ^ B BigInt</returns>
Public Shared Operator ^(ByVal A As BigInt, ByVal B As Long) As BigInt
Dim biTmp As New BigInt(1)
If B = 0 Then
Return New BigInt(1)
ElseIf B = 1 Then
Return A
ElseIf B < 0 Then ' le résultat ne sera pas un entier /!\
Return New BigInt(0)
Else
Do ' calcul des puissances par mod 2
If B And 1 Then biTmp = biTmp * A
B = B \ 2
A = A * A
Loop While B > 1
Return biTmp * A
End If
End Operator
''' <summary>
''' opérateur négation unaire
''' </summary>
''' <param name="nbr1">BigInt à inverser</param>
''' <returns>- nbr1</returns>
Public Shared Operator -(ByVal nbr1 As BigInt) As BigInt
nbr1.Sign = -nbr1.Sign
Return nbr1
End Operator
''' <summary>
''' Modulo : reste de la division entière A / B
''' </summary>
''' <param name="A">BigInt</param>
''' <param name="B">BigInt</param>
''' <returns>reste de A/B</returns>
Public Shared Operator Mod(ByVal A As BigInt, ByVal B As BigInt) As BigInt
If A.Sign = 0 Then
Return New BigInt("0")
ElseIf B.Sign = 0 Then
Throw New Exception("Erreur! Division par 0")
End If
Dim N As Short = B.Abs.Length
Dim biMinor As New BigInt(B.Abs), biReste As New BigInt(A.Abs)
Dim i As Long, lResult As String = ""
Do Until biMinor > A ' recherche du plus grand multiple de B*10 minorant A
' multiplication par 10 = décalage d'une unité, ajouter un 0 à droite
N = N + 1
biMinor = New BigInt(B.Abs.PadRight(N, "0")) ' B x BASE ^ N
Loop
N = N - 1
For k As Long = 0 To N - B.Abs.Length
' décalage à gauche pour le diviseur
biMinor = New BigInt(biMinor.Abs.Remove(N - k, 1))
For i = 0 To BASE_NOMBRE - 1
If (i + 1) * biMinor > biReste Then Exit For
Next i
' i => ajouté au résultat
lResult = lResult & i.ToString
' calcul du reste
biReste = biReste - i * biMinor
Next k
If A.Sign = B.Sign Then
Return biReste
Else
Return -biReste
End If
End Operator
''' <summary>
''' Multiplication (BigInt * Long)
''' </summary>
''' <param name="A">BigInt</param>
''' <param name="B">Long</param>
''' <returns>A * B BigInt</returns>
''' <remarks>plus simple que BigInt * BinInt et nécessaire pour l'opérateur *</remarks>
Public Shared Operator *(ByVal A As BigInt, ByVal B As Long) As BigInt
' une petite optimisation est possible ici
Dim lresult As String = ""
Dim lLength As Long = A.Abs.Length
Dim loperation As Long
Dim lretenue As Long = 0
For i As Long = lLength - 1 To 0 Step -1
loperation = Val(A.Abs(i)) * B + lretenue
' retenue pour le tour suivant
lretenue = loperation \ BASE_NOMBRE
' ôter le chiffre des dizaines
loperation = loperation Mod BASE_NOMBRE
lresult = loperation & lresult
Next
If lretenue <> 0 Then lresult = lretenue & lresult
Return New BigInt(lresult)
End Operator
#End Region
#End Region
#Region "Surcharge des opérateurs de comparaison = <> < > <= >="
''' <summary>
''' égalité ( l'opérateur = implique l'opérateur <> (différent) )
''' </summary>
''' <param name="a">A BigInt</param>
''' <param name="b">B bigInt</param>
''' <returns>True si A=B, False sinon</returns>
Public Shared Operator =(ByVal a As BigInt, ByVal b As BigInt) As Boolean
Return a.Sign = b.Sign AndAlso a.Abs = b.Abs
End Operator
Public Shared Operator <>(ByVal a As BigInt, ByVal b As BigInt) As Boolean
Return Not a = b
End Operator
''' <summary>
''' opérateurs de comparaison surchargé sur 2 objets de type BigInt ( > < >= <= )
''' </summary>
''' <param name="a">BigInt</param>
''' <param name="b">BigInt</param>
''' <returns>True ou False selon la comparaison de A et B</returns>
''' <remarks>Seul l'opérateur > est 'calculé', les autres sont déduit de celui ci.</remarks>
Public Shared Operator >(ByVal a As BigInt, ByVal b As BigInt) As Boolean
If a.Sign <> b.Sign Then
Return a.Sign > b.Sign
ElseIf a.Length <> b.Length Then ' a et b de même signe, comparer leur longueur
Return a.Length > b.Length ' le + long est le + grand
Else
Return a.Abs > b.Abs
End If
End Operator
Public Shared Operator <(ByVal a As BigInt, ByVal b As BigInt) As Boolean
Return Not (a > b OrElse a = b)
End Operator
Public Shared Operator >=(ByVal a As BigInt, ByVal b As BigInt) As Boolean
Return a > b OrElse a = b
End Operator
Public Shared Operator <=(ByVal a As BigInt, ByVal b As BigInt) As Boolean
Return Not a > b
End Operator
#End Region
#Region "Propriétés usuelles"
''' <summary>
''' calcul par itérations de la racine carrée.
''' </summary>
''' <param name="P">BigInt</param>
''' <returns>BigInt</returns>
''' <remarks>le résultat est une valeur approchée entière BigInt</remarks>
Public Function Sqr(Optional ByVal P As Double = 1) As BigInt
' racine carrée, algo par itérations
Dim X, Y As BigInt
Y = (Me + 1) / 2
X = Me / Y
Do While Y - X > P
Y = (X + Y) / 2
X = Me / Y
Loop
Return (X + Y) / 2
End Function
''' <summary>
''' Valeur du BigInt, c.à.d sa représentatino littérale
''' </summary>
''' <remarks>concaténation du signe (-) si besoin et du chiffre</remarks>
Public ReadOnly Property Value() As String
Get
Select Case Me.mSign
Case 1
Return Me.mNumber
Case -1
Return "-" & mNumber
Case Else
Return "0"
End Select
End Get
End Property
''' <summary>
''' Longueur du nombre
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks>nombre de chiffres +1 si négatif</remarks>
Public ReadOnly Property Length() As Int16
Get
Return mLength
End Get
End Property
''' <summary>
''' signe du nombre -1 si <0, +1 si >0, 0 si =0
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks>propriété lecture/écriture: on peut inverser un nombre par ce moyen</remarks>
Public Property Sign() As Int16
Get
Return mSign
End Get
' on peut changer de signe simplement
Set(ByVal value As Int16)
If value = 1 Or value = -1 Then mSign = value
End Set
End Property
''' <summary>
''' Valeur absolue du nombre
''' </summary>
''' <value></value>
''' <returns></returns>
Public ReadOnly Property Abs() As String
Get
Return mNumber
End Get
End Property
''' <summary>
''' exposant de 10 (base) = simple décalage, on ajoute ou supprime des zéros
''' </summary>
''' <param name="exposant">nombre de puissances de 10 à ajouter/supprimer</param>
''' <value></value>
''' <returns>Me * 10^exposant</returns>
Public ReadOnly Property Exp(ByVal exposant As Long) As BigInt
Get
If exposant > 0 Then ' ajouter n zéros
If Me.Sign > 0 Then
Return New BigInt(Me.Abs.PadRight(Me.Length + exposant, "0"))
ElseIf Me.Sign < 0 Then
Return -New BigInt(Me.Abs.PadRight(Me.Abs.Length + exposant, "0"))
Else
Return New BigInt(0)
End If
ElseIf exposant < 0 Then ' supprimer des zéros (ou pas) = arrondi /!\
If Me.Abs.Length > -exposant Then
If Me.Sign > 0 Then
Return New BigInt(Me.Abs.Remove(Me.Length + exposant, -exposant))
ElseIf Me.Sign < 0 Then
Return -New BigInt(Me.Abs.Remove(Me.Abs.Length + exposant, -exposant))
Else
Return New BigInt(0)
End If
Else
Return New BigInt(0)
End If
Else
Return Me
End If
End Get
End Property
''' <summary>
''' surcharges pour l'implémentation de l'interface IComparable
''' </summary>
''' <param name="other"></param>
''' <returns></returns>
''' <remarks>surcharges sur Object, Long, BigInt</remarks>
Public Overloads Function CompareTo(ByVal other As Object) As Integer Implements IComparable.CompareTo
If TypeOf other Is Long Then
Return Me.CompareTo(New BigInt(CType(other, Long)))
ElseIf TypeOf other Is Integer Then
Return Me.CompareTo(New BigInt(CType(other, Integer)))
ElseIf TypeOf other Is BigInt Then
Return Me.CompareTo(CType(other, BigInt))
End If
Throw New ArgumentException("Impossible de convertir l'objet en BigInt")
End Function
Public Overloads Function CompareTo(ByVal other As Long) As Integer Implements IComparable(Of Long).CompareTo
Return Me.CompareTo(New BigInt(other))
End Function
Public Overloads Function CompareTo(ByVal other As BigInt) As Integer Implements IComparable(Of BigInt).CompareTo
If other = Me Then
Return 0
ElseIf other < Me Then
Return -1
Else
Return 1
End If
End Function
''' <summary>
''' Surcharges pour l'implémentation de l'interface IEquatable
''' </summary>
''' <param name="other"></param>
''' <returns></returns>
''' <remarks>surcharges sur Long, BigInt</remarks>
Public Overloads Function EqualsTo(ByVal other As BigInt) As Boolean Implements IEquatable(Of BigInt).Equals
Return other.Sign = Me.Sign AndAlso other.Abs = Me.Abs
End Function
Public Overloads Function EqualsTo(ByVal other As Long) As Boolean Implements IEquatable(Of Long).Equals
Dim a As New BigInt(other)
Return a.Sign = Me.Sign AndAlso a.Abs = Me.Abs
End Function
#End Region
#Region "Conversions explicites et implicites"
''' <summary>
''' conversion implicite, Long ou Double ou String => BigInt, automatique et sans perte de données
''' </summary>
''' <param name="a"></param>
''' <returns></returns>
Public Shared Widening Operator CType(ByVal a As Long) As BigInt
Return New BigInt(a)
End Operator
' conversion implicite, Double => BigInt, automatique et sans perte de données
Public Shared Widening Operator CType(ByVal a As Double) As BigInt
Return New BigInt(a)
End Operator
' conversion implicite String => BigInt !
Public Shared Widening Operator CType(ByVal a As String) As BigInt
Return New BigInt(a)
End Operator
''' <summary>
''' conversion implicite BigInt => String
''' </summary>
''' <param name="c"></param>
''' <returns></returns>
Public Shared Widening Operator CType(ByVal c As BigInt) As String
Return c.Value
End Operator
#End Region
End Structure
Conclusion
J'ai pas cherché à pousser plus loin les performances pour l'instant. J'ai sous la main un algo pour calculer les puissances plus optimisé, je dois aussi rechercher du coté des génériques pour m'éviter tant de surcharge (c'est lourd la surcharge) mais en attendant d'avoir le temps je poste déjà ce résultat. Il faudra implémenter le modulo également.
Et plus tard j'espère construire une classe "BigNum" qui sera les nombres réels sans limite, en utilisant celle ci: simple, un BigNum c'est un BigInt et son exposant (entier, disons Long) en puissance de 10.
ps: j'ai purgé le ZIP des sous-répertoires bin et obj (à priori inutiles)
Historique
- 30 mars 2007 17:49:22 :
- épuration du zip. optimisation de la procédure de puissance.
J'ai laissé uniquement les surcharges des opérateurs ici pour l'exemple, le reste (déclarations, constructeurs, exemples...) est dans le zip.
De plus j'ai épuré le ZIP (suppression des rep inutiles, bin et obj).
- 10 avril 2007 16:00:57 :
- ajout des interfaces IEquatable(), IComparable()
ajout de quelques fonctions (racine, puissance optimisée, modulo...)
et surtout: ajout des conversions implicites Ctype (qui est un opérateur!) ce qui permet d'oublier tous ces problèmes de "conversion explicite" par exemple pour additionner un BigInt avec un Integer ou un Long... maintenant c'est automatique et naturel!
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
precision dun nombre decimal [ par darwish3 ]
bonjour a tous!!!je voudrais configure la precision des nombres decimaux a 2 chiffres apres la virgule mais je n c pas comment faire en vba.si qq'un p
precision du nombre decimal en vba [ par darwish3 ]
bonjour a tous!!!je voudrais configure la precision des nombres decimaux a 2 chiffres apres la virgule mais je n c pas comment faire en vba.si qq'un p
Selection d'un nombre dans un textbox [ par pericles0 ]
Bonsoir à tous !Je cherche à extraire nombre dans un textbox, qui contient des lettres, des nombres, ou les deux acollés (ex: Q403). Comment faire pou
Expression régulière [ par tabarrant ]
Bonjour,Voila j'ai un petit souci concernant l'expression d'un expression régulière, j'aimerais tester si une string est bien un nombre donc j'ai util
nombre cellule non vide dans une colonne [ par akmer ]
Bonjour,Quel formule permettrait de compter le nombre de cellule non vide dans la collone A de la feuille traitement?Merci d'avanceSa parrait tout bêt
Sacré Wend ! [ par OlivesGT ]
Cela fait longtemps que je parcours votre site ou j'ai trouvé plein de renseignements mais une fonction me résiste : While / Wend !Voici ce que je veu
Combobox [ par faucheuse ]
Bonjour tout le monde (osashiburi desuyo^^), J'utilise pour la premiere fois une combobox sous excel (en VBA) et je ne trouve pas comment ajouter des
Connaitre le nombre de chiffres après la virgule d'un nombre [ par Dagry ]
Bonjour à tous! je me tourne encore vers vous pour m'aider à résoudre un problème. J'aimerais savoir comment connaitre le nombre de chiffres après la
Moyenne sur un echantillon aleatoire [ par Taeris ]
Navre si la question a déjà ete posée auparavant, mais je n'ai rien réussi a trouver, étant donne la spécificité de ma demande ...Navre également pour
Structure TYPE [ par gmelapet ]
BonjourJe souhaite faire une grosse structure TYPE avec un tableau de 512 octets.Mais etant donné qu il y a beaucoup de variables, je voudrais utilise
|
Derniers Blogs
TECHDAYS PARIS 2010 : SHAREPOINT 2010 POUR LES DéVELOPPEURSTECHDAYS PARIS 2010 : SHAREPOINT 2010 POUR LES DéVELOPPEURS par ROMELARD Fabrice
Animé par: Laurent Cotton Le développement dans SharePoint 2010 passe par plusieurs axes qui seront évoqués dans cette session, mais plus particulièrement les développements simples lié au besoin Business Business Connectivity Services Ce BCS es...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice TECHDAYS PARIS 2010 : PLEINIèRE DERNIER JOURTECHDAYS PARIS 2010 : PLEINIèRE DERNIER JOUR par ROMELARD Fabrice
Cette session est la dernière pleinière de ces 3 jours de TechDays Paris 2010. Généralement, cette troisième journée est plus axée sur l'avenir vu par Microsoft. Après un retour sur l'avenir vu par la Science Fiction ou par ...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice UNE JOLIE-HORLOGE ET PAS QU'UN PEU !UNE JOLIE-HORLOGE ET PAS QU'UN PEU ! par neodante
Pour les possesseurs d'iPhone, ça y est Bijin Tokei - qui se traduit littéralement en Français par " Jolie Horloge " - est arrivé et GRATUITEMENT s'il vous plaît ! Après la version Tokyo, Hokkaido, night club, racing, Gal, "pour les mademoiselles'", . voi...
Cliquez pour lire la suite de l'article par neodante TECHDAYS PARIS 2010 : CONNECTEZ VOS DONNéES à SHAREPOINT 2010 AVEC LES BUSINESS CONNECTIVITY SERVICESTECHDAYS PARIS 2010 : CONNECTEZ VOS DONNéES à SHAREPOINT 2010 AVEC LES BUSINESS CONNECTIVITY SERVICES par ROMELARD Fabrice
Animé par: Gaetan Bouveret et Julien Chomarat Business Connectivity Services (BCS) est dans SharePoint 2010 la version 2 de Business Data Catalog (BDC dans SharePoint 2007). Il s'agit de la solution permettant de visualiser des données provenan...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice [DIVERS] SUIVRE VOS SéRIES PRéFéRéS SUR LA TOILE[DIVERS] SUIVRE VOS SéRIES PRéFéRéS SUR LA TOILE par orion
Comme de nombreux geek, je suis un grand amateur de série TV et je rate régulièrement des épisodes de mes séries préférés. Une solution s'offre à vous avec ce merveilleux site : Tv Gorge - www.tvgorge.com Moteur de recherche à l'appui, vous pouvez ...
Cliquez pour lire la suite de l'article par orion
Forum
RE : TAILLERE : TAILLE par Calade
Cliquez pour lire la suite par Calade
Logiciels
DB-MAIN (9.1.0)DB-MAIN (9.1.0)DB-MAIN is a data-modeling and data-architecture tool. It is designed to help developers and anal... Cliquez pour télécharger DB-MAIN Xilisoft DPG Convertisseur (5.1.37.0120)XILISOFT DPG CONVERTISSEUR (5.1.37.0120)Xilisoft DPG Convertisseur offre aux fans de Nintendo DS une bonne solution leur permettant de dé... Cliquez pour télécharger Xilisoft DPG Convertisseur GraphicsGale (2.01.01)GRAPHICSGALE (2.01.01)GraphicsGale est un logiciel de PixelArt avec de nombreuse fonctionnalités permettant de réalisé ... Cliquez pour télécharger GraphicsGale Architecte 3D (Platinum 2010)ARCHITECTE 3D (PLATINUM 2010)Architecte 3D Platinium vous permet de concevoir facilement les plans votre future maison, de l'é... Cliquez pour télécharger Architecte 3D TeamViewer 5 (TeamViewer 5)TEAMVIEWER 5 (TEAMVIEWER 5)Dépanner un ami,expliquer une manipulation devient un jeu d'enfant.
Prise en main d'un autre ord... Cliquez pour télécharger TeamViewer 5
|