001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package jet.runtime;
018    
019    public class ProgressionUtil {
020        private ProgressionUtil() {
021        }
022    
023        // a mod b (in arithmetical sense)
024        private static int mod(int a, int b) {
025            int mod = a % b;
026            return mod >= 0 ? mod : mod + b;
027        }
028    
029        private static long mod(long a, long b) {
030            long mod = a % b;
031            return mod >= 0 ? mod : mod + b;
032        }
033    
034        // (a - b) mod c
035        private static int differenceModulo(int a, int b, int c) {
036            return mod(mod(a, c) - mod(b, c), c);
037        }
038    
039        private static long differenceModulo(long a, long b, long c) {
040            return mod(mod(a, c) - mod(b, c), c);
041        }
042    
043    
044        /**
045         * Calculates the final element of a bounded arithmetic progression, i.e. the last element of the progression which is in the range
046         * from {@code start} to {@code end} in case of a positive {@code increment}, or from {@code end} to {@code start} in case of a negative
047         * increment.
048         *
049         * <p>No validation on passed parameters is performed. The given parameters should satisfy the condition: either
050         * {@code increment&nbsp;&gt; 0} and {@code start&nbsp;&lt;= end}, or {@code increment&nbsp;&lt; 0} and {@code start&nbsp;&gt;= end}.
051         * @param start first element of the progression
052         * @param end ending bound for the progression
053         * @param increment increment, or difference of successive elements in the progression
054         * @return the final element of the progression
055         */
056        public static int getProgressionFinalElement(int start, int end, int increment) {
057            if (increment > 0) {
058                return end - differenceModulo(end, start, increment);
059            }
060            else {
061                return end + differenceModulo(start, end, -increment);
062            }
063        }
064    
065        /**
066         * Calculates the final element of a bounded arithmetic progression, i.e. the last element of the progression which is in the range
067         * from {@code start} to {@code end} in case of a positive {@code increment}, or from {@code end} to {@code start} in case of a negative
068         * increment.
069         *
070         * <p>No validation on passed parameters is performed. The given parameters should satisfy the condition: either
071         * {@code increment&nbsp;&gt; 0} and {@code start&nbsp;&lt;= end}, or {@code increment&nbsp;&lt; 0} and {@code start&nbsp;&gt;= end}.
072         * @param start first element of the progression
073         * @param end ending bound for the progression
074         * @param increment increment, or difference of successive elements in the progression
075         * @return the final element of the progression
076         */
077        public static long getProgressionFinalElement(long start, long end, long increment) {
078            if (increment > 0) {
079                return end - differenceModulo(end, start, increment);
080            }
081            else {
082                return end + differenceModulo(start, end, -increment);
083            }
084        }
085    }