RosettaCodeData/Task/Imaginary-base-numbers/Java/imaginary-base-numbers.java

179 lines
5.8 KiB
Java

public class ImaginaryBaseNumber {
private static class Complex {
private Double real, imag;
public Complex(double r, double i) {
this.real = r;
this.imag = i;
}
public Complex(int r, int i) {
this.real = (double) r;
this.imag = (double) i;
}
public Complex add(Complex rhs) {
return new Complex(
real + rhs.real,
imag + rhs.imag
);
}
public Complex times(Complex rhs) {
return new Complex(
real * rhs.real - imag * rhs.imag,
real * rhs.imag + imag * rhs.real
);
}
public Complex times(double rhs) {
return new Complex(
real * rhs,
imag * rhs
);
}
public Complex inv() {
double denom = real * real + imag * imag;
return new Complex(
real / denom,
-imag / denom
);
}
public Complex unaryMinus() {
return new Complex(-real, -imag);
}
public Complex divide(Complex rhs) {
return this.times(rhs.inv());
}
// only works properly if 'real' and 'imag' are both integral
public QuaterImaginary toQuaterImaginary() {
if (real == 0.0 && imag == 0.0) return new QuaterImaginary("0");
int re = real.intValue();
int im = imag.intValue();
int fi = -1;
StringBuilder sb = new StringBuilder();
while (re != 0) {
int rem = re % -4;
re /= -4;
if (rem < 0) {
rem += 4;
re++;
}
sb.append(rem);
sb.append(0);
}
if (im != 0) {
Double f = new Complex(0.0, imag).divide(new Complex(0.0, 2.0)).real;
im = ((Double) Math.ceil(f)).intValue();
f = -4.0 * (f - im);
int index = 1;
while (im != 0) {
int rem = im % -4;
im /= -4;
if (rem < 0) {
rem += 4;
im++;
}
if (index < sb.length()) {
sb.setCharAt(index, (char) (rem + 48));
} else {
sb.append(0);
sb.append(rem);
}
index += 2;
}
fi = f.intValue();
}
sb.reverse();
if (fi != -1) sb.append(".").append(fi);
while (sb.charAt(0) == '0') sb.deleteCharAt(0);
if (sb.charAt(0) == '.') sb.insert(0, '0');
return new QuaterImaginary(sb.toString());
}
@Override
public String toString() {
double real2 = real == -0.0 ? 0.0 : real; // get rid of negative zero
double imag2 = imag == -0.0 ? 0.0 : imag; // ditto
String result = imag2 >= 0.0 ? String.format("%.0f + %.0fi", real2, imag2) : String.format("%.0f - %.0fi", real2, -imag2);
result = result.replace(".0 ", " ").replace(".0i", "i").replace(" + 0i", "");
if (result.startsWith("0 + ")) result = result.substring(4);
if (result.startsWith("0 - ")) result = result.substring(4);
return result;
}
}
private static class QuaterImaginary {
private static final Complex TWOI = new Complex(0.0, 2.0);
private static final Complex INVTWOI = TWOI.inv();
private String b2i;
public QuaterImaginary(String b2i) {
if (b2i.equals("") || !b2i.chars().allMatch(c -> "0123.".indexOf(c) > -1) || b2i.chars().filter(c -> c == '.').count() > 1) {
throw new RuntimeException("Invalid Base 2i number");
}
this.b2i = b2i;
}
public Complex toComplex() {
int pointPos = b2i.indexOf(".");
int posLen = pointPos != -1 ? pointPos : b2i.length();
Complex sum = new Complex(0, 0);
Complex prod = new Complex(1, 0);
for (int j = 0; j < posLen; ++j) {
double k = b2i.charAt(posLen - 1 - j) - '0';
if (k > 0.0) sum = sum.add(prod.times(k));
prod = prod.times(TWOI);
}
if (pointPos != -1) {
prod = INVTWOI;
for (int j = posLen + 1; j < b2i.length(); ++j) {
double k = b2i.charAt(j) - '0';
if (k > 0.0) sum = sum.add(prod.times(k));
prod = prod.times(INVTWOI);
}
}
return sum;
}
@Override
public String toString() {
return b2i;
}
}
public static void main(String[] args) {
String fmt = "%4s -> %8s -> %4s";
for (int i = 1; i <= 16; ++i) {
Complex c1 = new Complex(i, 0);
QuaterImaginary qi = c1.toQuaterImaginary();
Complex c2 = qi.toComplex();
System.out.printf(fmt + " ", c1, qi, c2);
c1 = c2.unaryMinus();
qi = c1.toQuaterImaginary();
c2 = qi.toComplex();
System.out.printf(fmt, c1, qi, c2);
System.out.println();
}
System.out.println();
for (int i = 1; i <= 16; ++i) {
Complex c1 = new Complex(0, i);
QuaterImaginary qi = c1.toQuaterImaginary();
Complex c2 = qi.toComplex();
System.out.printf(fmt + " ", c1, qi, c2);
c1 = c2.unaryMinus();
qi = c1.toQuaterImaginary();
c2 = qi.toComplex();
System.out.printf(fmt, c1, qi, c2);
System.out.println();
}
}
}