Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Add Math.Clamp methods#7242

Merged
jkotas merged 2 commits into
dotnet:masterfrom
hughbe:clamp
Sep 25, 2016
Merged

Add Math.Clamp methods#7242
jkotas merged 2 commits into
dotnet:masterfrom
hughbe:clamp

Conversation

@hughbe
Copy link
Copy Markdown

@hughbe hughbe commented Sep 17, 2016

Open Questions

  • Argument validation: should we check and enforce that max > min? Would this have a negative perf impact (that the old MaxMin approach didn't have)
  • Double and Single: currently, any NaN argument means that NaN is returned - the clamp implementation in VC++ is undefined for NaN btw
  • MathMin: I decided to implement Clamp without Math.Max(Math.Min(value, max), min) as I was unsure whether the JIT would inline these method calls (plus the code reads more easily IMO)
  • Have I exposed the new APIs in the right place(model.xml)?

dotnet/corefx#467

/cc @sgtfrankieboy @weshaggard @mellinoe @mikedn

Comment thread src/mscorlib/model.xml Outdated
<Member Name="Clamp(System.Single,System.Single)" />
<Member Name="Clamp(System.UInt16,System.UInt16)" />
<Member Name="Clamp(System.UInt32,System.UInt32)" />
<Member Name="Clamp(System.UInt64,System.UInt64)" />
Copy link
Copy Markdown

@sgtfrankieboy sgtfrankieboy Sep 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines should have 3 parameters instead of 2

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

knew I was doing something wrong! Thansk

@mikedn
Copy link
Copy Markdown

mikedn commented Sep 17, 2016

Argument validation: should we check and enforce that max > min? Would this have a negative perf impact (that the old MaxMin approach didn't have)

With the current JIT adding an additional branch for the check will prevent the method from being inlined. For better or worse this can be avoided by using [MethodImpl(MethodImplOptions.AggressiveInlining)].

It's worth noting here that if the method is inlined and if the min/max arguments are constants (that's pretty common) then the check will be eliminated.

Double and Single: currently, any NaN argument means that NaN is returned - the clamp implementation in VC++ is undefined for NaN btw

It may make sense to return NaN if any argument is NaN but currently double.IsNaN generates poor code. And if you're implementing Clamp using Math.Min/Max then it's even worse.

The results you get if don't add special handling for NaNs (directly or indirectly by using Math.Min/Max) are IMO reasonable. You get NaN if the input value is NaN and the min/max checks are basically ignored if min/max are NaN.

@hughbe
Copy link
Copy Markdown
Author

hughbe commented Sep 17, 2016

@mikedn thanks for taking a look - I'll add the argument validation and the inlining attribute as you suggested, and will remove the Math.Max(Math.Min...) stuff in double and single.
I've also rebased the PR to get it up to date with master

Comment thread src/mscorlib/src/System/Math.cs Outdated
return value;
}

private static void ThrowMinMaxException(object min, object max)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using object will result in boxing at the callsite, that will make clamp code larger. You could probably make this generic so boxing moves from the caller to the callee.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks

Avoid boxing at call site

private static void ThrowMinMaxException<T>(T min, T max)
{
throw new ArgumentException(Environment.GetResourceString("Argument_MinMaxValue", min, max));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it potentially help debugging if the value appeared in the exception message also?

Copy link
Copy Markdown
Author

@hughbe hughbe Sep 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does, unless I misunderstand. The message is "'{0}' cannot be greater than {1}."

@bendono
Copy link
Copy Markdown

bendono commented Sep 20, 2016

Has any consideration been given for a generic Clamp<T> constrained to T : IComparable<T>? This would greatly simplify the existing code which is essentially the same method defined 11 times for various argument types. It would also allow other types to be Clamped as long as they implement IComparable.

@sgtfrankieboy
Copy link
Copy Markdown

sgtfrankieboy commented Sep 20, 2016

@bendono Yes, it has been discussed in this issue: dotnet/corefx#467

@hughbe
Copy link
Copy Markdown
Author

hughbe commented Sep 25, 2016

@jkotas PTAL, thanks

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Sep 25, 2016

LGTM. Thanks!

@jkotas jkotas merged commit fe98399 into dotnet:master Sep 25, 2016
@hughbe hughbe deleted the clamp branch September 25, 2016 14:25
@hughbe
Copy link
Copy Markdown
Author

hughbe commented Sep 27, 2016

I was just looking at another PR updating src/mscorlib/model.xml, and I realised that they also update src/mscorlib/ref/mscorlib.cs.
I only did the former - do I need to add these to mscorlib.cs? I'm not sure what the difference is between these two files!

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Sep 27, 2016

src/mscorlib/ref/mscorlib.cs is temporary glue that is needed by the current corefx build. The corefx build should be switched to reference System.Private.CoreLib directly, like it does for corert. I would expect that this happens before these APIs get exposed in the contracts, so I do not think that it is necessary to add them to src/mscorlib/ref/mscorlib.cs.

cc @weshaggard

@weshaggard
Copy link
Copy Markdown
Member

We are enabling people to start exposing APIs as .NET Core specific (see dotnet/corefx#11886). So if that is going to happen before we make the switch to building everything against S.P.CoreLib then these will need to be added to mscorlib ref. In either case it doesn't hurt to include them.

picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants