/// POWER INTEGER /// /// <summary> /// Performs the quick mathematical power operation. /// Works only for integer exponent values. /// /// WARNING! The power value here should be an integer number, /// that is, the calculator method 'integerPower(power)' should /// return the same value as power. Otherwise, the result /// would be unpredictable AND INCORRECT. /// </summary> /// <param name="number">The number to raise to the power.</param> /// <param name="power">The INTEGER exponent of the power.</param> /// <returns>The number raised to the integer power.</returns> public static T PowerInteger_Generic(T number, T power) { power = calc.intPart(power); if (power == Numeric <T, C> .Zero) { return(calc.fromInt(1)); } else if (power < Numeric <T, C> .Zero) { if (number <= Numeric <T, C> .Zero) { throw new ArgumentException("Cannot raise a non-positive number to a negative power."); } return(calc.div(calc.fromInt(1), PowerInteger_Generic(number, calc.negate(power)))); } // Ноль в любой степени будет ноль: if (calc.eqv(number, calc.zero)) { return(calc.zero); } Numeric <T, C> res = calc.fromInt(1); // результат возведения в степень Numeric <T, C> copy = calc.getCopy(number); // изменяемая копия (переданное число может быть ссылочным типом) T two = calc.fromInt(2); T one = calc.fromInt(1); while (power > Numeric <T, C> .Zero) { // Если остаток от деления на 2 равен 1 if (calc.eqv(WhiteMath <T, C> .Modulus(power, two), one)) { res *= copy; } copy *= copy; power = calc.intPart(calc.div(power, two)); } return(res); }
/// <summary> /// Нормализует число, делит числитель и знаменатель на НОД, /// делает числитель положительным. /// </summary> private void normalize() { T gcd = WhiteMath <T, C> .GreatestCommonDivisor(WhiteMath <T, C> .Abs(num), WhiteMath <T, C> .Abs(denom)); if (calc.eqv(gcd, calc.zero)) { return; // for infinity-checking cases } num = calc.div(num, gcd); denom = calc.div(denom, gcd); // Если знаменатель меньше нуля if (calc.mor(calc.zero, denom)) { num = calc.negate(num); denom = calc.negate(denom); } }
public static bool operator >(Rational <T, C> one, Rational <T, C> two) { if (one is NotANumber || two is NotANumber) { return(false); } else if (one is Positive_Infinity || two is Negative_Infinity) { return(true); } else if (two is Positive_Infinity || one is Negative_Infinity) { return(false); } T denomLcm = WhiteMath <T, C> .LowestCommonMultiple(one.denom, two.denom, WhiteMath <T, C> .GreatestCommonDivisor(one.denom, two.denom)); return(calc.mor(calc.mul(one.num, calc.div(denomLcm, one.denom)), calc.mul(two.num, calc.div(denomLcm, two.denom)))); }
///----------------------------------- ///----ARITHMETIC OPERATORS----------- ///----------------------------------- public static Rational <T, C> operator +(Rational <T, C> one, Rational <T, C> two) { if (one is Infinities) { if (two is Infinities) { if (one.GetType().Equals(two.GetType())) { return(one); } else { return(NaN); } } return(one); } else if (two is Infinities) { return(two + one); } Rational <T, C> tmp = new Rational <T, C>(); tmp.denom = WhiteMath <T, C> .LowestCommonMultiple(one.denom, two.denom, WhiteMath <T, C> .GreatestCommonDivisor(one.denom, two.denom)); tmp.num = calc.sum(calc.mul(one.num, calc.div(tmp.denom, one.denom)), calc.mul(two.num, calc.div(tmp.denom, two.denom))); if (checkInf(ref tmp)) { tmp.normalize(); } return(tmp); }
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); }
public static Rational <T, C> operator -(Rational <T, C> one, Rational <T, C> two) { if (one is Infinities || two is Infinities) { if (one is NotANumber || two is NotANumber) { return(NaN); } else if (one is Positive_Infinity) { if (two is Infinities) { if (two is Negative_Infinity) { return(one); } else { return(NaN); } } return(one); } else if (two is Positive_Infinity) { if (one is Infinities) { if (one is Negative_Infinity) { return(one); } else { return(NaN); } } return(NegativeInfinity); } else if (one is Negative_Infinity) { if (two is Infinities) { if (two is Positive_Infinity) { return(one); } else { return(NaN); } } return(one); } else if (two is Negative_Infinity) { if (one is Infinities) { if (one is Positive_Infinity) { return(one); } else { return(NaN); } } return(PositiveInfinity); } } Rational <T, C> tmp = new Rational <T, C>(); tmp.denom = WhiteMath <T, C> .LowestCommonMultiple(one.denom, two.denom, WhiteMath <T, C> .GreatestCommonDivisor(one.denom, two.denom)); tmp.num = calc.dif(calc.mul(one.num, calc.div(tmp.denom, one.denom)), calc.mul(two.num, calc.div(tmp.denom, two.denom))); if (checkInf(ref tmp)) { tmp.normalize(); } return(tmp); }
/// <summary> /// Finds the greatest common divisor of two integer-like numbers /// using the simple Euclid algorithm. /// /// The calculator for the numbers is recommended to provide reasonable implementation /// of the remainder operation (%) - otherwise, the function /// Modulus from whiteMath class will be used. /// /// Will work with floating-point type numbers only if they are integers; /// In case of division errors the result will be rounded and thus not guaranteed. /// </summary> /// <param name="one"></param> /// <param name="two"></param> /// <returns></returns> public static T GreatestCommonDivisor(T one, T two) { Contract.Requires <ArgumentException>(one != Numeric <T, C> .Zero && two != Numeric <T, C> .Zero, "None of the numbers may be zero."); Contract.Ensures(Contract.Result <T>() > Numeric <T, C> .Zero); Contract.Ensures((Numeric <T, C>)one % Contract.Result <T>() == Numeric <T, C> .Zero); Contract.Ensures((Numeric <T, C>)two % Contract.Result <T>() == Numeric <T, C> .Zero); // T может быть ссылочным типом, поэтому необходимо // предостеречь объекты от изменения // а также отсечь знаки по необходимости T oneTmp; T twoTmp; if (calc.mor(calc.zero, one)) { oneTmp = calc.negate(one); } else { oneTmp = calc.getCopy(one); } if (calc.mor(calc.zero, two)) { twoTmp = calc.negate(two); } else { twoTmp = calc.getCopy(two); } try { while (!calc.eqv(oneTmp, calc.zero) && !calc.eqv(twoTmp, calc.zero)) { if (calc.mor(oneTmp, twoTmp)) { oneTmp = calc.rem(oneTmp, twoTmp); } else { twoTmp = calc.rem(twoTmp, oneTmp); } } } catch // calculator throws exception - working with fp's. { oneTmp = calc.intPart(oneTmp); twoTmp = calc.intPart(twoTmp); while (!calc.eqv(oneTmp, calc.zero) && !calc.eqv(twoTmp, calc.zero)) { if (calc.mor(oneTmp, twoTmp)) { oneTmp = WhiteMath <T, C> .Round(WhiteMath <T, C> .Modulus(oneTmp, twoTmp)); } else { twoTmp = WhiteMath <T, C> .Round(WhiteMath <T, C> .Modulus(twoTmp, oneTmp)); } } } return(calc.sum(oneTmp, twoTmp)); }
/// <summary> /// Returns the value of the Jacobi symbol for /// the two numbers, that is, the multiplication product /// of Legendre symbols with numerators all equal to the Jacobi symbol's /// numerator and denominators taken from the factorization /// of Jacobi symbol's denominator. /// </summary> /// <param name="num">The numerator of the Jacobi symbol.</param> /// <param name="denom">The denominator of the Jacobi symbol. Should be odd and positive.</param> /// <returns>The value of the Jacobi symbol for <paramref name="num"/> and <paramref name="denom"/>.</returns> public static int JacobiSymbol(T num, T denom) { Contract.Requires <NonIntegerTypeException>(Numeric <T, C> .Calculator.isIntegerCalculator, "The method works only for integer numeric types."); Contract.Requires <ArgumentException>(denom > Numeric <T, C> .Zero && !Numeric <T, C> .Calculator.isEven(denom), "The denominator of the Jacobi symbol should be odd and positive."); bool minus = false; // флаг минуса Numeric <T, C> x = num; Numeric <T, C> y = denom; if (y == Numeric <T, C> ._1) { return(1); } if (WhiteMath <T, C> .GreatestCommonDivisor(x, y) != Numeric <T, C> ._1) { return(0); } if (x < Numeric <T, C> .Zero) { // Надо домножить на (-1)^((y-1)/2) // Эта величина равна -1 тогда и только тогда, когда floor(y/2) - четное число. if ((y / Numeric <T, C> ._2).Even) { minus ^= true; } x = -x; } // На этом шаге ни в числителе, // ни в знаменателе не осталось отрицательных чисел. while (true) { // (x; y) = (x mod y; y) ------------------ if (x > y) { x = x % y; } // ---------- избавляемся от четности ----- int t = 0; while (x.Even) { // Надо домножить на (-1)^((y^2 - 1)/8) // Эта величина равна -1 тогда и только тогда, когда y имеет остатки 3 или 5 при делении на 8 ++t; x /= Numeric <T, C> ._2; } if (t % 2 != 0) { Numeric <T, C> rem = y % Numeric <T, C> ._8; if (rem == Numeric <T, C> ._3 || rem == Numeric <T, C> ._5) { minus ^= true; } } // ---------------------------------------- // --- Если x - единица, то надо вернуться. // ---------------------------------------- if (x == Numeric <T, C> ._1) { return(minus ? -1 : 1); } // ---------------------------------------------------- // -- x и y на этом этапе гарантированно взаимно просты // -- и нечетны, поэтому можно использовать свойство (8) из твоей тетрадочки // ---------------------------------------------------- if (x < y) { if (x % Numeric <T, C> ._4 == Numeric <T, C> ._3 && y % Numeric <T, C> ._4 == Numeric <T, C> ._3) { minus ^= true; } Numeric <T, C> tmp = x; x = y; y = tmp; } } }