Task: Zeckendorf arithmetic




Go: package main

import (
    "fmt"
    "strings"
)

var (
    dig  = [3]string{"00", "01", "10"}
    dig1 = [3]string{"", "1", "10"}
)

type Zeckendorf struct{ dVal, dLen int }

func NewZeck(x string) *Zeckendorf {
    z := new(Zeckendorf)
    if x == "" {
        x = "0"
    }
    q := 1
    i := len(x) - 1
    z.dLen = i / 2
    for ; i >= 0; i-- {
        z.dVal += int(x[i]-'0') * q
        q *= 2
    }
    return z
}

func (z *Zeckendorf) a(i int) {
    for ; ; i++ {
        if z.dLen < i {
            z.dLen = i
        }
        j := (z.dVal >> uint(i*2)) & 3
        switch j {
        case 0, 1:
            return
        case 2:
            if ((z.dVal >> (uint(i+1) * 2)) & 1) != 1 {
                return
            }
            z.dVal += 1 << uint(i*2+1)
            return
        case 3:
            z.dVal &= ^(3 << uint(i*2))
            z.b((i + 1) * 2)
        }
    }
}

func (z *Zeckendorf) b(pos int) {
    if pos == 0 {
        z.Inc()
        return
    }
    if ((z.dVal >> uint(pos)) & 1) == 0 {
        z.dVal += 1 << uint(pos)
        z.a(pos / 2)
        if pos > 1 {
            z.a(pos/2 - 1)
        }
    } else {
        z.dVal &= ^(1 << uint(pos))
        z.b(pos + 1)
        temp := 1
        if pos > 1 {
            temp = 2
        }
        z.b(pos - temp)
    }
}

func (z *Zeckendorf) c(pos int) {
    if ((z.dVal >> uint(pos)) & 1) == 1 {
        z.dVal &= ^(1 << uint(pos))
        return
    }
    z.c(pos + 1)
    if pos > 0 {
        z.b(pos - 1)
    } else {
        z.Inc()
    }
}

func (z *Zeckendorf) Inc() {
    z.dVal++
    z.a(0)
}

func (z1 *Zeckendorf) PlusAssign(z2 *Zeckendorf) {
    for gn := 0; gn < (z2.dLen+1)*2; gn++ {
        if ((z2.dVal >> uint(gn)) & 1) == 1 {
            z1.b(gn)
        }
    }
}

func (z1 *Zeckendorf) MinusAssign(z2 *Zeckendorf) {
    for gn := 0; gn < (z2.dLen+1)*2; gn++ {
        if ((z2.dVal >> uint(gn)) & 1) == 1 {
            z1.c(gn)
        }
    }

    for z1.dLen > 0 && ((z1.dVal>>uint(z1.dLen*2))&3) == 0 {
        z1.dLen--
    }
}

func (z1 *Zeckendorf) TimesAssign(z2 *Zeckendorf) {
    na := z2.Copy()
    nb := z2.Copy()
    nr := new(Zeckendorf)
    for i := 0; i <= (z1.dLen+1)*2; i++ {
        if ((z1.dVal >> uint(i)) & 1) > 0 {
            nr.PlusAssign(nb)
        }
        nt := nb.Copy()
        nb.PlusAssign(na)
        na = nt.Copy()
    }
    z1.dVal = nr.dVal
    z1.dLen = nr.dLen
}

func (z *Zeckendorf) Copy() *Zeckendorf {
    return &Zeckendorf{z.dVal, z.dLen}
}

func (z1 *Zeckendorf) Compare(z2 *Zeckendorf) int {
    switch {
    case z1.dVal < z2.dVal:
        return -1
    case z1.dVal > z2.dVal:
        return 1
    default:
        return 0
    }
}

func (z *Zeckendorf) String() string {
    if z.dVal == 0 {
        return "0"
    }
    var sb strings.Builder
    sb.WriteString(dig1[(z.dVal>>uint(z.dLen*2))&3])
    for i := z.dLen - 1; i >= 0; i-- {
        sb.WriteString(dig[(z.dVal>>uint(i*2))&3])
    }
    return sb.String()
}

func main() {
    fmt.Println("Addition:")
    g := NewZeck("10")
    g.PlusAssign(NewZeck("10"))
    fmt.Println(g)
    g.PlusAssign(NewZeck("10"))
    fmt.Println(g)
    g.PlusAssign(NewZeck("1001"))
    fmt.Println(g)
    g.PlusAssign(NewZeck("1000"))
    fmt.Println(g)
    g.PlusAssign(NewZeck("10101"))
    fmt.Println(g)

    fmt.Println("\nSubtraction:")
    g = NewZeck("1000")
    g.MinusAssign(NewZeck("101"))
    fmt.Println(g)
    g = NewZeck("10101010")
    g.MinusAssign(NewZeck("1010101"))
    fmt.Println(g)

    fmt.Println("\nMultiplication:")
    g = NewZeck("1001")
    g.TimesAssign(NewZeck("101"))
    fmt.Println(g)
    g = NewZeck("101010")
    g.PlusAssign(NewZeck("101"))
    fmt.Println(g)
}





VB: Imports System.Text

Module Module1

    Class Zeckendorf
        Implements IComparable(Of Zeckendorf)

        Private Shared ReadOnly dig As String() = {"00", "01", "10"}
        Private Shared ReadOnly dig1 As String() = {"", "1", "10"}

        Private dVal As Integer = 0
        Private dLen As Integer = 0

        Public Sub New(Optional x As String = "0")
            Dim q = 1
            Dim i = x.Length - 1
            dLen = i \ 2

            Dim z = Asc("0")
            While i >= 0
                Dim a = Asc(x(i))
                dVal += (a - z) * q
                q *= 2
                i -= 1
            End While
        End Sub

        Private Sub A(n As Integer)
            Dim i = n
            While True
                If dLen < i Then
                    dLen = i
                End If
                Dim j = (dVal >> (i * 2)) And 3
                If j = 0 OrElse j = 1 Then
                    Return
                ElseIf j = 2 Then
                    If ((dVal >> ((i + 1) * 2)) And 1) <> 1 Then
                        Return
                    End If
                    dVal += 1 << (i * 2 + 1)
                    Return
                ElseIf j = 3 Then
                    Dim temp = 3 << (i * 2)
                    temp = temp Xor -1
                    dVal = dVal And temp
                    B((i + 1) * 2)
                End If
                i += 1
            End While
        End Sub

        Private Sub B(pos As Integer)
            If pos = 0 Then
                Inc()
                Return
            End If
            If ((dVal >> pos) And 1) = 0 Then
                dVal += 1 << pos
                A(pos \ 2)
                If pos > 1 Then
                    A(pos \ 2 - 1)
                End If
            Else
                Dim temp = 1 << pos
                temp = temp Xor -1
                dVal = dVal And temp
                B(pos + 1)
                B(pos - If(pos > 1, 2, 1))
            End If
        End Sub

        Private Sub C(pos As Integer)
            If ((dVal >> pos) And 1) = 1 Then
                Dim temp = 1 << pos
                temp = temp Xor -1
                dVal = dVal And temp
                Return
            End If
            C(pos + 1)
            If pos > 0 Then
                B(pos - 1)
            Else
                Inc()
            End If
        End Sub

        Public Function Inc() As Zeckendorf
            dVal += 1
            A(0)
            Return Me
        End Function

        Public Function Copy() As Zeckendorf
            Dim z As New Zeckendorf With {
                .dVal = dVal,
                .dLen = dLen
            }
            Return z
        End Function

        Public Sub PlusAssign(other As Zeckendorf)
            Dim gn = 0
            While gn < (other.dLen + 1) * 2
                If ((other.dVal >> gn) And 1) = 1 Then
                    B(gn)
                End If
                gn += 1
            End While
        End Sub

        Public Sub MinusAssign(other As Zeckendorf)
            Dim gn = 0
            While gn < (other.dLen + 1) * 2
                If ((other.dVal >> gn) And 1) = 1 Then
                    C(gn)
                End If
                gn += 1
            End While
            While (((dVal >> dLen * 2) And 3) = 0) OrElse dLen = 0
                dLen -= 1
            End While
        End Sub

        Public Sub TimesAssign(other As Zeckendorf)
            Dim na = other.Copy
            Dim nb = other.Copy
            Dim nt As Zeckendorf
            Dim nr As New Zeckendorf
            Dim i = 0
            While i < (dLen + 1) * 2
                If ((dVal >> i) And 1) > 0 Then
                    nr.PlusAssign(nb)
                End If
                nt = nb.Copy
                nb.PlusAssign(na)
                na = nt.Copy
                i += 1
            End While
            dVal = nr.dVal
            dLen = nr.dLen
        End Sub

        Public Function CompareTo(other As Zeckendorf) As Integer Implements IComparable(Of Zeckendorf).CompareTo
            Return dVal.CompareTo(other.dVal)
        End Function

        Public Overrides Function ToString() As String
            If dVal = 0 Then
                Return "0"
            End If

            Dim idx = (dVal >> (dLen * 2)) And 3
            Dim sb As New StringBuilder(dig1(idx))
            Dim i = dLen - 1
            While i >= 0
                idx = (dVal >> (i * 2)) And 3
                sb.Append(dig(idx))
                i -= 1
            End While
            Return sb.ToString
        End Function
    End Class

    Sub Main()
        Console.WriteLine("Addition:")
        Dim g As New Zeckendorf("10")
        g.PlusAssign(New Zeckendorf("10"))
        Console.WriteLine(g)
        g.PlusAssign(New Zeckendorf("10"))
        Console.WriteLine(g)
        g.PlusAssign(New Zeckendorf("1001"))
        Console.WriteLine(g)
        g.PlusAssign(New Zeckendorf("1000"))
        Console.WriteLine(g)
        g.PlusAssign(New Zeckendorf("10101"))
        Console.WriteLine(g)
        Console.WriteLine()

        Console.WriteLine("Subtraction:")
        g = New Zeckendorf("1000")
        g.MinusAssign(New Zeckendorf("101"))
        Console.WriteLine(g)
        g = New Zeckendorf("10101010")
        g.MinusAssign(New Zeckendorf("1010101"))
        Console.WriteLine(g)
        Console.WriteLine()

        Console.WriteLine("Multiplication:")
        g = New Zeckendorf("1001")
        g.TimesAssign(New Zeckendorf("101"))
        Console.WriteLine(g)
        g = New Zeckendorf("101010")
        g.PlusAssign(New Zeckendorf("101"))
        Console.WriteLine(g)
    End Sub

End Module