001/*
002 * Units of Measurement Reference Implementation
003 * Copyright (c) 2005-2021, 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.internal.function.radix;
031
032import static org.apiguardian.api.API.Status.INTERNAL;
033
034import java.util.Objects;
035
036import javax.measure.UnitConverter;
037
038import org.apiguardian.api.API;
039
040import tech.units.indriya.function.Calculus;
041import tech.units.indriya.spi.NumberSystem;
042
043/**
044 * Internal utility for {@link MixedRadixSupport}.
045 * 
046 * @author Andi Huber
047 * @since 2.0
048 */
049@API(status=INTERNAL)
050public interface Radix {
051
052    /**
053     * Multiply without precision loss. 
054     * @param number
055     * @return
056     */
057    Number multiply(Number number);
058    
059    /**
060     * Returns a two-element Number array containing {number / radix, number % radix} 
061     * @param number
062     * @param roundRemainderTowardsZero - whether the division remainder should be rounded towards ZERO
063     * @return
064     */
065    Number[] divideAndRemainder(Number number, boolean roundRemainderTowardsZero);
066    
067    // -- FACTORIES
068    
069    public static Radix ofNumberFactor(Number number) {
070        return new NumberFactorRadix(number);
071    }
072    
073    public static Radix ofMultiplyConverter(UnitConverter linearUnitConverter) {
074        Objects.requireNonNull(linearUnitConverter, "unitConverter cannot be null");
075        if(!linearUnitConverter.isLinear()) {
076            throw new IllegalArgumentException("unitConverter is expected to be linear");
077        }
078        Number radix = Calculus.currentNumberSystem().narrow(linearUnitConverter.convert(1));
079        return new NumberFactorRadix(radix);
080    }
081    
082    // -- RADIX IMPLEMENTATION
083    
084    //can be made private with later java versions 
085    public static class NumberFactorRadix implements Radix {
086        
087        private final Number radix;
088        
089        public NumberFactorRadix(Number radix) {
090            this.radix = ns().narrow(radix);
091        }
092
093        @Override
094        public Number multiply(Number number) {
095            Number result = ns().multiply(radix, ns().narrow(number));
096            return ns().narrow(result);
097        }
098
099        @Override
100        public Number[] divideAndRemainder(Number number, boolean roundRemainderTowardsZero) {
101            
102            Number[] result =  ns().divideAndRemainder(
103                    ns().narrow(number), 
104                    radix, 
105                    roundRemainderTowardsZero);
106            result[0] = ns().narrow(result[0]);
107            result[1] = ns().narrow(result[1]);
108            return result;
109        }
110        
111        private static NumberSystem ns() {
112            return Calculus.currentNumberSystem();
113        }
114        
115    }
116    
117    
118}