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