-
Notifications
You must be signed in to change notification settings - Fork 385
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
Constrained the GenericMathExtensions to IQuantity #1448
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet. | ||
|
||
#if NET7_0_OR_GREATER | ||
using System; | ||
using System.Collections.Generic; | ||
using UnitsNet.GenericMath; | ||
using Xunit; | ||
|
||
|
@@ -10,19 +12,59 @@ namespace UnitsNet.Tests; | |
public class GenericMathExtensionsTests | ||
{ | ||
[Fact] | ||
public void CanCalcSum() | ||
public void Sum_Empty_ReturnsTheAdditiveIdentity() | ||
{ | ||
Length[] values = { Length.FromCentimeters(100), Length.FromCentimeters(200) }; | ||
Length[] values = []; | ||
|
||
Assert.Equal(Length.FromCentimeters(300), values.Sum()); | ||
Assert.Equal(Length.Zero, GenericMathExtensions.Sum(values)); | ||
} | ||
|
||
[Fact] | ||
public void CanCalcAverage_ForQuantitiesWithDoubleValueType() | ||
public void Sum_OneQuantity_ReturnsTheSameQuantity() | ||
{ | ||
Length[] values = { Length.FromCentimeters(100), Length.FromCentimeters(200) }; | ||
IEnumerable<Length> values = [Length.FromCentimeters(100)]; | ||
|
||
Assert.Equal(Length.FromCentimeters(150), values.Average()); | ||
Length sumOfQuantities = GenericMathExtensions.Sum(values); | ||
|
||
Assert.Equal(Length.FromCentimeters(100), sumOfQuantities); | ||
} | ||
|
||
[Fact] | ||
public void Sum_TwoQuantities_ReturnsTheExpectedSum() | ||
{ | ||
IEnumerable<Length> values = [Length.FromCentimeters(100), Length.FromCentimeters(200)]; | ||
|
||
Length sumOfQuantities = GenericMathExtensions.Sum(values); | ||
|
||
Assert.Equal(Length.FromCentimeters(300), sumOfQuantities); | ||
} | ||
|
||
[Fact] | ||
public void Average_Empty_ThrowsInvalidOperationException() | ||
{ | ||
IEnumerable<Length> values = []; | ||
|
||
Assert.Throws<InvalidOperationException>(() => GenericMathExtensions.Average(values)); | ||
} | ||
|
||
[Fact] | ||
public void Average_OneQuantity_ReturnsTheSameQuantity() | ||
{ | ||
IEnumerable<Length> values = [Length.FromCentimeters(100)]; | ||
|
||
Length averageOfQuantities = GenericMathExtensions.Average(values); | ||
|
||
Assert.Equal(Length.FromCentimeters(100), averageOfQuantities); | ||
} | ||
|
||
[Fact] | ||
public void Average_TwoQuantities_ReturnsTheExpectedAverage() | ||
{ | ||
IEnumerable<Length> values = [Length.FromCentimeters(100), Length.FromCentimeters(200)]; | ||
|
||
Length averageOfQuantities = GenericMathExtensions.Average(values); | ||
|
||
Assert.Equal(Length.FromCentimeters(150), averageOfQuantities); | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,67 +2,81 @@ | |
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet. | ||
|
||
#if NET7_0_OR_GREATER | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Numerics; | ||
|
||
namespace UnitsNet.GenericMath; | ||
|
||
/// <summary> | ||
/// Provides generic math operations to test out the new generic math interfaces implemented in .NET7 for UnitsNet | ||
/// quantities using <see cref="double" /> as the internal value type, which is the majority of quantities. | ||
/// Provides generic math operations using the generic math interfaces implemented in .NET7 for UnitsNet. | ||
/// </summary> | ||
public static class GenericMathExtensions | ||
{ | ||
/// <summary> | ||
/// Returns the sum of values. | ||
/// Returns the sum of a sequence of vector quantities, such as Mass and Length. | ||
/// </summary> | ||
/// <param name="source">The values.</param> | ||
/// <typeparam name="TQuantity">The type of the quantity elements in the source sequence.</typeparam> | ||
/// <returns>The sum of the quantities, using the unit of the first element in the sequence.</returns> | ||
/// <remarks> | ||
/// This method is experimental and intended to test out the new generic math interfaces implemented in .NET7 for | ||
/// UnitsNet quantities.<br /> | ||
/// Generic math interfaces might replace <see cref="UnitMath" />.<br /> | ||
/// Generic math LINQ support is still missing in the BCL, but is being worked on: | ||
/// Note that the generic math LINQ support is still missing in the BCL, but is being worked on: | ||
/// <a href="https://github.com/dotnet/runtime/issues/64031"> | ||
/// API Proposal: Generic LINQ Numeric Operators · Issue #64031 · dotnet/runtime | ||
/// API Proposal: Generic LINQ Numeric Operators · Issue | ||
/// #64031 · dotnet/runtime | ||
/// </a> | ||
/// </remarks> | ||
/// <param name="source">The values.</param> | ||
/// <typeparam name="T">The type of value.</typeparam> | ||
/// <returns>The sum.</returns> | ||
public static T Sum<T>(this IEnumerable<T> source) | ||
where T : IAdditionOperators<T, T, T>, IAdditiveIdentity<T, T> | ||
public static TQuantity Sum<TQuantity>(this IEnumerable<TQuantity> source) | ||
where TQuantity : IQuantity, IAdditionOperators<TQuantity, TQuantity, TQuantity>, IAdditiveIdentity<TQuantity, TQuantity> | ||
{ | ||
// Put accumulator on right hand side of the addition operator to construct quantities with the same unit as the values. | ||
// The addition operator implementation picks the unit from the left hand side, and the additive identity (e.g. Length.Zero) is always the base unit. | ||
return source.Aggregate(T.AdditiveIdentity, (acc, item) => item + acc); | ||
using IEnumerator<TQuantity> e = source.GetEnumerator(); | ||
if (!e.MoveNext()) | ||
{ | ||
return TQuantity.AdditiveIdentity; | ||
} | ||
|
||
TQuantity result = e.Current; | ||
while (e.MoveNext()) | ||
{ | ||
result += e.Current; | ||
} | ||
|
||
return result; | ||
} | ||
|
||
/// <summary> | ||
/// Returns the average of values. | ||
/// Calculates the arithmetic average of a sequence of vector quantities, such as Mass and Length. | ||
/// </summary> | ||
/// <param name="source">The values.</param> | ||
/// <typeparam name="TQuantity">The type of the quantity elements in the source sequence.</typeparam> | ||
/// <returns>The average of the quantities, using the unit of the first element in the sequence.</returns> | ||
/// <exception cref="InvalidOperationException">Thrown when the sequence is empty.</exception> | ||
/// <remarks> | ||
/// This method is experimental and intended to test out the new generic math interfaces implemented in .NET7 for | ||
/// UnitsNet quantities.<br /> | ||
/// Generic math interfaces might replace <see cref="UnitMath" />.<br /> | ||
/// Generic math LINQ support is still missing in the BCL, but is being worked on: | ||
/// Note that the generic math LINQ support is still missing in the BCL, but is being worked on: | ||
/// <a href="https://github.com/dotnet/runtime/issues/64031"> | ||
/// API Proposal: Generic LINQ Numeric Operators · Issue | ||
/// #64031 · dotnet/runtime | ||
/// </a> | ||
/// </remarks> | ||
/// <param name="source">The values.</param> | ||
/// <typeparam name="T">The value type.</typeparam> | ||
/// <returns>The average.</returns> | ||
public static T Average<T>(this IEnumerable<T> source) | ||
where T : IAdditionOperators<T, T, T>, IAdditiveIdentity<T, T>, IDivisionOperators<T, double, T> | ||
public static TQuantity Average<TQuantity>(this IEnumerable<TQuantity> source) | ||
where TQuantity : IQuantity, IAdditionOperators<TQuantity, TQuantity, TQuantity>, IAdditiveIdentity<TQuantity, TQuantity>, | ||
IDivisionOperators<TQuantity, double, TQuantity> | ||
{ | ||
// Put accumulator on right hand side of the addition operator to construct quantities with the same unit as the values. | ||
// The addition operator implementation picks the unit from the left hand side, and the additive identity (e.g. Length.Zero) is always the base unit. | ||
(T value, int count) result = source.Aggregate( | ||
(value: T.AdditiveIdentity, count: 0), | ||
(acc, item) => (value: item + acc.value, count: acc.count + 1)); | ||
using IEnumerator<TQuantity> e = source.GetEnumerator(); | ||
if (!e.MoveNext()) | ||
{ | ||
throw new InvalidOperationException("Sequence contains no elements"); | ||
} | ||
Comment on lines
+66
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notice this: in v5 this case would have caused an exception to be thrown because of the |
||
|
||
TQuantity result = e.Current; | ||
var nbQuantities = 1; | ||
while (e.MoveNext()) | ||
{ | ||
result += e.Current; | ||
nbQuantities++; | ||
} | ||
|
||
return result.value / result.count; | ||
return result / nbQuantities; | ||
} | ||
} | ||
#endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I'm not using
values.Sum()
is because when we add theIVectorQuantity
interface, this is going to start testing the other extension method (which is a better/more specific match for the list ofLength
).