VogelsNumberFormat - OOP

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
StarBootics
Addict
Addict
Posts: 823
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

VogelsNumberFormat - OOP

Post by StarBootics »

Hello erevyone,

Yep another code reviewed and augmented code from Guimauve and Michael Vogel huge number library.
The original code was found here : Huge #'s

I hope you will enjoy it as much as I do since the fully operational division is implemented.

EDIT : 1 The working code is presented at the 4th post in this topic. Sorry for the inconvenience.
EDIT : 2 For the working code look for file version 1.3.0. Sorry for the inconvenience.

Best regards
StarBootics

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : VogelsNumberFormat
; File Name : VogelsNumberFormat - OOP.pb
; File version: 1.0.0
; Programming : OK
; Programmed by : StarBootics
; Date : November 9th, 2020
; Last Update : November 14th, 2020
; PureBasic code : V5.73 beta 4
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Based on the code from Guimauve which itself is based on 
;    the original code by Michael Vogel.
;
; 2. The division algorithm is based on explanations found on 
;    this website :
;
;    http://justinparrtech.com/JustinParr-Tech/home/
;
;    Do a search with the keywords "INTEGER DIVISION"
;
;    Or you can watch on YouTube the video "Simple Algorithm for 
;    Arbitrary-Precision Integer Division".
; 
;    https://www.youtube.com/watch?v=6bpLYxk9TUQ
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule VogelsNumberFormat
  
  #CORRECT = 0
  #UNDEFINED = -1
  #INFINITIVE = -2
  #OVERFLOW = -3
  #DIVISION_BY_ZERO = -4
  #NOT_IMPLEMENTED = -5
  
  Interface VNF
    
    GetStatus.w()
    Set(*Other)
    Reset()
    Copy.i()
    Swapping(*Other)
    To_String.s(Group.i = 0)
    From_String(P_String.s)
    ZapLeadZeroes()
    Zero()
    One()
    Absolute()
    IsEqual.b(*Other, Abs.b = 0)
    IsGreaterThan.b(*Other, Abs.b = 0)
    IsPositive.b()
    Positive()
    Negative()
    Plus.i(*Other)
    Minus.i(*Other)
    Add(*Other)
    Substract(*Other)
    Product.i(*Other)
    Multiply(*Other)
    Halve(*Residue = #Null)
    Double()
    Increment()
    Decrement()
    Square()
    Power.i(Exponent.l, *Error.Byte = #Null)
    Divide.i(*Divisor, *Residue)
    Factorial(Value.l)
    Fibonacci(Value.l)
    Randomize(MaximumDigitCount.l, MinimumDigitCount.l = 0)
    ReadVogelsNumberFormat(FileID.i)
    WriteVogelsNumberFormat(FileID.i)
    Free()
    
  EndInterface
  
  Declare.i New(P_String.s = "0")
  
EndDeclareModule

Module VogelsNumberFormat
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Internal Constants declaration <<<<<
  
  #NEGATIVE = 1
  #POSITIVE = 0
  
  #LIMB_SIZE = 9
  #RADIX = 1000000000
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structure declaration <<<<<

  Structure Private_Members
    
    VirtualTable.i
    Status.w
    Sign.w
    List Limbs.q()
    
  EndStructure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Getter <<<<<

  Procedure.w GetStatus(*This.Private_Members)
    
    ProcedureReturn *This\Status
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Setter <<<<<
  
  Procedure Set(*This.Private_Members, *Other.Private_Members)
    
    *This\Status = *Other\Status
    *This\Sign = *Other\Sign
    CopyList(*Other\Limbs(), *This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Reset operator <<<<<

  Procedure Reset(*This.Private_Members)
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    ClearList(*This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Copy operatror <<<<<

  Procedure.i Copy(*This.Private_Members)
    
    *Copy.Private_Members = AllocateStructure(Private_Members)
    *Copy\VirtualTable = ?START_METHODS
    
    *Copy\Status = *This\Status
    *Copy\Sign = *This\Sign
    
    CopyList(*This\Limbs(), *Copy\Limbs())

    ProcedureReturn *Copy
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Swapping operator <<<<<

  Procedure Swapping(*This.Private_Members, *Other.Private_Members)

    Swap *This\Status, *Other\Status
    Swap *This\Sign, *Other\Sign
    
    NewList TempThis.q()
    NewList TempOther.q()
    
    CopyList(*This\Limbs(), TempThis())
    CopyList(*Other\Limbs(), TempOther())
    
    CopyList(TempOther(), *This\Limbs())
    CopyList(TempThis(), *Other\Limbs())
    
    FreeList(TempThis())
    FreeList(TempOther())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Error operator (Private) <<<<<
  
  Procedure Private_Error(*This.Private_Members, type, stype)
    
    If type >= 0
      type = stype
    EndIf
    
    *This\Status = type
    Debug "ERROR " + Str(type)
    
    ProcedureReturn Type
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The To_String transformation operator <<<<<
  
  Procedure.s To_String(*This.Private_Members, Group.i = 0)
    
    If *This\Status < #CORRECT
      
      Select *This\Status
          
        Case #UNDEFINED
          VFN_2_String.s = "Undefined"
          
        Case #INFINITIVE
          VFN_2_String = "Infinitive"
          If *This\Sign
            VFN_2_String = "Minus " + VFN_2_String
          EndIf
          
        Case #OVERFLOW
          VFN_2_String = "Overflow"
          
        Case #NOT_IMPLEMENTED
          VFN_2_String = "Not Implemented"
          
        Case #DIVISION_BY_ZERO
          VFN_2_String = "Division by zero"
          
      EndSelect
      
      ProcedureReturn VFN_2_String
      
    Else
      
      If LastElement(*This\Limbs())
        
        VFN_2_String + Str(*This\Limbs())
        
        While PreviousElement(*This\Limbs())
          VFN_2_String + RSet(Str(*This\Limbs()), #LIMB_SIZE, "0")
        Wend
        
      Else
        VFN_2_String + "0"
      EndIf
      
      If Group <= 0
        
        If *This\Sign
          FormatedNumber.s = "-" + VFN_2_String
        Else
          FormatedNumber = VFN_2_String
        EndIf
        
      ElseIf Group >= 1
        
        NumberLen = Len(VFN_2_String) 
        Start = NumberLen % Group 
        FormatedNumber = Left(VFN_2_String, Start) 
        
        CharsID = Start + 1  
        
        While CharsID <= NumberLen - Start 
          FormatedNumber + " " + Mid(VFN_2_String, CharsID, Group) 
          CharsID + Group 
        Wend 
        
        FormatedNumber = LTrim(FormatedNumber) 
        
        If *This\Sign
          FormatedNumber = "-" + FormatedNumber
        EndIf
        
      EndIf
      
      ProcedureReturn FormatedNumber
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The From_String transformation operator <<<<<
  
  Procedure From_String(*This.Private_Members, P_String.s)
    
    Reset(*This)

    *This\Sign = #POSITIVE
    
    If FindString(P_String, " ")
      P_String = RemoveString(P_String, " ")  
    EndIf
    
    NumID = Len(P_String) - #LIMB_SIZE
    
    While NumID > 0
      AddElement(*This\Limbs())
      *This\Limbs() = Val(Mid(P_String, NumID + 1, #LIMB_SIZE))
      NumID - #LIMB_SIZE
    Wend
    
    NumID = Val(Mid(P_String, 1, 9 + NumID))
    
    If NumID < 0
      *This\Sign = #NEGATIVE
      NumID = -NumID
    EndIf
    
    AddElement(*This\Limbs())
    *This\Limbs() = NumID
    *This\Status = #CORRECT
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ZapLeadZeroes operator <<<<<
  
  Procedure ZapLeadZeroes(*This.Private_Members)
    
    ; Strip leading zeros (000.000.000)
    
    If LastElement(*This\Limbs())
      
      Exit_Condition.b = #False 
      
      While Exit_Condition = #False
        
        If *This\Limbs() = 0
          
          DeleteElement(*This\Limbs())
          
          If LastElement(*This\Limbs()) = #Null
            Exit_Condition = #True
          EndIf
          
        ElseIf *This\Limbs() <> 0
          Exit_Condition = #True
        EndIf
        
      Wend
      
    EndIf
    
    If ListSize(*This\Limbs()) = 0
      AddElement(*This\Limbs())
      *This\Limbs() = 0
      *This\Status = #CORRECT
      *This\Sign = #POSITIVE
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Zero operator <<<<<
  
  Procedure Zero(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 0
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The One operator <<<<<
  
  Procedure One(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 1
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Absolute operator <<<<<
  
  Procedure Absolute(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsEqual test operator <<<<<
  
  Procedure.b IsEqual(*This.Private_Members, *Other.Private_Members, Abs.b = 0)
    
    If ListSize(*This\Limbs()) <> ListSize(*Other\Limbs())
      
      ProcedureReturn #False
      
    ElseIf (Abs = 0) And (*This\Sign <> *Other\Sign)
      
      ProcedureReturn #False
      
    Else
      
      FirstElement(*Other\Limbs())
      
      ForEach *This\Limbs()
        
        If *This\Limbs() <> *Other\Limbs()
          ProcedureReturn #False
        EndIf
        
        NextElement(*Other\Limbs())
        
      Next
      
      ProcedureReturn #True
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsGreaterThan test operator <<<<<
  
  Procedure.b IsGreaterThan(*This.Private_Members, *Other.Private_Members, Abs.b = 0)
    
    If *This = *Other
      ProcedureReturn #False
    EndIf
    
    If Abs = 0
      
      If *This\Sign <> *Other\Sign
        If *This\Sign = #POSITIVE
          ProcedureReturn #True
        Else
          ProcedureReturn #False
        EndIf
      EndIf
      
    Else
      
      If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
        ProcedureReturn #True
      ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
        ProcedureReturn #False
      Else
        
        FirstElement(*Other\Limbs())
        
        ForEach *This\Limbs()
          
          Delta = *This\Limbs() - *Other\Limbs()
          
          If Delta > 0
            ProcedureReturn #True
          ElseIf Delta < 0
            ProcedureReturn #False
          EndIf
          
          NextElement(*Other\Limbs())
          
        Next 
        
        ProcedureReturn #False
        
      EndIf
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsPositive test operator <<<<<
  
  Procedure.b IsPositive(*This.Private_Members)
    
    If *This\Sign = #POSITIVE
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Positive operator <<<<<
  
  Procedure Positive(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Negative operator <<<<<
  
  Procedure Negative(*This.Private_Members)
    
    *This\Sign = #NEGATIVE
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Add operator (Private) <<<<<
  
  Procedure Private_Add(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    *Result\Sign = *CacheA\Sign
    
    If ListSize(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
      Swap *CacheA, *CacheB
    EndIf
    
    ForEach *CacheA\Limbs()
      
      s + *CacheA\Limbs()
      
      If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
        SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
        s + *CacheB\Limbs()
      EndIf
      
      AddElement(*Result\Limbs())
      *Result\Limbs() = s % #RADIX
      s / #RADIX
      
    Next
    
    If s <> 0
      AddElement(*Result\Limbs())
      *Result\Limbs() = s 
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Substract operator (Private) <<<<<
  
  Procedure Private_Sub(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    
    If *CacheA\Sign <> *CacheB\Sign
      *CacheB\Sign = *CacheA\Sign
      Private_Add(*Result, *CacheA, *CacheB)
    Else
      
      If IsGreaterThan(*CacheA, *CacheB, #True)
        *Result\Sign = *CacheA\Sign
      Else
        Swap *CacheA, *CacheB
        *Result\Sign = #NEGATIVE - *CacheA\Sign
      EndIf
      
      ForEach *CacheA\Limbs()
        
        s + *CacheA\Limbs()
        
        If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
          SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
          s - *CacheB\Limbs()
        EndIf
        
        If s < 0
          AddElement(*Result\Limbs())
          *Result\Limbs() = s + #RADIX
          s = -1
        Else
          AddElement(*Result\Limbs())
          *Result\Limbs() = s
          s = 0
        EndIf
        
      Next
      
    EndIf
    
  EndProcedure  
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Plus operator : N = T + A <<<<<
  
  Procedure.i Plus(*This.Private_Members, *Other.Private_Members, *Error.Byte = #Null)
   
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)

    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*New, *CacheA\Status, *CacheB\Status)
      
      If *Error <> #Null
        *Error\b = Error
      EndIf
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*New, *CacheA, *CacheB)
      Else
        Private_Add(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Minus operator : N = T - A <<<<<
  
  Procedure.i Minus(*This.Private_Members, *Other.Private_Members, *Error.Byte = #Null)
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*New, *CacheA\Status, *CacheB\Status)
      
      If *Error <> #Null
        *Error\b = Error
      EndIf
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*New, *CacheA, *CacheB)
      Else
        Private_Sub(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Add operator : T = T + A <<<<<
  
  Procedure Add(*This.Private_Members, *Other.Private_Members)
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*This, *CacheA, *CacheB)
      Else
        Private_Add(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Substract operator : T = T - A <<<<<
  
  Procedure Substract(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*This, *CacheA, *CacheB)
      Else
        Private_Sub(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Product operator : N = T * A  <<<<<
  
  Procedure.i Product(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Private_Error(*New, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs())) - 1
        AddElement(*New\Limbs())
        *New\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*New\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *New\Limbs()
          *New\Limbs() = s % #RADIX
          SelectElement(*New\Limbs(), C_Index + 1)
          *New\Limbs() = *New\Limbs() + s / #RADIX
          
        Next
        
      Next
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Multiply operator : T = T * A <<<<<
  
  Procedure Multiply(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs())) - 1
        AddElement(*This\Limbs())
        *This\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*This\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *This\Limbs()
          *This\Limbs() = s % #RADIX
          SelectElement(*This\Limbs(), C_Index + 1)
          *This\Limbs() = *This\Limbs() + s / #RADIX     
          
        Next
        
      Next
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Halve operator <<<<<
  
  Procedure Halve(*This.Private_Members, *Residue.Private_Members = #Null)
    
    LastElement(*This\Limbs())
    
    While ListIndex(*This\Limbs()) > 0

      If *This\Limbs() & 1 = 1
        PushListPosition(*This\Limbs())
        SelectElement(*This\Limbs(), ListIndex(*This\Limbs()) - 1)
        *This\Limbs() + #Radix
        PopListPosition(*This\Limbs())
      EndIf
      
      *This\Limbs() = *This\Limbs() >> 1
      PreviousElement(*This\Limbs())
      
    Wend 
    
    FirstElement(*This\Limbs())
    
    If *Residue <> #Null
      If *This\Limbs() & 1 = 1
        One(*Residue)
      Else
        Zero(*Residue)
      EndIf
      
      *Residue\Sign = *This\Sign
    EndIf 
    
    *This\Limbs() = *This\Limbs() >> 1
    
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Double operator <<<<<
  
  Procedure Double(*This.Private_Members)
    
    ForEach *This\Limbs()

      If *This\Limbs() > (#Radix >> 1) - 1
        *This\Limbs() << 1 - #Radix + Carry
        Carry = 1
      Else
        *This\Limbs() << 1 + Carry
        Carry = 0
      EndIf
      
    Next
    
    If Carry = 1
      
      AddElement(*This\Limbs())
      
      For Index = 0 To ListSize(*This\Limbs()) - 2
        
        SelectElement(*This\Limbs(), Index)
        Temp.q = *This\Limbs()
        SelectElement(*This\Limbs(), Index+1)
        *This\Limbs() = Temp
        
      Next
      
      LastElement(*This\Limbs())
      
      *This\Limbs() = 1
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Increment operator <<<<<
  
  Procedure Increment(*This.Private_Members)
    
    *One.Private_Members = New("1")
    Add(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Decrement operator <<<<<
  
  Procedure Decrement(*This.Private_Members)
    
    *One.Private_Members = New("1")
    SubStract(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Square operator <<<<<
  
  Procedure Square(*This.Private_Members)
    
    If ListSize(*This\Limbs()) > 0
      Error = Multiply(*This, *This)
    EndIf  
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Power operator <<<<<
  
  Procedure.i Power(*This.Private_Members, Exponent.l, *Error.Byte = #Null)
    
    Protected z.q = 0, s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    If Exponent < 0
      
      ; a^b | b<0 not implemented for now...
      Error = Private_Error(*New, #NOT_IMPLEMENTED, 0)
      
      If *Error <> #Null
        *Error\b = Error
      EndIf
      
    ElseIf ListSize(*This\Limbs()) >= 0
      
      *CacheA.Private_Members = Copy(*This)
      *CacheB.Private_Members = New("1")
      
      If IsPositive(*This) = #False
        Absolute(*CacheA)
        If Exponent & 1 
          *CacheB\Sign = #NEGATIVE
        EndIf
      EndIf
      
      While Exponent > 0
        
        s = 1 << z
        
        If Exponent & s
          
          Multiply(*CacheB, *CacheA)
          Exponent = Exponent - s
          
        EndIf
        
        If Exponent
          Square(*CacheA)
          z = z + 1
        EndIf
        
      Wend
      
      Set(*New, *CacheB)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator (Private) <<<<<
  
  Procedure Private_Divide(*Answer.Private_Members, *Numerator.Private_Members, *Divisor.Private_Members, *Residue.Private_Members = #Null)
    
    Protected Carry.q, Divisor.q, Dividend.q

    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *Numerator\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *Numerator\Status, *Divisor\Status)
    Else
      
      ;// First eliminate the simple case where the divisor is 1 limb
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          
        ElseIf *Divisor\Limbs() = 1 ; Division by +/- 1
          
          *Answer\Status = *Numerator\Status
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          CopyList(*Numerator\Limbs(), *Answer\Limbs())
          
        Else
          
          ClearList(*Answer\Limbs())
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          *Answer\Status = #CORRECT
          
          LastElement(*Numerator\Limbs())
          
          Repeat
            
            Dividend = Carry * #Radix + *Numerator\Limbs()
            
            If Dividend < *Divisor\Limbs()
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = 0
              Carry = Dividend
            Else
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = Dividend / *Divisor\Limbs()
              Carry = Dividend - *Answer\Limbs() * *Divisor\Limbs()
              ;// This is almost free compared to the use of % (Mod)
            EndIf
            
          Until PreviousElement(*Numerator\Limbs()) = #Null
          
          If *Residue <> #Null
            Reset(*Residue)
            AddElement(*Residue\Limbs())
            *Residue\Limbs() = Carry
            *Residue\Sign = *Numerator\Sign
            *Residue\Status = #CORRECT
          EndIf
          
        EndIf
        
      EndIf
      
    EndIf
    
    If *Residue <> #Null
      ZapLeadZeroes(*Residue)
    EndIf
    
    ZapLeadZeroes(*Answer)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator : N = T / A <<<<<
  
  Procedure.i Divide(*This.Private_Members, *Divisor.Private_Members, *Residue.Private_Members)
    
    *Answer.Private_Members = AllocateStructure(Private_Members)
    *Answer\VirtualTable = ?START_METHODS
    
    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *This\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *This\Status, *Divisor\Status)
    Else
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          Zero(*Residue)
          
          ProcedureReturn *Answer
          
        EndIf
        
      EndIf
      
      ZapLeadZeroes(*Divisor)

      *One.Private_Members = New("1")
      StringDivisor.s = RemoveString(To_String(*Divisor, 0), "-")
      M.q = Len(StringDivisor) - 1
      *QuickDivisor.Private_Members = New(Left(StringDivisor, 1))
      
      StringNumerator.s = RemoveString(To_String(*This, 0), "-")
      *QuotientCandidate.Private_Members = New()
      
      *CutedNumerator.Private_Members = New(Left(StringNumerator, Len(StringNumerator) - M))
      Private_Divide(*QuotientCandidate, *CutedNumerator, *QuickDivisor)
      FreeStructure(*CutedNumerator)
      *Numerator.Private_Members = Copy(*This)
      Absolute(*Numerator)
      
      *ABSDivisor.Private_Members = Copy(*Divisor)
      Absolute(*ABSDivisor)
      
      *R_Over_A.Private_Members = New()
      *Remainder.Private_Members = Plus(*ABSDivisor, *One)
      
      While Exit_Condition = #False
        
        *ABSRemainder.Private_Members = Copy(*Remainder)
        Absolute(*ABSRemainder)
        
        If IsGreaterThan(*ABSRemainder, *ABSDivisor, #True) = #False
          Exit_Condition = #True
        Else
          
          *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
          Zero(*Remainder)
          Add(*Remainder, *Numerator)
          Substract(*Remainder, *QxD)
          
          StringNumerator.s = RemoveString(To_String(*Remainder, 0), "-")
          *CutedNumerator.Private_Members = New(Left(StringNumerator, Len(StringNumerator) - M))
          *CutedNumerator\Sign = *Remainder\Sign 
          
          Private_Divide(*R_Over_A, *CutedNumerator, *QuickDivisor)
          
          *Qn.Private_Members = Plus(*QuotientCandidate, *R_Over_A)
          *QnQ.Private_Members = Plus(*QuotientCandidate, *Qn)
          Zero(*QuotientCandidate)
          Add(*QuotientCandidate, *QnQ)
          Halve(*QuotientCandidate)

          FreeStructure(*CutedNumerator)
          FreeStructure(*QxD)
          FreeStructure(*QnQ)
          FreeStructure(*Qn)
          
        EndIf
        
        FreeStructure(*ABSRemainder)
        
      Wend 

      *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
      Zero(*Remainder)
      Add(*Remainder, *Numerator)
      Substract(*Remainder, *QxD)
      
      
      If IsPositive(*Remainder) = #False
        
        Decrement(*QuotientCandidate)
        Add(*Remainder, *ABSDivisor)
        
      EndIf
      
      Set(*Answer, *QuotientCandidate)
      Set(*Residue, *Remainder)
      
      If *Divisor\Sign = *This\Sign
        *Answer\Sign = #POSITIVE
      Else
        *Answer\Sign = #NEGATIVE
      EndIf
      
      *Residue\Sign = *This\Sign
      
      FreeStructure(*QxD)
      FreeStructure(*Numerator)
      FreeStructure(*ABSDivisor)
      FreeStructure(*QuotientCandidate)
      FreeStructure(*Remainder)
      FreeStructure(*QuickDivisor)
      FreeStructure(*One)
      FreeStructure(*R_Over_A)
      
    EndIf
    
    ZapLeadZeroes(*Residue)
    ZapLeadZeroes(*Answer)
    
    ProcedureReturn *Answer
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Factorial calculator <<<<<
  
  Procedure Factorial(*This.Private_Members, Value.l)

    *CacheA.Private_Members = New("1")
    *CacheB.Private_Members = New()
    
    For Index = 2 To Value
      From_String(*CacheB, Str(Index))
      Multiply(*CacheA, *CacheB)
    Next
    
    Set(*This, *CacheA)
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Fibonacci calculator <<<<<
  
  Procedure Fibonacci(*This.Private_Members, Value.l)
    
    *V_u.Private_Members = New("0")
    *V_v.Private_Members = New("1")
    
    For Index = 2 To Value
      
      *V_t.Private_Members = Plus(*V_u, *V_v)
      Set(*V_u, *V_v)
      Set(*V_v, *V_t)
      FreeStructure(*V_t)
      
    Next
    
    Set(*This, *V_v)
    
    FreeStructure(*V_u)
    FreeStructure(*V_v)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Randomize operator <<<<<
  
  Procedure Randomize(*This.Private_Members, MaximumDigitCount.l, MinimumDigitCount.l = 0)
    
    Max = Random(MaximumDigitCount, MinimumDigitCount)
    
    For Index = 0 To Max - 1
      RandomNumber.s = RandomNumber + Str(Random(9))
    Next
    
    From_String(*This, RandomNumber)
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Read in Binary file <<<<<

  Procedure ReadVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    *This\Status = ReadWord(FileID)
    *This\Sign = ReadWord(FileID)
    
    Num_Max.l = ReadLong(FileID) - 1
    
    For NumID = 0 To Num_Max
      AddElement(*This\Limbs())
      *This\Limbs() = ReadLong(FileID)
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Write in Binary file <<<<<

  Procedure WriteVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    WriteWord(FileID, *This\Status)
    WriteWord(FileID, *This\Sign)
    
    WriteLong(FileID, ListSize(*This\Limbs()))
    
    ForEach *This\Limbs()
      WriteLong(FileID, *This\Limbs())
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<

  Procedure Free(*This.Private_Members)
    
    FreeStructure(*This)
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<

  Procedure.i New(P_String.s = "0")
    
    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
    
    From_String(*This, P_String)
    
    ProcedureReturn *This
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Virtual Table Entries <<<<<

  DataSection
    START_METHODS:
    Data.i @GetStatus()
    Data.i @Set()
    Data.i @Reset()
    Data.i @Copy()
    Data.i @Swapping()
    Data.i @To_String()
    Data.i @From_String()
    Data.i @ZapLeadZeroes()
    Data.i @Zero()
    Data.i @One()
    Data.i @Absolute()
    Data.i @IsEqual()
    Data.i @IsGreaterThan()
    Data.i @IsPositive()
    Data.i @Positive()
    Data.i @Negative()
    Data.i @Plus()
    Data.i @Minus()
    Data.i @Add()
    Data.i @Substract()
    Data.i @Product()
    Data.i @Multiply()
    Data.i @Halve()
    Data.i @Double()
    Data.i @Increment()
    Data.i @Decrement()
    Data.i @Square()
    Data.i @Power()
    Data.i @Divide()
    Data.i @Factorial()
    Data.i @Fibonacci()
    Data.i @Randomize()
    Data.i @ReadVogelsNumberFormat()
    Data.i @WriteVogelsNumberFormat()
    Data.i @Free()
    END_METHODS:
  EndDataSection
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test ZapLeadZeroes"
  Debug ""
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("000000000123456789987654321123456789987654321")
  Debug NumA\To_String(3)
  NumA\ZapLeadZeroes()
  Debug NumA\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Swapping"
  Debug ""
  
  NumA\Zero()
  Debug "A = " + NumA\To_String(3)
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("123456789")
  Debug "B = " + NumB\To_String(3)
  Debug ""
  NumA\Swapping(NumB)
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  Debug ""
  Debug "Swapping pointers"
  Swap NumA, NumB
  Debug ""
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Plus / Minus"
  Debug ""
  
  One.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1")
  Two.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2")
  
  X.VogelsNumberFormat::VNF = VogelsNumberFormat::New("12345678987654321")
  Y.VogelsNumberFormat::VNF = VogelsNumberFormat::New("4321")
  
  X_Plus_Y.VogelsNumberFormat::VNF = X\Plus(Y)
  Debug X_Plus_Y\To_String(3) + " = " + X\To_String(3) + " + " + Y\To_String(3)
  
  X_Minus_Y.VogelsNumberFormat::VNF = X\Minus(Y)
  Debug X_Minus_Y\To_String(3) + " = " + X\To_String(3) + " - " + Y\To_String(3) 
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Add / Substract"
  Debug ""
  
  Z.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  MZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  Z\Add(X)
  Z\Add(Y)
  
  Debug "0 + " + X\To_String(3) + " + " + Y\To_String(3) + " = " + Z\To_String(3)
  
  MZ\Add(X)
  MZ\Substract(Y)  
  
  Debug "0 + " + X\To_String(3) + " - " + Y\To_String(3) + " = " + MZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Product"
  Debug ""
  
  X_Two.VogelsNumberFormat::VNF = X\Product(Two)
  Two_X.VogelsNumberFormat::VNF = Two\Product(X)
  
  Debug X_Two\To_String(3)
  Debug Two_X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Multiply"
  Debug ""
  
  X\Multiply(Two)
  Debug X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Square"
  Debug ""
  
  Six.VogelsNumberFormat::VNF = VogelsNumberFormat::New("6")
  
  Six\Square()
  Debug "6^2 = " + Six\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Power"
  Debug ""
  
  Five.VogelsNumberFormat::VNF = VogelsNumberFormat::New("5")
  
  FivePowerFive.VogelsNumberFormat::VNF = Five\Power(5)
  Debug "5^5 = " + FivePowerFive\To_String(3)
  
  TwoPower256.VogelsNumberFormat::VNF = Two\Power(256)
  TwoPower256\Substract(One)
  
  Debug "2^256 - 1 = " + TwoPower256\To_String(6)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Factorial"
  Debug ""
  
  Factorial.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FactorialID = 5 To 50
    Factorial\Factorial(FactorialID)
    Debug Str(FactorialID) + "! = " + Factorial\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Fibonacci"
  Debug ""
  
  Fibonacci.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FibonacciID = 1 To 50
    Fibonacci\Fibonacci(FibonacciID)
    Debug Str(FibonacciID) + " -> " + Fibonacci\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Randomize"
  Debug ""
  
  Random.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Random\Randomize(15, 4)
  Debug Random\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Halve"
  Debug ""
  
  NumZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1000000001")
  Residue2.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Debug "NumZ -> " + NumZ\To_String(3)
  NumZ\Halve(Residue2)
  Debug "NumZ -> " + NumZ\To_String(3)
  Debug "Residue -> " + Residue2\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Double"
  Debug ""
  
  NumZ\Double()
  Debug "NumZ -> " + NumZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Decrement / Increment"
  Debug ""
  
  NumZZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("0")
  Debug NumZZ\To_String(0)
  
  For Index = 0 To 4
    NumZZ\Decrement()
    Debug NumZZ\To_String(0)
  Next
  
  For Index = 0 To 4
    NumZZ\Increment()
    Debug NumZZ\To_String(0)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Divide"
  Debug ""
  
  Var00.q = 987654321
  Var01.q = 12345
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var00))
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var01))
  Residue.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer.VogelsNumberFormat::VNF = NumA\Divide(NumB, Residue)
  Debug Answer\To_String(0) + " -> " + Str(Var00 / Var01)
  Debug Residue\To_String(0) + " -> " + Str(Var00 % Var01)
  
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Last edited by StarBootics on Mon Nov 16, 2020 4:41 pm, edited 2 times in total.
The Stone Age did not end due to a shortage of stones !
User avatar
STARGÅTE
Addict
Addict
Posts: 1748
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: VogelsNumberFormat - OOP

Post by STARGÅTE »

Hi StarBootics,

interesting approach. Is there a reason why you use a linked list instead of an array for your limbs?

I have tested the code i little bit. Here are two issues:
  • In your code for multiplying you multiply two limbs and add the higher part of the product to the next limb. But why you do not check if this addition generates a next overflow? (Line 754)
  • Some code runs into an infinite loop during the division, for example:

    Code: Select all

     	Define A.s = "999999999999999999999999999999"
     	Define B.s = "2354783624532"
     
      NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New(A)
      NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New(B)
      Residue.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
     
      Answer.VogelsNumberFormat::VNF = NumA\Divide(NumB, Residue)
      Debug Answer\To_String(0)
      Debug Residue\To_String(0)
    
PB 5.73 ― Win 10, 20H2 ― Ryzen 9 3900X ― Radeon RX 5600 XT ITX ― Vivaldi 5.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
StarBootics
Addict
Addict
Posts: 823
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: VogelsNumberFormat - OOP

Post by StarBootics »

STARGÅTE wrote:interesting approach. Is there a reason why you use a linked list instead of an array for your limbs?
To not reserve memory for nothing I'm using linked list. An other reason is to avoid overflow, you will have to run out memory to have an overflow.

I will check the issues you pointed out, for he division we should not go into an infinite loop.

Edit 1 : After Analysis, the problem with the division infinite loop came from the faulty Product() procedure. And if the Product() is faulty the Multiply() is also faulty. The problem came from the original code and I just replicate it in to my code, sorry my bad.

Edit 2 : After more analysis the "s" value go well over the #RADIX value on line 751 instead of line 754.
Can someone confirm the exact result of this multiplication : 499999999999999999 X 2354783624532 = 1177391812265999997645216375468
The calculator return me 1,177391812×10^30 so we are loosing some precision.

Thanks
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
StarBootics
Addict
Addict
Posts: 823
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: VogelsNumberFormat - OOP

Post by StarBootics »

Hello everyone,

I think I got it right this time around. I had to correct the IsGreaterThan(), the Product() and Multiply() procedures. The division attempted by STARGÅTE is no longer entering into an infinite loop and give a result that seems to be OK.

EDIT 1: I have corrected the IsGreaterThan() procedure again. Everything should be fine now. Sorry if you have downloaded the code.

Best regards
StarBootics

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : VogelsNumberFormat
; File Name : VogelsNumberFormat - OOP.pb
; File version: 1.2.0
; Programming : OK
; Programmed by : StarBootics
; Date : November 9th, 2020
; Last Update : November 15th, 2020
; PureBasic code : V5.73 beta 4
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Based on the code from Guimauve's which itself is based on 
;    the original code by Michael Vogel.
;
; 2. The division algorithm is based on explainations found on 
;    this website :
;
;    http://justinparrtech.com/JustinParr-Tech/home/
;
;    Do a search with the keywords "INTEGER DIVISION"
;
;    Or you can watch on YouTube the video "Simple Algorithm for 
;    Arbitrary-Precision Integer Division".
; 
;    https://www.youtube.com/watch?v=6bpLYxk9TUQ
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule VogelsNumberFormat
  
  #CORRECT = 0
  #UNDEFINED = -1
  #INFINITIVE = -2
  #OVERFLOW = -3
  #DIVISION_BY_ZERO = -4
  #NOT_IMPLEMENTED = -5
  
  Interface VNF
    
    GetStatus.w()
    Set(*Other)
    Reset()
    Copy.i()
    Swapping(*Other)
    To_String.s(Group.i = 0)
    From_String(P_String.s)
    ZapLeadZeroes()
    Zero()
    One()
    Absolute()
    IsEqual.b(*Other, Abs.b = 0)
    IsGreaterThan.b(*Other, Abs.b = 0)
    IsPositive.b()
    Positive()
    Negative()
    Plus.i(*Other)
    Minus.i(*Other)
    Add(*Other)
    Substract(*Other)
    Product.i(*Other)
    Multiply(*Other)
    Halve(*Residue = #Null)
    Double()
    Increment()
    Decrement()
    Square()
    Power.i(Exponent.l, *Error.Byte = #Null)
    Divide.i(*Divisor, *Residue)
    Factorial(Value.l)
    Fibonacci(Value.l)
    Randomize(MaximumDigitCount.l, MinimumDigitCount.l = 0)
    ReadVogelsNumberFormat(FileID.i)
    WriteVogelsNumberFormat(FileID.i)
    Free()
    
  EndInterface
  
  Declare.i New(P_String.s = "0")
  
EndDeclareModule

Module VogelsNumberFormat
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Internal Constants declaration <<<<<
  
  #NEGATIVE = 1
  #POSITIVE = 0
  
  #LIMB_SIZE = 9
  #RADIX = 1000000000
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structure declaration <<<<<

  Structure Private_Members
    
    VirtualTable.i
    Status.w
    Sign.w
    List Limbs.q()
    
  EndStructure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Getter <<<<<

  Procedure.w GetStatus(*This.Private_Members)
    
    ProcedureReturn *This\Status
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Setter <<<<<
  
  Procedure Set(*This.Private_Members, *Other.Private_Members)
    
    *This\Status = *Other\Status
    *This\Sign = *Other\Sign
    CopyList(*Other\Limbs(), *This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Reset operator <<<<<

  Procedure Reset(*This.Private_Members)
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    ClearList(*This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Copy operatror <<<<<

  Procedure.i Copy(*This.Private_Members)
    
    *Copy.Private_Members = AllocateStructure(Private_Members)
    *Copy\VirtualTable = ?START_METHODS
    
    *Copy\Status = *This\Status
    *Copy\Sign = *This\Sign
    
    CopyList(*This\Limbs(), *Copy\Limbs())

    ProcedureReturn *Copy
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Swapping operator <<<<<

  Procedure Swapping(*This.Private_Members, *Other.Private_Members)

    Swap *This\Status, *Other\Status
    Swap *This\Sign, *Other\Sign
    
    NewList TempThis.q()
    NewList TempOther.q()
    
    CopyList(*This\Limbs(), TempThis())
    CopyList(*Other\Limbs(), TempOther())
    
    CopyList(TempOther(), *This\Limbs())
    CopyList(TempThis(), *Other\Limbs())
    
    FreeList(TempThis())
    FreeList(TempOther())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Error operator (Private) <<<<<
  
  Procedure Private_Error(*This.Private_Members, type, stype)
    
    If type >= 0
      type = stype
    EndIf
    
    *This\Status = type
    Debug "ERROR " + Str(type)
    
    ProcedureReturn Type
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The To_String transformation operator <<<<<
  
  Procedure.s To_String(*This.Private_Members, Group.i = 0)
    
    If *This\Status < #CORRECT
      
      Select *This\Status
          
        Case #UNDEFINED
          VFN_2_String.s = "Undefined"
          
        Case #INFINITIVE
          VFN_2_String = "Infinitive"
          If *This\Sign
            VFN_2_String = "Minus " + VFN_2_String
          EndIf
          
        Case #OVERFLOW
          VFN_2_String = "Overflow"
          
        Case #NOT_IMPLEMENTED
          VFN_2_String = "Not Implemented"
          
        Case #DIVISION_BY_ZERO
          VFN_2_String = "Division by zero"
          
      EndSelect
      
      ProcedureReturn VFN_2_String
      
    Else
      
      If LastElement(*This\Limbs())
        
        VFN_2_String + Str(*This\Limbs())
        
        While PreviousElement(*This\Limbs())
          VFN_2_String + RSet(Str(*This\Limbs()), #LIMB_SIZE, "0")
        Wend
        
      Else
        VFN_2_String + "0"
      EndIf
      
      If Group <= 0
        
        If *This\Sign
          FormatedNumber.s = "-" + VFN_2_String
        Else
          FormatedNumber = VFN_2_String
        EndIf
        
      ElseIf Group >= 1
        
        NumberLen = Len(VFN_2_String) 
        Start = NumberLen % Group 
        FormatedNumber = Left(VFN_2_String, Start) 
        
        CharsID = Start + 1  
        
        While CharsID <= NumberLen - Start 
          FormatedNumber + " " + Mid(VFN_2_String, CharsID, Group) 
          CharsID + Group 
        Wend 
        
        FormatedNumber = LTrim(FormatedNumber) 
        
        If *This\Sign
          FormatedNumber = "-" + FormatedNumber
        EndIf
        
      EndIf
      
      ProcedureReturn FormatedNumber
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The From_String transformation operator <<<<<
  
  Procedure From_String(*This.Private_Members, P_String.s)
    
    Reset(*This)

    *This\Sign = #POSITIVE
    
    If FindString(P_String, " ")
      P_String = RemoveString(P_String, " ")  
    EndIf
    
    NumID = Len(P_String) - #LIMB_SIZE
    
    While NumID > 0
      AddElement(*This\Limbs())
      *This\Limbs() = Val(Mid(P_String, NumID + 1, #LIMB_SIZE))
      NumID - #LIMB_SIZE
    Wend
    
    NumID = Val(Mid(P_String, 1, #LIMB_SIZE + NumID))
    
    If NumID < 0
      *This\Sign = #NEGATIVE
      NumID = -NumID
    EndIf
    
    AddElement(*This\Limbs())
    *This\Limbs() = NumID
    *This\Status = #CORRECT
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ZapLeadZeroes operator <<<<<
  
  Procedure ZapLeadZeroes(*This.Private_Members)
    
    ; Strip leading zeros (000.000.000)
    
    If LastElement(*This\Limbs())
      
      Exit_Condition.b = #False 
      
      While Exit_Condition = #False
        
        If *This\Limbs() = 0
          
          DeleteElement(*This\Limbs())
          
          If LastElement(*This\Limbs()) = #Null
            Exit_Condition = #True
          EndIf
          
        ElseIf *This\Limbs() <> 0
          Exit_Condition = #True
        EndIf
        
      Wend
      
    EndIf
    
    If ListSize(*This\Limbs()) = 0
      AddElement(*This\Limbs())
      *This\Limbs() = 0
      *This\Status = #CORRECT
      *This\Sign = #POSITIVE
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Zero operator <<<<<
  
  Procedure Zero(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 0
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The One operator <<<<<
  
  Procedure One(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 1
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Absolute operator <<<<<
  
  Procedure Absolute(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsEqual test operator <<<<<
  
  Procedure.b IsEqual(*This.Private_Members, *Other.Private_Members, Abs.b = 0)
    
    If ListSize(*This\Limbs()) <> ListSize(*Other\Limbs())
      
      ProcedureReturn #False
      
    ElseIf (Abs = 0) And (*This\Sign <> *Other\Sign)
      
      ProcedureReturn #False
      
    Else
      
      FirstElement(*Other\Limbs())
      
      ForEach *This\Limbs()
        
        If *This\Limbs() <> *Other\Limbs()
          ProcedureReturn #False
        EndIf
        
        NextElement(*Other\Limbs())
        
      Next
      
      ProcedureReturn #True
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsGreaterThan test operator <<<<<
  
  Procedure.b IsGreaterThan(*This.Private_Members, *Other.Private_Members, Abs.b = 0)
    
    If *This = *Other
      ProcedureReturn #False
    EndIf
    
    If Abs = 0
      
      If *This\Sign <> *Other\Sign
        
        If *This\Sign = #POSITIVE
          ProcedureReturn #True
        Else
          ProcedureReturn #False
        EndIf
        
      Else
        
        If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
          ProcedureReturn #True
        ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
          ProcedureReturn #False
        Else
          
          LastElement(*This\Limbs())
          LastElement(*Other\Limbs())
          
          Repeat
            
            Delta = *This\Limbs() - *Other\Limbs()
            
            If Delta > 0
              ProcedureReturn #True
            ElseIf Delta < 0
              ProcedureReturn #False
            EndIf
            
            PreviousElement(*Other\Limbs())
            
          Until PreviousElement(*This\Limbs()) = #Null
          
          ProcedureReturn #False
          
        EndIf
        
      EndIf
      
    Else
      
      If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
        ProcedureReturn #True
      ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
        ProcedureReturn #False
      Else
        
        LastElement(*This\Limbs())
        LastElement(*Other\Limbs())
        
        Repeat
          
          Delta = *This\Limbs() - *Other\Limbs()
          
          If Delta > 0
            ProcedureReturn #True
          ElseIf Delta < 0
            ProcedureReturn #False
          EndIf
          
          PreviousElement(*Other\Limbs())
          
        Until PreviousElement(*This\Limbs()) = #Null
        
        ProcedureReturn #False
        
      EndIf
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsPositive test operator <<<<<
  
  Procedure.b IsPositive(*This.Private_Members)
    
    If *This\Sign = #POSITIVE
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Positive operator <<<<<
  
  Procedure Positive(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Negative operator <<<<<
  
  Procedure Negative(*This.Private_Members)
    
    *This\Sign = #NEGATIVE
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Add operator (Private) <<<<<
  
  Procedure Private_Add(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    *Result\Sign = *CacheA\Sign
    
    If ListSize(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
      Swap *CacheA, *CacheB
    EndIf
    
    ForEach *CacheA\Limbs()
      
      s + *CacheA\Limbs()
      
      If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
        SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
        s + *CacheB\Limbs()
      EndIf
      
      AddElement(*Result\Limbs())
      *Result\Limbs() = s % #RADIX
      s / #RADIX
      
    Next
    
    If s <> 0
      AddElement(*Result\Limbs())
      *Result\Limbs() = s 
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Substract operator (Private) <<<<<
  
  Procedure Private_Sub(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    
    If *CacheA\Sign <> *CacheB\Sign
      *CacheB\Sign = *CacheA\Sign
      Private_Add(*Result, *CacheA, *CacheB)
    Else
      
      If IsGreaterThan(*CacheA, *CacheB, #True)
        *Result\Sign = *CacheA\Sign
      Else
        Swap *CacheA, *CacheB
        *Result\Sign = #NEGATIVE - *CacheA\Sign
      EndIf
      
      ForEach *CacheA\Limbs()
        
        s + *CacheA\Limbs()
        
        If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
          SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
          s - *CacheB\Limbs()
        EndIf
        
        If s < 0
          AddElement(*Result\Limbs())
          *Result\Limbs() = s + #RADIX
          s = -1
        Else
          AddElement(*Result\Limbs())
          *Result\Limbs() = s
          s = 0
        EndIf
        
      Next
      
    EndIf
    
  EndProcedure  
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Plus operator : N = T + A <<<<<
  
  Procedure.i Plus(*This.Private_Members, *Other.Private_Members, *Error.Byte = #Null)
   
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)

    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*New, *CacheA\Status, *CacheB\Status)
      
      If *Error <> #Null
        *Error\b = Error
      EndIf
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*New, *CacheA, *CacheB)
      Else
        Private_Add(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Minus operator : N = T - A <<<<<
  
  Procedure.i Minus(*This.Private_Members, *Other.Private_Members, *Error.Byte = #Null)
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*New, *CacheA\Status, *CacheB\Status)
      
      If *Error <> #Null
        *Error\b = Error
      EndIf
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*New, *CacheA, *CacheB)
      Else
        Private_Sub(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Add operator : T = T + A <<<<<
  
  Procedure Add(*This.Private_Members, *Other.Private_Members)
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*This, *CacheA, *CacheB)
      Else
        Private_Add(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Substract operator : T = T - A <<<<<
  
  Procedure Substract(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*This, *CacheA, *CacheB)
      Else
        Private_Sub(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Product operator : N = T * A  <<<<<
  
  Procedure.i Product(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Private_Error(*New, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs()))
        AddElement(*New\Limbs())
        *New\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*New\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *New\Limbs()
          ;Debug "s -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
          
          If s >= #RADIX
            CarryA.q = s / #RADIX
            s % #RADIX 
          Else
            CarryA = 0
          EndIf
          
          ;Debug "s corrected -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
          ;Debug "CarryA -> " + Str(CarryA) + " -> " + Str(Bool(CarryA >= #RADIX))
          
          *New\Limbs() = s % #RADIX
          SelectElement(*New\Limbs(), C_Index + 1)
          Temp.q = *New\Limbs() + s / #RADIX + CarryA
          ;Debug "Temp -> " + Str(Temp) + " -> " + Str(Bool(Temp >= #RADIX))
          ;Debug ""
          
          If Temp >= #RADIX
            
            Carry = Temp / #RADIX
            Temp % #RADIX
            *New\Limbs() = Temp
            SelectElement(*New\Limbs(), C_Index + 2)
            *New\Limbs() + Carry
            Carry = 0 
            
          Else
            *New\Limbs() = Temp
          EndIf
          
        Next
        
      Next
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Multiply operator : T = T * A <<<<<
  
  Procedure Multiply(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs()))
        AddElement(*This\Limbs())
        *This\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*This\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *This\Limbs()
          
          If s >= #RADIX
            CarryA.q = s / #RADIX
            s % #RADIX 
          Else
            CarryA = 0
          EndIf
          
          *This\Limbs() = s % #RADIX
          SelectElement(*This\Limbs(), C_Index + 1)
          Temp.q = *This\Limbs() + s / #RADIX + CarryA
          
          If Temp >= #RADIX
            
            Carry = Temp - #RADIX
            Temp % #Radix
            *This\Limbs() = Temp
            SelectElement(*This\Limbs(), C_Index + 2)
            *This\Limbs() + Carry
            
          Else
            *This\Limbs() = Temp
          EndIf
          
          
        Next
        
      Next
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Halve operator <<<<<
  
  Procedure Halve(*This.Private_Members, *Residue.Private_Members = #Null)
    
    LastElement(*This\Limbs())
    
    While ListIndex(*This\Limbs()) > 0

      If *This\Limbs() & 1 = 1
        PushListPosition(*This\Limbs())
        SelectElement(*This\Limbs(), ListIndex(*This\Limbs()) - 1)
        *This\Limbs() + #Radix
        PopListPosition(*This\Limbs())
      EndIf
      
      *This\Limbs() = *This\Limbs() >> 1
      PreviousElement(*This\Limbs())
      
    Wend 
    
    FirstElement(*This\Limbs())
    
    If *Residue <> #Null
      If *This\Limbs() & 1 = 1
        One(*Residue)
      Else
        Zero(*Residue)
      EndIf
      
      *Residue\Sign = *This\Sign
    EndIf 
    
    *This\Limbs() = *This\Limbs() >> 1
    
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Double operator <<<<<
  
  Procedure Double(*This.Private_Members)
    
    ForEach *This\Limbs()

      If *This\Limbs() > (#Radix >> 1) - 1
        *This\Limbs() << 1 - #Radix + Carry
        Carry = 1
      Else
        *This\Limbs() << 1 + Carry
        Carry = 0
      EndIf
      
    Next
    
    If Carry = 1
      
      AddElement(*This\Limbs())
      
      For Index = 0 To ListSize(*This\Limbs()) - 2
        
        SelectElement(*This\Limbs(), Index)
        Temp.q = *This\Limbs()
        SelectElement(*This\Limbs(), Index+1)
        *This\Limbs() = Temp
        
      Next
      
      LastElement(*This\Limbs())
      
      *This\Limbs() = 1
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Increment operator <<<<<
  
  Procedure Increment(*This.Private_Members)
    
    *One.Private_Members = New("1")
    Add(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Decrement operator <<<<<
  
  Procedure Decrement(*This.Private_Members)
    
    *One.Private_Members = New("1")
    SubStract(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Square operator <<<<<
  
  Procedure Square(*This.Private_Members)
    
    If ListSize(*This\Limbs()) > 0
      Error = Multiply(*This, *This)
    EndIf  
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Power operator <<<<<
  
  Procedure.i Power(*This.Private_Members, Exponent.l, *Error.Byte = #Null)
    
    Protected z.q = 0, s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    If Exponent < 0
      
      ; a^b | b<0 not implemented for now...
      Error = Private_Error(*New, #NOT_IMPLEMENTED, 0)
      
      If *Error <> #Null
        *Error\b = Error
      EndIf
      
    ElseIf ListSize(*This\Limbs()) >= 0
      
      *CacheA.Private_Members = Copy(*This)
      *CacheB.Private_Members = New("1")
      
      If IsPositive(*This) = #False
        Absolute(*CacheA)
        If Exponent & 1 
          *CacheB\Sign = #NEGATIVE
        EndIf
      EndIf
      
      While Exponent > 0
        
        s = 1 << z
        
        If Exponent & s
          
          Multiply(*CacheB, *CacheA)
          Exponent = Exponent - s
          
        EndIf
        
        If Exponent
          Square(*CacheA)
          z = z + 1
        EndIf
        
      Wend
      
      Set(*New, *CacheB)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator (Private) <<<<<
  
  Procedure Private_Divide(*Answer.Private_Members, *Numerator.Private_Members, *Divisor.Private_Members, *Residue.Private_Members = #Null)
    
    Protected Carry.q, Divisor.q, Dividend.q

    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *Numerator\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *Numerator\Status, *Divisor\Status)
    Else
      
      ;// First eliminate the simple case where the divisor is 1 limb
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          
        ElseIf *Divisor\Limbs() = 1 ; Division by +/- 1
          
          *Answer\Status = *Numerator\Status
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          CopyList(*Numerator\Limbs(), *Answer\Limbs())
          
        Else
          
          ClearList(*Answer\Limbs())
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          *Answer\Status = #CORRECT
          
          LastElement(*Numerator\Limbs())
          
          Repeat
            
            Dividend = Carry * #Radix + *Numerator\Limbs()
            
            If Dividend < *Divisor\Limbs()
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = 0
              Carry = Dividend
            Else
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = Dividend / *Divisor\Limbs()
              Carry = Dividend - *Answer\Limbs() * *Divisor\Limbs()
              ;// This is almost free compared to the use of % (Mod)
            EndIf
            
          Until PreviousElement(*Numerator\Limbs()) = #Null
          
          If *Residue <> #Null
            Reset(*Residue)
            AddElement(*Residue\Limbs())
            *Residue\Limbs() = Carry
            *Residue\Sign = *Numerator\Sign
            *Residue\Status = #CORRECT
          EndIf
          
        EndIf
        
      EndIf
      
    EndIf
    
    If *Residue <> #Null
      ZapLeadZeroes(*Residue)
    EndIf
    
    ZapLeadZeroes(*Answer)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator : N = T / A <<<<<
  
  Procedure.i Divide(*This.Private_Members, *Divisor.Private_Members, *Residue.Private_Members)
    
    *Answer.Private_Members = AllocateStructure(Private_Members)
    *Answer\VirtualTable = ?START_METHODS
    
    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *This\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *This\Status, *Divisor\Status)
    Else
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          Zero(*Residue)
          
          ProcedureReturn *Answer
          
        EndIf
        
      EndIf
      
      ZapLeadZeroes(*Divisor)
      
      *One.Private_Members = New("1")
      StringDivisor.s = RemoveString(To_String(*Divisor, 0), "-")
      M.q = Len(StringDivisor) - 1
      *QuickDivisor.Private_Members = New(Left(StringDivisor, 1))
      
      StringNumerator.s = RemoveString(To_String(*This, 0), "-")
      *QuotientCandidate.Private_Members = New()
      
      *CutedNumerator.Private_Members = New(Left(StringNumerator, Len(StringNumerator) - M))
      Private_Divide(*QuotientCandidate, *CutedNumerator, *QuickDivisor)
      
      *Numerator.Private_Members = Copy(*This)
      Absolute(*Numerator)
      
      *ABSDivisor.Private_Members = Copy(*Divisor)
      Absolute(*ABSDivisor)
      
      *R_Over_A.Private_Members = New()
      *Remainder.Private_Members = Plus(*ABSDivisor, *One)
      
      While Exit_Condition = #False
        
        *ABSRemainder.Private_Members = Copy(*Remainder)
        Absolute(*ABSRemainder)
        
        If IsGreaterThan(*ABSRemainder, *ABSDivisor, #True) = #False
          Exit_Condition = #True
        Else
          
          *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
          ;Debug "Q -> " + To_String(*QuotientCandidate, 0)
          ;Debug "D -> " + To_String(*ABSDivisor, 0)
          ;Debug "QxD -> " + To_String(*QxD, 0)
          ;Debug "N -> " + To_String(*Numerator, 0)
          
          Zero(*Remainder)
          Add(*Remainder, *Numerator)
          Substract(*Remainder, *QxD)
          
          ;Debug "R -> " + To_String(*Remainder, 0)
          
          StringNumerator.s = RemoveString(To_String(*Remainder, 0), "-")
          From_String(*CutedNumerator, Left(StringNumerator, Len(StringNumerator) - M))
          *CutedNumerator\Sign = *Remainder\Sign 
          
          Private_Divide(*R_Over_A, *CutedNumerator, *QuickDivisor)
          ;Debug "R/A -> " + To_String(*R_Over_A, 0)
          
          *Qn.Private_Members = Plus(*QuotientCandidate, *R_Over_A)
          ;Debug "Qn -> " + To_String(*Qn, 0)
          *QnQ.Private_Members = Plus(*QuotientCandidate, *Qn)
          ; Debug "Q + Qn -> " + To_String(*QnQ, 0)
          Zero(*QuotientCandidate)
          Add(*QuotientCandidate, *QnQ)
          Halve(*QuotientCandidate)
          ;Debug "Q -> " + To_String(*QuotientCandidate, 0)
          ; Debug ""
          ; End
          FreeStructure(*QxD)
          FreeStructure(*QnQ)
          FreeStructure(*Qn)
          
        EndIf
        
        FreeStructure(*ABSRemainder)
        ;Delay(250)
        
      Wend 
      
      *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
      Zero(*Remainder)
      Add(*Remainder, *Numerator)
      Substract(*Remainder, *QxD)
      
      If IsPositive(*Remainder) = #False
        
        Decrement(*QuotientCandidate)
        Add(*Remainder, *ABSDivisor)
        
      EndIf
      
      Set(*Answer, *QuotientCandidate)
      Set(*Residue, *Remainder)
      
      If *Divisor\Sign = *This\Sign
        *Answer\Sign = #POSITIVE
      Else
        *Answer\Sign = #NEGATIVE
      EndIf
      
      *Residue\Sign = *This\Sign
      
      FreeStructure(*QxD)
      FreeStructure(*Numerator)
      FreeStructure(*ABSDivisor)
      FreeStructure(*QuotientCandidate)
      FreeStructure(*Remainder)
      FreeStructure(*QuickDivisor)
      FreeStructure(*One)
      FreeStructure(*R_Over_A)
      FreeStructure(*CutedNumerator)
      
    EndIf
    
    ZapLeadZeroes(*Residue)
    ZapLeadZeroes(*Answer)
    
    ProcedureReturn *Answer
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Factorial calculator <<<<<
  
  Procedure Factorial(*This.Private_Members, Value.l)

    *CacheA.Private_Members = New("1")
    *CacheB.Private_Members = New()
    
    For Index = 2 To Value
      From_String(*CacheB, Str(Index))
      Multiply(*CacheA, *CacheB)
    Next
    
    Set(*This, *CacheA)
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Fibonacci calculator <<<<<
  
  Procedure Fibonacci(*This.Private_Members, Value.l)
    
    *V_u.Private_Members = New("0")
    *V_v.Private_Members = New("1")
    
    For Index = 2 To Value
      
      *V_t.Private_Members = Plus(*V_u, *V_v)
      Set(*V_u, *V_v)
      Set(*V_v, *V_t)
      FreeStructure(*V_t)
      
    Next
    
    Set(*This, *V_v)
    
    FreeStructure(*V_u)
    FreeStructure(*V_v)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Randomize operator <<<<<
  
  Procedure Randomize(*This.Private_Members, MaximumDigitCount.l, MinimumDigitCount.l = 0)
    
    Max = Random(MaximumDigitCount, MinimumDigitCount)
    
    For Index = 0 To Max - 1
      RandomNumber.s = RandomNumber + Str(Random(9))
    Next
    
    From_String(*This, RandomNumber)
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Read in Binary file <<<<<

  Procedure ReadVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    *This\Status = ReadWord(FileID)
    *This\Sign = ReadWord(FileID)
    
    Num_Max.l = ReadLong(FileID) - 1
    
    For NumID = 0 To Num_Max
      AddElement(*This\Limbs())
      *This\Limbs() = ReadLong(FileID)
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Write in Binary file <<<<<

  Procedure WriteVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    WriteWord(FileID, *This\Status)
    WriteWord(FileID, *This\Sign)
    
    WriteLong(FileID, ListSize(*This\Limbs()))
    
    ForEach *This\Limbs()
      WriteLong(FileID, *This\Limbs())
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<

  Procedure Free(*This.Private_Members)
    
    FreeStructure(*This)
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<

  Procedure.i New(P_String.s = "0")
    
    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
    
    From_String(*This, P_String)
    
    ProcedureReturn *This
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Virtual Table Entries <<<<<

  DataSection
    START_METHODS:
    Data.i @GetStatus()
    Data.i @Set()
    Data.i @Reset()
    Data.i @Copy()
    Data.i @Swapping()
    Data.i @To_String()
    Data.i @From_String()
    Data.i @ZapLeadZeroes()
    Data.i @Zero()
    Data.i @One()
    Data.i @Absolute()
    Data.i @IsEqual()
    Data.i @IsGreaterThan()
    Data.i @IsPositive()
    Data.i @Positive()
    Data.i @Negative()
    Data.i @Plus()
    Data.i @Minus()
    Data.i @Add()
    Data.i @Substract()
    Data.i @Product()
    Data.i @Multiply()
    Data.i @Halve()
    Data.i @Double()
    Data.i @Increment()
    Data.i @Decrement()
    Data.i @Square()
    Data.i @Power()
    Data.i @Divide()
    Data.i @Factorial()
    Data.i @Fibonacci()
    Data.i @Randomize()
    Data.i @ReadVogelsNumberFormat()
    Data.i @WriteVogelsNumberFormat()
    Data.i @Free()
    END_METHODS:
  EndDataSection
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test ZapLeadZeroes"
  Debug ""
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("000000000123456789987654321123456789987654321")
  Debug NumA\To_String(3)
  NumA\ZapLeadZeroes()
  Debug NumA\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Swapping"
  Debug ""
  
  NumA\Zero()
  Debug "A = " + NumA\To_String(3)
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("123456789")
  Debug "B = " + NumB\To_String(3)
  Debug ""
  NumA\Swapping(NumB)
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  Debug ""
  Debug "Swapping pointers"
  Swap NumA, NumB
  Debug ""
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Plus / Minus"
  Debug ""
  
  One.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1")
  Two.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2")
  
  X.VogelsNumberFormat::VNF = VogelsNumberFormat::New("12345678987654321")
  Y.VogelsNumberFormat::VNF = VogelsNumberFormat::New("4321")
  
  X_Plus_Y.VogelsNumberFormat::VNF = X\Plus(Y)
  Debug X_Plus_Y\To_String(3) + " = " + X\To_String(3) + " + " + Y\To_String(3)
  
  X_Minus_Y.VogelsNumberFormat::VNF = X\Minus(Y)
  Debug X_Minus_Y\To_String(3) + " = " + X\To_String(3) + " - " + Y\To_String(3) 
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Add / Substract"
  Debug ""
  
  Z.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  MZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  Z\Add(X)
  Z\Add(Y)
  
  Debug "0 + " + X\To_String(3) + " + " + Y\To_String(3) + " = " + Z\To_String(3)
  
  MZ\Add(X)
  MZ\Substract(Y)  
  
  Debug "0 + " + X\To_String(3) + " - " + Y\To_String(3) + " = " + MZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Product"
  Debug ""
  
  X_Two.VogelsNumberFormat::VNF = X\Product(Two)
  Two_X.VogelsNumberFormat::VNF = Two\Product(X)
  
  Debug X_Two\To_String(3)
  Debug Two_X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Multiply"
  Debug ""
  
  X\Multiply(Two)
  Debug X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Square"
  Debug ""
  
  Six.VogelsNumberFormat::VNF = VogelsNumberFormat::New("6")
  
  Six\Square()
  Debug "6^2 = " + Six\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Power"
  Debug ""
  
  Five.VogelsNumberFormat::VNF = VogelsNumberFormat::New("5")
  
  FivePowerFive.VogelsNumberFormat::VNF = Five\Power(5)
  Debug "5^5 = " + FivePowerFive\To_String(3)
  
  TwoPower256.VogelsNumberFormat::VNF = Two\Power(256)
  TwoPower256\Substract(One)
  
  Debug "2^256 - 1 = " + TwoPower256\To_String(6)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Factorial"
  Debug ""
  
  Factorial.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FactorialID = 5 To 50
    Factorial\Factorial(FactorialID)
    Debug Str(FactorialID) + "! = " + Factorial\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Fibonacci"
  Debug ""
  
  Fibonacci.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FibonacciID = 1 To 50
    Fibonacci\Fibonacci(FibonacciID)
    Debug Str(FibonacciID) + " -> " + Fibonacci\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Randomize"
  Debug ""
  
  Random.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Random\Randomize(15, 4)
  Debug Random\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Halve"
  Debug ""
  
  NumZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1000000001")
  Residue2.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Debug "NumZ -> " + NumZ\To_String(3)
  NumZ\Halve(Residue2)
  Debug "NumZ -> " + NumZ\To_String(3)
  Debug "Residue -> " + Residue2\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Double"
  Debug ""
  
  NumZ\Double()
  Debug "NumZ -> " + NumZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Decrement / Increment"
  Debug ""
  
  NumZZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("0")
  Debug NumZZ\To_String(0)
  
  For Index = 0 To 4
    NumZZ\Decrement()
    Debug NumZZ\To_String(0)
  Next
  
  For Index = 0 To 4
    NumZZ\Increment()
    Debug NumZZ\To_String(0)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Divide"
  Debug ""
  
  Var00.q = 987654321
  Var01.q = 12345
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var00))
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var01))
  Residue.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer.VogelsNumberFormat::VNF = NumA\Divide(NumB, Residue)
  Debug Answer\To_String(0) + " -> " + Str(Var00 / Var01)
  Debug Residue\To_String(0) + " -> " + Str(Var00 % Var01)
  
  NumAA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("999999999999999999999999999999")
  NumBB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2354783624532")
  Residue3.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer3.VogelsNumberFormat::VNF = NumAA\Divide(NumBB, Residue3)
  Debug "Answer -> " + Answer3\To_String(0); + " -> " + Str(Var00 / Var01)
  Debug "Remainer -> " + Residue3\To_String(0); + " -> " + Str(Var00 % Var01)
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
The Stone Age did not end due to a shortage of stones !
infratec
Always Here
Always Here
Posts: 5853
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: VogelsNumberFormat - OOP

Post by infratec »

User avatar
STARGÅTE
Addict
Addict
Posts: 1748
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: VogelsNumberFormat - OOP

Post by STARGÅTE »

StarBootics wrote:Edit 2 : After more analysis the "s" value go well over the #RADIX value on line 751 instead of line 754.
Of cause yes. But this was not the problem. The new code here, do exactly the same as before, see my comments:

Code: Select all

          If s >= #RADIX
            CarryA.q = s / #RADIX   ; you define CarryA.q = s / #RADIX
            s % #RADIX                  ; Now s is < #RADIX 
          Else
            CarryA = 0
          EndIf
          
          *New\Limbs() = s % #RADIX
          SelectElement(*New\Limbs(), C_Index + 1)
          Temp.q = *New\Limbs() + s / #RADIX + CarryA    ; here  s / #RADIX = 0, but CarryA = s / #RADIX
Means, this code is also fine:

Code: Select all

          *New\Limbs() = s % #RADIX
          SelectElement(*New\Limbs(), C_Index + 1)
          Temp.q = *New\Limbs() + s / #RADIX
The problem comes again with your carry of the addition:

Code: Select all

If Temp >= #RADIX
           
            Carry = Temp / #RADIX
            Temp % #RADIX
            *New\Limbs() = Temp
            SelectElement(*New\Limbs(), C_Index + 2)
            *New\Limbs() + Carry                       ; !! At this line the addition could be end up again over #RADIX !!
            Carry = 0
           
          Else
            *New\Limbs() = Temp
          EndIf
PB 5.73 ― Win 10, 20H2 ― Ryzen 9 3900X ― Radeon RX 5600 XT ITX ― Vivaldi 5.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
StarBootics
Addict
Addict
Posts: 823
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: VogelsNumberFormat - OOP

Post by StarBootics »

Hello everyone,

This is the version 1.3.0 with some correction inside the Product() and Multiply() methods.

EDIT : Updated to version 1.3.1, Small correction in the ReadVogelsNumberFormat() and WriteVogelsNumberFormat()
EDIT : Updated to version 1.3.2, Removal of Error.Byte = #Null for the Plus(), Minus() and Power()


Best regards
StarBootics

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : VogelsNumberFormat
; File Name : VogelsNumberFormat - OOP.pb
; File version: 1.3.2
; Programming : OK
; Programmed by : StarBootics
; Date : November 9th, 2020
; Last Update : December 3rd, 2020
; PureBasic code : V5.73 LTS
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Based on the code from Guimauve's which itself is based on 
;    the original code by Michael Vogel.
;
; 2. The division algorithm is based on explainations found on 
;    this website :
;
;    http://justinparrtech.com/JustinParr-Tech/home/
;
;    Do a search with the keywords "INTEGER DIVISION"
;
;    Or you can watch on YouTube the video "Simple Algorithm for 
;    Arbitrary-Precision Integer Division".
; 
;    https://www.youtube.com/watch?v=6bpLYxk9TUQ
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule VogelsNumberFormat
  
  #CORRECT = 0
  #UNDEFINED = -1
  #INFINITIVE = -2
  #OVERFLOW = -3
  #DIVISION_BY_ZERO = -4
  #NOT_IMPLEMENTED = -5
  
  Interface VNF
    
    GetStatus.w()
    Set(*Other)
    Reset()
    Copy.i()
    Swapping(*Other)
    To_String.s(Group.i = 0)
    From_String(P_String.s)
    ZapLeadZeroes()
    Zero()
    One()
    Absolute()
    IsEqual.b(*Other, Abs.b = 0)
    IsGreaterThan.b(*Other, Abs.b = 0)
    IsPositive.b()
    Positive()
    Negative()
    Plus.i(*Other)
    Minus.i(*Other)
    Add(*Other)
    Substract(*Other)
    Product.i(*Other)
    Multiply(*Other)
    Halve(*Residue = #Null)
    Double()
    Increment()
    Decrement()
    Square()
    Power.i(Exponent.l, *Error.Byte = #Null)
    Divide.i(*Divisor, *Residue)
    Factorial(Value.l)
    Fibonacci(Value.l)
    Randomize(MaximumDigitCount.l, MinimumDigitCount.l = 0)
    ReadVogelsNumberFormat(FileID.i)
    WriteVogelsNumberFormat(FileID.i)
    Free()
    
  EndInterface
  
  Declare.i New(P_String.s = "0")
  
EndDeclareModule

Module VogelsNumberFormat
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Internal Constants declaration <<<<<
  
  #NEGATIVE = 1
  #POSITIVE = 0
  
  #LIMB_SIZE = 9
  #RADIX = 1000000000
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structure declaration <<<<<

  Structure Private_Members
    
    VirtualTable.i
    Status.w
    Sign.w
    List Limbs.q()
    
  EndStructure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Getter <<<<<

  Procedure.w GetStatus(*This.Private_Members)
    
    ProcedureReturn *This\Status
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Setter <<<<<
  
  Procedure Set(*This.Private_Members, *Other.Private_Members)
    
    *This\Status = *Other\Status
    *This\Sign = *Other\Sign
    CopyList(*Other\Limbs(), *This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Reset operator <<<<<

  Procedure Reset(*This.Private_Members)
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    ClearList(*This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Copy operatror <<<<<

  Procedure.i Copy(*This.Private_Members)
    
    *Copy.Private_Members = AllocateStructure(Private_Members)
    *Copy\VirtualTable = ?START_METHODS
    
    *Copy\Status = *This\Status
    *Copy\Sign = *This\Sign
    
    CopyList(*This\Limbs(), *Copy\Limbs())

    ProcedureReturn *Copy
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Swapping operator <<<<<

  Procedure Swapping(*This.Private_Members, *Other.Private_Members)

    Swap *This\Status, *Other\Status
    Swap *This\Sign, *Other\Sign
    
    NewList TempThis.q()
    NewList TempOther.q()
    
    CopyList(*This\Limbs(), TempThis())
    CopyList(*Other\Limbs(), TempOther())
    
    CopyList(TempOther(), *This\Limbs())
    CopyList(TempThis(), *Other\Limbs())
    
    FreeList(TempThis())
    FreeList(TempOther())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Error operator (Private) <<<<<
  
  Procedure Private_Error(*This.Private_Members, type, stype)
    
    If type >= 0
      type = stype
    EndIf
    
    *This\Status = type
    Debug "ERROR " + Str(type)
    
    ProcedureReturn Type
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The To_String transformation operator <<<<<
  
  Procedure.s To_String(*This.Private_Members, Group.i = 0)
    
    If *This\Status < #CORRECT
      
      Select *This\Status
          
        Case #UNDEFINED
          VFN_2_String.s = "Undefined"
          
        Case #INFINITIVE
          VFN_2_String = "Infinitive"
          If *This\Sign
            VFN_2_String = "Minus " + VFN_2_String
          EndIf
          
        Case #OVERFLOW
          VFN_2_String = "Overflow"
          
        Case #NOT_IMPLEMENTED
          VFN_2_String = "Not Implemented"
          
        Case #DIVISION_BY_ZERO
          VFN_2_String = "Division by zero"
          
      EndSelect
      
      ProcedureReturn VFN_2_String
      
    Else
      
      If LastElement(*This\Limbs())
        
        VFN_2_String + Str(*This\Limbs())
        
        While PreviousElement(*This\Limbs())
          VFN_2_String + RSet(Str(*This\Limbs()), #LIMB_SIZE, "0")
        Wend
        
      Else
        VFN_2_String + "0"
      EndIf
      
      If Group <= 0
        
        If *This\Sign
          FormatedNumber.s = "-" + VFN_2_String
        Else
          FormatedNumber = VFN_2_String
        EndIf
        
      ElseIf Group >= 1
        
        NumberLen = Len(VFN_2_String) 
        Start = NumberLen % Group 
        FormatedNumber = Left(VFN_2_String, Start) 
        
        CharsID = Start + 1  
        
        While CharsID <= NumberLen - Start 
          FormatedNumber + " " + Mid(VFN_2_String, CharsID, Group) 
          CharsID + Group 
        Wend 
        
        FormatedNumber = LTrim(FormatedNumber) 
        
        If *This\Sign
          FormatedNumber = "-" + FormatedNumber
        EndIf
        
      EndIf
      
      ProcedureReturn FormatedNumber
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The From_String transformation operator <<<<<
  
  Procedure From_String(*This.Private_Members, P_String.s)
    
    Reset(*This)

    *This\Sign = #POSITIVE
    
    If FindString(P_String, " ")
      P_String = RemoveString(P_String, " ")  
    EndIf
    
    NumID = Len(P_String) - #LIMB_SIZE
    
    While NumID > 0
      AddElement(*This\Limbs())
      *This\Limbs() = Val(Mid(P_String, NumID + 1, #LIMB_SIZE))
      NumID - #LIMB_SIZE
    Wend
    
    NumID = Val(Mid(P_String, 1, 9 + NumID))
    
    If NumID < 0
      *This\Sign = #NEGATIVE
      NumID = -NumID
    EndIf
    
    AddElement(*This\Limbs())
    *This\Limbs() = NumID
    *This\Status = #CORRECT
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ZapLeadZeroes operator <<<<<
  
  Procedure ZapLeadZeroes(*This.Private_Members)
    
    ; Strip leading zeros (000.000.000)
    
    If LastElement(*This\Limbs())
      
      Exit_Condition.b = #False 
      
      While Exit_Condition = #False
        
        If *This\Limbs() = 0
          
          DeleteElement(*This\Limbs())
          
          If LastElement(*This\Limbs()) = #Null
            Exit_Condition = #True
          EndIf
          
        ElseIf *This\Limbs() <> 0
          Exit_Condition = #True
        EndIf
        
      Wend
      
    EndIf
    
    If ListSize(*This\Limbs()) = 0
      AddElement(*This\Limbs())
      *This\Limbs() = 0
      *This\Status = #CORRECT
      *This\Sign = #POSITIVE
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Zero operator <<<<<
  
  Procedure Zero(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 0
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The One operator <<<<<
  
  Procedure One(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 1
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Absolute operator <<<<<
  
  Procedure Absolute(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsEqual test operator <<<<<
  
  Procedure.b IsEqual(*This.Private_Members, *Other.Private_Members, Abs.b = 0)
    
    If ListSize(*This\Limbs()) <> ListSize(*Other\Limbs())
      
      ProcedureReturn #False
      
    ElseIf (Abs = 0) And (*This\Sign <> *Other\Sign)
      
      ProcedureReturn #False
      
    Else
      
      FirstElement(*Other\Limbs())
      
      ForEach *This\Limbs()
        
        If *This\Limbs() <> *Other\Limbs()
          ProcedureReturn #False
        EndIf
        
        NextElement(*Other\Limbs())
        
      Next
      
      ProcedureReturn #True
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsGreaterThan test operator <<<<<
  
  Procedure.b IsGreaterThan(*This.Private_Members, *Other.Private_Members, Abs.b = 0)
    
    If *This = *Other
      ProcedureReturn #False
    EndIf
    
    If Abs = 0
      
      If *This\Sign <> *Other\Sign
        
        If *This\Sign = #POSITIVE
          ProcedureReturn #True
        Else
          ProcedureReturn #False
        EndIf
        
      Else
        
        If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
          ProcedureReturn #True
        ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
          ProcedureReturn #False
        Else
          
          LastElement(*This\Limbs())
          LastElement(*Other\Limbs())
          
          Repeat
            
            Delta = *This\Limbs() - *Other\Limbs()
            
            If Delta > 0
              ProcedureReturn #True
            ElseIf Delta < 0
              ProcedureReturn #False
            EndIf
            
            PreviousElement(*Other\Limbs())
            
          Until PreviousElement(*This\Limbs()) = #Null
          
          ProcedureReturn #False
          
        EndIf
        
      EndIf
      
    Else
      
      If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
        ProcedureReturn #True
      ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
        ProcedureReturn #False
      Else
        
        LastElement(*This\Limbs())
        LastElement(*Other\Limbs())
        
        Repeat
          
          Delta = *This\Limbs() - *Other\Limbs()
          
          If Delta > 0
            ProcedureReturn #True
          ElseIf Delta < 0
            ProcedureReturn #False
          EndIf
          
          PreviousElement(*Other\Limbs())
          
        Until PreviousElement(*This\Limbs()) = #Null
        
        ProcedureReturn #False
        
      EndIf
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsPositive test operator <<<<<
  
  Procedure.b IsPositive(*This.Private_Members)
    
    If *This\Sign = #POSITIVE
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Positive operator <<<<<
  
  Procedure Positive(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Negative operator <<<<<
  
  Procedure Negative(*This.Private_Members)
    
    *This\Sign = #NEGATIVE
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Add operator (Private) <<<<<
  
  Procedure Private_Add(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    *Result\Sign = *CacheA\Sign
    
    If ListSize(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
      Swap *CacheA, *CacheB
    EndIf
    
    ForEach *CacheA\Limbs()
      
      s + *CacheA\Limbs()
      
      If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
        SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
        s + *CacheB\Limbs()
      EndIf
      
      AddElement(*Result\Limbs())
      *Result\Limbs() = s % #RADIX
      s / #RADIX
      
    Next
    
    If s <> 0
      AddElement(*Result\Limbs())
      *Result\Limbs() = s 
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Substract operator (Private) <<<<<
  
  Procedure Private_Sub(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    
    If *CacheA\Sign <> *CacheB\Sign
      *CacheB\Sign = *CacheA\Sign
      Private_Add(*Result, *CacheA, *CacheB)
    Else
      
      If IsGreaterThan(*CacheA, *CacheB, #True)
        *Result\Sign = *CacheA\Sign
      Else
        Swap *CacheA, *CacheB
        *Result\Sign = #NEGATIVE - *CacheA\Sign
      EndIf
      
      ForEach *CacheA\Limbs()
        
        s + *CacheA\Limbs()
        
        If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
          SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
          s - *CacheB\Limbs()
        EndIf
        
        If s < 0
          AddElement(*Result\Limbs())
          *Result\Limbs() = s + #RADIX
          s = -1
        Else
          AddElement(*Result\Limbs())
          *Result\Limbs() = s
          s = 0
        EndIf
        
      Next
      
    EndIf
    
  EndProcedure  
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Plus operator : N = T + A <<<<<
  
  Procedure.i Plus(*This.Private_Members, *Other.Private_Members)
   
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)

    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Private_Error(*New, *CacheA\Status, *CacheB\Status)

    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*New, *CacheA, *CacheB)
      Else
        Private_Add(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Minus operator : N = T - A <<<<<
  
  Procedure.i Minus(*This.Private_Members, *Other.Private_Members)
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*New, *CacheA\Status, *CacheB\Status)
      
      If *Error <> #Null
        *Error\b = Error
      EndIf
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*New, *CacheA, *CacheB)
      Else
        Private_Sub(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Add operator : T = T + A <<<<<
  
  Procedure Add(*This.Private_Members, *Other.Private_Members)
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*This, *CacheA, *CacheB)
      Else
        Private_Add(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Substract operator : T = T - A <<<<<
  
  Procedure Substract(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*This, *CacheA, *CacheB)
      Else
        Private_Sub(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Product operator : N = T * A  <<<<<
  
  Procedure.i Product(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Private_Error(*New, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs())) - 1
        AddElement(*New\Limbs())
        *New\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*New\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *New\Limbs()
          
          CarryCounter = 0
          
          If s >= #RADIX
            
            ;Debug "s >= #RADIX"
            
            While s >= #RADIX
              
              ;Debug "s -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              Carry.q = s / #RADIX
              s % #RADIX 
              
              ;Debug "Carry -> " + Str(Carry) + " -> " + Str(Bool(Carry >= #RADIX))
              ;Debug "s corrected -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              
              SelectElement(*New\Limbs(), C_Index + CarryCounter)
              *New\Limbs() = s
              SelectElement(*New\Limbs(), C_Index + CarryCounter + 1)
              s = *New\Limbs() + s / #RADIX + Carry
              
              ;Debug "Next s -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              ;Debug "CarryCounter -> " + Str(CarryCounter)
              
              If s < #RADIX
                *New\Limbs() = s
              EndIf
              
              CarryCounter + 1
              
            Wend
            
          Else
            
            *New\Limbs() = s
            
          EndIf
          
          ;ForEach *New\Limbs()
          ;  Debug "*New\Limbs() -> " + Str(*New\Limbs())
          ;Next
          
          ;Debug ""
          
        Next
        
      Next
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Multiply operator : T = T * A <<<<<
  
  Procedure Multiply(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Private_Error(*This, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs())) - 1
        AddElement(*This\Limbs())
        *This\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*This\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *This\Limbs()
          
          CarryCounter = 0
          
          If s >= #RADIX
            
            While s >= #RADIX
              
              Carry.q = s / #RADIX
              s % #RADIX 
              
              SelectElement(*This\Limbs(), C_Index + CarryCounter)
              *This\Limbs() = s
              SelectElement(*This\Limbs(), C_Index + CarryCounter + 1)
              s = *This\Limbs() + s / #RADIX + Carry
              
              If s < #RADIX
                *This\Limbs() = s
              EndIf
              
              CarryCounter + 1
              
            Wend
            
          Else
            
            *This\Limbs() = s
            
          EndIf
          
        Next
        
      Next
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Halve operator <<<<<
  
  Procedure Halve(*This.Private_Members, *Residue.Private_Members = #Null)
    
    LastElement(*This\Limbs())
    
    While ListIndex(*This\Limbs()) > 0

      If *This\Limbs() & 1 = 1
        PushListPosition(*This\Limbs())
        SelectElement(*This\Limbs(), ListIndex(*This\Limbs()) - 1)
        *This\Limbs() + #Radix
        PopListPosition(*This\Limbs())
      EndIf
      
      *This\Limbs() = *This\Limbs() >> 1
      PreviousElement(*This\Limbs())
      
    Wend 
    
    FirstElement(*This\Limbs())
    
    If *Residue <> #Null
      If *This\Limbs() & 1 = 1
        One(*Residue)
      Else
        Zero(*Residue)
      EndIf
      
      *Residue\Sign = *This\Sign
    EndIf 
    
    *This\Limbs() = *This\Limbs() >> 1
    
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Double operator <<<<<
  
  Procedure Double(*This.Private_Members)
    
    ForEach *This\Limbs()

      If *This\Limbs() > (#Radix >> 1) - 1
        *This\Limbs() << 1 - #Radix + Carry
        Carry = 1
      Else
        *This\Limbs() << 1 + Carry
        Carry = 0
      EndIf
      
    Next
    
    If Carry = 1
      
      AddElement(*This\Limbs())
      
      For Index = 0 To ListSize(*This\Limbs()) - 2
        
        SelectElement(*This\Limbs(), Index)
        Temp.q = *This\Limbs()
        SelectElement(*This\Limbs(), Index+1)
        *This\Limbs() = Temp
        
      Next
      
      LastElement(*This\Limbs())
      
      *This\Limbs() = 1
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Increment operator <<<<<
  
  Procedure Increment(*This.Private_Members)
    
    *One.Private_Members = New("1")
    Add(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Decrement operator <<<<<
  
  Procedure Decrement(*This.Private_Members)
    
    *One.Private_Members = New("1")
    SubStract(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Square operator <<<<<
  
  Procedure Square(*This.Private_Members)
    
    If ListSize(*This\Limbs()) > 0
      Multiply(*This, *This)
    EndIf  
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Power operator <<<<<
  
  Procedure.i Power(*This.Private_Members, Exponent.l)
    
    Protected z.q = 0, s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    If Exponent < 0
      
      ; a^b | b<0 not implemented for now...
      Private_Error(*New, #NOT_IMPLEMENTED, 0)

    ElseIf ListSize(*This\Limbs()) >= 0
      
      *CacheA.Private_Members = Copy(*This)
      *CacheB.Private_Members = New("1")
      
      If IsPositive(*This) = #False
        Absolute(*CacheA)
        If Exponent & 1 
          *CacheB\Sign = #NEGATIVE
        EndIf
      EndIf
      
      While Exponent > 0
        
        s = 1 << z
        
        If Exponent & s
          
          Multiply(*CacheB, *CacheA)
          Exponent = Exponent - s
          
        EndIf
        
        If Exponent
          Square(*CacheA)
          z = z + 1
        EndIf
        
      Wend
      
      Set(*New, *CacheB)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator (Private) <<<<<
  
  Procedure Private_Divide(*Answer.Private_Members, *Numerator.Private_Members, *Divisor.Private_Members, *Residue.Private_Members = #Null)
    
    Protected Carry.q, Divisor.q, Dividend.q

    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *Numerator\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *Numerator\Status, *Divisor\Status)
    Else
      
      ;// First eliminate the simple case where the divisor is 1 limb
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          
        ElseIf *Divisor\Limbs() = 1 ; Division by +/- 1
          
          *Answer\Status = *Numerator\Status
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          CopyList(*Numerator\Limbs(), *Answer\Limbs())
          
        Else
          
          ClearList(*Answer\Limbs())
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          *Answer\Status = #CORRECT
          
          LastElement(*Numerator\Limbs())
          
          Repeat
            
            Dividend = Carry * #Radix + *Numerator\Limbs()
            
            If Dividend < *Divisor\Limbs()
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = 0
              Carry = Dividend
            Else
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = Dividend / *Divisor\Limbs()
              Carry = Dividend - *Answer\Limbs() * *Divisor\Limbs()
              ;// This is almost free compared to the use of % (Mod)
            EndIf
            
          Until PreviousElement(*Numerator\Limbs()) = #Null
          
          If *Residue <> #Null
            Reset(*Residue)
            AddElement(*Residue\Limbs())
            *Residue\Limbs() = Carry
            *Residue\Sign = *Numerator\Sign
            *Residue\Status = #CORRECT
          EndIf
          
        EndIf
        
      EndIf
      
    EndIf
    
    If *Residue <> #Null
      ZapLeadZeroes(*Residue)
    EndIf
    
    ZapLeadZeroes(*Answer)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator : N = T / A <<<<<
  
  Procedure.i Divide(*This.Private_Members, *Divisor.Private_Members, *Residue.Private_Members)
    
    *Answer.Private_Members = AllocateStructure(Private_Members)
    *Answer\VirtualTable = ?START_METHODS
    
    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *This\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *This\Status, *Divisor\Status)
    Else
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          Zero(*Residue)
          
          ProcedureReturn *Answer
          
        EndIf
        
      EndIf
      
      ZapLeadZeroes(*Divisor)
      
      *One.Private_Members = New("1")
      StringDivisor.s = RemoveString(To_String(*Divisor, 0), "-")
      M.q = Len(StringDivisor) - 1
      *QuickDivisor.Private_Members = New(Left(StringDivisor, 1))
      
      StringNumerator.s = RemoveString(To_String(*This, 0), "-")
      *QuotientCandidate.Private_Members = New()
      
      *CutedNumerator.Private_Members = New(Left(StringNumerator, Len(StringNumerator) - M))
      Private_Divide(*QuotientCandidate, *CutedNumerator, *QuickDivisor)
      
      *Numerator.Private_Members = Copy(*This)
      Absolute(*Numerator)
      
      *ABSDivisor.Private_Members = Copy(*Divisor)
      Absolute(*ABSDivisor)
      
      *R_Over_A.Private_Members = New()
      *Remainder.Private_Members = Plus(*ABSDivisor, *One)
      
      While Exit_Condition = #False
        
        *ABSRemainder.Private_Members = Copy(*Remainder)
        Absolute(*ABSRemainder)
        
        If IsGreaterThan(*ABSRemainder, *ABSDivisor, #True) = #False
          Exit_Condition = #True
        Else
          
          *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
          ;Debug "Q -> " + To_String(*QuotientCandidate, 0)
          ;Debug "D -> " + To_String(*ABSDivisor, 0)
          ;Debug "QxD -> " + To_String(*QxD, 0)
          ;Debug "N -> " + To_String(*Numerator, 0)
          
          Zero(*Remainder)
          Add(*Remainder, *Numerator)
          Substract(*Remainder, *QxD)
          
          ;Debug "R -> " + To_String(*Remainder, 0)
          
          StringNumerator.s = RemoveString(To_String(*Remainder, 0), "-")
          From_String(*CutedNumerator, Left(StringNumerator, Len(StringNumerator) - M))
          *CutedNumerator\Sign = *Remainder\Sign 
          
          Private_Divide(*R_Over_A, *CutedNumerator, *QuickDivisor)
          ;Debug "R/A -> " + To_String(*R_Over_A, 0)
          
          *Qn.Private_Members = Plus(*QuotientCandidate, *R_Over_A)
          ;Debug "Qn -> " + To_String(*Qn, 0)
          *QnQ.Private_Members = Plus(*QuotientCandidate, *Qn)
          ; Debug "Q + Qn -> " + To_String(*QnQ, 0)
          Zero(*QuotientCandidate)
          Add(*QuotientCandidate, *QnQ)
          Halve(*QuotientCandidate)
          ;Debug "Q -> " + To_String(*QuotientCandidate, 0)
          ; Debug ""
          ; End
          FreeStructure(*QxD)
          FreeStructure(*QnQ)
          FreeStructure(*Qn)
          
        EndIf
        
        FreeStructure(*ABSRemainder)
        ;Delay(250)
        
      Wend 
      
      *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
      Zero(*Remainder)
      Add(*Remainder, *Numerator)
      Substract(*Remainder, *QxD)
      
      If IsPositive(*Remainder) = #False
        
        Decrement(*QuotientCandidate)
        Add(*Remainder, *ABSDivisor)
        
      EndIf
      
      Set(*Answer, *QuotientCandidate)
      Set(*Residue, *Remainder)
      
      If *Divisor\Sign = *This\Sign
        *Answer\Sign = #POSITIVE
      Else
        *Answer\Sign = #NEGATIVE
      EndIf
      
      *Residue\Sign = *This\Sign
      
      FreeStructure(*QxD)
      FreeStructure(*Numerator)
      FreeStructure(*ABSDivisor)
      FreeStructure(*QuotientCandidate)
      FreeStructure(*Remainder)
      FreeStructure(*QuickDivisor)
      FreeStructure(*One)
      FreeStructure(*R_Over_A)
      FreeStructure(*CutedNumerator)
      
    EndIf
    
    ZapLeadZeroes(*Residue)
    ZapLeadZeroes(*Answer)
    
    ProcedureReturn *Answer
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Factorial calculator <<<<<
  
  Procedure Factorial(*This.Private_Members, Value.l)

    *CacheA.Private_Members = New("1")
    *CacheB.Private_Members = New()
    
    For Index = 2 To Value
      From_String(*CacheB, Str(Index))
      Multiply(*CacheA, *CacheB)
    Next
    
    Set(*This, *CacheA)
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Fibonacci calculator <<<<<
  
  Procedure Fibonacci(*This.Private_Members, Value.l)
    
    *V_u.Private_Members = New("0")
    *V_v.Private_Members = New("1")
    
    For Index = 2 To Value
      
      *V_t.Private_Members = Plus(*V_u, *V_v)
      Set(*V_u, *V_v)
      Set(*V_v, *V_t)
      FreeStructure(*V_t)
      
    Next
    
    Set(*This, *V_v)
    
    FreeStructure(*V_u)
    FreeStructure(*V_v)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Randomize operator <<<<<
  
  Procedure Randomize(*This.Private_Members, MaximumDigitCount.l, MinimumDigitCount.l = 0)
    
    Max = Random(MaximumDigitCount, MinimumDigitCount)
    
    For Index = 0 To Max - 1
      RandomNumber.s = RandomNumber + Str(Random(9))
    Next
    
    From_String(*This, RandomNumber)
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Read in Binary file <<<<<

  Procedure ReadVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    *This\Status = ReadWord(FileID)
    *This\Sign = ReadWord(FileID)
    
    Num_Max.l = ReadLong(FileID) - 1
    
    For NumID = 0 To Num_Max
      AddElement(*This\Limbs())
      *This\Limbs() = ReadQuad(FileID)
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Write in Binary file <<<<<

  Procedure WriteVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    WriteWord(FileID, *This\Status)
    WriteWord(FileID, *This\Sign)
    
    WriteLong(FileID, ListSize(*This\Limbs()))
    
    ForEach *This\Limbs()
      WriteQuad(FileID, *This\Limbs())
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<

  Procedure Free(*This.Private_Members)
    
    FreeStructure(*This)
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<

  Procedure.i New(P_String.s = "0")
    
    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
    
    From_String(*This, P_String)
    
    ProcedureReturn *This
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Virtual Table Entries <<<<<

  DataSection
    START_METHODS:
    Data.i @GetStatus()
    Data.i @Set()
    Data.i @Reset()
    Data.i @Copy()
    Data.i @Swapping()
    Data.i @To_String()
    Data.i @From_String()
    Data.i @ZapLeadZeroes()
    Data.i @Zero()
    Data.i @One()
    Data.i @Absolute()
    Data.i @IsEqual()
    Data.i @IsGreaterThan()
    Data.i @IsPositive()
    Data.i @Positive()
    Data.i @Negative()
    Data.i @Plus()
    Data.i @Minus()
    Data.i @Add()
    Data.i @Substract()
    Data.i @Product()
    Data.i @Multiply()
    Data.i @Halve()
    Data.i @Double()
    Data.i @Increment()
    Data.i @Decrement()
    Data.i @Square()
    Data.i @Power()
    Data.i @Divide()
    Data.i @Factorial()
    Data.i @Fibonacci()
    Data.i @Randomize()
    Data.i @ReadVogelsNumberFormat()
    Data.i @WriteVogelsNumberFormat()
    Data.i @Free()
    END_METHODS:
  EndDataSection
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test ZapLeadZeroes"
  Debug ""
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("000000000123456789987654321123456789987654321")
  Debug NumA\To_String(3)
  NumA\ZapLeadZeroes()
  Debug NumA\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Swapping"
  Debug ""
  
  NumA\Zero()
  Debug "A = " + NumA\To_String(3)
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("123456789")
  Debug "B = " + NumB\To_String(3)
  Debug ""
  NumA\Swapping(NumB)
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  Debug ""
  Debug "Swapping pointers"
  Swap NumA, NumB
  Debug ""
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Plus / Minus"
  Debug ""
  
  One.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1")
  Two.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2")
  
  X.VogelsNumberFormat::VNF = VogelsNumberFormat::New("12345678987654321")
  Y.VogelsNumberFormat::VNF = VogelsNumberFormat::New("4321")
  
  X_Plus_Y.VogelsNumberFormat::VNF = X\Plus(Y)
  Debug X_Plus_Y\To_String(3) + " = " + X\To_String(3) + " + " + Y\To_String(3)
  
  X_Minus_Y.VogelsNumberFormat::VNF = X\Minus(Y)
  Debug X_Minus_Y\To_String(3) + " = " + X\To_String(3) + " - " + Y\To_String(3) 
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Add / Substract"
  Debug ""
  
  Z.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  MZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  Z\Add(X)
  Z\Add(Y)
  
  Debug "0 + " + X\To_String(3) + " + " + Y\To_String(3) + " = " + Z\To_String(3)
  
  MZ\Add(X)
  MZ\Substract(Y)  
  
  Debug "0 + " + X\To_String(3) + " - " + Y\To_String(3) + " = " + MZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Product"
  Debug ""
  
  X_Two.VogelsNumberFormat::VNF = X\Product(Two)
  Two_X.VogelsNumberFormat::VNF = Two\Product(X)
  
  Debug X_Two\To_String(3)
  Debug Two_X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Multiply"
  Debug ""
  
  X\Multiply(Two)
  Debug X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Square"
  Debug ""
  
  Six.VogelsNumberFormat::VNF = VogelsNumberFormat::New("6")
  
  Six\Square()
  Debug "6^2 = " + Six\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Power"
  Debug ""
  
  Five.VogelsNumberFormat::VNF = VogelsNumberFormat::New("5")
  
  FivePowerFive.VogelsNumberFormat::VNF = Five\Power(5)
  Debug "5^5 = " + FivePowerFive\To_String(3)
  
  TwoPower256.VogelsNumberFormat::VNF = Two\Power(256)
  TwoPower256\Substract(One)
  
  Debug "2^256 - 1 = " + TwoPower256\To_String(6)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Factorial"
  Debug ""
  
  Factorial.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FactorialID = 5 To 50
    Factorial\Factorial(FactorialID)
    Debug Str(FactorialID) + "! = " + Factorial\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Fibonacci"
  Debug ""
  
  Fibonacci.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FibonacciID = 1 To 50
    Fibonacci\Fibonacci(FibonacciID)
    Debug Str(FibonacciID) + " -> " + Fibonacci\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Randomize"
  Debug ""
  
  Random.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Random\Randomize(15, 4)
  Debug Random\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Halve"
  Debug ""
  
  NumZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1000000001")
  Residue2.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Debug "NumZ -> " + NumZ\To_String(3)
  NumZ\Halve(Residue2)
  Debug "NumZ -> " + NumZ\To_String(3)
  Debug "Residue -> " + Residue2\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Double"
  Debug ""
  
  NumZ\Double()
  Debug "NumZ -> " + NumZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Decrement / Increment"
  Debug ""
  
  NumZZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("0")
  Debug NumZZ\To_String(0)
  
  For Index = 0 To 4
    NumZZ\Decrement()
    Debug NumZZ\To_String(0)
  Next
  
  For Index = 0 To 4
    NumZZ\Increment()
    Debug NumZZ\To_String(0)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Divide"
  Debug ""
  
  Var00.q = 987654321
  Var01.q = 12345
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var00))
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var01))
  Residue.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer.VogelsNumberFormat::VNF = NumA\Divide(NumB, Residue)
  Debug "Answer -> " + Answer\To_String(0) + " -> " + Str(Var00 / Var01)
  Debug "Remainer -> " + Residue\To_String(0) + " -> " + Str(Var00 % Var01)
  
  NumAA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("999999999999999999999999999999")
  NumBB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2354783624532")
  Residue3.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer3.VogelsNumberFormat::VNF = NumAA\Divide(NumBB, Residue3)
  Debug "Answer -> " + Answer3\To_String(0)
  Debug "Remainer -> " + Residue3\To_String(0)
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
The Stone Age did not end due to a shortage of stones !
User avatar
jacdelad
Enthusiast
Enthusiast
Posts: 349
Joined: Wed Feb 03, 2021 12:46 pm
Location: Planet Riesa
Contact:

Re: VogelsNumberFormat - OOP

Post by jacdelad »

I get a compiler error on line 659 on 6.0 Beta 6:

Code: Select all

        *Error\b = Error
The following variable has no assigned structure: *Error
PureBasic 6.0/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800+/32GB RAM/Radeon 7770 OC/3TB SSD/70TB HDD
Synology DS920+/20GB RAM/38TB
User avatar
StarBootics
Addict
Addict
Posts: 823
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: VogelsNumberFormat - OOP

Post by StarBootics »

jacdelad wrote: Mon May 16, 2022 4:48 am I get a compiler error on line 659 on 6.0 Beta 6:

Code: Select all

        *Error\b = Error
The following variable has no assigned structure: *Error
Thanks for reporting the error. There is a corrected version (V1.3.3)

best regards
StarBootics

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : VogelsNumberFormat
; File Name : VogelsNumberFormat - OOP.pb
; File version: 1.3.3
; Programming : OK
; Programmed by : StarBootics
; Date : November 9th, 2020
; Last Update : May 16th, 2022
; PureBasic code : V6.00 Beta 7
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Based on the code from Guimauve's which itself is based on 
;    the original code by Michael Vogel.
;
; 2. The division algorithm is based on explainations found on 
;    this website :
;
;    http://justinparrtech.com/JustinParr-Tech/home/
;
;    Do a search with the keywords "INTEGER DIVISION"
;
;    Or you can watch on YouTube the video "Simple Algorithm for 
;    Arbitrary-Precision Integer Division".
; 
;    https://www.youtube.com/watch?v=6bpLYxk9TUQ
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule VogelsNumberFormat
  
  #CORRECT = 0
  #UNDEFINED = -1
  #INFINITIVE = -2
  #OVERFLOW = -3
  #DIVISION_BY_ZERO = -4
  #NOT_IMPLEMENTED = -5
  
  Interface VNF
    
    GetStatus.w()
    Set(*Other)
    Reset()
    Copy.i()
    Swapping(*Other)
    To_String.s(Group.i = 0)
    From_String(P_String.s)
    ZapLeadZeroes()
    Zero()
    One()
    Absolute()
    IsEqual.b(*Other, Abs.b = 0)
    IsGreaterThan.b(*Other, Abs.b = 0)
    IsPositive.b()
    Positive()
    Negative()
    Plus.i(*Other)
    Minus.i(*Other)
    Add(*Other)
    Subtract(*Other)
    Product.i(*Other)
    Multiply(*Other)
    Halve(*Residue = #Null)
    Double()
    Increment()
    Decrement()
    Square()
    Power.i(Exponent.l)
    Divide.i(*Divisor, *Residue)
    Factorial(Value.l)
    Fibonacci(Value.l)
    Randomize(MaximumDigitCount.l, MinimumDigitCount.l = 0)
    ReadVogelsNumberFormat(FileID.i)
    WriteVogelsNumberFormat(FileID.i)
    Free()
    
  EndInterface
  
  Declare.i New(P_String.s = "0")
  
EndDeclareModule

Module VogelsNumberFormat
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Internal Constants declaration <<<<<
  
  #NEGATIVE = 1
  #POSITIVE = 0
  
  #LIMB_SIZE = 9
  #RADIX = 1000000000
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structure declaration <<<<<

  Structure Private_Members
    
    VirtualTable.i
    Status.w
    Sign.w
    List Limbs.q()
    
  EndStructure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Getter <<<<<

  Procedure.w GetStatus(*This.Private_Members)
    
    ProcedureReturn *This\Status
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Setter <<<<<
  
  Procedure Set(*This.Private_Members, *Other.Private_Members)
    
    *This\Status = *Other\Status
    *This\Sign = *Other\Sign
    CopyList(*Other\Limbs(), *This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Reset operator <<<<<

  Procedure Reset(*This.Private_Members)
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    ClearList(*This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Copy operatror <<<<<

  Procedure.i Copy(*This.Private_Members)
    
    *Copy.Private_Members = AllocateStructure(Private_Members)
    *Copy\VirtualTable = ?START_METHODS
    
    *Copy\Status = *This\Status
    *Copy\Sign = *This\Sign
    
    CopyList(*This\Limbs(), *Copy\Limbs())

    ProcedureReturn *Copy
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Swapping operator <<<<<

  Procedure Swapping(*This.Private_Members, *Other.Private_Members)

    Swap *This\Status, *Other\Status
    Swap *This\Sign, *Other\Sign
    
    NewList TempThis.q()
    NewList TempOther.q()
    
    CopyList(*This\Limbs(), TempThis())
    CopyList(*Other\Limbs(), TempOther())
    
    CopyList(TempOther(), *This\Limbs())
    CopyList(TempThis(), *Other\Limbs())
    
    FreeList(TempThis())
    FreeList(TempOther())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Error operator (Private) <<<<<
  
  Procedure Private_Error(*This.Private_Members, type, stype)
    
    If type >= 0
      type = stype
    EndIf
    
    *This\Status = type
    Debug "ERROR " + Str(type)
    
    ProcedureReturn Type
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The To_String transformation operator <<<<<
  
  Procedure.s To_String(*This.Private_Members, Group.i = 0)
    
    If *This\Status < #CORRECT
      
      Select *This\Status
          
        Case #UNDEFINED
          VFN_2_String.s = "Undefined"
          
        Case #INFINITIVE
          VFN_2_String = "Infinitive"
          If *This\Sign
            VFN_2_String = "Minus " + VFN_2_String
          EndIf
          
        Case #OVERFLOW
          VFN_2_String = "Overflow"
          
        Case #NOT_IMPLEMENTED
          VFN_2_String = "Not Implemented"
          
        Case #DIVISION_BY_ZERO
          VFN_2_String = "Division by zero"
          
      EndSelect
      
      ProcedureReturn VFN_2_String
      
    Else
      
      If LastElement(*This\Limbs())
        
        VFN_2_String + Str(*This\Limbs())
        
        While PreviousElement(*This\Limbs())
          VFN_2_String + RSet(Str(*This\Limbs()), #LIMB_SIZE, "0")
        Wend
        
      Else
        VFN_2_String + "0"
      EndIf
      
      If Group <= 0
        
        If *This\Sign
          FormatedNumber.s = "-" + VFN_2_String
        Else
          FormatedNumber = VFN_2_String
        EndIf
        
      ElseIf Group >= 1
        
        NumberLen = Len(VFN_2_String) 
        Start = NumberLen % Group 
        FormatedNumber = Left(VFN_2_String, Start) 
        
        CharsID = Start + 1  
        
        While CharsID <= NumberLen - Start 
          FormatedNumber + " " + Mid(VFN_2_String, CharsID, Group) 
          CharsID + Group 
        Wend 
        
        FormatedNumber = LTrim(FormatedNumber) 
        
        If *This\Sign
          FormatedNumber = "-" + FormatedNumber
        EndIf
        
      EndIf
      
      ProcedureReturn FormatedNumber
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The From_String transformation operator <<<<<
  
  Procedure From_String(*This.Private_Members, P_String.s)
    
    Reset(*This)

    *This\Sign = #POSITIVE
    
    If FindString(P_String, " ")
      P_String = RemoveString(P_String, " ")  
    EndIf
    
    NumID = Len(P_String) - #LIMB_SIZE
    
    While NumID > 0
      AddElement(*This\Limbs())
      *This\Limbs() = Val(Mid(P_String, NumID + 1, #LIMB_SIZE))
      NumID - #LIMB_SIZE
    Wend
    
    NumID = Val(Mid(P_String, 1, 9 + NumID))
    
    If NumID < 0
      *This\Sign = #NEGATIVE
      NumID = -NumID
    EndIf
    
    AddElement(*This\Limbs())
    *This\Limbs() = NumID
    *This\Status = #CORRECT
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ZapLeadZeroes operator <<<<<
  
  Procedure ZapLeadZeroes(*This.Private_Members)
    
    ; Strip leading zeros (000.000.000)
    
    If LastElement(*This\Limbs())
      
      Exit_Condition.b = #False 
      
      While Exit_Condition = #False
        
        If *This\Limbs() = 0
          
          DeleteElement(*This\Limbs())
          
          If LastElement(*This\Limbs()) = #Null
            Exit_Condition = #True
          EndIf
          
        ElseIf *This\Limbs() <> 0
          Exit_Condition = #True
        EndIf
        
      Wend
      
    EndIf
    
    If ListSize(*This\Limbs()) = 0
      AddElement(*This\Limbs())
      *This\Limbs() = 0
      *This\Status = #CORRECT
      *This\Sign = #POSITIVE
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Zero operator <<<<<
  
  Procedure Zero(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 0
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The One operator <<<<<
  
  Procedure One(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 1
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Absolute operator <<<<<
  
  Procedure Absolute(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsEqual test operator <<<<<
  
  Procedure.b IsEqual(*This.Private_Members, *Other.Private_Members, Abs.b = 0)
    
    If ListSize(*This\Limbs()) <> ListSize(*Other\Limbs())
      
      ProcedureReturn #False
      
    ElseIf (Abs = 0) And (*This\Sign <> *Other\Sign)
      
      ProcedureReturn #False
      
    Else
      
      FirstElement(*Other\Limbs())
      
      ForEach *This\Limbs()
        
        If *This\Limbs() <> *Other\Limbs()
          ProcedureReturn #False
        EndIf
        
        NextElement(*Other\Limbs())
        
      Next
      
      ProcedureReturn #True
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsGreaterThan test operator <<<<<
  
  Procedure.b IsGreaterThan(*This.Private_Members, *Other.Private_Members, Abs.b = 0)
    
    If *This = *Other
      ProcedureReturn #False
    EndIf
    
    If Abs = 0
      
      If *This\Sign <> *Other\Sign
        
        If *This\Sign = #POSITIVE
          ProcedureReturn #True
        Else
          ProcedureReturn #False
        EndIf
        
      Else
        
        If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
          ProcedureReturn #True
        ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
          ProcedureReturn #False
        Else
          
          LastElement(*This\Limbs())
          LastElement(*Other\Limbs())
          
          Repeat
            
            Delta = *This\Limbs() - *Other\Limbs()
            
            If Delta > 0
              ProcedureReturn #True
            ElseIf Delta < 0
              ProcedureReturn #False
            EndIf
            
            PreviousElement(*Other\Limbs())
            
          Until PreviousElement(*This\Limbs()) = #Null
          
          ProcedureReturn #False
          
        EndIf
        
      EndIf
      
    Else
      
      If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
        ProcedureReturn #True
      ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
        ProcedureReturn #False
      Else
        
        LastElement(*This\Limbs())
        LastElement(*Other\Limbs())
        
        Repeat
          
          Delta = *This\Limbs() - *Other\Limbs()
          
          If Delta > 0
            ProcedureReturn #True
          ElseIf Delta < 0
            ProcedureReturn #False
          EndIf
          
          PreviousElement(*Other\Limbs())
          
        Until PreviousElement(*This\Limbs()) = #Null
        
        ProcedureReturn #False
        
      EndIf
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsPositive test operator <<<<<
  
  Procedure.b IsPositive(*This.Private_Members)
    
    If *This\Sign = #POSITIVE
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Positive operator <<<<<
  
  Procedure Positive(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Negative operator <<<<<
  
  Procedure Negative(*This.Private_Members)
    
    *This\Sign = #NEGATIVE
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Add operator (Private) <<<<<
  
  Procedure Private_Add(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    *Result\Sign = *CacheA\Sign
    
    If ListSize(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
      Swap *CacheA, *CacheB
    EndIf
    
    ForEach *CacheA\Limbs()
      
      s + *CacheA\Limbs()
      
      If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
        SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
        s + *CacheB\Limbs()
      EndIf
      
      AddElement(*Result\Limbs())
      *Result\Limbs() = s % #RADIX
      s / #RADIX
      
    Next
    
    If s <> 0
      AddElement(*Result\Limbs())
      *Result\Limbs() = s 
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Substract operator (Private) <<<<<
  
  Procedure Private_Sub(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    
    If *CacheA\Sign <> *CacheB\Sign
      *CacheB\Sign = *CacheA\Sign
      Private_Add(*Result, *CacheA, *CacheB)
    Else
      
      If IsGreaterThan(*CacheA, *CacheB, #True)
        *Result\Sign = *CacheA\Sign
      Else
        Swap *CacheA, *CacheB
        *Result\Sign = #NEGATIVE - *CacheA\Sign
      EndIf
      
      ForEach *CacheA\Limbs()
        
        s + *CacheA\Limbs()
        
        If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
          SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
          s - *CacheB\Limbs()
        EndIf
        
        If s < 0
          AddElement(*Result\Limbs())
          *Result\Limbs() = s + #RADIX
          s = -1
        Else
          AddElement(*Result\Limbs())
          *Result\Limbs() = s
          s = 0
        EndIf
        
      Next
      
    EndIf
    
  EndProcedure  
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Plus operator : N = T + A <<<<<
  
  Procedure.i Plus(*This.Private_Members, *Other.Private_Members)
   
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)

    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Private_Error(*New, *CacheA\Status, *CacheB\Status)

    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*New, *CacheA, *CacheB)
      Else
        Private_Add(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Minus operator : N = T - A <<<<<
  
  Procedure.i Minus(*This.Private_Members, *Other.Private_Members)
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Private_Error(*New, *CacheA\Status, *CacheB\Status)

    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*New, *CacheA, *CacheB)
      Else
        Private_Sub(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Add operator : T = T + A <<<<<
  
  Procedure Add(*This.Private_Members, *Other.Private_Members)
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*This, *CacheA, *CacheB)
      Else
        Private_Add(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Subtract operator : T = T - A <<<<<
  
  Procedure Subtract(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*This, *CacheA, *CacheB)
      Else
        Private_Sub(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Product operator : N = T * A  <<<<<
  
  Procedure.i Product(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Private_Error(*New, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs())) - 1
        AddElement(*New\Limbs())
        *New\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*New\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *New\Limbs()
          
          CarryCounter = 0
          
          If s >= #RADIX
            
            ;Debug "s >= #RADIX"
            
            While s >= #RADIX
              
              ;Debug "s -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              Carry.q = s / #RADIX
              s % #RADIX 
              
              ;Debug "Carry -> " + Str(Carry) + " -> " + Str(Bool(Carry >= #RADIX))
              ;Debug "s corrected -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              
              SelectElement(*New\Limbs(), C_Index + CarryCounter)
              *New\Limbs() = s
              SelectElement(*New\Limbs(), C_Index + CarryCounter + 1)
              s = *New\Limbs() + s / #RADIX + Carry
              
              ;Debug "Next s -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              ;Debug "CarryCounter -> " + Str(CarryCounter)
              
              If s < #RADIX
                *New\Limbs() = s
              EndIf
              
              CarryCounter + 1
              
            Wend
            
          Else
            
            *New\Limbs() = s
            
          EndIf
          
          ;ForEach *New\Limbs()
          ;  Debug "*New\Limbs() -> " + Str(*New\Limbs())
          ;Next
          
          ;Debug ""
          
        Next
        
      Next
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Multiply operator : T = T * A <<<<<
  
  Procedure Multiply(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Private_Error(*This, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs())) - 1
        AddElement(*This\Limbs())
        *This\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*This\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *This\Limbs()
          
          CarryCounter = 0
          
          If s >= #RADIX
            
            While s >= #RADIX
              
              Carry.q = s / #RADIX
              s % #RADIX 
              
              SelectElement(*This\Limbs(), C_Index + CarryCounter)
              *This\Limbs() = s
              SelectElement(*This\Limbs(), C_Index + CarryCounter + 1)
              s = *This\Limbs() + s / #RADIX + Carry
              
              If s < #RADIX
                *This\Limbs() = s
              EndIf
              
              CarryCounter + 1
              
            Wend
            
          Else
            
            *This\Limbs() = s
            
          EndIf
          
        Next
        
      Next
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Halve operator <<<<<
  
  Procedure Halve(*This.Private_Members, *Residue.Private_Members = #Null)
    
    LastElement(*This\Limbs())
    
    While ListIndex(*This\Limbs()) > 0

      If *This\Limbs() & 1 = 1
        PushListPosition(*This\Limbs())
        SelectElement(*This\Limbs(), ListIndex(*This\Limbs()) - 1)
        *This\Limbs() + #Radix
        PopListPosition(*This\Limbs())
      EndIf
      
      *This\Limbs() = *This\Limbs() >> 1
      PreviousElement(*This\Limbs())
      
    Wend 
    
    FirstElement(*This\Limbs())
    
    If *Residue <> #Null
      If *This\Limbs() & 1 = 1
        One(*Residue)
      Else
        Zero(*Residue)
      EndIf
      
      *Residue\Sign = *This\Sign
    EndIf 
    
    *This\Limbs() = *This\Limbs() >> 1
    
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Double operator <<<<<
  
  Procedure Double(*This.Private_Members)
    
    ForEach *This\Limbs()

      If *This\Limbs() > (#Radix >> 1) - 1
        *This\Limbs() << 1 - #Radix + Carry
        Carry = 1
      Else
        *This\Limbs() << 1 + Carry
        Carry = 0
      EndIf
      
    Next
    
    If Carry = 1
      
      AddElement(*This\Limbs())
      
      For Index = 0 To ListSize(*This\Limbs()) - 2
        
        SelectElement(*This\Limbs(), Index)
        Temp.q = *This\Limbs()
        SelectElement(*This\Limbs(), Index+1)
        *This\Limbs() = Temp
        
      Next
      
      LastElement(*This\Limbs())
      
      *This\Limbs() = 1
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Increment operator <<<<<
  
  Procedure Increment(*This.Private_Members)
    
    *One.Private_Members = New("1")
    Add(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Decrement operator <<<<<
  
  Procedure Decrement(*This.Private_Members)
    
    *One.Private_Members = New("1")
    Subtract(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Square operator <<<<<
  
  Procedure Square(*This.Private_Members)
    
    If ListSize(*This\Limbs()) > 0
      Multiply(*This, *This)
    EndIf  
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Power operator <<<<<
  
  Procedure.i Power(*This.Private_Members, Exponent.l)
    
    Protected z.q = 0, s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    If Exponent < 0
      
      ; a^b | b<0 not implemented for now...
      Private_Error(*New, #NOT_IMPLEMENTED, 0)

    ElseIf ListSize(*This\Limbs()) >= 0
      
      *CacheA.Private_Members = Copy(*This)
      *CacheB.Private_Members = New("1")
      
      If IsPositive(*This) = #False
        Absolute(*CacheA)
        If Exponent & 1 
          *CacheB\Sign = #NEGATIVE
        EndIf
      EndIf
      
      While Exponent > 0
        
        s = 1 << z
        
        If Exponent & s
          
          Multiply(*CacheB, *CacheA)
          Exponent = Exponent - s
          
        EndIf
        
        If Exponent
          Square(*CacheA)
          z = z + 1
        EndIf
        
      Wend
      
      Set(*New, *CacheB)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator (Private) <<<<<
  
  Procedure Private_Divide(*Answer.Private_Members, *Numerator.Private_Members, *Divisor.Private_Members, *Residue.Private_Members = #Null)
    
    Protected Carry.q, Divisor.q, Dividend.q

    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *Numerator\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *Numerator\Status, *Divisor\Status)
    Else
      
      ;// First eliminate the simple case where the divisor is 1 limb
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          
        ElseIf *Divisor\Limbs() = 1 ; Division by +/- 1
          
          *Answer\Status = *Numerator\Status
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          CopyList(*Numerator\Limbs(), *Answer\Limbs())
          
        Else
          
          ClearList(*Answer\Limbs())
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          *Answer\Status = #CORRECT
          
          LastElement(*Numerator\Limbs())
          
          Repeat
            
            Dividend = Carry * #Radix + *Numerator\Limbs()
            
            If Dividend < *Divisor\Limbs()
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = 0
              Carry = Dividend
            Else
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = Dividend / *Divisor\Limbs()
              Carry = Dividend - *Answer\Limbs() * *Divisor\Limbs()
              ;// This is almost free compared to the use of % (Mod)
            EndIf
            
          Until PreviousElement(*Numerator\Limbs()) = #Null
          
          If *Residue <> #Null
            Reset(*Residue)
            AddElement(*Residue\Limbs())
            *Residue\Limbs() = Carry
            *Residue\Sign = *Numerator\Sign
            *Residue\Status = #CORRECT
          EndIf
          
        EndIf
        
      EndIf
      
    EndIf
    
    If *Residue <> #Null
      ZapLeadZeroes(*Residue)
    EndIf
    
    ZapLeadZeroes(*Answer)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator : N = T / A <<<<<
  
  Procedure.i Divide(*This.Private_Members, *Divisor.Private_Members, *Residue.Private_Members)
    
    *Answer.Private_Members = AllocateStructure(Private_Members)
    *Answer\VirtualTable = ?START_METHODS
    
    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *This\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *This\Status, *Divisor\Status)
    Else
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          Zero(*Residue)
          
          ProcedureReturn *Answer
          
        EndIf
        
      EndIf
      
      ZapLeadZeroes(*Divisor)
      
      *One.Private_Members = New("1")
      StringDivisor.s = RemoveString(To_String(*Divisor, 0), "-")
      M.q = Len(StringDivisor) - 1
      *QuickDivisor.Private_Members = New(Left(StringDivisor, 1))
      
      StringNumerator.s = RemoveString(To_String(*This, 0), "-")
      *QuotientCandidate.Private_Members = New()
      
      *CutedNumerator.Private_Members = New(Left(StringNumerator, Len(StringNumerator) - M))
      Private_Divide(*QuotientCandidate, *CutedNumerator, *QuickDivisor)
      
      *Numerator.Private_Members = Copy(*This)
      Absolute(*Numerator)
      
      *ABSDivisor.Private_Members = Copy(*Divisor)
      Absolute(*ABSDivisor)
      
      *R_Over_A.Private_Members = New()
      *Remainder.Private_Members = Plus(*ABSDivisor, *One)
      
      While Exit_Condition = #False
        
        *ABSRemainder.Private_Members = Copy(*Remainder)
        Absolute(*ABSRemainder)
        
        If IsGreaterThan(*ABSRemainder, *ABSDivisor, #True) = #False
          Exit_Condition = #True
        Else
          
          *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
          ;Debug "Q -> " + To_String(*QuotientCandidate, 0)
          ;Debug "D -> " + To_String(*ABSDivisor, 0)
          ;Debug "QxD -> " + To_String(*QxD, 0)
          ;Debug "N -> " + To_String(*Numerator, 0)
          
          Zero(*Remainder)
          Add(*Remainder, *Numerator)
          Subtract(*Remainder, *QxD)
          
          ;Debug "R -> " + To_String(*Remainder, 0)
          
          StringNumerator.s = RemoveString(To_String(*Remainder, 0), "-")
          From_String(*CutedNumerator, Left(StringNumerator, Len(StringNumerator) - M))
          *CutedNumerator\Sign = *Remainder\Sign 
          
          Private_Divide(*R_Over_A, *CutedNumerator, *QuickDivisor)
          ;Debug "R/A -> " + To_String(*R_Over_A, 0)
          
          *Qn.Private_Members = Plus(*QuotientCandidate, *R_Over_A)
          ;Debug "Qn -> " + To_String(*Qn, 0)
          *QnQ.Private_Members = Plus(*QuotientCandidate, *Qn)
          ; Debug "Q + Qn -> " + To_String(*QnQ, 0)
          Zero(*QuotientCandidate)
          Add(*QuotientCandidate, *QnQ)
          Halve(*QuotientCandidate)
          ;Debug "Q -> " + To_String(*QuotientCandidate, 0)
          ; Debug ""
          ; End
          FreeStructure(*QxD)
          FreeStructure(*QnQ)
          FreeStructure(*Qn)
          
        EndIf
        
        FreeStructure(*ABSRemainder)
        ;Delay(250)
        
      Wend 
      
      *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
      Zero(*Remainder)
      Add(*Remainder, *Numerator)
      Subtract(*Remainder, *QxD)
      
      If IsPositive(*Remainder) = #False
        
        Decrement(*QuotientCandidate)
        Add(*Remainder, *ABSDivisor)
        
      EndIf
      
      Set(*Answer, *QuotientCandidate)
      Set(*Residue, *Remainder)
      
      If *Divisor\Sign = *This\Sign
        *Answer\Sign = #POSITIVE
      Else
        *Answer\Sign = #NEGATIVE
      EndIf
      
      *Residue\Sign = *This\Sign
      
      FreeStructure(*QxD)
      FreeStructure(*Numerator)
      FreeStructure(*ABSDivisor)
      FreeStructure(*QuotientCandidate)
      FreeStructure(*Remainder)
      FreeStructure(*QuickDivisor)
      FreeStructure(*One)
      FreeStructure(*R_Over_A)
      FreeStructure(*CutedNumerator)
      
    EndIf
    
    ZapLeadZeroes(*Residue)
    ZapLeadZeroes(*Answer)
    
    ProcedureReturn *Answer
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Factorial calculator <<<<<
  
  Procedure Factorial(*This.Private_Members, Value.l)

    *CacheA.Private_Members = New("1")
    *CacheB.Private_Members = New()
    
    For Index = 2 To Value
      From_String(*CacheB, Str(Index))
      Multiply(*CacheA, *CacheB)
    Next
    
    Set(*This, *CacheA)
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Fibonacci calculator <<<<<
  
  Procedure Fibonacci(*This.Private_Members, Value.l)
    
    *V_u.Private_Members = New("0")
    *V_v.Private_Members = New("1")
    
    For Index = 2 To Value
      
      *V_t.Private_Members = Plus(*V_u, *V_v)
      Set(*V_u, *V_v)
      Set(*V_v, *V_t)
      FreeStructure(*V_t)
      
    Next
    
    Set(*This, *V_v)
    
    FreeStructure(*V_u)
    FreeStructure(*V_v)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Randomize operator <<<<<
  
  Procedure Randomize(*This.Private_Members, MaximumDigitCount.l, MinimumDigitCount.l = 0)
    
    Max = Random(MaximumDigitCount, MinimumDigitCount)
    
    For Index = 0 To Max - 1
      RandomNumber.s = RandomNumber + Str(Random(9))
    Next
    
    From_String(*This, RandomNumber)
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Read in Binary file <<<<<

  Procedure ReadVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    *This\Status = ReadWord(FileID)
    *This\Sign = ReadWord(FileID)
    
    Num_Max.l = ReadLong(FileID) - 1
    
    For NumID = 0 To Num_Max
      AddElement(*This\Limbs())
      *This\Limbs() = ReadQuad(FileID)
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Write in Binary file <<<<<

  Procedure WriteVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    WriteWord(FileID, *This\Status)
    WriteWord(FileID, *This\Sign)
    
    WriteLong(FileID, ListSize(*This\Limbs()))
    
    ForEach *This\Limbs()
      WriteQuad(FileID, *This\Limbs())
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<

  Procedure Free(*This.Private_Members)
    
    FreeStructure(*This)
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<

  Procedure.i New(P_String.s = "0")
    
    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
    
    From_String(*This, P_String)
    
    ProcedureReturn *This
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Virtual Table Entries <<<<<

  DataSection
    START_METHODS:
    Data.i @GetStatus()
    Data.i @Set()
    Data.i @Reset()
    Data.i @Copy()
    Data.i @Swapping()
    Data.i @To_String()
    Data.i @From_String()
    Data.i @ZapLeadZeroes()
    Data.i @Zero()
    Data.i @One()
    Data.i @Absolute()
    Data.i @IsEqual()
    Data.i @IsGreaterThan()
    Data.i @IsPositive()
    Data.i @Positive()
    Data.i @Negative()
    Data.i @Plus()
    Data.i @Minus()
    Data.i @Add()
    Data.i @Subtract()
    Data.i @Product()
    Data.i @Multiply()
    Data.i @Halve()
    Data.i @Double()
    Data.i @Increment()
    Data.i @Decrement()
    Data.i @Square()
    Data.i @Power()
    Data.i @Divide()
    Data.i @Factorial()
    Data.i @Fibonacci()
    Data.i @Randomize()
    Data.i @ReadVogelsNumberFormat()
    Data.i @WriteVogelsNumberFormat()
    Data.i @Free()
    END_METHODS:
  EndDataSection
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test ZapLeadZeroes"
  Debug ""
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("000000000123456789987654321123456789987654321")
  Debug NumA\To_String(3)
  NumA\ZapLeadZeroes()
  Debug NumA\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Swapping"
  Debug ""
  
  NumA\Zero()
  Debug "A = " + NumA\To_String(3)
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("123456789")
  Debug "B = " + NumB\To_String(3)
  Debug ""
  NumA\Swapping(NumB)
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  Debug ""
  Debug "Swapping pointers"
  Swap NumA, NumB
  Debug ""
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Plus / Minus"
  Debug ""
  
  One.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1")
  Two.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2")
  
  X.VogelsNumberFormat::VNF = VogelsNumberFormat::New("12345678987654321")
  Y.VogelsNumberFormat::VNF = VogelsNumberFormat::New("4321")
  
  X_Plus_Y.VogelsNumberFormat::VNF = X\Plus(Y)
  Debug X_Plus_Y\To_String(3) + " = " + X\To_String(3) + " + " + Y\To_String(3)
  
  X_Minus_Y.VogelsNumberFormat::VNF = X\Minus(Y)
  Debug X_Minus_Y\To_String(3) + " = " + X\To_String(3) + " - " + Y\To_String(3) 
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Add / Substract"
  Debug ""
  
  Z.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  MZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  Z\Add(X)
  Z\Add(Y)
  
  Debug "0 + " + X\To_String(3) + " + " + Y\To_String(3) + " = " + Z\To_String(3)
  
  MZ\Add(X)
  MZ\Subtract(Y)  
  
  Debug "0 + " + X\To_String(3) + " - " + Y\To_String(3) + " = " + MZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Product"
  Debug ""
  
  X_Two.VogelsNumberFormat::VNF = X\Product(Two)
  Two_X.VogelsNumberFormat::VNF = Two\Product(X)
  
  Debug X_Two\To_String(3)
  Debug Two_X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Multiply"
  Debug ""
  
  X\Multiply(Two)
  Debug X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Square"
  Debug ""
  
  Six.VogelsNumberFormat::VNF = VogelsNumberFormat::New("6")
  
  Six\Square()
  Debug "6^2 = " + Six\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Power"
  Debug ""
  
  Five.VogelsNumberFormat::VNF = VogelsNumberFormat::New("5")
  
  FivePowerFive.VogelsNumberFormat::VNF = Five\Power(5)
  Debug "5^5 = " + FivePowerFive\To_String(3)
  
  TwoPower256.VogelsNumberFormat::VNF = Two\Power(256)
  TwoPower256\Subtract(One)
  
  Debug "2^256 - 1 = " + TwoPower256\To_String(6)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Factorial"
  Debug ""
  
  Factorial.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FactorialID = 5 To 50
    Factorial\Factorial(FactorialID)
    Debug Str(FactorialID) + "! = " + Factorial\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Fibonacci"
  Debug ""
  
  Fibonacci.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FibonacciID = 1 To 50
    Fibonacci\Fibonacci(FibonacciID)
    Debug Str(FibonacciID) + " -> " + Fibonacci\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Randomize"
  Debug ""
  
  Random.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Random\Randomize(15, 4)
  Debug Random\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Halve"
  Debug ""
  
  NumZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1000000001")
  Residue2.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Debug "NumZ -> " + NumZ\To_String(3)
  NumZ\Halve(Residue2)
  Debug "NumZ -> " + NumZ\To_String(3)
  Debug "Residue -> " + Residue2\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Double"
  Debug ""
  
  NumZ\Double()
  Debug "NumZ -> " + NumZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Decrement / Increment"
  Debug ""
  
  NumZZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("0")
  Debug NumZZ\To_String(0)
  
  For Index = 0 To 4
    NumZZ\Decrement()
    Debug NumZZ\To_String(0)
  Next
  
  For Index = 0 To 4
    NumZZ\Increment()
    Debug NumZZ\To_String(0)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Divide"
  Debug ""
  
  Var00.q = 987654321
  Var01.q = 12345
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var00))
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var01))
  Residue.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer.VogelsNumberFormat::VNF = NumA\Divide(NumB, Residue)
  Debug "Answer -> " + Answer\To_String(0) + " -> " + Str(Var00 / Var01)
  Debug "Remainer -> " + Residue\To_String(0) + " -> " + Str(Var00 % Var01)
  
  NumAA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("999999999999999999999999999999")
  NumBB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2354783624532")
  Residue3.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer3.VogelsNumberFormat::VNF = NumAA\Divide(NumBB, Residue3)
  Debug "Answer -> " + Answer3\To_String(0)
  Debug "Remainer -> " + Residue3\To_String(0)
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Last edited by StarBootics on Mon May 16, 2022 12:56 pm, edited 1 time in total.
The Stone Age did not end due to a shortage of stones !
User avatar
jacdelad
Enthusiast
Enthusiast
Posts: 349
Joined: Wed Feb 03, 2021 12:46 pm
Location: Planet Riesa
Contact:

Re: VogelsNumberFormat - OOP

Post by jacdelad »

Great, and it works. I couldn't find out what the error was, beside the obvious, that it is assigned to a structure. Was it meant to read a byte from an address or something? I'd like to understand.
PureBasic 6.0/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800+/32GB RAM/Radeon 7770 OC/3TB SSD/70TB HDD
Synology DS920+/20GB RAM/38TB
User avatar
StarBootics
Addict
Addict
Posts: 823
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: VogelsNumberFormat - OOP

Post by StarBootics »

jacdelad wrote: Mon May 16, 2022 6:18 am Great, and it works. I couldn't find out what the error was, beside the obvious, that it is assigned to a structure. Was it meant to read a byte from an address or something? I'd like to understand.
It was a parameter like that :

Code: Select all

*Error.Byte = #Null
Some procedure use to have this parameter the retrieve error but I have found this solution little overdoing since the Resulting number will end up with the error also. So I took the decision to remove all of them. And I miss some part of the code because I always have two version of every code I post on the forum and sometime I'm not runnig the code on the forum and this is not good.

Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
jacdelad
Enthusiast
Enthusiast
Posts: 349
Joined: Wed Feb 03, 2021 12:46 pm
Location: Planet Riesa
Contact:

Re: VogelsNumberFormat - OOP

Post by jacdelad »

Ah, thanks for explaining.
PureBasic 6.0/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800+/32GB RAM/Radeon 7770 OC/3TB SSD/70TB HDD
Synology DS920+/20GB RAM/38TB
User avatar
jacdelad
Enthusiast
Enthusiast
Posts: 349
Joined: Wed Feb 03, 2021 12:46 pm
Location: Planet Riesa
Contact:

Re: VogelsNumberFormat - OOP

Post by jacdelad »

I'm still trying to understand how it works, but this may take some time.

I have two questions:

1. Can you implement something to choose whether I want the output number grouped when using the function "To_String"? Maybe a second parameter to choose between nothing, " " and "." (or a symbol of my choice).

2. When calculating the Fibonacci sequence the numbers are always recalculated from the start. Does ist make sense to store the results you already have (maybe in a map?). This would speed up calculation of greater Fibonacci numbers. I know, this may take a lot of space, so maybe this could be optional too.

Also I'm aware that I can do this by myself, but maybe these additions are good enough to implement them for everyone (also, you could do this much faster).
PureBasic 6.0/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800+/32GB RAM/Radeon 7770 OC/3TB SSD/70TB HDD
Synology DS920+/20GB RAM/38TB
User avatar
StarBootics
Addict
Addict
Posts: 823
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: VogelsNumberFormat - OOP

Post by StarBootics »

jacdelad wrote: Mon May 16, 2022 8:04 am 1. Can you implement something to choose whether I want the output number grouped when using the function "To_String"? Maybe a second parameter to choose between nothing, " " and "." (or a symbol of my choice).
The problem is if do that to format the number into a string with any possible separator character I will have problems to convert it back with From_String method. That's why I make an arbitrary decision to use only space as separator. Maybe I could add the separator character as parameter to both methods.
jacdelad wrote: Mon May 16, 2022 8:04 am 2. When calculating the Fibonacci sequence the numbers are always recalculated from the start. Does it make sense to store the results you already have (maybe in a map?). This would speed up calculation of greater Fibonacci numbers. I know, this may take a lot of space, so maybe this could be optional too.
The technique is called Dynamic programming and of course it's possible. That being said I have added the Fibonacci sequence to demonstrate the possibility of the library because the sequence grows extremely fast out of the capability of a quad. The same goes for Factorial.
jacdelad wrote: Mon May 16, 2022 8:04 am Also I'm aware that I can do this by myself, but maybe these additions are good enough to implement them for everyone (also, you could do this much faster).
So for the question #1 I will think about what I can do. But for question #2 I don't think the dynamic programming part of the calculation should be part of the library because it is too specific to the problem you might want to solve. Keep in mind that this library is meant to be a large integer type like Quad are but with more capacity with some convenient methods to work with it . How you use them is up to you.

Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
StarBootics
Addict
Addict
Posts: 823
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: VogelsNumberFormat - OOP

Post by StarBootics »

Hello everyone,

Some more correction to be more C backend friendly and some modification to the To_String() and From_String() methods and the consrtructor.

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : VogelsNumberFormat
; File Name : VogelsNumberFormat - OOP.pb
; File version: 1.3.4
; Programming : OK
; Programmed by : StarBootics
; Date : November 9th, 2020
; Last Update : May 16th, 2022
; PureBasic code : V6.00 Beta 7
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes
;
; 1. Based on the code from Guimauve's which itself is based on 
;    the original code by Michael Vogel.
;
; 2. The division algorithm is based on explainations found on 
;    this website :
;
;    http://justinparrtech.com/JustinParr-Tech/home/
;
;    Do a search with the keywords "INTEGER DIVISION"
;
;    Or you can watch on YouTube the video "Simple Algorithm for 
;    Arbitrary-Precision Integer Division".
; 
;    https://www.youtube.com/watch?v=6bpLYxk9TUQ
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule VogelsNumberFormat
  
  #CORRECT = 0
  #UNDEFINED = -1
  #INFINITIVE = -2
  #OVERFLOW = -3
  #DIVISION_BY_ZERO = -4
  #NOT_IMPLEMENTED = -5
  
  Interface VNF
    
    GetStatus.w()
    Set(*Other)
    Reset()
    Copy.i()
    Swapping(*Other)
    To_String.s(Group.i = 0, Separator.s = " ")
    From_String(String.s, Separator.s = " ")
    ZapLeadZeroes()
    Zero()
    One()
    Absolute()
    IsEqual.i(*Other, Abs.i = 0)
    IsGreaterThan.i(*Other, Abs.i = 0)
    IsPositive.i()
    Positive()
    Negative()
    Plus.i(*Other)
    Minus.i(*Other)
    Add(*Other)
    Subtract(*Other)
    Product.i(*Other)
    Multiply(*Other)
    Halve(*Residue = #Null)
    Double()
    Increment()
    Decrement()
    Square()
    Power.i(Exponent.l)
    Divide.i(*Divisor, *Residue)
    Factorial(Value.l)
    Fibonacci(Value.l)
    Randomize(MaximumDigitCount.l, MinimumDigitCount.l = 0)
    ReadVogelsNumberFormat(FileID.i)
    WriteVogelsNumberFormat(FileID.i)
    Free()
    
  EndInterface
  
  Declare.i New(String.s = "0", Separator.s = " ")
  
EndDeclareModule

Module VogelsNumberFormat
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Internal Constants declaration <<<<<
  
  #NEGATIVE = 1
  #POSITIVE = 0
  
  #LIMB_SIZE = 9
  #RADIX = 1000000000
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structure declaration <<<<<

  Structure Private_Members
    
    VirtualTable.i
    Status.w
    Sign.w
    List Limbs.q()
    
  EndStructure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Getter <<<<<

  Procedure.w GetStatus(*This.Private_Members)
    
    ProcedureReturn *This\Status
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Setter <<<<<
  
  Procedure Set(*This.Private_Members, *Other.Private_Members)
    
    *This\Status = *Other\Status
    *This\Sign = *Other\Sign
    CopyList(*Other\Limbs(), *This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Reset operator <<<<<

  Procedure Reset(*This.Private_Members)
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    ClearList(*This\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Copy operatror <<<<<

  Procedure.i Copy(*This.Private_Members)
    
    *Copy.Private_Members = AllocateStructure(Private_Members)
    *Copy\VirtualTable = ?START_METHODS
    
    *Copy\Status = *This\Status
    *Copy\Sign = *This\Sign
    
    CopyList(*This\Limbs(), *Copy\Limbs())

    ProcedureReturn *Copy
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Swapping operator <<<<<

  Procedure Swapping(*This.Private_Members, *Other.Private_Members)

    Swap *This\Status, *Other\Status
    Swap *This\Sign, *Other\Sign
    
    NewList TempThis.q()
    NewList TempOther.q()
    
    CopyList(*This\Limbs(), TempThis())
    CopyList(*Other\Limbs(), TempOther())
    
    CopyList(TempOther(), *This\Limbs())
    CopyList(TempThis(), *Other\Limbs())
    
    FreeList(TempThis())
    FreeList(TempOther())
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Error operator (Private) <<<<<
  
  Procedure Private_Error(*This.Private_Members, type, stype)
    
    If type >= 0
      type = stype
    EndIf
    
    *This\Status = type
    Debug "ERROR " + Str(type)
    
    ProcedureReturn Type
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The To_String transformation operator <<<<<
  
  Procedure.s To_String(*This.Private_Members, Group.i = 0, Separator.s = " ")
    
    If *This\Status < #CORRECT
      
      Select *This\Status
          
        Case #UNDEFINED
          VFN_2_String.s = "Undefined"
          
        Case #INFINITIVE
          VFN_2_String = "Infinitive"
          If *This\Sign
            VFN_2_String = "Minus " + VFN_2_String
          EndIf
          
        Case #OVERFLOW
          VFN_2_String = "Overflow"
          
        Case #NOT_IMPLEMENTED
          VFN_2_String = "Not Implemented"
          
        Case #DIVISION_BY_ZERO
          VFN_2_String = "Division by zero"
          
      EndSelect
      
      ProcedureReturn VFN_2_String
      
    Else
      
      If LastElement(*This\Limbs())
        
        VFN_2_String + Str(*This\Limbs())
        
        While PreviousElement(*This\Limbs())
          VFN_2_String + RSet(Str(*This\Limbs()), #LIMB_SIZE, "0")
        Wend
        
      Else
        VFN_2_String + "0"
      EndIf
      
      If Group <= 0
        
        If *This\Sign
          FormatedNumber.s = "-" + VFN_2_String
        Else
          FormatedNumber = VFN_2_String
        EndIf
        
      ElseIf Group >= 1
        
        NumberLen = Len(VFN_2_String) 
        Start = NumberLen % Group 
        FormatedNumber = Left(VFN_2_String, Start) 
        
        CharsID = Start + 1  
        
        While CharsID <= NumberLen - Start 
          FormatedNumber + Separator + Mid(VFN_2_String, CharsID, Group) 
          CharsID + Group 
        Wend 
        
        FormatedNumber = LTrim(FormatedNumber) 
        
        If *This\Sign
          FormatedNumber = "-" + FormatedNumber
        EndIf
        
      EndIf
      
      ProcedureReturn FormatedNumber
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The From_String transformation operator <<<<<
  
  Procedure From_String(*This.Private_Members, String.s, Separator.s = " ")
    
    Reset(*This)

    *This\Sign = #POSITIVE
    
    If FindString(String, Separator)
      String = RemoveString(String, Separator)  
    EndIf
    
    NumID = Len(String) - #LIMB_SIZE
    
    While NumID > 0
      AddElement(*This\Limbs())
      *This\Limbs() = Val(Mid(String, NumID + 1, #LIMB_SIZE))
      NumID - #LIMB_SIZE
    Wend
    
    NumID = Val(Mid(String, 1, 9 + NumID))
    
    If NumID < 0
      *This\Sign = #NEGATIVE
      NumID = -NumID
    EndIf
    
    AddElement(*This\Limbs())
    *This\Limbs() = NumID
    *This\Status = #CORRECT
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ZapLeadZeroes operator <<<<<
  
  Procedure ZapLeadZeroes(*This.Private_Members)
    
    ; Strip leading zeros (000.000.000)
    
    If LastElement(*This\Limbs())
      
      Exit_Condition.i = #False 
      
      While Exit_Condition = #False
        
        If *This\Limbs() = 0
          
          DeleteElement(*This\Limbs())
          
          If LastElement(*This\Limbs()) = #Null
            Exit_Condition = #True
          EndIf
          
        ElseIf *This\Limbs() <> 0
          Exit_Condition = #True
        EndIf
        
      Wend
      
    EndIf
    
    If ListSize(*This\Limbs()) = 0
      AddElement(*This\Limbs())
      *This\Limbs() = 0
      *This\Status = #CORRECT
      *This\Sign = #POSITIVE
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Zero operator <<<<<
  
  Procedure Zero(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 0
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The One operator <<<<<
  
  Procedure One(*This.Private_Members)
    
    ClearList(*This\Limbs())
    
    *This\Status = #CORRECT
    *This\Sign = #POSITIVE
    
    AddElement(*This\Limbs())
    *This\Limbs() = 1
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Absolute operator <<<<<
  
  Procedure Absolute(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsEqual test operator <<<<<
  
  Procedure.i IsEqual(*This.Private_Members, *Other.Private_Members, Abs.i = 0)
    
    If ListSize(*This\Limbs()) <> ListSize(*Other\Limbs())
      
      ProcedureReturn #False
      
    ElseIf (Abs = 0) And (*This\Sign <> *Other\Sign)
      
      ProcedureReturn #False
      
    Else
      
      FirstElement(*Other\Limbs())
      
      ForEach *This\Limbs()
        
        If *This\Limbs() <> *Other\Limbs()
          ProcedureReturn #False
        EndIf
        
        NextElement(*Other\Limbs())
        
      Next
      
      ProcedureReturn #True
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsGreaterThan test operator <<<<<
  
  Procedure.i IsGreaterThan(*This.Private_Members, *Other.Private_Members, Abs.i = 0)
    
    If *This = *Other
      ProcedureReturn #False
    EndIf
    
    If Abs = 0
      
      If *This\Sign <> *Other\Sign
        
        If *This\Sign = #POSITIVE
          ProcedureReturn #True
        Else
          ProcedureReturn #False
        EndIf
        
      Else
        
        If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
          ProcedureReturn #True
        ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
          ProcedureReturn #False
        Else
          
          LastElement(*This\Limbs())
          LastElement(*Other\Limbs())
          
          Repeat
            
            Delta = *This\Limbs() - *Other\Limbs()
            
            If Delta > 0
              ProcedureReturn #True
            ElseIf Delta < 0
              ProcedureReturn #False
            EndIf
            
            PreviousElement(*Other\Limbs())
            
          Until PreviousElement(*This\Limbs()) = #Null
          
          ProcedureReturn #False
          
        EndIf
        
      EndIf
      
    Else
      
      If ListSize(*This\Limbs()) > ListSize(*Other\Limbs())
        ProcedureReturn #True
      ElseIf ListSize(*This\Limbs()) < ListSize(*Other\Limbs())
        ProcedureReturn #False
      Else
        
        LastElement(*This\Limbs())
        LastElement(*Other\Limbs())
        
        Repeat
          
          Delta = *This\Limbs() - *Other\Limbs()
          
          If Delta > 0
            ProcedureReturn #True
          ElseIf Delta < 0
            ProcedureReturn #False
          EndIf
          
          PreviousElement(*Other\Limbs())
          
        Until PreviousElement(*This\Limbs()) = #Null
        
        ProcedureReturn #False
        
      EndIf
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The IsPositive test operator <<<<<
  
  Procedure.i IsPositive(*This.Private_Members)
    
    If *This\Sign = #POSITIVE
      ProcedureReturn #True
    Else
      ProcedureReturn #False
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Positive operator <<<<<
  
  Procedure Positive(*This.Private_Members)
    
    *This\Sign = #POSITIVE
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Negative operator <<<<<
  
  Procedure Negative(*This.Private_Members)
    
    *This\Sign = #NEGATIVE
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Add operator (Private) <<<<<
  
  Procedure Private_Add(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    *Result\Sign = *CacheA\Sign
    
    If ListSize(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
      Swap *CacheA, *CacheB
    EndIf
    
    ForEach *CacheA\Limbs()
      
      s + *CacheA\Limbs()
      
      If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
        SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
        s + *CacheB\Limbs()
      EndIf
      
      AddElement(*Result\Limbs())
      *Result\Limbs() = s % #RADIX
      s / #RADIX
      
    Next
    
    If s <> 0
      AddElement(*Result\Limbs())
      *Result\Limbs() = s 
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Substract operator (Private) <<<<<
  
  Procedure Private_Sub(*Result.Private_Members, *CacheA.Private_Members, *CacheB.Private_Members)
    
    Protected s.q
    
    If *CacheA\Sign <> *CacheB\Sign
      *CacheB\Sign = *CacheA\Sign
      Private_Add(*Result, *CacheA, *CacheB)
    Else
      
      If IsGreaterThan(*CacheA, *CacheB, #True)
        *Result\Sign = *CacheA\Sign
      Else
        Swap *CacheA, *CacheB
        *Result\Sign = #NEGATIVE - *CacheA\Sign
      EndIf
      
      ForEach *CacheA\Limbs()
        
        s + *CacheA\Limbs()
        
        If ListIndex(*CacheA\Limbs()) < ListSize(*CacheB\Limbs())
          SelectElement(*CacheB\Limbs(), ListIndex(*CacheA\Limbs()))
          s - *CacheB\Limbs()
        EndIf
        
        If s < 0
          AddElement(*Result\Limbs())
          *Result\Limbs() = s + #RADIX
          s = -1
        Else
          AddElement(*Result\Limbs())
          *Result\Limbs() = s
          s = 0
        EndIf
        
      Next
      
    EndIf
    
  EndProcedure  
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Plus operator : N = T + A <<<<<
  
  Procedure.i Plus(*This.Private_Members, *Other.Private_Members)
   
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)

    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Private_Error(*New, *CacheA\Status, *CacheB\Status)

    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*New, *CacheA, *CacheB)
      Else
        Private_Add(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Minus operator : N = T - A <<<<<
  
  Procedure.i Minus(*This.Private_Members, *Other.Private_Members)
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Private_Error(*New, *CacheA\Status, *CacheB\Status)

    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*New, *CacheA, *CacheB)
      Else
        Private_Sub(*New, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Add operator : T = T + A <<<<<
  
  Procedure Add(*This.Private_Members, *Other.Private_Members)
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Sub(*This, *CacheA, *CacheB)
      Else
        Private_Add(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Subtract operator : T = T - A <<<<<
  
  Procedure Subtract(*This.Private_Members, *Other.Private_Members)
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      
      Error = Private_Error(*This, *CacheA\Status, *CacheB\Status)
      
    Else
      
      If *CacheA\Sign <> *CacheB\Sign
        *CacheB\Sign = *CacheA\Sign
        Private_Add(*This, *CacheA, *CacheB)
      Else
        Private_Sub(*This, *CacheA, *CacheB)
      EndIf
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn Error
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Product operator : N = T * A  <<<<<
  
  Procedure.i Product(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Private_Error(*New, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs())) - 1
        AddElement(*New\Limbs())
        *New\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*New\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *New\Limbs()
          
          CarryCounter = 0
          
          If s >= #RADIX
            
            ;Debug "s >= #RADIX"
            
            While s >= #RADIX
              
              ;Debug "s -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              Carry.q = s / #RADIX
              s % #RADIX 
              
              ;Debug "Carry -> " + Str(Carry) + " -> " + Str(Bool(Carry >= #RADIX))
              ;Debug "s corrected -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              
              SelectElement(*New\Limbs(), C_Index + CarryCounter)
              *New\Limbs() = s
              SelectElement(*New\Limbs(), C_Index + CarryCounter + 1)
              s = *New\Limbs() + s / #RADIX + Carry
              
              ;Debug "Next s -> " + Str(s) + " -> " + Str(Bool(s >= #RADIX))
              ;Debug "CarryCounter -> " + Str(CarryCounter)
              
              If s < #RADIX
                *New\Limbs() = s
              EndIf
              
              CarryCounter + 1
              
            Wend
            
          Else
            
            *New\Limbs() = s
            
          EndIf
          
          ;ForEach *New\Limbs()
          ;  Debug "*New\Limbs() -> " + Str(*New\Limbs())
          ;Next
          
          ;Debug ""
          
        Next
        
      Next
      
      ZapLeadZeroes(*New)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Multiply operator : T = T * A <<<<<
  
  Procedure Multiply(*This.Private_Members, *Other.Private_Members)
    
    Protected s.q
    
    *CacheA.Private_Members = Copy(*This)
    *CacheB.Private_Members = Copy(*Other)
    
    Reset(*This)
    
    If *CacheA\Status < #CORRECT Or *CacheB\Status < #CORRECT
      Private_Error(*This, *CacheA\Status, *CacheB\Status)
    Else
      
      *This\Sign = (*CacheA\Sign + *CacheB\Sign) & 1
      
      For Index = 0 To (ListSize(*CacheA\Limbs()) + ListSize(*CacheB\Limbs())) - 1
        AddElement(*This\Limbs())
        *This\Limbs() = 0
      Next 
      
      ForEach *CacheA\Limbs()
        
        ForEach *CacheB\Limbs()
          
          C_Index = ListIndex(*CacheA\Limbs()) + ListIndex(*CacheB\Limbs())
          
          SelectElement(*This\Limbs(), C_Index)
          s = *CacheA\Limbs() * *CacheB\Limbs() + *This\Limbs()
          
          CarryCounter = 0
          
          If s >= #RADIX
            
            While s >= #RADIX
              
              Carry.q = s / #RADIX
              s % #RADIX 
              
              SelectElement(*This\Limbs(), C_Index + CarryCounter)
              *This\Limbs() = s
              SelectElement(*This\Limbs(), C_Index + CarryCounter + 1)
              s = *This\Limbs() + s / #RADIX + Carry
              
              If s < #RADIX
                *This\Limbs() = s
              EndIf
              
              CarryCounter + 1
              
            Wend
            
          Else
            
            *This\Limbs() = s
            
          EndIf
          
        Next
        
      Next
      
      ZapLeadZeroes(*This)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Halve operator <<<<<
  
  Procedure Halve(*This.Private_Members, *Residue.Private_Members = #Null)
    
    LastElement(*This\Limbs())
    
    While ListIndex(*This\Limbs()) > 0

      If *This\Limbs() & 1 = 1
        PushListPosition(*This\Limbs())
        SelectElement(*This\Limbs(), ListIndex(*This\Limbs()) - 1)
        *This\Limbs() + #Radix
        PopListPosition(*This\Limbs())
      EndIf
      
      *This\Limbs() = *This\Limbs() >> 1
      PreviousElement(*This\Limbs())
      
    Wend 
    
    FirstElement(*This\Limbs())
    
    If *Residue <> #Null
      
      If *This\Limbs() & 1 = 1
        One(*Residue)
      Else
        Zero(*Residue)
      EndIf
      
      *Residue\Sign = *This\Sign
      
    EndIf 
    
    *This\Limbs() = *This\Limbs() >> 1
    
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Double operator <<<<<
  
  Procedure Double(*This.Private_Members)
    
    ForEach *This\Limbs()

      If *This\Limbs() > (#Radix >> 1) - 1
        *This\Limbs() << 1 - #Radix + Carry
        Carry = 1
      Else
        *This\Limbs() << 1 + Carry
        Carry = 0
      EndIf
      
    Next
    
    If Carry = 1
      
      AddElement(*This\Limbs())
      
      For Index = 0 To ListSize(*This\Limbs()) - 2
        
        SelectElement(*This\Limbs(), Index)
        Temp.q = *This\Limbs()
        SelectElement(*This\Limbs(), Index+1)
        *This\Limbs() = Temp
        
      Next
      
      LastElement(*This\Limbs())
      
      *This\Limbs() = 1
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Increment operator <<<<<
  
  Procedure Increment(*This.Private_Members)
    
    *One.Private_Members = New("1")
    Add(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Decrement operator <<<<<
  
  Procedure Decrement(*This.Private_Members)
    
    *One.Private_Members = New("1")
    Subtract(*This, *One)
    FreeStructure(*One)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Square operator <<<<<
  
  Procedure Square(*This.Private_Members)
    
    If ListSize(*This\Limbs()) > 0
      Multiply(*This, *This)
    EndIf  
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Power operator <<<<<
  
  Procedure.i Power(*This.Private_Members, Exponent.l)
    
    Protected z.q = 0, s.q
    
    *New.Private_Members = AllocateStructure(Private_Members)
    *New\VirtualTable = ?START_METHODS
    
    If Exponent < 0
      
      ; a^b | b<0 not implemented for now...
      Private_Error(*New, #NOT_IMPLEMENTED, 0)

    ElseIf ListSize(*This\Limbs()) >= 0
      
      *CacheA.Private_Members = Copy(*This)
      *CacheB.Private_Members = New("1")
      
      If IsPositive(*This) = #False
        Absolute(*CacheA)
        If Exponent & 1 
          *CacheB\Sign = #NEGATIVE
        EndIf
      EndIf
      
      While Exponent > 0
        
        s = 1 << z
        
        If Exponent & s
          
          Multiply(*CacheB, *CacheA)
          Exponent = Exponent - s
          
        EndIf
        
        If Exponent
          Square(*CacheA)
          z = z + 1
        EndIf
        
      Wend
      
      Set(*New, *CacheB)
      
    EndIf
    
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
    ProcedureReturn *New
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator (Private) <<<<<
  
  Procedure Private_Divide(*Answer.Private_Members, *Numerator.Private_Members, *Divisor.Private_Members, *Residue.Private_Members = #Null)
    
    Protected Carry.q, Divisor.q, Dividend.q

    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *Numerator\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *Numerator\Status, *Divisor\Status)
    Else
      
      ;// First eliminate the simple case where the divisor is 1 limb
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          
        ElseIf *Divisor\Limbs() = 1 ; Division by +/- 1
          
          *Answer\Status = *Numerator\Status
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          CopyList(*Numerator\Limbs(), *Answer\Limbs())
          
        Else
          
          ClearList(*Answer\Limbs())
          
          If *Divisor\Sign = *Numerator\Sign
            *Answer\Sign = #POSITIVE
          Else
            *Answer\Sign = #NEGATIVE
          EndIf
          
          *Answer\Status = #CORRECT
          
          LastElement(*Numerator\Limbs())
          
          Repeat
            
            Dividend = Carry * #Radix + *Numerator\Limbs()
            
            If Dividend < *Divisor\Limbs()
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = 0
              Carry = Dividend
            Else
              InsertElement(*Answer\Limbs())
              *Answer\Limbs() = Dividend / *Divisor\Limbs()
              Carry = Dividend - *Answer\Limbs() * *Divisor\Limbs()
              ;// This is almost free compared to the use of % (Mod)
            EndIf
            
          Until PreviousElement(*Numerator\Limbs()) = #Null
          
          If *Residue <> #Null
            Reset(*Residue)
            AddElement(*Residue\Limbs())
            *Residue\Limbs() = Carry
            *Residue\Sign = *Numerator\Sign
            *Residue\Status = #CORRECT
          EndIf
          
        EndIf
        
      EndIf
      
    EndIf
    
    If *Residue <> #Null
      ZapLeadZeroes(*Residue)
    EndIf
    
    ZapLeadZeroes(*Answer)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Divide operator : N = T / A <<<<<
  
  Procedure.i Divide(*This.Private_Members, *Divisor.Private_Members, *Residue.Private_Members)
    
    *Answer.Private_Members = AllocateStructure(Private_Members)
    *Answer\VirtualTable = ?START_METHODS
    
    ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    If *This\Status < #CORRECT Or *Divisor\Status < #CORRECT
      Private_Error(*Answer, *This\Status, *Divisor\Status)
    Else
      
      If ListSize(*Divisor\Limbs()) = 1
        
        FirstElement(*Divisor\Limbs())
        
        If *Divisor\Limbs() = 0
          
          *Answer\Status = #DIVISION_BY_ZERO
          Zero(*Residue)
          
          ProcedureReturn *Answer
          
        EndIf
        
      EndIf
      
      ZapLeadZeroes(*Divisor)
      
      *One.Private_Members = New("1")
      StringDivisor.s = RemoveString(To_String(*Divisor, 0), "-")
      M.q = Len(StringDivisor) - 1
      *QuickDivisor.Private_Members = New(Left(StringDivisor, 1))
      
      StringNumerator.s = RemoveString(To_String(*This, 0), "-")
      *QuotientCandidate.Private_Members = New()
      
      *CutedNumerator.Private_Members = New(Left(StringNumerator, Len(StringNumerator) - M))
      Private_Divide(*QuotientCandidate, *CutedNumerator, *QuickDivisor)
      
      *Numerator.Private_Members = Copy(*This)
      Absolute(*Numerator)
      
      *ABSDivisor.Private_Members = Copy(*Divisor)
      Absolute(*ABSDivisor)
      
      *R_Over_A.Private_Members = New()
      *Remainder.Private_Members = Plus(*ABSDivisor, *One)
      
      While Exit_Condition = #False
        
        *ABSRemainder.Private_Members = Copy(*Remainder)
        Absolute(*ABSRemainder)
        
        If IsGreaterThan(*ABSRemainder, *ABSDivisor, #True) = #False
          Exit_Condition = #True
        Else
          
          *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
          ;Debug "Q -> " + To_String(*QuotientCandidate, 0)
          ;Debug "D -> " + To_String(*ABSDivisor, 0)
          ;Debug "QxD -> " + To_String(*QxD, 0)
          ;Debug "N -> " + To_String(*Numerator, 0)
          
          Zero(*Remainder)
          Add(*Remainder, *Numerator)
          Subtract(*Remainder, *QxD)
          
          ;Debug "R -> " + To_String(*Remainder, 0)
          
          StringNumerator.s = RemoveString(To_String(*Remainder, 0), "-")
          From_String(*CutedNumerator, Left(StringNumerator, Len(StringNumerator) - M))
          *CutedNumerator\Sign = *Remainder\Sign 
          
          Private_Divide(*R_Over_A, *CutedNumerator, *QuickDivisor)
          ;Debug "R/A -> " + To_String(*R_Over_A, 0)
          
          *Qn.Private_Members = Plus(*QuotientCandidate, *R_Over_A)
          ;Debug "Qn -> " + To_String(*Qn, 0)
          *QnQ.Private_Members = Plus(*QuotientCandidate, *Qn)
          ; Debug "Q + Qn -> " + To_String(*QnQ, 0)
          Zero(*QuotientCandidate)
          Add(*QuotientCandidate, *QnQ)
          Halve(*QuotientCandidate)
          ;Debug "Q -> " + To_String(*QuotientCandidate, 0)
          ; Debug ""
          ; End
          FreeStructure(*QxD)
          FreeStructure(*QnQ)
          FreeStructure(*Qn)
          
        EndIf
        
        FreeStructure(*ABSRemainder)
        ;Delay(250)
        
      Wend 
      
      *QxD.Private_Members = Product(*QuotientCandidate, *ABSDivisor)
      Zero(*Remainder)
      Add(*Remainder, *Numerator)
      Subtract(*Remainder, *QxD)
      
      If IsPositive(*Remainder) = #False
        
        Decrement(*QuotientCandidate)
        Add(*Remainder, *ABSDivisor)
        
      EndIf
      
      Set(*Answer, *QuotientCandidate)
      Set(*Residue, *Remainder)
      
      If *Divisor\Sign = *This\Sign
        *Answer\Sign = #POSITIVE
      Else
        *Answer\Sign = #NEGATIVE
      EndIf
      
      *Residue\Sign = *This\Sign
      
      FreeStructure(*QxD)
      FreeStructure(*Numerator)
      FreeStructure(*ABSDivisor)
      FreeStructure(*QuotientCandidate)
      FreeStructure(*Remainder)
      FreeStructure(*QuickDivisor)
      FreeStructure(*One)
      FreeStructure(*R_Over_A)
      FreeStructure(*CutedNumerator)
      
    EndIf
    
    ZapLeadZeroes(*Residue)
    ZapLeadZeroes(*Answer)
    
    ProcedureReturn *Answer
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Factorial calculator <<<<<
  
  Procedure Factorial(*This.Private_Members, Value.l)

    *CacheA.Private_Members = New("1")
    *CacheB.Private_Members = New()
    
    For Index = 2 To Value
      From_String(*CacheB, Str(Index))
      Multiply(*CacheA, *CacheB)
    Next
    
    Set(*This, *CacheA)
    FreeStructure(*CacheA)
    FreeStructure(*CacheB)
    
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Fibonacci calculator <<<<<
  
  Procedure Fibonacci(*This.Private_Members, Value.l)
    
    *V_u.Private_Members = New("0")
    *V_v.Private_Members = New("1")
    
    For Index = 2 To Value
      
      *V_t.Private_Members = Plus(*V_u, *V_v)
      Set(*V_u, *V_v)
      Set(*V_v, *V_t)
      FreeStructure(*V_t)
      
    Next
    
    Set(*This, *V_v)
    
    FreeStructure(*V_u)
    FreeStructure(*V_v)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Randomize operator <<<<<
  
  Procedure Randomize(*This.Private_Members, MaximumDigitCount.l, MinimumDigitCount.l = 0)
    
    Max = Random(MaximumDigitCount, MinimumDigitCount)
    
    For Index = 0 To Max - 1
      RandomNumber.s = RandomNumber + Str(Random(9))
    Next
    
    From_String(*This, RandomNumber)
    ZapLeadZeroes(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Read in Binary file <<<<<

  Procedure ReadVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    *This\Status = ReadWord(FileID)
    *This\Sign = ReadWord(FileID)
    
    Num_Max.l = ReadLong(FileID) - 1
    
    For NumID = 0 To Num_Max
      AddElement(*This\Limbs())
      *This\Limbs() = ReadQuad(FileID)
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Write in Binary file <<<<<

  Procedure WriteVogelsNumberFormat(*This.Private_Members, FileID.i)
    
    WriteWord(FileID, *This\Status)
    WriteWord(FileID, *This\Sign)
    
    WriteLong(FileID, ListSize(*This\Limbs()))
    
    ForEach *This\Limbs()
      WriteQuad(FileID, *This\Limbs())
    Next
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<

  Procedure Free(*This.Private_Members)
    
    FreeStructure(*This)
    
  EndProcedure

  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<

  Procedure.i New(String.s = "0", Separator.s = " ")
    
    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
    
    From_String(*This, String, Separator)
    
    ProcedureReturn *This
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Virtual Table Entries <<<<<

  DataSection
    START_METHODS:
    Data.i @GetStatus()
    Data.i @Set()
    Data.i @Reset()
    Data.i @Copy()
    Data.i @Swapping()
    Data.i @To_String()
    Data.i @From_String()
    Data.i @ZapLeadZeroes()
    Data.i @Zero()
    Data.i @One()
    Data.i @Absolute()
    Data.i @IsEqual()
    Data.i @IsGreaterThan()
    Data.i @IsPositive()
    Data.i @Positive()
    Data.i @Negative()
    Data.i @Plus()
    Data.i @Minus()
    Data.i @Add()
    Data.i @Subtract()
    Data.i @Product()
    Data.i @Multiply()
    Data.i @Halve()
    Data.i @Double()
    Data.i @Increment()
    Data.i @Decrement()
    Data.i @Square()
    Data.i @Power()
    Data.i @Divide()
    Data.i @Factorial()
    Data.i @Fibonacci()
    Data.i @Randomize()
    Data.i @ReadVogelsNumberFormat()
    Data.i @WriteVogelsNumberFormat()
    Data.i @Free()
    END_METHODS:
  EndDataSection
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test ZapLeadZeroes"
  Debug ""
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("000000000123456789987654321123456789987654321")
  Debug NumA\To_String(3, ",")
  NumA\ZapLeadZeroes()
  Debug NumA\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Swapping"
  Debug ""
  
  NumA\Zero()
  Debug "A = " + NumA\To_String(3)
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("123456789")
  Debug "B = " + NumB\To_String(3)
  Debug ""
  NumA\Swapping(NumB)
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  Debug ""
  Debug "Swapping pointers"
  Swap NumA, NumB
  Debug ""
  Debug "A = " + NumA\To_String(3)
  Debug "B = " + NumB\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Plus / Minus"
  Debug ""
  
  One.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1")
  Two.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2")
  
  X.VogelsNumberFormat::VNF = VogelsNumberFormat::New("12345678987654321")
  Y.VogelsNumberFormat::VNF = VogelsNumberFormat::New("4321")
  
  X_Plus_Y.VogelsNumberFormat::VNF = X\Plus(Y)
  Debug X_Plus_Y\To_String(3) + " = " + X\To_String(3) + " + " + Y\To_String(3)
  
  X_Minus_Y.VogelsNumberFormat::VNF = X\Minus(Y)
  Debug X_Minus_Y\To_String(3) + " = " + X\To_String(3) + " - " + Y\To_String(3) 
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Add / Substract"
  Debug ""
  
  Z.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  MZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  Z\Add(X)
  Z\Add(Y)
  
  Debug "0 + " + X\To_String(3) + " + " + Y\To_String(3) + " = " + Z\To_String(3)
  
  MZ\Add(X)
  MZ\Subtract(Y)  
  
  Debug "0 + " + X\To_String(3) + " - " + Y\To_String(3) + " = " + MZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Product"
  Debug ""
  
  X_Two.VogelsNumberFormat::VNF = X\Product(Two)
  Two_X.VogelsNumberFormat::VNF = Two\Product(X)
  
  Debug X_Two\To_String(3)
  Debug Two_X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Multiply"
  Debug ""
  
  X\Multiply(Two)
  Debug X\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Square"
  Debug ""
  
  Six.VogelsNumberFormat::VNF = VogelsNumberFormat::New("6")
  
  Six\Square()
  Debug "6^2 = " + Six\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Power"
  Debug ""
  
  Five.VogelsNumberFormat::VNF = VogelsNumberFormat::New("5")
  
  FivePowerFive.VogelsNumberFormat::VNF = Five\Power(5)
  Debug "5^5 = " + FivePowerFive\To_String(3)
  
  TwoPower256.VogelsNumberFormat::VNF = Two\Power(256)
  TwoPower256\Subtract(One)
  
  Debug "2^256 - 1 = " + TwoPower256\To_String(6)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Factorial"
  Debug ""
  
  Factorial.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FactorialID = 5 To 50
    Factorial\Factorial(FactorialID)
    Debug Str(FactorialID) + "! = " + Factorial\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Fibonacci"
  Debug ""
  
  Fibonacci.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  
  For FibonacciID = 50 To 150
    Fibonacci\Fibonacci(FibonacciID)
    Debug Str(FibonacciID) + " -> " + Fibonacci\To_String(3)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Randomize"
  Debug ""
  
  Random.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Random\Randomize(15, 4)
  Debug Random\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Halve"
  Debug ""
  
  NumZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("1000000001")
  Residue2.VogelsNumberFormat::VNF = VogelsNumberFormat::New()
  Debug "NumZ -> " + NumZ\To_String(3)
  NumZ\Halve(Residue2)
  Debug "NumZ -> " + NumZ\To_String(3)
  Debug "Residue -> " + Residue2\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Double"
  Debug ""
  
  NumZ\Double()
  Debug "NumZ -> " + NumZ\To_String(3)
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Decrement / Increment"
  Debug ""
  
  NumZZ.VogelsNumberFormat::VNF = VogelsNumberFormat::New("0")
  Debug NumZZ\To_String(0)
  
  For Index = 0 To 4
    NumZZ\Decrement()
    Debug NumZZ\To_String(0)
  Next
  
  For Index = 0 To 4
    NumZZ\Increment()
    Debug NumZZ\To_String(0)
  Next
  
  Debug ""
  Debug "; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  Debug "; Test Divide"
  Debug ""
  
  Var00.q = 987654321
  Var01.q = 12345
  
  NumA.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var00))
  NumB.VogelsNumberFormat::VNF = VogelsNumberFormat::New(Str(Var01))
  Residue.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer.VogelsNumberFormat::VNF = NumA\Divide(NumB, Residue)
  Debug "Answer -> " + Answer\To_String(0) + " -> " + Str(Var00 / Var01)
  Debug "Remainer -> " + Residue\To_String(0) + " -> " + Str(Var00 % Var01)
  
  NumAA.VogelsNumberFormat::VNF = VogelsNumberFormat::New("999999999999999999999999999999")
  NumBB.VogelsNumberFormat::VNF = VogelsNumberFormat::New("2354783624532")
  Residue3.VogelsNumberFormat::VNF = VogelsNumberFormat::New("")
  
  Answer3.VogelsNumberFormat::VNF = NumAA\Divide(NumBB, Residue3)
  Debug "Answer -> " + Answer3\To_String(0)
  Debug "Remainer -> " + Residue3\To_String(0)
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
Post Reply