123

I would like to clamp a value x to a range [a, b]:

x = (x < a) ? a : ((x > b) ? b : x);

This is quite basic. But I do not see a function "clamp" in the class library - at least not in System.Math.

(For the unaware to "clamp" a value is to make sure that it lies between some maximum and minimum values. If it’s greater than the max value, then it’s replaced by the max, etc.)

Amro
  • 123,847
  • 25
  • 243
  • 454
Danvil
  • 22,240
  • 19
  • 65
  • 88
  • 2
    @Danvil: There is no "C# Class Library". You mean "The .NET Framework". – John Saunders Apr 21 '10 at 14:01
  • 2
    Still nothing as of C# 7.1? – joce May 03 '17 at 13:10
  • 2
    @JohnSaunders I don't believe that's strictly true https://stackoverflow.com/questions/807880/bcl-base-class-library-vs-fcl-framework-class-library – Adam Naylor Jun 19 '17 at 11:58
  • 2
    @Bob Some words have historical, well defined meaning. Clamp is one of them. https://en.wikipedia.org/wiki/Clamping_(graphics) or https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/clamp.xhtml or https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-clamp "Limit" would be misleading, especially that "limit" already has a different meaning in maths. – kaalus May 17 '20 at 23:06
  • It is now added to .NET 5.0 – Zimano Dec 10 '20 at 15:40
  • @Bob I have only ever heard and used "clamp" in 25 years as a professional software engineer. Have never used "limit". This is while working in the UK, the USA and Canada. – Kaitain Jul 23 '22 at 16:58
  • @Bob I'm *fairly* confident that programmers are allowed to use languages outside of .NET. Every professional C++ codebase I've worked with in my career has had a "clamp" function defined somewhere, usually as a template func if hand-rolled, or just using the std::clamp function in recent years. https://en.cppreference.com/w/cpp/algorithm/clamp There is no std::limit, needless to say. – Kaitain Jul 25 '22 at 01:09
  • To recap, your claim was: "If I asked how to "limit" a value every single English speaking programmer in the world would know immediately what I meant." Honestly, I wouldn't know specifically what you meant, because I've never heard the term used. I could guess at what the speaker meant, and indeed if forced to speculate prior to this conversation I would think they might be imposing a max or a min on it. But if they said "clamp", I would know immediately: essentially a combo min and max operation to constrain the value within a specified range. – Kaitain Jul 26 '22 at 01:25
  • Well, IT CLEARLY ISN'T OBSCURE THEN, is it? You're basically speaking like a neophyte to software engineering who is surprised and annoyed that a term that is so widespread as to have become a keyword in several major languages does not accord with his everyday, non-SE thought on what the word ought to be. "only gaining traction relatively recently" Sure, if 1998 counts as 'recently'. "So I think you've made my point for me." O, the irony. Welcome to the world of computer programming, btw. – Kaitain Jul 29 '22 at 17:44
  • 1
    Bob, Really hope you're enjoying this late transition to being a programmer. Best of luck! CSS: https://css-tricks.com/snippets/sass/clamping-number C#: https://www.tutorialkart.com/c-sharp-tutorial/c-sharp-math-clamp/ Java: https://www.demo2s.com/java/java-math-clamp-int-val-int-min-int-max.html Rust: https://docs.rs/num/0.2.1/num/fn.clamp.html C++: https://www.geeksforgeeks.org/stdclamp-in-cpp-17/ Boost: https://www.geeksforgeeks.org/boostalgorithmclamp-in-c-library/ Ruby: https://jemma.dev/blog/comparable-clamp – Kaitain Jul 31 '22 at 03:25

11 Answers11

173

You could write an extension method:

public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
    if (val.CompareTo(min) < 0) return min;
    else if(val.CompareTo(max) > 0) return max;
    else return val;
}

Extension methods go in static classes - since this is quite a low-level function, it should probably go in some core namespace in your project. You can then use the method in any code file that contains a using directive for the namespace e.g.

using Core.ExtensionMethods

int i = 4.Clamp(1, 3);

.NET Core 2.0

Starting with .NET Core 2.0 System.Math now has a Clamp method that can be used instead:

using System;

int i = Math.Clamp(4, 1, 3);
Neuron
  • 5,141
  • 5
  • 38
  • 59
Lee
  • 142,018
  • 20
  • 234
  • 287
  • 1
    Where would I put this and is calling CompareTo slower than comparing with < (for integral types)? – Danvil Apr 21 '10 at 13:55
  • 1
    In a static class, and in the .NET framework (not sure about mono, compact, etc.), the generic should be recompiled for the type, and CompareTo inlined, so no performance penalty. – Robert Fraser Apr 21 '10 at 14:01
  • 1
    @Frasier Unless this is ultra performance sensitive code, you are unlikely to be making any meaningful performance gains by doing so. Having it be generic is probably more useful than saving a few microseconds. – MgSam Jun 06 '13 at 04:36
  • 6
    The good thing about constraining to the *generic* version of `IComparable` is that no boxing occurs. This ought to run very fast. Remember that with `double` and `float`, the `CompareTo` method corresponds to a total order where `NaN` is less than all other values, including `NegativeInfinity`. So it is not equivalent to the `<` operator. If you used `<` with a floating-point type, you would have to consider how to treat `NaN` also. This is not relevant for other numeric types. – Jeppe Stig Nielsen Aug 07 '13 at 20:05
  • 1
    You would need to consider how to treat `NaN` in either case. The version with `<` and `>` would output `NaN` and using `NaN` for `min` or `max` would effectively make a one-sided clamp. With `CompareTo` it would always return `NaN` if `max` is `NaN`. – Herman Mar 18 '14 at 10:12
  • Nice solution Lee. An equally helpful extension method for some things, in the same vein: public static T TrapInvalid(this T val, T min, T max, T valueIfInvalid) where T : IComparable { if (val.CompareTo(min) < 0) return valueIfInvalid; else if (val.CompareTo(max) > 0) return valueIfInvalid; else return val; } – radsdau May 15 '14 at 12:27
  • A static function would be better as the extension suggest that the method is changing the type itself. But it is not! – aggsol Jan 16 '15 at 10:05
  • 1
    @CodeClown - Extension methods are static methods so you can call it as `int c = Clamp(a, b, c)` if you want. However I don't see how this implementation suggests the type is being changed. If you mean it implies the `this` parameter is being mutated, then I disagree since it returns a value. – Lee Jan 16 '15 at 10:21
  • @Lee - [See example](https://gist.github.com/aggsol/3d876ab91ef9c5c85608) Having no extension would prevent the error as `foo` itself is never clamped. Would the extension have a more verbose name like `CalcClampedVal` this would be obvious. But now that I think about it more, my issue could be considered minor. – aggsol Jan 16 '15 at 10:53
  • @CodeClown - I see the issue although I think your example will result in a warning about an ignored return value. The benefit of using an extension method is that it makes the clamped argument explicit. – Lee Jan 16 '15 at 13:16
  • I'd throw in a 'struct' constraint on that generic T type, so we don't accidentally use it on reference types and risk null exceptions, unless you do want to use it on reference types, of course. Those two 'else' statements are also redundant. – angularsen Apr 19 '15 at 15:33
  • It's quite normal for methods to return a transformed version of the argument; they do necessarily mutate the object. A common convention is to use an appropriate verb tense, e.g., list.Sort to sort in place and list.Sorted to return a sorted copy of list. By that convention, this should be called Clamped rather than Clamp. – Jim Balter Sep 15 '15 at 06:12
  • Two more remarks: __(1)__ You do not constrain to value types, so if `T` is a reference type and `val` is `null`, we get a `NullReferenceException`. Note that `Comparer.Default.Compare(val, min)` will consider `null` less than non-null, so you could use that if you wanted. Or check for null. Or constrain with `where T : struct`. __(2)__ If some idiot one day passes a `min` and `max` that are in the wrong relative order, then it (unintensionally) becomes important that you check with `min` first. (Since `val` could satisfy both conditions.) We should throw an exception instead in that case. – Jeppe Stig Nielsen Sep 18 '17 at 13:10
36

Just use Math.Min and Math.Max:

x = Math.Min(Math.Max(x, a), b);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
d7samurai
  • 3,086
  • 2
  • 30
  • 43
  • That translates to `int a0 = x > a ? x : a; return a0 < b ? a0 : b` which (although gives correct results) isn't exactly ideal. – Mr. Smith Apr 24 '14 at 03:25
  • 4
    @d7samurai If we know that min <= max, `Math.Min(Math.Max(x, min), max)` results in one more comparison than necessary if x < min. – Jim Balter Sep 15 '15 at 05:58
  • @JimBalter, in theory this is true. If you look at how CompareTo() is typically implemented, the accepted answer can take upto 6 comparisons. I don't know though, if the compiler is smart enough and inlines the CompareTo() and removes the superfluous comparisons. – quinmars Sep 06 '16 at 21:41
  • 2
    This is good for cases when you only need to do it once, then whole new function for that feels like an overkill. – feos Nov 30 '17 at 16:51
25

Try:

public static int Clamp(int value, int min, int max)  
{  
    return (value < min) ? min : (value > max) ? max : value;  
}
Jwosty
  • 3,497
  • 2
  • 22
  • 50
Clit
  • 259
  • 2
  • 2
  • 10
    Ugh! Those ugly redundant parenthesis! If you're going to be an evil genius with the double ternary operators, at least do it properly and get rid of those as well! – CosmicGiant Oct 01 '17 at 08:07
  • 19
    @XenoRo Those "redundant" parenthesis are what makes it readable. – Clearer May 11 '18 at 07:46
  • 3
    @Cleaner - 1) If you're going for readability, double ternaries would be avoided and IF blocks would be used instead. 2) You don't get the joke, do you? xD – CosmicGiant May 11 '18 at 20:55
13

There isn't one, but it's not too hard to make one. I found one here: clamp

It is:

public static T Clamp<T>(T value, T max, T min)
    where T : System.IComparable<T> {
        T result = value;
        if (value.CompareTo(max) > 0)
            result = max;
        if (value.CompareTo(min) < 0)
            result = min;
        return result;
    }

And it can be used like:

int i = Clamp(12, 10, 0); -> i == 10
double d = Clamp(4.5, 10.0, 0.0); -> d == 4.5
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jeremy B.
  • 9,168
  • 3
  • 45
  • 57
  • This solution is better than the accepted one. No ambiguity. – aggsol Jan 16 '15 at 10:06
  • 6
    @CodeClown This solution results in an unnecessary comparison when value > max, and the inverted argument order invites (and virtually guarantees) bugs. I don't know what ambiguity you think is avoided. – Jim Balter Sep 15 '15 at 06:05
  • For consistency with the legacy Math.Clamp implementation, recommend switching the order of the min/max parameters: `Clamp(T value, T min, T max)` – josh poley Feb 14 '20 at 23:33
10

There isn't one in the System.Math namespace.

There is a MathHelper Class where it is available for the XNA game studio if that happens to be what you are doing:

Neuron
  • 5,141
  • 5
  • 38
  • 59
kemiller2002
  • 113,795
  • 27
  • 197
  • 251
5

System.Math.Clamp is the method you want if you are on .NET 5+, .NET Core 3.x, or .NET Core 2.x.

var a = Math.Clamp(5, 1, 10); // = 5
var b = Math.Clamp(-99, 1, 10); // = 1
var c = Math.Clamp(99, 1, 10); // = 10
mfluehr
  • 2,832
  • 2
  • 23
  • 31
juFo
  • 17,849
  • 10
  • 105
  • 142
4

Just sharing Lee's solution with the comments' issues and concerns addressed, where possible:

public static T Clamped<T>(this T value, T min, T max) where T : IComparable<T> {
    if (value == null) throw new ArgumentNullException(nameof(value), "is null.");
    if (min == null) throw new ArgumentNullException(nameof(min), "is null.");
    if (max == null) throw new ArgumentNullException(nameof(max), "is null.");
    //If min <= max, clamp
    if (min.CompareTo(max) <= 0) return value.CompareTo(min) < 0 ? min : value.CompareTo(max) > 0 ? max : value;
    //If min > max, clamp on swapped min and max
    return value.CompareTo(max) < 0 ? max : value.CompareTo(min) > 0 ? min : value;
}

Differences:

Limitations: No one-sided clamps. If max is NaN, always returns NaN (See Herman's comment).

CosmicGiant
  • 6,275
  • 5
  • 43
  • 58
0

Using the previous answers, I condensed it down to the below code for my needs. This will also allow you to clamp a number only by its min or max.

public static class IComparableExtensions
{
    public static T Clamped<T>(this T value, T min, T max) 
        where T : IComparable<T>
    {
        return value.CompareTo(min) < 0 ? min : value.ClampedMaximum(max);
    }

    public static T ClampedMinimum<T>(this T value, T min)
        where T : IComparable<T>
    {
        return value.CompareTo(min) < 0 ? min : value;
    }

    public static T ClampedMaximum<T>(this T value, T max)
        where T : IComparable<T>
    {
        return value.CompareTo(max) > 0 ? max : value;
    }
}
Bobby Speirs
  • 667
  • 2
  • 7
  • 14
0

The below code supports specifying bounds in any order (i.e. bound1 <= bound2, or bound2 <= bound1). I've found this useful for clamping values calculated from linear equations (y=mx+b) where the slope of the line can be increasing or decreasing.

I know: The code consists of five super-ugly conditional expression operators. The thing is, it works, and the tests below prove it. Feel free to add strictly unnecessary parentheses if you so desire.

You can easily create other overloads for other numeric types and basically copy/paste the tests.

Warning: Comparing floating point numbers is not simple. This code does not implement double comparisons robustly. Use a floating point comparison library to replace the uses of comparison operators.

public static class MathExtensions
{
    public static double Clamp(this double value, double bound1, double bound2)
    {
        return bound1 <= bound2 ? value <= bound1 ? bound1 : value >= bound2 ? bound2 : value : value <= bound2 ? bound2 : value >= bound1 ? bound1 : value;
    }
}

xUnit/FluentAssertions tests:

public class MathExtensionsTests
{
    [Theory]
    [InlineData(0, 0, 0, 0)]
    [InlineData(0, 0, 2, 0)]
    [InlineData(-1, 0, 2, 0)]
    [InlineData(1, 0, 2, 1)]
    [InlineData(2, 0, 2, 2)]
    [InlineData(3, 0, 2, 2)]
    [InlineData(0, 2, 0, 0)]
    [InlineData(-1, 2, 0, 0)]
    [InlineData(1, 2, 0, 1)]
    [InlineData(2, 2, 0, 2)]
    [InlineData(3, 2, 0, 2)]
    public void MustClamp(double value, double bound1, double bound2, double expectedValue)
    {
        value.Clamp(bound1, bound2).Should().Be(expectedValue);
    }
}
NathanAldenSr
  • 7,841
  • 4
  • 40
  • 51
0

If I want to validate the range of an argument in [min, max], the I use the following handy class:

public class RangeLimit<T> where T : IComparable<T>
{
    public T Min { get; }
    public T Max { get; }
    public RangeLimit(T min, T max)
    {
        if (min.CompareTo(max) > 0)
            throw new InvalidOperationException("invalid range");
        Min = min;
        Max = max;
    }

    public void Validate(T param)
    {
        if (param.CompareTo(Min) < 0 || param.CompareTo(Max) > 0)
            throw new InvalidOperationException("invalid argument");
    }

    public T Clamp(T param) => param.CompareTo(Min) < 0 ? Min : param.CompareTo(Max) > 0 ? Max : param;
}

The class works for all object which are IComparable. I create an instance with a certain range:

RangeLimit<int> range = new RangeLimit<int>(0, 100);

I an either validate an argument

range.Validate(value);

or clamp the argument to the range:

var v = range.Validate(value);
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
0

Based on the @JeremyB answer, with suggested corrections.

namespace App
{
  /// <summary>
  /// Miscellaneous utilities.
  /// </summary>
  public static class Util
  {
    /// <summary>
    /// Clamp a value to the inclusive range [min, max].
    /// </summary>
    /// <remarks>
    /// In newer versions of the .NET Framework, there is a System.Math.Clamp() method. 
    /// </remarks>
    /// <typeparam name="T">The type of value.</typeparam>
    /// <param name="value">The value to clamp.</param>
    /// <param name="min">The minimum value.</param>
    /// <param name="max">The maximum value.</param>
    /// <returns>The clamped value.</returns>
    public static T clamp<T>( T value, T min, T max ) where T : System.IComparable<T>
    {
      if ( value.CompareTo( max ) > 0 )
      {
        return max;
      }

      if ( value.CompareTo( min ) < 0 )
      {
        return min;
      }

      return value;
    }
  }
}
Mike Finch
  • 746
  • 1
  • 7
  • 20