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.IntExponentSupplier; 040 041/** 042 * This class represents a converter multiplying numeric values by a factor of 043 * Pi to the power of an integer exponent (π^exponent). 044 * @author Andi Huber 045 * @author Werner Keil 046 * @version 1.1, May 10, 2018 047 * @since 2.0 048 */ 049public final class PowerOfPiConverter extends AbstractConverter 050 implements IntExponentSupplier { 051 private static final long serialVersionUID = 5000593326722785126L; 052 053 private final int exponent; 054 private final int hashCode; 055 private final double doubleFactor; // for double calculus only 056 057 /** 058 * Creates a converter with the specified exponent. 059 * 060 * @param exponent 061 * the exponent for the factor π^exponent. 062 */ 063 public static PowerOfPiConverter of(int exponent) { 064 return new PowerOfPiConverter(exponent); 065 } 066 067 protected PowerOfPiConverter(int exponent) { 068 this.exponent = exponent; 069 this.doubleFactor = Math.pow(Math.PI, exponent); 070 this.hashCode = Objects.hash(exponent); 071 } 072 073 public int getExponent() { 074 return exponent; 075 } 076 077 @Override 078 public boolean isIdentity() { 079 return exponent == 0; // x^0 = 1, for any x!=0 080 } 081 082 @Override 083 public boolean isLinear() { 084 return true; 085 } 086 087 @Override 088 public AbstractConverter inverseWhenNotIdentity() { 089 return new PowerOfPiConverter(-exponent); 090 } 091 092 @Override 093 public BigDecimal convertWhenNotIdentity(BigDecimal value, MathContext ctx) throws ArithmeticException { 094 int nbrDigits = ctx.getPrecision(); 095 if (nbrDigits == 0) { 096 throw new ArithmeticException("Pi multiplication with unlimited precision"); 097 } 098 BigDecimal pi = Constants.Pi.ofNumDigits(nbrDigits); 099 return pi.pow(exponent, ctx).multiply(value); 100 } 101 102 @Override 103 public double convertWhenNotIdentity(double value) { 104 //[ahuber] multiplication is probably non-critical regarding preservation of precision 105 return value * doubleFactor; 106 } 107 108 @Override 109 protected boolean isSimpleCompositionWith(AbstractConverter that) { 110 return that instanceof PowerOfPiConverter; 111 } 112 113 @Override 114 protected AbstractConverter simpleCompose(AbstractConverter that) { 115 return new PowerOfPiConverter(this.exponent + ((PowerOfPiConverter)that).exponent); 116 } 117 118 @Override 119 public boolean equals(Object obj) { 120 if (this == obj) { 121 return true; 122 } 123 if (obj instanceof UnitConverter) { 124 UnitConverter other = (UnitConverter) obj; 125 if(this.isIdentity() && other.isIdentity()) { 126 return true; 127 } 128 } 129 if (obj instanceof PowerOfPiConverter) { 130 PowerOfPiConverter other = (PowerOfPiConverter) obj; 131 return this.exponent == other.exponent; 132 } 133 return false; 134 } 135 136 @Override 137 public final String transformationLiteral() { 138 return String.format("x -> x * π^%s", exponent); 139 } 140 141 @Override 142 public int compareTo(UnitConverter o) { 143 if (this == o) { 144 return 0; 145 } 146 if(this.isIdentity() && o.isIdentity()) { 147 return 0; 148 } 149 if (o instanceof PowerOfPiConverter) { 150 PowerOfPiConverter other = (PowerOfPiConverter) o; 151 return Integer.compare(exponent, other.exponent); 152 } 153 return this.getClass().getName().compareTo(o.getClass().getName()); 154 } 155 156 @Override 157 public int hashCode() { 158 return hashCode; 159 } 160 161}