private void _MakeGeronIteration() { OmgNum rootAprox = m_rootAprox.OmgWrapper(); var res = OmgOp.DivMod(m_targetSquareNum, rootAprox); res.mod.Release(); OmgNum sum = OmgOp.Add(rootAprox, res.div); res.div.Release(); sum.Raw.DivByTwo(); OmgPool.ReleaseNumber(m_buffer); m_buffer = m_rootAprox; m_rootAprox = sum.Raw; }
private OmgNum _MakeFastPow(OmgNum left, RawNum right, OmgNum mod) { if (right.IsZero()) { var res = OmgPool.GetRawZero(); res.Digits.Add(1); return(new OmgNum(res)); } var rightCopy = OmgPool.GetRawZero(); rightCopy.CopyFrom(right); bool even = (rightCopy.Digits[0] & 1) == 0; if (even) { rightCopy.DivByTwo(); var p = _MakeFastPow(left, rightCopy, mod); OmgNum powSquare = OmgOp.Multiply(p, p); OmgNum powSquareModded = OmgOp.Mod(powSquare, mod); powSquare.Release(); p.Release(); OmgPool.ReleaseNumber(rightCopy); return(powSquareModded); } else { _SubOne(rightCopy); var p = _MakeFastPow(left, rightCopy, mod); OmgNum powPlusOne = OmgOp.Multiply(p, left); OmgNum powPlusOneModded = OmgOp.Mod(powPlusOne, mod); powPlusOne.Release(); p.Release(); OmgPool.ReleaseNumber(rightCopy); return(powPlusOneModded); } }
internal RawNum FindGcd(RawNum left, RawNum right) { if (left.IsZero()) { RawNum gcd = OmgPool.GetRawZero(); gcd.CopyFrom(right); return(gcd); } var divModRes = OmgOp.DivMod(right.OmgWrapper(), left.OmgWrapper()); divModRes.div.Release(); RawNum gcdRes = FindGcd(divModRes.mod.Raw, left); divModRes.mod.Release(); return(gcdRes); }
public bool Equal(RawNum left, RawNum right) { int sizeDif = right.Size - left.Size; if (sizeDif != 0) { return(false); } for (int i = 0; i < left.Size; i++) { if (right.Digits[i] != left.Digits[i]) { return(false); } } return(true); }
private bool _ModLessThan(RawNum right, bool strictly = true) { if (m_modRaw.Size - m_modLeadingZeros != right.Size) { return(m_modRaw.Size - m_modLeadingZeros < right.Size); } int commonSize = right.Size; for (int i = m_modLeadingZeros; i < m_modRaw.Size; i++) { int rightIndex = commonSize - (i - m_modLeadingZeros) - 1; if (m_modRaw.Digits[i] != right.Digits[rightIndex]) { return(m_modRaw.Digits[i] < right.Digits[rightIndex]); } } return(!strictly); }
public bool Less(RawNum left, RawNum right) { int sizeDif = right.Size - left.Size; if (sizeDif != 0) { return(sizeDif > 0); } for (int i = left.Size - 1; i >= 0; i--) { Int32 diff = (Int32)right.Digits[i] - (Int32)left.Digits[i]; if (diff != 0) { return(diff > 0); } } return(false); }
internal RawNum GenerateWithBitlength(int bitLength) { m_result = OmgPool.GetRawZero(); int intermediateDigits = bitLength / 16; for (int i = 0; i < intermediateDigits; i++) { m_result.Digits.Add((UInt32)m_rand.Next(1 << 16)); } int restBits = bitLength % 16; if (restBits > 0) { m_result.Digits.Add((UInt32)m_rand.Next(1 << restBits)); } m_result.RemoveLeadingZeros(); return(m_result); }
private void _SubtractFromMod(RawNum subtrahend) { const UInt32 leadingBit = (1 << 16); UInt32 z = 0; for (int i = 0; i < m_modRaw.Size - m_modLeadingZeros; i++) { UInt32 modDig = m_modRaw.Digits[m_modRaw.Size - i - 1]; UInt32 subDig = (i < subtrahend.Size) ? subtrahend.Digits[i] : 0; UInt32 sub = (leadingBit | modDig) - subDig - z; m_modRaw.Digits[m_modRaw.Size - i - 1] = sub & UInt16.MaxValue; z = (~sub & leadingBit) >> 16; } for (int i = m_modLeadingZeros; i < m_modRaw.Size && m_modRaw.Digits[i] == 0; i++) { m_modLeadingZeros++; } }
internal RawNum Multiply(RawNum left, RawNum right) { m_multRaw = OmgPool.GetRawZero(); if (left.IsZero() || right.IsZero()) { return(m_multRaw); } if (left.Size < right.Size) { _Swap(ref left, ref right); } _MakeMult(left, right); while (m_multRaw.Size > 0 && m_multRaw.Digits[m_multRaw.Size - 1] == 0) { m_multRaw.Digits.RemoveAt(m_multRaw.Size - 1); } return(m_multRaw); }
private UInt16 _FindDivDigit(RawNum right) { UInt32 down = 0, upper = UInt16.MaxValue; UInt32 answer = 0; while (upper >= down) { UInt32 tested = (upper + down) >> 1; _MultiplyByDigit(right, tested, m_buffer); if (_ModLessThan(m_buffer, strictly: true)) { upper = tested - 1; } else { answer = tested; down = tested + 1; } } return((UInt16)answer); }
private void _CalcDivMod(RawNum left, RawNum right) { int offset = left.Size - right.Size + 1; _CopyHead(left, right.Size - 1, m_modRaw); while (offset > 0) { m_modRaw.Digits.Add(left.Digits[--offset]); if (_ModLessThan(right)) { _AddZeroToResult(); } else { UInt16 divDigit = _FindDivDigit(right); _MultiplyByDigit(right, divDigit, m_buffer); _SubtractFromMod(m_buffer); m_divRaw.Digits.Add(divDigit); } } }
internal RawNum Pow(RawNum left, RawNum right, RawNum mod = null) { m_powRes = OmgPool.GetZero(); if (left.IsZero()) { return(m_powRes.Raw); } if (right.IsZero()) { m_powRes.Raw.Digits.Add(1); return(m_powRes.Raw); } if (mod == null) { return(_MakeFastPow(new OmgNum(left), right).Raw); } else { return(_MakeFastPow(new OmgNum(left), right, new OmgNum(mod)).Raw); } }
public static OmgNum ToOmgNum(this int number) { OmgNum result = OmgPool.GetZero(); if (number == 0) { return(result); } RawNum rawNumber = result.Raw; result.IsNegative = number < 0; UInt32 absNum = (UInt32)Math.Abs(number); rawNumber.Digits.Add((UInt16)(absNum & ((1 << 16) - 1))); if ((absNum >> 16) > 0) { rawNumber.Digits.Add((UInt16)(absNum >> 16)); } return(result); }
internal RawNum MultiplyKaratsuba(RawNum left, RawNum right) { if (left.IsZero() || right.IsZero()) { return(OmgPool.GetRawZero()); } int n = Math.Min(left.Size, right.Size); (RawNum head, RawNum tail)leftSep = _SeparateHead(left, n); (RawNum head, RawNum tail)rightSep = _SeparateHead(right, n); RawNum headsProd = Multiply(leftSep.head, rightSep.head); RawNum tailsProd = Multiply(leftSep.tail, rightSep.tail); RawNum headTail = Multiply(leftSep.head, rightSep.tail); RawNum tailHead = Multiply(leftSep.tail, rightSep.head); OmgNum midSum = OmgOp.Add(new OmgNum(headTail), new OmgNum(tailHead)); m_multRaw = OmgPool.GetRawZero(); m_multRaw.CopyFrom(tailsProd); midSum.Raw.Digits.InsertRange(0, Enumerable.Repeat <uint>(0, n)); headsProd.Digits.InsertRange(0, Enumerable.Repeat <uint>(0, 2 * n)); OmgNum res = OmgOp.Add(new OmgNum(tailsProd), midSum); OmgNum finalRes = OmgOp.Add(new OmgNum(headsProd), res); midSum.Release(); res.Release(); OmgPool.ReleaseNumber(headTail); OmgPool.ReleaseNumber(tailHead); return(finalRes.Raw); }
private void _Subtract(RawNum left, RawNum right) { const UInt32 leadingBit = (1 << 16); UInt32 z = 0; for (int i = 0; i < left.Size; i++) { UInt32 rightDig = (i < right.Size) ? right.Digits[i] : 0; UInt32 sub = (leadingBit | left.Digits[i]) - rightDig - z; if (i < right.Digits.Count) { right.Digits[i] = sub & UInt16.MaxValue; } else { right.Digits.Add(sub & UInt16.MaxValue); } z = (~sub & leadingBit) >> 16; } }
internal OmgNum(RawNum raw) { this.Raw = raw; }
private void _InitializeModResult() { m_modRes = OmgPool.GetZero(); m_modRaw = m_modRes.Raw; m_modLeadingZeros = 0; }
public OmgNum(OmgNum other) { this.Raw = OmgPool.GetRawZero(); this.Raw.CopyFrom(other.Raw); this.IsNegative = other.IsNegative; }
public void Release() { OmgPool.ReleaseNumber(Raw); Raw = null; }