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