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 logarithmic converter of limited precision. Such converter is typically used to create logarithmic unit. For example:<code> 044 * Unit<Dimensionless> BEL = Unit.ONE.transform(new LogConverter(10).inverse()); </code> 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.1, December 28, 2017 049 * @since 1.0 050 */ 051public final class LogConverter extends AbstractConverter implements ValueSupplier<String> { // implements 052 // Immutable<String> 053 // { 054 055 /** 056 * 057 */ 058 private static final long serialVersionUID = -7584688290961460870L; 059 060 /** 061 * Holds the logarithmic base. 062 */ 063 private final double base; 064 /** 065 * Holds the natural logarithm of the base. 066 */ 067 private final double logOfBase; 068 069 /** 070 * Returns a logarithmic converter having the specified base. 071 * 072 * @param base 073 * the logarithmic base (e.g. <code>Math.E</code> for the Natural Logarithm). 074 */ 075 public LogConverter(double base) { 076 this.base = base; 077 this.logOfBase = Math.log(base); 078 } 079 080 /** 081 * Returns the logarithmic base of this converter. 082 * 083 * @return the logarithmic base (e.g. <code>Math.E</code> for the Natural Logarithm). 084 */ 085 public double getBase() { 086 return base; 087 } 088 089 @Override 090 public boolean isIdentity() { 091 return false; 092 } 093 094 @Override 095 protected boolean isSimpleCompositionWith(AbstractConverter that) { 096 if(that instanceof ExpConverter) { 097 return ((ExpConverter)that).getBase() == base; // can compose with exp to identity, provided it has same base 098 } 099 return false; 100 } 101 102 @Override 103 protected AbstractConverter simpleCompose(AbstractConverter that) { 104 return AbstractConverter.IDENTITY; 105 } 106 107 @Override 108 public AbstractConverter inverseWhenNotIdentity() { 109 return new ExpConverter(base); 110 } 111 112 @Override 113 public final String transformationLiteral() { 114 if (base == Math.E) { 115 return "x -> ln(x)"; 116 } else { 117 return String.format("x -> log(base=%s, x)", base); 118 } 119 } 120 121 @Override 122 public boolean equals(Object obj) { 123 if (this == obj) { 124 return true; 125 } 126 if (obj instanceof LogConverter) { 127 LogConverter that = (LogConverter) obj; 128 return Objects.equals(base, that.base); 129 } 130 return false; 131 } 132 133 @Override 134 public int hashCode() { 135 return Objects.hash(base); 136 } 137 138 @Override 139 public double convertWhenNotIdentity(double amount) { 140 return Math.log(amount) / logOfBase; 141 } 142 143 @Override 144 public BigDecimal convertWhenNotIdentity(BigDecimal value, MathContext ctx) throws ArithmeticException { 145 return BigDecimal.valueOf(convert(value.doubleValue())); // Reverts to 146 // double 147 // conversion. 148 } 149 150 @Override 151 public boolean isLinear() { 152 return false; 153 } 154 155 @Override 156 public String getValue() { 157 return toString(); 158 } 159 160 @Override 161 public int compareTo(UnitConverter o) { 162 if (this == o) { 163 return 0; 164 } 165 if (o instanceof ValueSupplier) { 166 return getValue().compareTo(String.valueOf(((ValueSupplier<?>) o).getValue())); 167 } 168 return -1; 169 } 170}