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
017package jet.runtime;
018
019public 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}