001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2016, Jean-Marie Dautelle, Werner Keil, V2COM. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tec.units.ri.function; 031 032import static tec.units.ri.internal.MathUtil.gcd; 033import static tec.units.ri.internal.MathUtil.negateExact; 034 035import javax.measure.UnitConverter; 036 037import tec.units.ri.AbstractConverter; 038import tec.uom.lib.common.function.ValueSupplier; 039 040/** 041 * <p> 042 * This class represents a converter multiplying numeric values by an exact scaling factor (represented as the quotient of two <code>double</code> 043 * numbers). 044 * </p> 045 * 046 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 047 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 048 * @version 0.8, April 3, 2016 049 */ 050public final class RationalConverter extends AbstractConverter implements ValueSupplier<Double> { 051 052 /** 053 * 054 */ 055 // private static final long serialVersionUID = 1L; 056 057 /** 058 * Holds the converter dividend. 059 */ 060 private final double dividend; 061 062 /** 063 * Holds the converter divisor (always positive). 064 */ 065 private final double divisor; 066 067 /** 068 * Constructor 069 * 070 * @param dividend 071 * the dividend. 072 * @param divisor 073 * the positive divisor. 074 * @throws IllegalArgumentException 075 * if <code>divisor <= 0</code> 076 * @throws IllegalArgumentException 077 * if <code>dividend == divisor</code> 078 */ 079 public RationalConverter(double dividend, double divisor) { 080 if (divisor <= 0) 081 throw new IllegalArgumentException("Negative or zero divisor"); 082 if (dividend == divisor) 083 throw new IllegalArgumentException("Would result in identity converter"); 084 this.dividend = dividend; 085 this.divisor = divisor; 086 } 087 088 /** 089 * Convenience method equivalent to <code>new RationalConverter(dividend, divisor)</code> 090 * 091 * @param dividend 092 * the dividend. 093 * @param divisor 094 * the positive divisor. 095 * @throws IllegalArgumentException 096 * if <code>divisor <= 0</code> 097 * @throws IllegalArgumentException 098 * if <code>dividend == divisor</code> 099 */ 100 public static final RationalConverter of(long dividend, long divisor) { 101 return new RationalConverter((double) dividend, (double) divisor); 102 } 103 104 /** 105 * Convenience method equivalent to <code>new RationalConverter(dividend, divisor)</code> 106 * 107 * @param dividend 108 * the dividend. 109 * @param divisor 110 * the positive divisor. 111 * @throws IllegalArgumentException 112 * if <code>divisor <= 0</code> 113 * @throws IllegalArgumentException 114 * if <code>dividend == divisor</code> 115 */ 116 public static final RationalConverter of(double dividend, double divisor) { 117 return new RationalConverter(dividend, divisor); 118 } 119 120 /** 121 * Returns the integer dividend for this rational converter. 122 * 123 * @return this converter dividend. 124 */ 125 public double getDividend() { 126 return dividend; 127 } 128 129 /** 130 * Returns the integer (positive) divisor for this rational converter. 131 * 132 * @return this converter divisor. 133 */ 134 public double getDivisor() { 135 return divisor; 136 } 137 138 @Override 139 public double convert(double value) { 140 return value * ((double) dividend / (double) divisor); 141 } 142 143 @Override 144 public UnitConverter concatenate(UnitConverter converter) { 145 if (!(converter instanceof RationalConverter)) 146 return super.concatenate(converter); 147 RationalConverter that = (RationalConverter) converter; 148 double newDividend = this.getDividend() * that.getDividend(); 149 double newDivisor = this.getDivisor() * that.getDivisor(); 150 double gcd = gcd(newDividend, newDivisor); 151 newDividend = newDividend / gcd; // TODO clarify if this works with long 152 newDivisor = newDivisor / gcd; 153 return (newDividend == 1 && newDivisor == 1) ? IDENTITY : new RationalConverter(newDividend, newDivisor); 154 } 155 156 @Override 157 public RationalConverter inverse() { 158 return Math.signum(dividend) == -1 ? new RationalConverter(negateExact(getDivisor()), negateExact(getDividend())) : new RationalConverter( 159 getDivisor(), getDividend()); 160 } 161 162 @Override 163 public final String toString() { 164 return "RationalConverter(" + dividend + "," + divisor + ")"; 165 } 166 167 @Override 168 public boolean equals(Object obj) { 169 if (!(obj instanceof RationalConverter)) 170 return false; 171 RationalConverter that = (RationalConverter) obj; 172 return (this.dividend == that.dividend && this.divisor == that.divisor); 173 } 174 175 @Override 176 public int hashCode() { 177 return Double.valueOf(dividend).hashCode() + Double.valueOf(dividend).hashCode(); 178 } 179 180 public boolean isLinear() { 181 return true; 182 } 183 184 public double getAsDouble() { 185 return (double) dividend / (double) divisor; 186 } 187 188 public Double getValue() { 189 return Double.valueOf(getAsDouble()); 190 } 191}