001/* 002 * Units of Measurement Implementation for Java SE 003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. 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-363 nor the names of its 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 tec.uom.se.function; 031 032import java.math.BigDecimal; 033import java.math.MathContext; 034import java.math.RoundingMode; 035import java.util.logging.Level; 036import java.util.logging.Logger; 037 038import tec.uom.lib.common.function.ValueSupplier; 039import tec.uom.se.AbstractConverter; 040 041/** 042 * <p> 043 * This class represents a converter multiplying numeric values by π (Pi). 044 * </p> 045 * 046 * @see <a href="http://en.wikipedia.org/wiki/Pi"> Wikipedia: Pi</a> 047 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 048 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 049 * @version 1.0.1, November 3, 2016 050 * @since 1.0 051 */ 052public final class PiMultiplierConverter extends AbstractConverter implements ValueSupplier<String> { 053 054 /** 055 * 056 */ 057 private static final long serialVersionUID = -5763262154104962367L; 058 059 private static final Logger logger = Logger.getLogger(PiMultiplierConverter.class.getName()); 060 061 /** 062 * Creates a Pi multiplier converter. 063 */ 064 public PiMultiplierConverter() { 065 } 066 067 @Override 068 public double convert(double value) { 069 return value * PI; 070 } 071 072 @Override 073 public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { 074 int nbrDigits = ctx.getPrecision(); 075 if (nbrDigits == 0) 076 throw new ArithmeticException("Pi multiplication with unlimited precision"); 077 BigDecimal pi = Pi.pi(nbrDigits); 078 return value.multiply(pi, ctx).scaleByPowerOfTen(1 - nbrDigits); 079 } 080 081 @Override 082 public AbstractConverter inverse() { 083 return new PiDivisorConverter(); 084 } 085 086 @Override 087 public final String toString() { 088 return "(π)"; 089 } 090 091 @Override 092 public boolean equals(Object obj) { 093 return (obj instanceof PiMultiplierConverter); 094 } 095 096 @Override 097 public int hashCode() { 098 return 0; 099 } 100 101 @Override 102 public boolean isLinear() { 103 return true; 104 } 105 106 /** 107 * Pi calculation with Machin's formula. 108 * 109 * @see <a href= "http://en.literateprograms.org/Pi_with_Machin's_formula_(Java)" >Pi with Machin's formula</a> 110 * 111 */ 112 static final class Pi { 113 114 private Pi() { 115 } 116 117 public static BigDecimal pi(int numDigits) { 118 int calcDigits = numDigits + 10; 119 return FOUR.multiply((FOUR.multiply(arccot(FIVE, calcDigits))).subtract(arccot(TWO_THIRTY_NINE, calcDigits))).setScale(numDigits, 120 RoundingMode.DOWN); 121 } 122 123 /* 124 * private static BigDecimal compute(int numDigits, boolean verbose) { 125 * int calcDigits = numDigits + 10; 126 * 127 * return FOUR .multiply((FOUR.multiply(arccot(FIVE, 128 * calcDigits))).subtract(arccot(TWO_THIRTY_NINE, calcDigits))) 129 * .setScale(numDigits, RoundingMode.DOWN); } 130 */ 131 /** Compute arccot via the Taylor series expansion. */ 132 private static BigDecimal arccot(BigDecimal x, int numDigits) { 133 BigDecimal unity = BigDecimal.ONE.setScale(numDigits, RoundingMode.DOWN); 134 BigDecimal sum = unity.divide(x, RoundingMode.DOWN); 135 BigDecimal xpower = new BigDecimal(sum.toString()); 136 BigDecimal term = null; 137 int nTerms = 0; 138 139 BigDecimal nearZero = BigDecimal.ONE.scaleByPowerOfTen(-numDigits); 140 logger.log(Level.FINER, "arccot: ARGUMENT=" + x + " (nearZero=" + nearZero + ")"); 141 boolean add = false; 142 // Add one term of Taylor series each time thru loop. Stop looping 143 // when _term_ 144 // gets very close to zero. 145 for (BigDecimal n = THREE; term == null || !term.equals(BigDecimal.ZERO); n = n.add(TWO)) { 146 if (term != null && term.compareTo(nearZero) < 0) 147 break; 148 xpower = xpower.divide(x.pow(2), RoundingMode.DOWN); 149 term = xpower.divide(n, RoundingMode.DOWN); 150 sum = add ? sum.add(term) : sum.subtract(term); 151 add = !add; 152 // System.out.println("arccot: xpower=" + xpower + ", term=" + 153 // term); 154 logger.log(Level.FINEST, "arccot: term=" + term); 155 nTerms++; 156 } 157 logger.log(Level.FINER, "arccot: done. nTerms=" + nTerms); 158 return sum; 159 } 160 } 161 162 private static final BigDecimal TWO = new BigDecimal("2"); 163 164 private static final BigDecimal THREE = new BigDecimal("3"); 165 166 private static final BigDecimal FOUR = new BigDecimal("4"); 167 168 private static final BigDecimal FIVE = new BigDecimal("5"); 169 170 private static final BigDecimal TWO_THIRTY_NINE = new BigDecimal("239"); 171 172 @Override 173 public String getValue() { 174 return toString(); 175 } 176}