001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2017, 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 1.0, October 6, 2016 049 * @since 1.0 050 */ 051public final class RationalConverter extends AbstractConverter implements ValueSupplier<Double> { 052 053 /** 054 * 055 */ 056 // private static final long serialVersionUID = 1L; 057 058 /** 059 * Holds the converter dividend. 060 */ 061 private final double dividend; 062 063 /** 064 * Holds the converter divisor (always positive). 065 */ 066 private final double divisor; 067 068 /** 069 * Constructor 070 * 071 * @param dividend 072 * the dividend. 073 * @param divisor 074 * the positive divisor. 075 * @throws IllegalArgumentException 076 * if <code>divisor <= 0</code> 077 * @throws IllegalArgumentException 078 * if <code>dividend == divisor</code> 079 */ 080 public RationalConverter(double dividend, double divisor) { 081 if (divisor <= 0) 082 throw new IllegalArgumentException("Negative or zero divisor"); 083 if (dividend == divisor) 084 throw new IllegalArgumentException("Would result in identity converter"); 085 this.dividend = dividend; 086 this.divisor = divisor; 087 } 088 089 /** 090 * Convenience method equivalent to <code>new RationalConverter(dividend, divisor)</code> 091 * 092 * @param dividend 093 * the dividend. 094 * @param divisor 095 * the positive divisor. 096 * @throws IllegalArgumentException 097 * if <code>divisor <= 0</code> 098 * @throws IllegalArgumentException 099 * if <code>dividend == divisor</code> 100 */ 101 public static final RationalConverter of(long dividend, long divisor) { 102 return new RationalConverter((double) dividend, (double) divisor); 103 } 104 105 /** 106 * Convenience method equivalent to <code>new RationalConverter(dividend, divisor)</code> 107 * 108 * @param dividend 109 * the dividend. 110 * @param divisor 111 * the positive divisor. 112 * @throws IllegalArgumentException 113 * if <code>divisor <= 0</code> 114 * @throws IllegalArgumentException 115 * if <code>dividend == divisor</code> 116 */ 117 public static final RationalConverter of(double dividend, double divisor) { 118 return new RationalConverter(dividend, divisor); 119 } 120 121 /** 122 * Returns the integer dividend for this rational converter. 123 * 124 * @return this converter dividend. 125 */ 126 public double getDividend() { 127 return dividend; 128 } 129 130 /** 131 * Returns the integer (positive) divisor for this rational converter. 132 * 133 * @return this converter divisor. 134 */ 135 public double getDivisor() { 136 return divisor; 137 } 138 139 @Override 140 public double convert(double value) { 141 return value * ((double) dividend / (double) divisor); 142 } 143 144 @Override 145 public UnitConverter concatenate(UnitConverter converter) { 146 if (!(converter instanceof RationalConverter)) 147 return super.concatenate(converter); 148 RationalConverter that = (RationalConverter) converter; 149 double newDividend = this.getDividend() * that.getDividend(); 150 double newDivisor = this.getDivisor() * that.getDivisor(); 151 double gcd = gcd(newDividend, newDivisor); 152 newDividend = newDividend / gcd; // TODO clarify if this works with long 153 newDivisor = newDivisor / gcd; 154 return (newDividend == 1 && newDivisor == 1) ? IDENTITY : new RationalConverter(newDividend, newDivisor); 155 } 156 157 @Override 158 public RationalConverter inverse() { 159 return Math.signum(dividend) == -1 ? new RationalConverter(negateExact(getDivisor()), negateExact(getDividend())) : new RationalConverter( 160 getDivisor(), getDividend()); 161 } 162 163 @Override 164 public final String toString() { 165 return "RationalConverter(" + dividend + "," + divisor + ")"; 166 } 167 168 @Override 169 public boolean equals(Object obj) { 170 if (!(obj instanceof RationalConverter)) 171 return false; 172 RationalConverter that = (RationalConverter) obj; 173 return (this.dividend == that.dividend && this.divisor == that.divisor); 174 } 175 176 @Override 177 public int hashCode() { 178 return Double.valueOf(dividend).hashCode() + Double.valueOf(dividend).hashCode(); 179 } 180 181 public boolean isLinear() { 182 return true; 183 } 184 185 public double getAsDouble() { 186 return (double) dividend / (double) divisor; 187 } 188 189 public Double getValue() { 190 return Double.valueOf(getAsDouble()); 191 } 192}