mirror of
https://github.com/LanZhan-Harmony/WindowsMusicPlayer-TheUntamedMusicPlayer.git
synced 2026-05-07 03:25:48 +08:00
340 lines
9.8 KiB
C#
340 lines
9.8 KiB
C#
using System.Diagnostics;
|
|
|
|
namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
|
|
internal static partial class BigIntegerCalculator
|
|
{
|
|
// Executes different exponentiation algorithms, which are
|
|
// based on the classic square-and-multiply method.
|
|
|
|
// https://en.wikipedia.org/wiki/Exponentiation_by_squaring
|
|
|
|
public static uint Pow(uint value, uint power, uint modulus) =>
|
|
// The 32-bit modulus pow method for a 32-bit integer
|
|
// raised by a 32-bit integer...
|
|
|
|
PowCore(power, modulus, value, 1);
|
|
|
|
public static uint Pow(uint[] value, uint power, uint modulus)
|
|
{
|
|
Debug.Assert(value != null);
|
|
|
|
// The 32-bit modulus pow method for a big integer
|
|
// raised by a 32-bit integer...
|
|
|
|
var v = Remainder(value, modulus);
|
|
return PowCore(power, modulus, v, 1);
|
|
}
|
|
|
|
public static uint Pow(uint value, uint[] power, uint modulus)
|
|
{
|
|
Debug.Assert(power != null);
|
|
|
|
// The 32-bit modulus pow method for a 32-bit integer
|
|
// raised by a big integer...
|
|
|
|
return PowCore(power, modulus, value, 1);
|
|
}
|
|
|
|
public static uint Pow(uint[] value, uint[] power, uint modulus)
|
|
{
|
|
Debug.Assert(value != null);
|
|
Debug.Assert(power != null);
|
|
|
|
// The 32-bit modulus pow method for a big integer
|
|
// raised by a big integer...
|
|
|
|
var v = Remainder(value, modulus);
|
|
return PowCore(power, modulus, v, 1);
|
|
}
|
|
|
|
private static uint PowCore(uint[] power, uint modulus,
|
|
ulong value, ulong result)
|
|
{
|
|
// The 32-bit modulus pow algorithm for all but
|
|
// the last power limb using square-and-multiply.
|
|
|
|
for (var i = 0; i < power.Length - 1; i++)
|
|
{
|
|
var p = power[i];
|
|
for (var j = 0; j < 32; j++)
|
|
{
|
|
if ((p & 1) == 1)
|
|
{
|
|
result = result * value % modulus;
|
|
}
|
|
|
|
value = value * value % modulus;
|
|
p >>= 1;
|
|
}
|
|
}
|
|
|
|
return PowCore(power[^1], modulus, value, result);
|
|
}
|
|
|
|
private static uint PowCore(uint power, uint modulus,
|
|
ulong value, ulong result)
|
|
{
|
|
// The 32-bit modulus pow algorithm for the last or
|
|
// the only power limb using square-and-multiply.
|
|
|
|
while (power != 0)
|
|
{
|
|
if ((power & 1) == 1)
|
|
{
|
|
result = result * value % modulus;
|
|
}
|
|
|
|
if (power != 1)
|
|
{
|
|
value = value * value % modulus;
|
|
}
|
|
|
|
power >>= 1;
|
|
}
|
|
|
|
return (uint)(result % modulus);
|
|
}
|
|
|
|
public static uint[] Pow(uint value, uint power, uint[] modulus)
|
|
{
|
|
Debug.Assert(modulus != null);
|
|
|
|
// The big modulus pow method for a 32-bit integer
|
|
// raised by a 32-bit integer...
|
|
|
|
var size = modulus.Length + modulus.Length;
|
|
var v = new BitsBuffer(size, value);
|
|
return PowCore(power, modulus, ref v);
|
|
}
|
|
|
|
public static uint[] Pow(uint[] value, uint power, uint[] modulus)
|
|
{
|
|
Debug.Assert(value != null);
|
|
Debug.Assert(modulus != null);
|
|
|
|
// The big modulus pow method for a big integer
|
|
// raised by a 32-bit integer...
|
|
|
|
if (value.Length > modulus.Length)
|
|
{
|
|
value = Remainder(value, modulus);
|
|
}
|
|
|
|
var size = modulus.Length + modulus.Length;
|
|
var v = new BitsBuffer(size, value);
|
|
return PowCore(power, modulus, ref v);
|
|
}
|
|
|
|
public static uint[] Pow(uint value, uint[] power, uint[] modulus)
|
|
{
|
|
Debug.Assert(power != null);
|
|
Debug.Assert(modulus != null);
|
|
|
|
// The big modulus pow method for a 32-bit integer
|
|
// raised by a big integer...
|
|
|
|
var size = modulus.Length + modulus.Length;
|
|
var v = new BitsBuffer(size, value);
|
|
return PowCore(power, modulus, ref v);
|
|
}
|
|
|
|
public static uint[] Pow(uint[] value, uint[] power, uint[] modulus)
|
|
{
|
|
Debug.Assert(value != null);
|
|
Debug.Assert(power != null);
|
|
Debug.Assert(modulus != null);
|
|
|
|
// The big modulus pow method for a big integer
|
|
// raised by a big integer...
|
|
|
|
if (value.Length > modulus.Length)
|
|
{
|
|
value = Remainder(value, modulus);
|
|
}
|
|
|
|
var size = modulus.Length + modulus.Length;
|
|
var v = new BitsBuffer(size, value);
|
|
return PowCore(power, modulus, ref v);
|
|
}
|
|
|
|
// Mutable for unit testing...
|
|
private static readonly int ReducerThreshold = 32;
|
|
|
|
private static uint[] PowCore(uint[] power, uint[] modulus,
|
|
ref BitsBuffer value)
|
|
{
|
|
// Executes the big pow algorithm.
|
|
|
|
var size = value.GetSize();
|
|
|
|
var temp = new BitsBuffer(size, 0);
|
|
var result = new BitsBuffer(size, 1);
|
|
|
|
if (modulus.Length < ReducerThreshold)
|
|
{
|
|
PowCore(power, modulus, ref value, ref result, ref temp);
|
|
}
|
|
else
|
|
{
|
|
var reducer = new FastReducer(modulus);
|
|
PowCore(power, ref reducer, ref value, ref result, ref temp);
|
|
}
|
|
|
|
return result.GetBits();
|
|
}
|
|
|
|
private static uint[] PowCore(uint power, uint[] modulus,
|
|
ref BitsBuffer value)
|
|
{
|
|
// Executes the big pow algorithm.
|
|
|
|
var size = value.GetSize();
|
|
|
|
var temp = new BitsBuffer(size, 0);
|
|
var result = new BitsBuffer(size, 1);
|
|
|
|
if (modulus.Length < ReducerThreshold)
|
|
{
|
|
PowCore(power, modulus, ref value, ref result, ref temp);
|
|
}
|
|
else
|
|
{
|
|
var reducer = new FastReducer(modulus);
|
|
PowCore(power, ref reducer, ref value, ref result, ref temp);
|
|
}
|
|
|
|
return result.GetBits();
|
|
}
|
|
|
|
private static void PowCore(uint[] power, uint[] modulus,
|
|
ref BitsBuffer value, ref BitsBuffer result,
|
|
ref BitsBuffer temp)
|
|
{
|
|
// The big modulus pow algorithm for all but
|
|
// the last power limb using square-and-multiply.
|
|
|
|
// NOTE: we're using an ordinary remainder here,
|
|
// since the reducer overhead doesn't pay off.
|
|
|
|
for (var i = 0; i < power.Length - 1; i++)
|
|
{
|
|
var p = power[i];
|
|
for (var j = 0; j < 32; j++)
|
|
{
|
|
if ((p & 1) == 1)
|
|
{
|
|
result.MultiplySelf(ref value, ref temp);
|
|
result.Reduce(modulus);
|
|
}
|
|
value.SquareSelf(ref temp);
|
|
value.Reduce(modulus);
|
|
p >>= 1;
|
|
}
|
|
}
|
|
|
|
PowCore(power[^1], modulus, ref value, ref result,
|
|
ref temp);
|
|
}
|
|
|
|
private static void PowCore(uint power, uint[] modulus,
|
|
ref BitsBuffer value, ref BitsBuffer result,
|
|
ref BitsBuffer temp)
|
|
{
|
|
// The big modulus pow algorithm for the last or
|
|
// the only power limb using square-and-multiply.
|
|
|
|
// NOTE: we're using an ordinary remainder here,
|
|
// since the reducer overhead doesn't pay off.
|
|
|
|
while (power != 0)
|
|
{
|
|
if ((power & 1) == 1)
|
|
{
|
|
result.MultiplySelf(ref value, ref temp);
|
|
result.Reduce(modulus);
|
|
}
|
|
if (power != 1)
|
|
{
|
|
value.SquareSelf(ref temp);
|
|
value.Reduce(modulus);
|
|
}
|
|
power >>= 1;
|
|
}
|
|
}
|
|
|
|
private static void PowCore(uint[] power, ref FastReducer reducer,
|
|
ref BitsBuffer value, ref BitsBuffer result,
|
|
ref BitsBuffer temp)
|
|
{
|
|
// The big modulus pow algorithm for all but
|
|
// the last power limb using square-and-multiply.
|
|
|
|
// NOTE: we're using a special reducer here,
|
|
// since it's additional overhead does pay off.
|
|
|
|
for (var i = 0; i < power.Length - 1; i++)
|
|
{
|
|
var p = power[i];
|
|
for (var j = 0; j < 32; j++)
|
|
{
|
|
if ((p & 1) == 1)
|
|
{
|
|
result.MultiplySelf(ref value, ref temp);
|
|
result.Reduce(ref reducer);
|
|
}
|
|
value.SquareSelf(ref temp);
|
|
value.Reduce(ref reducer);
|
|
p >>= 1;
|
|
}
|
|
}
|
|
|
|
PowCore(power[^1], ref reducer, ref value, ref result,
|
|
ref temp);
|
|
}
|
|
|
|
private static void PowCore(uint power, ref FastReducer reducer,
|
|
ref BitsBuffer value, ref BitsBuffer result,
|
|
ref BitsBuffer temp)
|
|
{
|
|
// The big modulus pow algorithm for the last or
|
|
// the only power limb using square-and-multiply.
|
|
|
|
// NOTE: we're using a special reducer here,
|
|
// since it's additional overhead does pay off.
|
|
|
|
while (power != 0)
|
|
{
|
|
if ((power & 1) == 1)
|
|
{
|
|
result.MultiplySelf(ref value, ref temp);
|
|
result.Reduce(ref reducer);
|
|
}
|
|
if (power != 1)
|
|
{
|
|
value.SquareSelf(ref temp);
|
|
value.Reduce(ref reducer);
|
|
}
|
|
power >>= 1;
|
|
}
|
|
}
|
|
|
|
private static int ActualLength(uint[] value) =>
|
|
// Since we're reusing memory here, the actual length
|
|
// of a given value may be less then the array's length
|
|
|
|
ActualLength(value, value.Length);
|
|
|
|
private static int ActualLength(uint[] value, int length)
|
|
{
|
|
Debug.Assert(value != null);
|
|
Debug.Assert(length <= value.Length);
|
|
|
|
while (length > 0 && value[length - 1] == 0)
|
|
{
|
|
--length;
|
|
}
|
|
|
|
return length;
|
|
}
|
|
}
|