import java.util.Scanner;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Formatter;
import java.util.Formattable;
import java.util.regex.Pattern;
import static java.util.FormattableFlags.ALTERNATE;
import static java.util.FormattableFlags.LEFT_JUSTIFY;
import java.util.FormatFlagsConversionMismatchException;
import java.util.IllegalFormatPrecisionException;
import java.util.IllegalFormatException;
public final class Rational extends Number
implements Comparable<Rational>, Formattable {
public static final Rational ZERO = new Rational(0, 1);
public static final Rational ONE = new Rational(1, 1);
public static final Rational MAX_VALUE
= new Rational(Integer.MAX_VALUE, 1);
public static final Rational MIN_VALUE
= new Rational(1, Integer.MAX_VALUE);
private final int numerator;
private final int denominator;
public static Rational valueOf(int n, int d) {
return new Rational(n, d);
}
public static Rational valueOf(int n) {
switch (n) {
case 0:
return ZERO;
case 1:
return ONE;
case Integer.MAX_VALUE:
return MAX_VALUE;
default:
return new Rational(n, 1);
}
}
public static Rational valueOf(String s) {
Scanner sc = new Scanner(s);
if (!sc.hasNext(FORMAT)) {
throw new NumberFormatException(s);
}
sc.useDelimiter("/");
return new Rational(sc.nextInt(), sc.nextInt());
}
private static final Pattern FORMAT = Pattern.compile("^[+-]?\\d+/\\d+$");
private Rational(long n, long d) {
if (d == 0) {
throw new IllegalArgumentException("invalid denominator 0");
}
if (n == 0) {
this.numerator = 0;
this.denominator = 1;
return;
}
int sign = Long.signum(n) * Long.signum(d);
long nn = Math.abs(n);
long dd = Math.abs(d);
if (dd != 1) {
long f = gcd(nn, dd);
nn /= f;
dd /= f;
}
if (nn > Integer.MAX_VALUE) {
throw new ArithmeticException(
String.format("numerator overflow: %d/%d", sign * nn, dd));
}
if (dd > Integer.MAX_VALUE) {
throw new ArithmeticException(
String.format("denominator overflow: %d/%d", sign * nn, dd));
}
this.numerator = sign * (int) nn;
this.denominator = (int) dd;
}
private static long gcd(long a, long b) {
while (a > 0 && b > 0) {
if (a > b) {
a = a % b;
} else {
b = b % a;
}
}
return Math.max(a, b);
}
public int getNumerator() {
return this.numerator;
}
public int getDenominator() {
return this.denominator;
}
public int signum() {
return Integer.signum(numerator);
}
public Rational negate() {
return new Rational(-this.numerator, this.denominator);
}
public Rational invert() {
return new Rational(this.denominator, this.numerator);
}
public Rational add(Rational r) {
if (this.denominator == r.denominator) {
return new Rational((long) this.numerator + r.numerator,
this.denominator);
}
long n = (long) this.numerator * r.denominator
+ (long) r.numerator * this.denominator;
long d = (long) this.denominator * r.denominator;
return new Rational(n, d);
}
public Rational subtract(Rational r) {
if (this.denominator == r.denominator) {
return new Rational((long) this.numerator - r.numerator,
this.denominator);
}
long n = (long) this.numerator * r.denominator
- (long) r.numerator * this.denominator;
long d = (long) this.denominator * r.denominator;
return new Rational(n, d);
}
public Rational multiply(Rational r) {
long n = (long) this.numerator * r.numerator;
long d = (long) this.denominator * r.denominator;
return new Rational(n, d);
}
public Rational divide(Rational r) {
if (r.numerator == 0) {
throw new IllegalArgumentException("invalid divisor: " + r);
}
long n = (long) this.numerator * r.denominator;
long d = (long) this.denominator * r.numerator;
return new Rational(n, d);
}
@Override
public String toString() {
return new StringBuilder()
.append(this.numerator)
.append('/')
.append(this.denominator)
.toString();
}
@Override
public boolean equals(Object o) {
if (o instanceof Rational) {
Rational r = (Rational) o;
return this.numerator == r.numerator
&& this.denominator == r.denominator;
}
return false;
}
@Override
public int hashCode() {
return this.numerator * 31 + this.denominator;
}
@Override
public int intValue() {
return (int) ((double) this.numerator / this.denominator);
}
@Override
public long longValue() {
return (long) ((double) this.numerator / this.denominator);
}
@Override
public double doubleValue() {
return (double) this.numerator / this.denominator;
}
@Override
public float floatValue() {
return (float) this.doubleValue();
}
@Override
public int compareTo(Rational r) {
if (this.denominator == r.denominator) {
return Integer.compare(this.numerator, r.numerator);
}
return Long.compare((long) this.numerator * r.denominator,
(long) r.numerator * this.denominator);
}
@Override
public void formatTo(Formatter f, int flags, int width, int precision) {
if (precision != -1) {
throw new IllegalFormatPrecisionException(precision);
}
if ((flags & ALTERNATE) == ALTERNATE) {
throw new FormatFlagsConversionMismatchException("#", 's');
}
String s = this.toString();
if (width <= s.length()) {
f.format(s);
return;
}
if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) {
f.format("%-" + width + "s", s);
return;
}
f.format("%" + width + "s", s);
}
}
final class RationalTest {
private RationalTest() { }
public static void main(String[] args) {
Rational[] stack = new Rational[args.length];
int top = 0;
Locale.setDefault(Locale.ENGLISH);
Scanner input = new Scanner(System.in);
for (String arg : args) {
try {
switch (arg) {
case "stackdump":
for (int j = 0; j < top; ++j) {
System.out.printf("%d: %s (%.15e)%n",
j, stack[j], stack[j].doubleValue());
}
continue;
case "negate":
stack[top - 1] = stack[top - 1].negate();
break;
case "invert":
stack[top - 1] = stack[top - 1].invert();
break;
case "add":
stack[top - 2] = stack[top - 2].add(stack[top - 1]);
--top;
break;
case "subtract":
stack[top - 2] = stack[top - 2].subtract(stack[top - 1]);
--top;
break;
case "multiply":
stack[top - 2] = stack[top - 2].multiply(stack[top - 1]);
--top;
break;
case "divide":
stack[top - 2] = stack[top - 2].divide(stack[top - 1]);
--top;
break;
case "getNumerator":
System.out.printf("%s: %d%n",
arg, stack[top - 1].getNumerator());
continue;
case "getDenominator":
System.out.printf("%s: %d%n",
arg, stack[top - 1].getDenominator());
continue;
case "signum":
System.out.printf("%s: %d%n",
arg, stack[top - 1].signum());
continue;
case "toString":
System.out.printf("%s: %s%n",
arg, stack[top - 1].toString());
continue;
case "hashCode":
System.out.printf("%s: %d%n",
arg, stack[top - 1].hashCode());
continue;
case "equals":
System.out.printf("%s: %b%n",
arg,
stack[top - 2].equals(stack[top - 1]));
continue;
case "intValue":
System.out.printf("%s: %d%n",
arg, stack[top - 1].intValue());
continue;
case "longValue":
System.out.printf("%s: %d%n",
arg, stack[top - 1].longValue());
continue;
case "doubleValue":
System.out.printf("%s: %.15e%n",
arg, stack[top - 1].doubleValue());
continue;
case "floatValue":
System.out.printf("%s: %.7e%n",
arg, stack[top - 1].floatValue());
continue;
case "compareTo":
System.out.printf("%s: %d%n",
arg,
stack[top - 2].compareTo(stack[top - 1]));
continue;
case "formatTo":
System.err.print("Enter format string: ");
try {
System.out.printf("%s: " + input.next() + "%n",
arg, stack[top - 1]);
} catch (NoSuchElementException x) {
System.err.println("no input");
System.exit(1);
}
continue;
case "ZERO":
stack[top++] = Rational.ZERO;
continue;
case "ONE":
stack[top++] = Rational.ONE;
continue;
case "MAX_VALUE":
stack[top++] = Rational.MAX_VALUE;
continue;
case "MIN_VALUE":
stack[top++] = Rational.MIN_VALUE;
continue;
case "int":
System.err.print("Enter integer: ");
try {
stack[top] = Rational.valueOf(input.nextInt());
++top;
} catch (NoSuchElementException x) {
System.err.println(input.next() + ": invalid input");
System.exit(1);
}
continue;
case "intint":
System.err.print("Enter numerator and denominator: ");
try {
stack[top] = Rational.valueOf(input.nextInt(),
input.nextInt());
++top;
} catch (NoSuchElementException x) {
System.err.println(input.next() + ": invalid input");
System.exit(1);
}
continue;
default:
stack[top] = Rational.valueOf(arg);
++top;
continue;
}
System.out.println(arg);
} catch (ArrayIndexOutOfBoundsException x) {
System.err.println(arg + ": missing operand");
System.exit(1);
} catch (NumberFormatException x) {
System.err.println(x.getMessage() + ": not a rational number");
} catch (ArithmeticException x) {
System.err.println(x.getMessage());
} catch (IllegalFormatException x) {
System.err.printf("%s: %s%n", arg, x);
} catch (IllegalArgumentException x) {
System.err.println(x.getMessage());
}
}
for (int j = 0; j < top; ++j) {
System.out.printf("%d: %s (%.15e)%n",
j, stack[j], stack[j].doubleValue());
}
}
}