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 */ 009package 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 */ 021public 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("Identity converter not allowed"); 047 _dividend = dividend; 048 _divisor = divisor; 049 } 050 051 /** 052 * Returns the dividend for this rational converter. 053 * 054 * @return this converter dividend. 055 */ 056 public long getDividend() { 057 return _dividend; 058 } 059 060 /** 061 * Returns the positive divisor for this rational converter. 062 * 063 * @return this converter divisor. 064 */ 065 public long getDivisor() { 066 return _divisor; 067 } 068 069 @Override 070 public UnitConverter inverse() { 071 return _dividend < 0 ? new RationalConverter(-_divisor, -_dividend) 072 : new RationalConverter(_divisor, _dividend); 073 } 074 075 @Override 076 public double convert(double amount) { 077 return amount * _dividend / _divisor; 078 } 079 080 @Override 081 public boolean isLinear() { 082 return true; 083 } 084 085 @Override 086 public UnitConverter concatenate(UnitConverter converter) { 087 if (converter instanceof RationalConverter) { 088 RationalConverter that = (RationalConverter) converter; 089 long dividendLong = this._dividend * that._dividend; 090 long divisorLong = this._divisor * that._divisor; 091 double dividendDouble = ((double)this._dividend) * that._dividend; 092 double divisorDouble = ((double)this._divisor) * that._divisor; 093 if ((dividendLong != dividendDouble) || 094 (divisorLong != divisorDouble)) { // Long overflows. 095 return new MultiplyConverter(dividendDouble / divisorDouble); 096 } 097 long gcd = gcd(dividendLong, divisorLong); 098 return RationalConverter.valueOf(dividendLong / gcd, divisorLong / gcd); 099 } else if (converter instanceof MultiplyConverter) { 100 return converter.concatenate(this); 101 } else { 102 return super.concatenate(converter); 103 } 104 } 105 106 private static UnitConverter valueOf(long dividend, long divisor) { 107 return (dividend == 1L) && (divisor == 1L) ? UnitConverter.IDENTITY 108 : new RationalConverter(dividend, divisor); 109 } 110 111 /** 112 * Returns the greatest common divisor (Euclid's algorithm). 113 * 114 * @param m the first number. 115 * @param nn the second number. 116 * @return the greatest common divisor. 117 */ 118 private static long gcd(long m, long n) { 119 if (n == 0L) { 120 return m; 121 } else { 122 return gcd(n, m % n); 123 } 124 } 125 126 private static final long serialVersionUID = 1L; 127}