001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2020, Units of Measurement project. 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-385, Indriya nor the names of their 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 tech.units.indriya.function; 031 032import java.util.Objects; 033 034import javax.measure.UnitConverter; 035 036import tech.units.indriya.internal.function.calc.Calculator; 037import tech.uom.lib.common.function.ValueSupplier; 038 039/** 040 * <p> 041 * This class represents a exponential converter of limited precision. Such converter is used to create inverse of logarithmic unit. 042 * 043 * <p> 044 * This class is package private, instances are created using the {@link LogConverter#inverse()} method. 045 * </p> 046 * 047 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 048 * @author <a href="mailto:werner@units.tech">Werner Keil</a> 049 * @author Andi Huber 050 * @version 1.5, Jun 21, 2019 051 * @since 1.0 052 */ 053public final class ExpConverter extends AbstractConverter implements ValueSupplier<String> { 054 055 /** 056 * 057 */ 058 private static final long serialVersionUID = -8851436813812059827L; 059 060 /** 061 * Holds the logarithmic base. 062 */ 063 private final double base; 064 065 /** 066 * Holds the natural logarithm of the base. 067 */ 068 private final double logOfBase; 069 070 /** 071 * Creates a logarithmic converter having the specified base. 072 * 073 * @param base 074 * the logarithmic base (e.g. <code>Math.E</code> for the Natural Logarithm). 075 */ 076 public ExpConverter(double base) { 077 this.base = base; 078 this.logOfBase = Math.log(base); 079 } 080 081 /** 082 * Creates a logarithmic converter having the specified base. 083 * 084 * @param base 085 * the logarithmic base (e.g. <code>Math.E</code> for the Natural Logarithm). 086 */ 087 public static ExpConverter of(double base) { 088 return new ExpConverter(base); 089 } 090 091 /** 092 * Returns the exponential base of this converter. 093 * 094 * @return the exponential base (e.g. <code>Math.E</code> for the Natural Exponential). 095 */ 096 public double getBase() { 097 return base; 098 } 099 100 @Override 101 public boolean isIdentity() { 102 return false; 103 } 104 105 @Override 106 protected boolean canReduceWith(AbstractConverter that) { 107 if(that instanceof LogConverter) { 108 return ((LogConverter)that).getBase() == base; // can compose with log to identity, provided it has same base 109 } 110 return false; 111 } 112 113 @Override 114 protected AbstractConverter reduce(AbstractConverter that) { 115 return AbstractConverter.IDENTITY; 116 } 117 118 @Override 119 public AbstractConverter inverseWhenNotIdentity() { 120 return new LogConverter(base); 121 } 122 123 @Override 124 public final String transformationLiteral() { 125 if (base == Math.E) return "x -> e^x"; 126 127 if (base<0) return String.format("x -> (%s)^x", base); 128 129 return String.format("x -> %s^x", base); 130 } 131 132 @Override 133 public boolean equals(Object obj) { 134 if (this == obj) { 135 return true; 136 } 137 if (obj instanceof ExpConverter) { 138 ExpConverter that = (ExpConverter) obj; 139 return Objects.equals(base, that.base); 140 } 141 return false; 142 } 143 144 @Override 145 public int hashCode() { 146 return Objects.hash(base); 147 } 148 149 @Override 150 protected Number convertWhenNotIdentity(Number value) { 151 return Calculator.of(logOfBase) 152 .multiply(value) 153 .exp() 154 .peek(); 155 } 156 157 @Override 158 public boolean isLinear() { 159 return false; 160 } 161 162 @Override 163 public String getValue() { 164 return toString(); 165 } 166 167 @SuppressWarnings("rawtypes") 168 @Override 169 public int compareTo(UnitConverter o) { 170 if (this == o) { 171 return 0; 172 } 173 if (o instanceof ValueSupplier) { 174 return getValue().compareTo(String.valueOf(((ValueSupplier) o).getValue())); 175 } 176 return -1; 177 } 178 179 180}