| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.imaging.common; |
| |
| import java.text.DecimalFormat; |
| import java.text.NumberFormat; |
| |
| public class RationalNumber extends Number |
| { |
| private static final long serialVersionUID = -1; |
| |
| public final int numerator; |
| public final int divisor; |
| |
| public RationalNumber(int numerator, int divisor) |
| { |
| this.numerator = numerator; |
| this.divisor = divisor; |
| } |
| |
| public static final RationalNumber factoryMethod(long n, long d) |
| { |
| // safer than constructor - handles values outside min/max range. |
| // also does some simple finding of common denominators. |
| |
| if (n > Integer.MAX_VALUE || n < Integer.MIN_VALUE |
| || d > Integer.MAX_VALUE || d < Integer.MIN_VALUE) |
| { |
| while ((n > Integer.MAX_VALUE || n < Integer.MIN_VALUE |
| || d > Integer.MAX_VALUE || d < Integer.MIN_VALUE) |
| && (Math.abs(n) > 1) && (Math.abs(d) > 1)) |
| { |
| // brutal, inprecise truncation =( |
| // use the sign-preserving right shift operator. |
| n >>= 1; |
| d >>= 1; |
| } |
| |
| if (d == 0) |
| throw new NumberFormatException("Invalid value, numerator: " |
| + n + ", divisor: " + d); |
| } |
| |
| long gcd = gcd(n, d); |
| d = d / gcd; |
| n = n / gcd; |
| |
| return new RationalNumber((int) n, (int) d); |
| } |
| |
| /** |
| * Return the greatest common divisor |
| */ |
| private static long gcd(long a, long b) |
| { |
| |
| if (b == 0) |
| return a; |
| else |
| return gcd(b, a % b); |
| } |
| |
| public RationalNumber negate() |
| { |
| return new RationalNumber(-numerator, divisor); |
| } |
| |
| @Override |
| public double doubleValue() |
| { |
| return (double) numerator / (double) divisor; |
| } |
| |
| @Override |
| public float floatValue() |
| { |
| return (float) numerator / (float) divisor; |
| } |
| |
| @Override |
| public int intValue() |
| { |
| return numerator / divisor; |
| } |
| |
| @Override |
| public long longValue() |
| { |
| return (long) numerator / (long) divisor; |
| } |
| |
| public boolean isValid() |
| { |
| return divisor != 0; |
| } |
| |
| private static final NumberFormat nf = DecimalFormat.getInstance(); |
| |
| @Override |
| public String toString() |
| { |
| if (divisor == 0) |
| return "Invalid rational (" + numerator + "/" + divisor + ")"; |
| if ((numerator % divisor) == 0) |
| return nf.format(numerator / divisor); |
| return numerator + "/" + divisor + " (" |
| + nf.format((double) numerator / divisor) + ")"; |
| } |
| |
| public String toDisplayString() |
| { |
| if ((numerator % divisor) == 0) |
| return "" + (numerator / divisor); |
| NumberFormat nf = DecimalFormat.getInstance(); |
| nf.setMaximumFractionDigits(3); |
| return nf.format((double) numerator / (double) divisor); |
| } |
| } |