/// <summary> /// Finds the maximum number '<c>k</c>' within a given integer interval such that a predicate /// holds for this number '<c>k</c>'. /// </summary> /// <typeparam name="T">The type of numbers contained inside the interval.</typeparam> /// <typeparam name="C">A calculator for the <typeparamref name="T"/> type.</typeparam> /// <param name="interval"> /// An integer interval, containing at least one number for which the <paramref name="predicate"/> /// holds. /// </param> /// <param name="predicate"> /// A predicate that should hold for the desired number and not for every number that is bigger and located /// inside the interval. /// </param> /// <remarks> /// This method takes <c>O(n)</c> time for intervals of length '<c>n</c>'. Thus, it usually works significantly /// slower than <see cref="Max_BinarySearch<T,C>"/>, but does not put any restrictions /// on the <paramref name="interval"/> object passed. /// </remarks> /// <returns> /// A <c>PotentialResult<Numeric<T, C>></c> object which will store /// the maximum number within a given interval for which the <paramref name="predicate"/> holds, if the algorithm /// finds one. /// </returns> public static PotentialResult <Numeric <T, C> > Max_LinearSearch <T, C>(this BoundedInterval <T, C> interval, Predicate <T> predicate) where C : ICalc <T>, new() { Contract.Requires <ArgumentException>(Numeric <T, C> .Calculator.isIntegerCalculator, "This method works only for integer numbers."); Contract.Requires <ArgumentNullException>(predicate != null, "predicate"); Contract.Requires <ArgumentException>(!interval.IsEmptyInteger, "The interval should contain at least one integer point."); BoundedInterval <T, C> inclusive = interval.ToInclusiveIntegerInterval(); bool found = false; Numeric <T, C> max = Numeric <T, C> .Zero; for (Numeric <T, C> current = inclusive.LeftBound; current <= inclusive.RightBound; ++current) { if (predicate(current)) { found = true; max = current; } } if (!found) { return(PotentialResult <Numeric <T, C> > .CreateFailure()); } else { return(PotentialResult <Numeric <T, C> > .CreateSuccess(max)); } }
/// <summary> /// Finds the maximum number '<c>k</c>' within a given integer interval of special structure /// such that a predicate holds for this number '<c>k</c>'. /// </summary> /// <typeparam name="T">The type of numbers contained inside the interval.</typeparam> /// <typeparam name="C">A calculator for the <typeparamref name="T"/> type.</typeparam> /// <param name="interval"> /// <para> /// An integer interval which has a structure such that all numbers, starting with the leftmost inclusive bound and /// ending with the desired (sought-for) number, satisfy the predicate (and only these). /// In other words, the leftmost 'tail' of the interval should satisfy the predicate, /// and the rightmost 'tail' should not; the rightmost tail, though, may be empty. /// </para> /// <para> /// It should be KNOWN that the interval has such structure and that at least the leftmost inclusive bound satisfies the predicate. /// Otherwise, the behaviour of the function is undefined. /// </para> /// </param> /// <param name="predicate"> /// A predicate that should hold for all numbers, starting with the leftmost bound and ending with the /// desired (sought-for) number, and only for these. /// </param> /// <returns>The maximum number within a given interval for which the <paramref name="predicate"/> holds.</returns> public static T Max_BinarySearch <T, C>(this BoundedInterval <T, C> interval, Predicate <T> predicate) where C : ICalc <T>, new() { Contract.Requires <NonIntegerTypeException>(Numeric <T, C> .Calculator.isIntegerCalculator, "This method works only for integer numbers."); Contract.Requires <ArgumentException>(!interval.IsEmptyInteger, "The interval should contain at least one integer point."); Numeric <T, C> lb = (interval.IsLeftInclusive ? interval.LeftBound : interval.LeftBound + Numeric <T, C> ._1); Numeric <T, C> rb = (interval.IsRightInclusive ? interval.RightBound : interval.RightBound - Numeric <T, C> ._1); Numeric <T, C> one = Numeric <T, C> ._1; Numeric <T, C> two = Numeric <T, C> ._2; while (!(lb > rb)) { Numeric <T, C> mid = (lb + rb) / two; if (predicate(mid)) { lb = mid + one; } else { rb = mid - one; } } return(lb - one); }
public override bool Equals(object obj) { if (!(obj is BoundedInterval <T, C>)) { return(false); } BoundedInterval <T, C> interval = (BoundedInterval <T, C>)obj; return (this.IsLeftInclusive == interval.IsLeftInclusive && this.IsRightInclusive == interval.IsRightInclusive && calc.eqv(this.RightBound, interval.RightBound) && calc.eqv(this.LeftBound, interval.LeftBound)); }
public static Dictionary <T, List <T> > RootsOfUnity(T module, IEnumerable <T> rootDegrees, BoundedInterval <T, C>?searchInterval = null) { Contract.Requires <NonIntegerTypeException>(Numeric <T, C> .Calculator.isIntegerCalculator, "This method supports only integral types."); Contract.Requires <ArgumentNullException>(module != null, "module"); Contract.Requires <ArgumentOutOfRangeException>(module > Numeric <T, C> ._1, "The module should be more than 1."); Contract.Requires <ArgumentOutOfRangeException>(Contract.ForAll <T>(rootDegrees, (x => x >= Numeric <T, C> ._1 && x < (Numeric <T, C>)module)), "All of the root degrees specified should be located inside the [1; N-1] interval."); if (!searchInterval.HasValue) { searchInterval = new BoundedInterval <T, C>(Numeric <T, C> .Zero, module - Numeric <T, C> ._1, true, true); } Numeric <T, C> lowerBound = searchInterval.Value.LeftBound; Numeric <T, C> upperBound = searchInterval.Value.RightBound; if (!searchInterval.Value.IsLeftInclusive) { lowerBound++; } if (!searchInterval.Value.IsRightInclusive) { upperBound--; } // Contract.Requires<ArgumentOutOfRangeException>(lowerBound > Numeric<T, C>.Zero && upperBound < module - Numeric<T, C>.CONST_1, "The search interval should be located inside the [0; N-1] interval."); // Нам нужны только уникальные значения // поэтому сгенерируем множество ISet <Numeric <T, C> > rootDegreeSet = new HashSet <Numeric <T, C> >(); foreach (T degree in rootDegrees) { rootDegreeSet.Add(degree); } // ----------------------------- bool evenModule = calc.isEven(module); // Если нижняя граница четная, и модуль четный - по любому взаимно не простые. // Значит число - делитель нуля, и не может быть корнем из единицы ни при каких условиях. // Прибавляем единицу. if (calc.isEven(lowerBound) && evenModule) { lowerBound++; } Dictionary <T, List <T> > result = new Dictionary <T, List <T> >(); for (Numeric <T, C> current = lowerBound; current <= upperBound; current++) { // Если не взаимно просты с модулем - по-любому не может быть // примитивным корнем. if (WhiteMath <T, C> .GreatestCommonDivisor(current, module) != Numeric <T, C> ._1) { goto ENDING; } // Теперь занимаемся тестированием. Numeric <T, C> currentPower = Numeric <T, C> ._1; Numeric <T, C> tmp = current; while (true) { if (tmp == Numeric <T, C> ._1) { // Проверить степень корня if (rootDegreeSet.Contains(currentPower)) { if (!result.ContainsKey(currentPower)) { result.Add(currentPower, new List <T>()); } List <T> currentDegreeRootList = result[currentPower]; currentDegreeRootList.Add(current); } goto ENDING; } else if (tmp == Numeric <T, C> .Zero) { goto ENDING; } tmp = (tmp * tmp) % module; ++currentPower; } ENDING: // Если четный модуль - надо перескочить через два. if (evenModule) { current++; } } return(result); }