001: /*
002: * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003: * Copyright (C) 2006 - JScience (http://jscience.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javax.measure.converter;
010:
011: /**
012: * <p> This class represents a converter multiplying numeric values by an
013: * exact scaling factor (represented as the quotient of two
014: * <code>long</code> numbers).</p>
015: *
016: * <p> Instances of this class are immutable.</p>
017: *
018: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
019: * @version 3.1, April 22, 2006
020: */
021: public final class RationalConverter extends UnitConverter {
022:
023: /**
024: * Holds the converter dividend.
025: */
026: private final long _dividend;
027:
028: /**
029: * Holds the converter divisor (always positive).
030: */
031: private final long _divisor;
032:
033: /**
034: * Creates a rational converter with the specified dividend and
035: * divisor.
036: *
037: * @param dividend the dividend.
038: * @param divisor the positive divisor.
039: * @throws IllegalArgumentException if <code>divisor < 0</code>
040: * @throws IllegalArgumentException if <code>dividend == divisor</code>
041: */
042: public RationalConverter(long dividend, long divisor) {
043: if (divisor < 0)
044: throw new IllegalArgumentException("Negative divisor");
045: if (dividend == divisor)
046: throw new IllegalArgumentException(
047: "Identity converter not allowed");
048: _dividend = dividend;
049: _divisor = divisor;
050: }
051:
052: /**
053: * Returns the dividend for this rational converter.
054: *
055: * @return this converter dividend.
056: */
057: public long getDividend() {
058: return _dividend;
059: }
060:
061: /**
062: * Returns the positive divisor for this rational converter.
063: *
064: * @return this converter divisor.
065: */
066: public long getDivisor() {
067: return _divisor;
068: }
069:
070: @Override
071: public UnitConverter inverse() {
072: return _dividend < 0 ? new RationalConverter(-_divisor,
073: -_dividend)
074: : new RationalConverter(_divisor, _dividend);
075: }
076:
077: @Override
078: public double convert(double amount) {
079: return amount * _dividend / _divisor;
080: }
081:
082: @Override
083: public boolean isLinear() {
084: return true;
085: }
086:
087: @Override
088: public UnitConverter concatenate(UnitConverter converter) {
089: if (converter instanceof RationalConverter) {
090: RationalConverter that = (RationalConverter) converter;
091: long dividendLong = this ._dividend * that._dividend;
092: long divisorLong = this ._divisor * that._divisor;
093: double dividendDouble = ((double) this ._dividend)
094: * that._dividend;
095: double divisorDouble = ((double) this ._divisor)
096: * that._divisor;
097: if ((dividendLong != dividendDouble)
098: || (divisorLong != divisorDouble)) { // Long overflows.
099: return new MultiplyConverter(dividendDouble
100: / divisorDouble);
101: }
102: long gcd = gcd(dividendLong, divisorLong);
103: return RationalConverter.valueOf(dividendLong / gcd,
104: divisorLong / gcd);
105: } else if (converter instanceof MultiplyConverter) {
106: return converter.concatenate(this );
107: } else {
108: return super .concatenate(converter);
109: }
110: }
111:
112: private static UnitConverter valueOf(long dividend, long divisor) {
113: return (dividend == 1L) && (divisor == 1L) ? UnitConverter.IDENTITY
114: : new RationalConverter(dividend, divisor);
115: }
116:
117: /**
118: * Returns the greatest common divisor (Euclid's algorithm).
119: *
120: * @param m the first number.
121: * @param nn the second number.
122: * @return the greatest common divisor.
123: */
124: private static long gcd(long m, long n) {
125: if (n == 0L) {
126: return m;
127: } else {
128: return gcd(n, m % n);
129: }
130: }
131:
132: private static final long serialVersionUID = 1L;
133: }
|