diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a76416..8d89511 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [3.6.0] - 2023-11-23
+### Added
+- Add `Parse`/`TryParse` to `ModInt`
+
## [3.5.0] - 2023-10-29
### Added
- Add MfGraph.Count
diff --git a/Directory.Build.props b/Directory.Build.props
index 48d7850..e6b1222 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -7,8 +7,8 @@
https://github.com/kzrnm/ac-library-csharp
https://github.com/kzrnm/ac-library-csharp/blob/main/CHANGELOG.md
- 3.5.0
- 3.5.0.101
+ 3.6.0
+ 3.6.0.101
$(GIT_COMMIT)
True
diff --git a/Source/ac-library-csharp/Math/ModInt/DynamicModInt.cs b/Source/ac-library-csharp/Math/ModInt/DynamicModInt.cs
index b0d0772..c1ffa40 100644
--- a/Source/ac-library-csharp/Math/ModInt/DynamicModInt.cs
+++ b/Source/ac-library-csharp/Math/ModInt/DynamicModInt.cs
@@ -239,6 +239,35 @@ public DynamicModInt Inv()
[MethodImpl(256)] public bool Equals(DynamicModInt other) => Value == other.Value;
public override int GetHashCode() => _v.GetHashCode();
+ public static bool TryParse(ReadOnlySpan s, out DynamicModInt result)
+ {
+ result = Zero;
+ DynamicModInt ten = 10u;
+ s = s.Trim();
+ bool minus = false;
+ if (s.Length > 0 && s[0] == '-')
+ {
+ minus = true;
+ s = s.Slice(1);
+ }
+ for (int i = 0; i < s.Length; i++)
+ {
+ var d = (uint)(s[i] - '0');
+ if (d >= 10) return false;
+ result = result * ten + d;
+ }
+ if (minus)
+ result = -result;
+ return true;
+ }
+ public static DynamicModInt Parse(ReadOnlySpan s)
+ {
+ if (!TryParse(s, out var r))
+ Throw();
+ return r;
+ void Throw() => throw new FormatException();
+ }
+
#if GENERIC_MATH
static int INumberBase>.Radix => 2;
static DynamicModInt IAdditiveIdentity, DynamicModInt>.AdditiveIdentity => default;
@@ -265,24 +294,16 @@ public DynamicModInt Inv()
static DynamicModInt INumberBase>.MaxMagnitudeNumber(DynamicModInt x, DynamicModInt y) => new DynamicModInt(uint.Max(x._v, y._v));
static DynamicModInt INumberBase>.MinMagnitude(DynamicModInt x, DynamicModInt y) => new DynamicModInt(uint.Min(x._v, y._v));
static DynamicModInt INumberBase>.MinMagnitudeNumber(DynamicModInt x, DynamicModInt y) => new DynamicModInt(uint.Min(x._v, y._v));
- static DynamicModInt INumberBase>.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => long.Parse(s, style, provider);
- static DynamicModInt INumberBase>.Parse(string s, NumberStyles style, IFormatProvider provider) => long.Parse(s, style, provider);
- static DynamicModInt ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider provider) => long.Parse(s, provider);
- static DynamicModInt IParsable>.Parse(string s, IFormatProvider provider) => long.Parse(s, provider);
- static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider provider, out DynamicModInt result)
- => TryParse(s, NumberStyles.None, provider, out result);
- static bool IParsable>.TryParse(string s, IFormatProvider provider, out DynamicModInt result)
- => TryParse(s, NumberStyles.None, provider, out result);
- static bool INumberBase>.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out DynamicModInt result)
- => TryParse(s, style, provider, out result);
- static bool INumberBase>.TryParse(string s, NumberStyles style, IFormatProvider provider, out DynamicModInt result)
- => TryParse(s, style, provider, out result);
- private static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out DynamicModInt result)
- {
- var b = long.TryParse(s, style, provider, out var r);
- result = r;
- return b;
- }
+
+ static DynamicModInt INumberBase>.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => Parse(s);
+ static DynamicModInt INumberBase>.Parse(string s, NumberStyles style, IFormatProvider provider) => Parse(s);
+ static DynamicModInt ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider provider) => Parse(s);
+ static DynamicModInt IParsable>.Parse(string s, IFormatProvider provider) => Parse(s);
+ static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider provider, out DynamicModInt result) => TryParse(s, out result);
+ static bool IParsable>.TryParse(string s, IFormatProvider provider, out DynamicModInt result) => TryParse(s, out result);
+ static bool INumberBase>.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out DynamicModInt result) => TryParse(s, out result);
+ static bool INumberBase>.TryParse(string s, NumberStyles style, IFormatProvider provider, out DynamicModInt result) => TryParse(s, out result);
+
bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider provider) => _v.TryFormat(destination, out charsWritten, format, provider);
diff --git a/Source/ac-library-csharp/Math/ModInt/StaticModInt.cs b/Source/ac-library-csharp/Math/ModInt/StaticModInt.cs
index 7125c0c..c74c461 100644
--- a/Source/ac-library-csharp/Math/ModInt/StaticModInt.cs
+++ b/Source/ac-library-csharp/Math/ModInt/StaticModInt.cs
@@ -222,6 +222,34 @@ public StaticModInt Inv()
public override bool Equals(object obj) => obj is StaticModInt m && Equals(m);
[MethodImpl(256)] public bool Equals(StaticModInt other) => _v == other._v;
public override int GetHashCode() => _v.GetHashCode();
+ public static bool TryParse(ReadOnlySpan s, out StaticModInt result)
+ {
+ result = Zero;
+ StaticModInt ten = 10u;
+ s = s.Trim();
+ bool minus = false;
+ if (s.Length > 0 && s[0] == '-')
+ {
+ minus = true;
+ s = s.Slice(1);
+ }
+ for (int i = 0; i < s.Length; i++)
+ {
+ var d = (uint)(s[i] - '0');
+ if (d >= 10) return false;
+ result = result * ten + d;
+ }
+ if (minus)
+ result = -result;
+ return true;
+ }
+ public static StaticModInt Parse(ReadOnlySpan s)
+ {
+ if (!TryParse(s, out var r))
+ Throw();
+ return r;
+ void Throw() => throw new FormatException();
+ }
#if GENERIC_MATH
static int INumberBase>.Radix => 2;
@@ -249,24 +277,16 @@ public StaticModInt Inv()
static StaticModInt INumberBase>.MaxMagnitudeNumber(StaticModInt x, StaticModInt y) => new StaticModInt(uint.Max(x._v, y._v));
static StaticModInt INumberBase>.MinMagnitude(StaticModInt x, StaticModInt y) => new StaticModInt(uint.Min(x._v, y._v));
static StaticModInt INumberBase>.MinMagnitudeNumber(StaticModInt x, StaticModInt y) => new StaticModInt(uint.Min(x._v, y._v));
- static StaticModInt INumberBase>.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => long.Parse(s, style, provider);
- static StaticModInt INumberBase>.Parse(string s, NumberStyles style, IFormatProvider provider) => long.Parse(s, style, provider);
- static StaticModInt ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider provider) => long.Parse(s, provider);
- static StaticModInt IParsable>.Parse(string s, IFormatProvider provider) => long.Parse(s, provider);
- static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider provider, out StaticModInt result)
- => TryParse(s, NumberStyles.None, provider, out result);
- static bool IParsable>.TryParse(string s, IFormatProvider provider, out StaticModInt result)
- => TryParse(s, NumberStyles.None, provider, out result);
- static bool INumberBase>.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out StaticModInt result)
- => TryParse(s, style, provider, out result);
- static bool INumberBase>.TryParse(string s, NumberStyles style, IFormatProvider provider, out StaticModInt result)
- => TryParse(s, style, provider, out result);
- private static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out StaticModInt result)
- {
- var b = long.TryParse(s, style, provider, out var r);
- result = r;
- return b;
- }
+
+ static StaticModInt INumberBase>.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => Parse(s);
+ static StaticModInt INumberBase>.Parse(string s, NumberStyles style, IFormatProvider provider) => Parse(s);
+ static StaticModInt ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider provider) => Parse(s);
+ static StaticModInt IParsable>.Parse(string s, IFormatProvider provider) => Parse(s);
+ static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider provider, out StaticModInt result) => TryParse(s, out result);
+ static bool IParsable>.TryParse(string s, IFormatProvider provider, out StaticModInt result) => TryParse(s, out result);
+ static bool INumberBase>.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out StaticModInt result) => TryParse(s, out result);
+ static bool INumberBase>.TryParse(string s, NumberStyles style, IFormatProvider provider, out StaticModInt result) => TryParse(s, out result);
+
bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider provider) => _v.TryFormat(destination, out charsWritten, format, provider);
diff --git a/Test/ac-library-csharp.Test/Math/ModIntTest.cs b/Test/ac-library-csharp.Test/Math/ModIntTest.cs
index f091dd8..85813a7 100644
--- a/Test/ac-library-csharp.Test/Math/ModIntTest.cs
+++ b/Test/ac-library-csharp.Test/Math/ModIntTest.cs
@@ -1,13 +1,12 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
+using System.Numerics;
using System.Runtime.InteropServices;
using AtCoder.Internal;
using FluentAssertions;
using MersenneTwister;
using Xunit;
-#if NET7_0_OR_GREATER
-using System.Numerics;
-#endif
namespace AtCoder
{
@@ -261,6 +260,99 @@ public void Increment()
}
}
+ [Fact]
+ public void Parse()
+ {
+ var bigs = new[]{
+ BigInteger.Pow(10, 1000),
+ BigInteger.Pow(10, 1000),
+ };
+ var invalids = new[]
+ {
+ "2-2",
+ "ABC",
+ "111.0",
+ "111,1",
+ };
+ RunStatic();
+ RunStatic();
+ RunStatic();
+ RunStatic();
+ RunStatic();
+
+ DynamicModInt.Mod = 998244353;
+ RunDynamic();
+
+ DynamicModInt.Mod = 1000000008;
+ RunDynamic();
+
+ void RunStatic() where T : struct, IStaticMod
+ {
+ var mod = (int)new T().Mod;
+ var nums = Enumerable.Range(-100, 200).Concat(Enumerable.Range(mod - 100, 200));
+ foreach (var n in nums)
+ {
+ var s = n.ToString();
+ var expected = (n % mod + mod) % mod;
+ StaticModInt.TryParse(s, out var num1).Should().BeTrue();
+ var num2 = StaticModInt.Parse(s);
+
+ num1.Value.Should().Be(expected);
+ num2.Value.Should().Be(expected);
+ }
+
+ foreach (var n in bigs)
+ {
+ var s = n.ToString();
+ var expected = (int)(n % mod + mod) % mod;
+ StaticModInt.TryParse(s, out var num1).Should().BeTrue();
+ var num2 = StaticModInt.Parse(s);
+
+ num1.Value.Should().Be(expected);
+ num2.Value.Should().Be(expected);
+ }
+
+ foreach (var s in invalids)
+ {
+ StaticModInt.TryParse(s, out _).Should().BeFalse();
+ s.Invoking(s => StaticModInt.Parse(s)).Should().ThrowExactly();
+ }
+ }
+
+ void RunDynamic() where T : struct
+ {
+ var mod = DynamicModInt.Mod;
+ var nums = Enumerable.Range(-100, 200).Concat(Enumerable.Range(mod - 100, 200));
+ foreach (var n in nums)
+ {
+ var s = n.ToString();
+ var expected = (n % mod + mod) % mod;
+ DynamicModInt.TryParse(s, out var num1).Should().BeTrue();
+ var num2 = DynamicModInt.Parse(s);
+
+ num1.Value.Should().Be(expected);
+ num2.Value.Should().Be(expected);
+ }
+
+ foreach (var n in bigs)
+ {
+ var s = n.ToString();
+ var expected = (int)(n % mod + mod) % mod;
+ DynamicModInt.TryParse(s, out var num1).Should().BeTrue();
+ var num2 = DynamicModInt.Parse(s);
+
+ num1.Value.Should().Be(expected);
+ num2.Value.Should().Be(expected);
+ }
+
+ foreach (var s in invalids)
+ {
+ DynamicModInt.TryParse(s, out _).Should().BeFalse();
+ s.Invoking(s => DynamicModInt.Parse(s)).Should().ThrowExactly();
+ }
+ }
+ }
+
private struct DynamicUsageID { }
[Fact]
@@ -314,6 +406,7 @@ public void ConstructorStatic()
(1 + new StaticModInt(1)).Value.Should().Be(2);
}
+
private struct MemoryID : IStaticMod
{
public uint Mod => 101;