Task: Imaginary base numbers


C++: #include <algorithm>
#include <complex>
#include <iomanip>
#include <iostream>

std::complex<double> inv(const std::complex<double>& c) {
    double denom = c.real() * c.real() + c.imag() * c.imag();
    return std::complex<double>(c.real() / denom, -c.imag() / denom);
}

class QuaterImaginary {
public:
    QuaterImaginary(const std::string& s) : b2i(s) {
        static std::string base("0123.");

        if (b2i.empty()
            || std::any_of(s.cbegin(), s.cend(), [](char c) { return base.find(c) == std::string::npos; })
            || std::count(s.cbegin(), s.cend(), '.') > 1) {
            throw std::runtime_error("Invalid base 2i number");
        }
    }

    QuaterImaginary& operator=(const QuaterImaginary& q) {
        b2i = q.b2i;
        return *this;
    }

    std::complex<double> toComplex() const {
        int pointPos = b2i.find('.');
        int posLen = (pointPos != std::string::npos) ? pointPos : b2i.length();
        std::complex<double> sum(0.0, 0.0);
        std::complex<double> prod(1.0, 0.0);
        for (int j = 0; j < posLen; j++) {
            double k = (b2i[posLen - 1 - j] - '0');
            if (k > 0.0) {
                sum += prod * k;
            }
            prod *= twoI;
        }
        if (pointPos != -1) {
            prod = invTwoI;
            for (size_t j = posLen + 1; j < b2i.length(); j++) {
                double k = (b2i[j] - '0');
                if (k > 0.0) {
                    sum += prod * k;
                }
                prod *= invTwoI;
            }
        }

        return sum;
    }

    friend std::ostream& operator<<(std::ostream&, const QuaterImaginary&);

private:
    const std::complex<double> twoI{ 0.0, 2.0 };
    const std::complex<double> invTwoI = inv(twoI);

    std::string b2i;
};

std::ostream& operator<<(std::ostream& os, const QuaterImaginary& q) {
    return os << q.b2i;
}


QuaterImaginary toQuaterImaginary(const std::complex<double>& c) {
    if (c.real() == 0.0 && c.imag() == 0.0) return QuaterImaginary("0");

    int re = (int)c.real();
    int im = (int)c.imag();
    int fi = -1;
    std::stringstream ss;
    while (re != 0) {
        int rem = re % -4;
        re /= -4;
        if (rem < 0) {
            rem = 4 + rem;
            re++;
        }
        ss << rem << 0;
    }
    if (im != 0) {
        double f = (std::complex<double>(0.0, c.imag()) / std::complex<double>(0.0, 2.0)).real();
        im = (int)ceil(f);
        f = -4.0 * (f - im);
        size_t index = 1;
        while (im != 0) {
            int rem = im % -4;
            im /= -4;
            if (rem < 0) {
                rem = 4 + rem;
                im++;
            }
            if (index < ss.str().length()) {
                ss.str()[index] = (char)(rem + 48);
            } else {
                ss << 0 << rem;
            }
            index += 2;
        }
        fi = (int)f;
    }

    auto r = ss.str();
    std::reverse(r.begin(), r.end());
    ss.str("");
    ss.clear();
    ss << r;
    if (fi != -1) ss << '.' << fi;
    r = ss.str();
    r.erase(r.begin(), std::find_if(r.begin(), r.end(), [](char c) { return c != '0'; }));
    if (r[0] == '.')r = "0" + r;
    return QuaterImaginary(r);
}

int main() {
    using namespace std;

    for (int i = 1; i <= 16; i++) {
        complex<double> c1(i, 0);
        QuaterImaginary qi = toQuaterImaginary(c1);
        complex<double> c2 = qi.toComplex();
        cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << "     ";
        c1 = -c1;
        qi = toQuaterImaginary(c1);
        c2 = qi.toComplex();
        cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << endl;
    }
    cout << endl;

    for (int i = 1; i <= 16; i++) {
        complex<double> c1(0, i);
        QuaterImaginary qi = toQuaterImaginary(c1);
        complex<double> c2 = qi.toComplex();
        cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << "     ";
        c1 = -c1;
        qi = toQuaterImaginary(c1);
        c2 = qi.toComplex();
        cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << endl;
    }

    return 0;
}







VB: Imports System.Text

Module Module1

    Class Complex : Implements IFormattable
        Private ReadOnly real As Double
        Private ReadOnly imag As Double

        Public Sub New(r As Double, i As Double)
            real = r
            imag = i
        End Sub

        Public Sub New(r As Integer, i As Integer)
            real = r
            imag = i
        End Sub

        Public Function Inv() As Complex
            Dim denom = real * real + imag * imag
            Return New Complex(real / denom, -imag / denom)
        End Function

        Public Shared Operator -(self As Complex) As Complex
            Return New Complex(-self.real, -self.imag)
        End Operator

        Public Shared Operator +(lhs As Complex, rhs As Complex) As Complex
            Return New Complex(lhs.real + rhs.real, lhs.imag + rhs.imag)
        End Operator

        Public Shared Operator -(lhs As Complex, rhs As Complex) As Complex
            Return New Complex(lhs.real - rhs.real, lhs.imag - rhs.imag)
        End Operator

        Public Shared Operator *(lhs As Complex, rhs As Complex) As Complex
            Return New Complex(lhs.real * rhs.real - lhs.imag * rhs.imag, lhs.real * rhs.imag + lhs.imag * rhs.real)
        End Operator

        Public Shared Operator /(lhs As Complex, rhs As Complex) As Complex
            Return lhs * rhs.Inv
        End Operator

        Public Shared Operator *(lhs As Complex, rhs As Double) As Complex
            Return New Complex(lhs.real * rhs, lhs.imag * rhs)
        End Operator

        Public Function ToQuaterImaginary() As QuaterImaginary
            If real = 0.0 AndAlso imag = 0.0 Then
                Return New QuaterImaginary("0")
            End If
            Dim re = CType(real, Integer)
            Dim im = CType(imag, Integer)
            Dim fi = -1
            Dim sb As New StringBuilder
            While re <> 0
                Dim rm = re Mod -4
                re \= -4
                If rm < 0 Then
                    rm += 4
                    re += 1
                End If
                sb.Append(rm)
                sb.Append(0)
            End While
            If im <> 0 Then
                Dim f = (New Complex(0.0, imag) / New Complex(0.0, 2.0)).real
                im = Math.Ceiling(f)
                f = -4.0 * (f - im)
                Dim index = 1
                While im <> 0
                    Dim rm = im Mod -4
                    im \= -4
                    If rm < 0 Then
                        rm += 4
                        im += 1
                    End If
                    If index < sb.Length Then
                        sb(index) = Chr(rm + 48)
                    Else
                        sb.Append(0)
                        sb.Append(rm)
                    End If
                    index += 2
                End While
                fi = f
            End If
            Dim reverse As New String(sb.ToString().Reverse().ToArray())
            sb.Length = 0
            sb.Append(reverse)
            If fi <> -1 Then
                sb.AppendFormat(".{0}", fi)
            End If
            Dim s = sb.ToString().TrimStart("0")
            If s(0) = "." Then
                s = "0" + s
            End If
            Return New QuaterImaginary(s)
        End Function

        Public Overloads Function ToString() As String
            Dim r2 = If(real = -0.0, 0.0, real) 
            Dim i2 = If(imag = -0.0, 0.0, imag) 
            If i2 = 0.0 Then
                Return String.Format("{0}", r2)
            End If
            If r2 = 0.0 Then
                Return String.Format("{0}i", i2)
            End If
            If i2 > 0.0 Then
                Return String.Format("{0} + {1}i", r2, i2)
            End If
            Return String.Format("{0} - {1}i", r2, -i2)
        End Function

        Public Overloads Function ToString(format As String, formatProvider As IFormatProvider) As String Implements IFormattable.ToString
            Return ToString()
        End Function
    End Class

    Class QuaterImaginary
        Private Shared ReadOnly twoI = New Complex(0.0, 2.0)
        Private Shared ReadOnly invTwoI = twoI.Inv()

        Private ReadOnly b2i As String

        Public Sub New(b2i As String)
            If b2i = "" OrElse Not b2i.All(Function(c) "0123.".IndexOf(c) > -1) OrElse b2i.Count(Function(c) c = ".") > 1 Then
                Throw New Exception("Invalid Base 2i number")
            End If
            Me.b2i = b2i
        End Sub

        Public Function ToComplex() As Complex
            Dim pointPos = b2i.IndexOf(".")
            Dim posLen = If(pointPos <> -1, pointPos, b2i.Length)
            Dim sum = New Complex(0.0, 0.0)
            Dim prod = New Complex(1.0, 0.0)
            For j = 0 To posLen - 1
                Dim k = Asc(b2i(posLen - 1 - j)) - Asc("0")
                If k > 0.0 Then
                    sum += prod * k
                End If
                prod *= twoI
            Next
            If pointPos <> -1 Then
                prod = invTwoI
                For j = posLen + 1 To b2i.Length - 1
                    Dim k = Asc(b2i(j)) - Asc("0")
                    If k > 0.0 Then
                        sum += prod * k
                    End If
                    prod *= invTwoI
                Next
            End If
            Return sum
        End Function

        Public Overrides Function ToString() As String
            Return b2i
        End Function
    End Class

    Sub Main()
        For i = 1 To 16
            Dim c1 As New Complex(i, 0)
            Dim qi = c1.ToQuaterImaginary()
            Dim c2 = qi.ToComplex()
            Console.Write("{0,4} -> {1,8} -> {2,4}     ", c1, qi, c2)
            c1 = -c1
            qi = c1.ToQuaterImaginary()
            c2 = qi.ToComplex()
            Console.WriteLine("{0,4} -> {1,8} -> {2,4}", c1, qi, c2)
        Next
        Console.WriteLine()
        For i = 1 To 16
            Dim c1 As New Complex(0, i)
            Dim qi = c1.ToQuaterImaginary()
            Dim c2 = qi.ToComplex()
            Console.Write("{0,4} -> {1,8} -> {2,4}     ", c1, qi, c2)
            c1 = -c1
            qi = c1.ToQuaterImaginary()
            c2 = qi.ToComplex()
            Console.WriteLine("{0,4} -> {1,8} -> {2,4}", c1, qi, c2)
        Next
    End Sub

End Module