Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 7 Generic math support #52

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/Rationals/Formatting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ public IEnumerable<char> Digits
/// <param name="formatProvider">Ignored, custom format providers are not supported</param>
public string ToString(string format, IFormatProvider formatProvider) => ToString(format);

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_0_OR_GREATER

/// <summary>Tries to format the value of the current instance into the provided span of characters.</summary>
/// <param name="destination">When this method returns, this instance's value formatted as a span of characters.</param>
/// <param name="charsWritten">When this method returns, the number of characters that were written in <paramref name="destination"/>.</param>
/// <param name="format">A span containing the characters that represent a standard or custom format string that defines the acceptable format for <paramref name="destination"/>.</param>
/// <param name="provider">An optional object that supplies culture-specific formatting information for <paramref name="destination"/>.</param>
/// <returns><see langword="true"/> if the formatting was successful; otherwise, <see langword="false"/>.</returns>
/// <remarks>
/// An implementation of this interface should produce the same string of characters as an implementation of <see cref="IFormattable.ToString(string?, IFormatProvider?)"/>
/// on the same type.
/// TryFormat should return false only if there is not enough space in the destination buffer. Any other failures should throw an exception.
/// </remarks>
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)
=> throw new NotImplementedException();

#endif

/// <summary>
/// Formats rational number to string
/// </summary>
Expand Down
189 changes: 189 additions & 0 deletions src/Rationals/GenericMath.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
using System;
using System.Numerics;

#if NET7_0_OR_GREATER

namespace Rationals
{
public partial struct Rational : INumber<Rational>
{
/// <inheritdoc />
static Rational INumberBase<Rational>.One
=> One;

/// <inheritdoc />
static int INumberBase<Rational>.Radix
=> 2;

/// <inheritdoc />
static Rational INumberBase<Rational>.Zero
=> Zero;

/// <inheritdoc />
static Rational IAdditiveIdentity<Rational, Rational>.AdditiveIdentity
=> Zero;

/// <inheritdoc />
static Rational IMultiplicativeIdentity<Rational, Rational>.MultiplicativeIdentity
=> One;

/// <inheritdoc />
static bool INumberBase<Rational>.IsCanonical(Rational value)
{
var canonical = value.CanonicalForm;
return value.Numerator == canonical.Numerator && value.Denominator == canonical.Denominator;
}

/// <inheritdoc />
static bool INumberBase<Rational>.IsComplexNumber(Rational value)
=> false;

/// <inheritdoc />
static bool INumberBase<Rational>.IsEvenInteger(Rational value)
{
var canonical = value.CanonicalForm;
return canonical.Denominator.IsOne && canonical.Numerator.IsEven;
}

/// <inheritdoc />
static bool INumberBase<Rational>.IsFinite(Rational value)
=> true;

/// <inheritdoc />
static bool INumberBase<Rational>.IsImaginaryNumber(Rational value)
=> false;

/// <inheritdoc />
static bool INumberBase<Rational>.IsInfinity(Rational value)
=> false;

/// <inheritdoc />
static bool INumberBase<Rational>.IsInteger(Rational value)
=> value.CanonicalForm.Denominator.IsOne;

/// <inheritdoc />
static bool INumberBase<Rational>.IsNaN(Rational value)
=> value.IsNaN;

/// <inheritdoc />
static bool INumberBase<Rational>.IsNegative(Rational value)
=> value.Sign < 0;

/// <inheritdoc />
static bool INumberBase<Rational>.IsNegativeInfinity(Rational value)
=> false;

/// <inheritdoc />
static bool INumberBase<Rational>.IsNormal(Rational value)
=> !value.IsZero && !value.IsNaN;

/// <inheritdoc />
static bool INumberBase<Rational>.IsOddInteger(Rational value)
{
var canonical = value.CanonicalForm;
return canonical.Denominator.IsOne && !canonical.Numerator.IsEven;
}

/// <inheritdoc />
static bool INumberBase<Rational>.IsPositive(Rational value)
=> value.Sign > 0;

/// <inheritdoc />
static bool INumberBase<Rational>.IsPositiveInfinity(Rational value)
=> false;

/// <inheritdoc />
static bool INumberBase<Rational>.IsRealNumber(Rational value)
=> true;

/// <inheritdoc />
static bool INumberBase<Rational>.IsSubnormal(Rational value)
=> false;

/// <inheritdoc />
static bool INumberBase<Rational>.IsZero(Rational value)
=> value.IsZero;

private static Rational MaxMagnitudeInner(Rational x, Rational y)
{
if (x.IsNaN)
return NaN;

if (y.IsNaN)
return NaN;

var ax = Abs(x);
var ay = Abs(y);

if (ax > ay)
return x;

if (ax == ay)
return x.Sign < 0 ? y : x;

return y;
}

private static Rational MinMagnitudeInner(Rational x, Rational y)
{
if (x.IsNaN)
return NaN;

if (y.IsNaN)
return NaN;

var ax = Abs(x);
var ay = Abs(y);

if (ax < ay)
return x;

if (ax == ay)
return x.Sign < 0 ? x : y;

return y;
}

/// <inheritdoc />
static Rational INumberBase<Rational>.MaxMagnitude(Rational x, Rational y)
=> MaxMagnitudeInner(x, y);

/// <inheritdoc />
static Rational INumberBase<Rational>.MaxMagnitudeNumber(Rational x, Rational y)
=> MaxMagnitudeInner(x, y);

/// <inheritdoc />
static Rational INumberBase<Rational>.MinMagnitude(Rational x, Rational y)
=> MinMagnitudeInner(x, y);

/// <inheritdoc />
static Rational INumberBase<Rational>.MinMagnitudeNumber(Rational x, Rational y)
=> MinMagnitudeInner(x, y);

/// <inheritdoc />
static bool INumberBase<Rational>.TryConvertFromChecked<TOther>(TOther value, out Rational result)
=> throw new NotImplementedException();

/// <inheritdoc />
static bool INumberBase<Rational>.TryConvertFromSaturating<TOther>(TOther value, out Rational result)
=> throw new NotImplementedException();

/// <inheritdoc />
static bool INumberBase<Rational>.TryConvertFromTruncating<TOther>(TOther value, out Rational result)
=> throw new NotImplementedException();

/// <inheritdoc />
static bool INumberBase<Rational>.TryConvertToChecked<TOther>(Rational value, out TOther result)
=> throw new NotImplementedException();

/// <inheritdoc />
static bool INumberBase<Rational>.TryConvertToSaturating<TOther>(Rational value, out TOther result)
=> throw new NotImplementedException();

/// <inheritdoc />
static bool INumberBase<Rational>.TryConvertToTruncating<TOther>(Rational value, out TOther result)
=> throw new NotImplementedException();
}
}

#endif
18 changes: 16 additions & 2 deletions src/Rationals/Operators.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Rationals
using System;

namespace Rationals
{
/// <summary>
/// Rational number.
Expand Down Expand Up @@ -69,5 +71,17 @@ public partial struct Rational
/// Overload of the &gt;= operator.
/// </summary>
public static bool operator >=(Rational left, Rational right) => !left.IsNaN && !right.IsNaN && left.CompareTo(right) >= 0;

/// <summary>
/// Overload of the % operator.
/// </summary>
public static Rational operator %(Rational left, Rational right)
=> throw new NotImplementedException();

/// <summary>
/// Overload of the unary + operator.
/// </summary>
public static Rational operator +(Rational value)
=> new(+value.Denominator, +value.Numerator);
}
}
}
40 changes: 40 additions & 0 deletions src/Rationals/Parsing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ public static Rational Parse(string value, NumberStyles style, IFormatProvider p
return Parse(value, style, NumberFormatInfo.GetInstance(provider));
}


#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_0_OR_GREATER

/// <inheritdoc cref="Parse(string)"/>
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static Rational Parse(ReadOnlySpan<char> value, IFormatProvider provider)
{
return Parse(value, NumberStyles.Float, NumberFormatInfo.GetInstance(provider));
}

/// <inheritdoc cref="Parse(string)"/>
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static Rational Parse(ReadOnlySpan<char> value, NumberStyles style, IFormatProvider provider)
=> Parse(value.ToString(), style, NumberFormatInfo.GetInstance(provider));

#endif

private static Rational Parse(string value, NumberStyles style, NumberFormatInfo info)
{
if (!TryParse(value, style, info, out var result))
Expand All @@ -74,6 +91,29 @@ public static bool TryParse(string value, NumberStyles style, IFormatProvider pr
return TryParse(value, style, NumberFormatInfo.GetInstance(provider), out result);
}

/// <inheritdoc cref="Parse(string)"/>
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static bool TryParse(string value, IFormatProvider provider, out Rational result)
{
return TryParse(value, NumberStyles.Float, NumberFormatInfo.GetInstance(provider), out result);
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_0_OR_GREATER

/// <inheritdoc cref="Parse(string)"/>
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static bool TryParse(ReadOnlySpan<char> value, IFormatProvider provider, out Rational result)
{
return TryParse(value, NumberStyles.Float, NumberFormatInfo.GetInstance(provider), out result);
}

/// <inheritdoc cref="Parse(string)"/>
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static bool TryParse(ReadOnlySpan<char> value, NumberStyles style, IFormatProvider provider, out Rational result)
=> TryParse(value.ToString(), style, NumberFormatInfo.GetInstance(provider), out result);

#endif

private static bool TryParse(string value, NumberStyles style, NumberFormatInfo info, out Rational result)
{
result = default;
Expand Down
4 changes: 2 additions & 2 deletions src/Rationals/Rationals.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup Label="Basic build">
<TargetFrameworks>netstandard1.3;net40;</TargetFrameworks>
<LangVersion>7.3</LangVersion>
<TargetFrameworks>net7.0;netstandard2.1;netstandard1.3;net40</TargetFrameworks>
<LangVersion>11</LangVersion>
<Deterministic>true</Deterministic>
</PropertyGroup>

Expand Down