I am not sure if "clamping" is the correct terminology for this, however I really don't know what else to call it. Suppose we wanted to limit an integer to stay within some arbitrary range, like 0-50. This can be easily achieved by testing the current value with an if statement and assigning the maximum or minimum value accordingly. However, what is the fastest way to keep the Integer at its maximum value or minimum value?
As easy as
var normalized = Math.Min(50, Math.Max(0, value));
As of performance:
public static int Max(int val1, int val2) {
return (val1>=val2)?val1:val2;
}
That's how it's implemented in .NET, so it's unlikely you can implement it even better.
If you want speed, you should keep the CPU's branch predictor happy. So make the "happy path" return 'n' (the most probable outcome of calling 'Clamp'):
public static int Clamp( int n, int min, int max ) {
if( value < min ) return min;
if( value > max ) return max;
return n;
}
Math.Clamp was introduced since .NET Core 2.0 so you can use it directly. It should be the current fastest method
Math.Clamp(12, 0, 50)
Related
I need to round-robin some calls between N different connections because of some rate limits in a multithreaded context. I've decided to implement this functionality using a list and a "counter," which is supposed to "jump by one" between instances on each call.
I'll illustrate this concept with a minimal example (using a class called A to stand in for the connections)
class A
{
public A()
{
var newIndex = Interlocked.Increment(ref index);
ID = newIndex.ToString();
}
private static int index;
public string ID;
}
static int crt = 0;
static List<A> Items = Enumerable.Range(1, 15).Select(i => new A()).ToList();
static int itemsCount = Items.Count;
static A GetInstance()
{
var newIndex = Interlocked.Increment(ref crt);
var instance = Items[newIndex % itemsCount];
//Console.WriteLine($"{DateTime.Now.Ticks}, {Guid.NewGuid()}, Got instance: {instance.ID}");
return instance;
}
static void Test()
{
var sw = Stopwatch.StartNew();
var tasks = Enumerable.Range(1, 1000000).Select(i => Task.Run(GetInstance)).ToArray();
Task.WaitAll(tasks);
}
This works as expected in that it ensures that calls are round-robin-ed between the connections. I will probably stick to this implementation in the "real" code (with a long instead of an int for the counter)
However, even if it is unlikely to reach int.MaxValue in my use case, I wondered if there is a way to "safely overflow" the counter.
I know that "%" in C# is "Remainder" rather than "Modulus," which would mean that some ?: gymnastics would be required to always return positives, which I want to avoid.
So what I wanted to cume up with is instead something like:
static A GetInstance()
{
var newIndex = Interlocked.Increment(ref crt);
Interlocked.CompareExchange(ref crt, 0, itemsCount); //?? the return value is the original value, how to know if it succeeded
var instance = Items[newIndex];
//Console.WriteLine($"{DateTime.Now.Ticks}, {Guid.NewGuid()}, Got instance: {instance.ID}");
return instance;
}
What I am expecting is that Interlocked.CompareExchange(ref crt, 0, itemsCount) would be "won" by only one thread, setting the counter back to 0 once it reaches the number of connections available. However, I don't know how to use this in this context.
Can CompareExchange or another mechanism in Interlocked be used here?
You could probably:
static int crt = -1;
static readonly IReadOnlyList<A> Items = Enumerable.Range(1, 15).Select(i => new A()).ToList();
static readonly int itemsCount = Items.Count;
static readonly int maxItemCount = itemsCount * 100;
static A GetInstance()
{
int newIndex;
while (true)
{
newIndex = Interlocked.Increment(ref crt);
if (newIndex >= itemsCount)
{
while (newIndex >= itemsCount && Interlocked.CompareExchange(ref crt, -1, newIndex) != newIndex)
{
// There is an implicit memory barrier caused by the Interlockd.CompareExchange around the
// next line
// See for example https://afana.me/archive/2015/07/10/memory-barriers-in-dot-net.aspx/
// A full memory barrier is the strongest and interesting one. At least all of the following generate a full memory barrier implicitly:
// Interlocked class mehods
newIndex = crt;
}
continue;
}
break;
}
var instance = Items[newIndex % itemsCount];
//Console.WriteLine($"{DateTime.Now.Ticks}, {Guid.NewGuid()}, Got instance: {instance.ID}");
return instance;
}
But I have to say the truth... I'm not sure if it is correct (it should be), and explaining it is hard, and if anyone touches it in any way it will break.
The basic idea is to have a "low" ceiling for crt (we don't want to overflow, it would break everything... so we want to keep veeeeeery far from int.MaxValue, or you could use uint).
The maximum possible value is:
maxItemCount = (int.MaxValue - MaximumNumberOfThreads) / itemsCount * itemsCount;
The / itemsCount * itemsCount is because we want the rounds to be equally distributed. In the example I give I use a probably much lower number (itemsCount * 100) because lowering this ceiling will only cause the reset more often, but the reset isn't so much slow that it is truly important (it depends on what you are doing on the threads. If they are very small threads that only use cpu then the reset is slow, but if not then it isn't).
Then when we overflow this ceiling we try to move it back to -1 (our starting point). We know that at the same time other bad bad threads could Interlocked.Increment it and create a race on this reset. Thanks to the Interlocked.CompareExchange only one thread can successfully reset the counter, but the other racing threads will immediately see this and break from their attempts.
Mmmh... The if can be rewritten as:
if (newIndex >= itemsCount)
{
int newIndex2;
while (newIndex >= itemsCount && (newIndex2 = Interlocked.CompareExchange(ref crt, 0, newIndex)) != newIndex)
{
// If the Interlocked.CompareExchange is successfull, the while will end and so we won't be here,
// if it fails, newIndex2 is the current value of crt
newIndex = newIndex2;
}
continue;
}
No, the Interlocked class offers no mechanism that would allow you to restore an Int32 value back to zero in case it overflows. The reason is that it is possible for two threads to invoke concurrently the var newIndex = Interlocked.Increment(ref crt); statement, in which case both with overflow the counter, and then none will succeed in updating the value back to zero. This functionality is just beyond the capabilities of the Interlocked class. To make such complex operations atomic you'll need to use some other synchronization mechanism, like a lock.
Update: xanatos's answer proves that the above statement is wrong. It is also proven wrong by the answers of this 9-year old question. Below are two implementation of an InterlockedIncrementRoundRobin method. The first is a simplified version of this answer, by Alex Sorokoletov:
public static int InterlockedRoundRobinIncrement(ref int location, int modulo)
{
// Arguments validation omitted (the modulo should be a positive number)
uint current = unchecked((uint)Interlocked.Increment(ref location));
return (int)(current % modulo);
}
This implementation is very efficient, but it has the drawback that the backing int value is not directly usable, since it circles through the whole range of the Int32 type (including negative values). The usable information comes by the return value of the method itself, which is guaranteed to be in the range [0..modulo]. If you want to read the current value without incrementing it, you would need another similar method that does the same int -> uint -> int conversion:
public static int InterlockedRoundRobinRead(ref int location, int modulo)
{
uint current = unchecked((uint)Volatile.Read(ref location));
return (int)(current % modulo);
}
It also has the drawback that once every 4,294,967,296 increments, and unless the modulo is a power of 2, it returns a 0 value prematurely, before having reached the modulo - 1 value. In other words the rollover logic is technically flawed. This may or may not be a big issue, depending on the application.
The second implementation is a modified version of xanatos's algorithm:
public static int InterlockedRoundRobinIncrement(ref int location, int modulo)
{
// Arguments validation omitted (the modulo should be a positive number)
while (true)
{
int current = Interlocked.Increment(ref location);
if (current >= 0 && current < modulo) return current;
// Overflow. Try to zero the number.
while (true)
{
int current2 = Interlocked.CompareExchange(ref location, 0, current);
if (current2 == current) return 0; // Success
current = current2;
if (current >= 0 && current < modulo)
{
break; // Another thread zeroed the number. Retry increment.
}
}
}
}
This is slightly less efficient (especially for small modulo values), because once in a while an Interlocked.Increment operation results to an out-of-range value, and the value is rejected and the operation repeated. It does have the advantage though that the backing int value remains in the [0..modulo] range, except for some very brief time spans, during some of this method's invocations.
An alternative to using CompareExchange would be to simply let the values overflow.
I have tested this and could not prove it wrong (so far), but of course that does not mean that it isn't.
//this incurs some cost, but "should" ensure that the int range
// is mapped to the unit range (int.MinValue is mapped to 0 in the uint range)
static ulong toPositive(int i) => (uint)1 + long.MaxValue + (uint)i;
static A GetInstance()
{
//this seems to overflow safely without unchecked
var newCounter = Interlocked.Increment(ref crt);
//convert the counter to a list index, that is map the unsigned value
//to a signed range and get the value modulus the itemCount value
var newIndex = (int)(toPositive(newCounter) % (ulong)itemsCount);
var instance = Items[newIndex];
//Console.WriteLine($"{DateTime.Now.Ticks}, Got instance: {instance.ID}");
return instance;
}
PS: Another part of the xy problem part of my question: At a friend's suggestion I am currently investigating using a LinkedList or something similar (with locks) to achieve the same purpose.
I have a class,
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(y == null)
return -1;
else if(x == null)
return 1;
else
return (int)x - (int)y;
}
}
which is self-explanatory on how it is supposed to work.
Whenever I run
arr.OrderBy(i => i, new NullsAreLast())
with at least two null values in arr it runs forever! Any idea why?
Keep in mind that a sorting algorithm may compare the same two values several times over the process of ordering the whole sequence. Because of this, it's very important to be aware of all three possible results: less than, greater than, and equal.
This is (mostly) fine for your integer comparison at the end (the subtraction operation). There are some weird/rare edge cases when working with floating point numbers instead of integers, and calling .CompareTo() is the preferred practice anyway, but subtraction is usually good enough in this case. However, the null checks here are a real problem.
Think about what happens as a list is nearly finished sorting. You have two null values that have both made their way to the front of the list; the algorithm just needs to verify they are in the correct position. Because both x and y are null, your function should return 0. They are equivalent (for this purpose, at least). Instead, the code always returns -1. The y value will always be less than then x value, and so the algorithm will always believe it still needs to swap them. It swaps, and tries to do the same thing again. And again. And again. And again. It can never finish.
Try this instead:
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(!y.HasValue)
{
if (!x.HasValue) return 0;
return -1;
}
if(!x.HasValue) return 1;
return x.Value.CompareTo(y.Value);
}
}
The minus operation at the end of your Compare method isn't appropriate for comparison. You need to handle exactly three possibilities - x is bigger, y is bigger, or they are the same.
MSDN
Compares two objects and returns a value indicating whether one is
less than, equal to, or greater than the other.
With this code, suppose X was 1000 and Y was 15. Your result would be 985, which doesn't make sense here.
Given your code and method name, I'm going to guess what you meant is this:
public class NullsAreLast : IComparer<int?>
{
public int Compare (int? x, int? y)
{
if(y == null)
return -1;
else if(x == null)
return 1;
else{
int diff = x - y;
if (diff == 0) return 0; //same
if (diff < 0) return 1; //y was bigger
if (diff > 0) return -1; //x was bigger
}
}
}
You could even smash it into a horrible one-liner:
return (y==null?-1:(x==null?1:(x-y==0?0:(x-y<0?1:-1))));
I have two methods in an IntExtensions class to help generate the next available incremental value (which is not in a list of existing integers which need to be excluded).
I dont think I'm addressing the NextIncrementalValueNotInList method in the best way and am wondering if I can better use linq to return the next available int?
public static bool IsInList(this int value, List<int> ListOfIntegers) {
if (ListOfIntegers.Contains(value))
return true;
return false;
}
public static int NextIncrementalValueNotInList(this int value,
List<int> ListOfIntegers) {
int maxResult;
maxResult = ListOfIntegers.Max() + 1;
for (int i = value; i <= maxResult; i++)
{
if (!(i.IsInList(ListOfIntegers)))
{
return i;
}
}
return maxResult;
}
Using linq your method will look like:
return IEnumerable.Range(1, ListOfIntegers.Count + 1)
.Except(ListOfIntegers)
.First();
I guess it starting at 1.
You could also proceed like this:
IEnumerable.Range(1, ListOfIntegers.Count)
.Where(i => !ListOfIntegers.Contains(i))
.Union(new []{ ListOfIntegers.Count + 1 })
.First();
You don't actually need to calculate the Max value - just keep incrementing i until you find a value that doesn't exist in the list, e.g:
public static int NextIncrementalValueNotInList(this int value,
List<int> ListOfIntegers)
{
int i = value;
while(true)
{
if (!(i.IsInList(ListOfIntegers)))
{
return i;
}
i++;
}
return maxResult;
}
. Besides that, I'm not sure if there's much more you can do about this unless:
ListOfIntegers is guaranteed to be, or needs to be, sorted, or
ListOfIntegers doesn't actually need to be a List<int>
If the answer to the first is no, and to the second is yes, then you might instead use a HashSet<int>, which might provide a faster implementation by allowing you to simply use HashSet<T>'s own bool Contains(T) method:
public static int NextIncrementalValueNotInList(this int value,
HashSet<int> ListOfIntegers)
{
int i = value;
while(true)
{
if (!(ListOfIntegers.Contains(i))
{
return value;
}
i++;
}
}
Note that this version shows how to do away with the Max check also.
Although be careful of premature optimisation - if your current implementation is fast enough, then I wouldn't worry. You should properly benchmark any alternative solution with extreme cases as well as real-world cases to see if there's actually any difference.
Also what you don't want to do is use my suggestion above by turning your list into a HashSet for every call. I'm suggesting changing entirely your use of List to HashSet - any piecemeal conversion per-call will negate any potential performance benefits due to the overhead of creating the HashSet.
Finally, if you're not actually expecting much fragmentation in your integer list, then it's possible that a HashSet might not be much different from the current Linq version, because it's possibly going to end up doing similar amounts of work anyway.
I need to limit the value on overflow.
I implemented this as follows:
public static sbyte LimitValueToSByte(this int val)
{
if (val > sbyte.MaxValue) return sbyte.MaxValue;
if (val < sbyte.MinValue) return sbyte.MinValue;
return (sbyte)val;
}
Is there a more elegant way?
This is the code in a time critical system, therefore performance is important.
That seems like a perfectly readable and valid code that doesn't need any improvement whatsoever. It's just the name of the method. Maybe use ToSbyte rather than LimitValueToSByte.
Can't think of a better way to write that function.
I'd call it ClampToSByte, since this kind of limiting operation is usually called Clamp. Limit is a bit less specific, and allows for other boundary conditions, such as wrapping around.
You should be careful if you implement similar code for floating point numbers. In particular you need to decide what behavior you want for NaNs and signed zeros. But luckily that are no issues with integral values.
Looks pretty good to me. If you want something more elegant, how about a generic clamp function?
public static T Clamp<T>(this T value, T min, T max)
where T : IComparable<T>
{
if (value.CompareTo(min) <= 0) return min;
if (value.CompareTo(max) >= 0) return max;
return value;
}
(Warning: I didn't test this.) You could use it like this:
int a = 42;
sbyte b = (sbyte)a.Clamp(sbyte.MinValue, sbyte.MaxValue);
My new solution of this problem:
public static sbyte Clamp(this int val)
{
return (sbyte)Math.Max(Math.Min(value, sbyte.MaxValue), sbyte.MinValue);
}
This question already has answers here:
Where can I find the "clamp" function in .NET?
(11 answers)
Closed 6 years ago.
In C#, I often have to limit an integer value to a range of values. For example, if an application expects a percentage, an integer from a user input must not be less than zero or more than one hundred. Another example: if there are five web pages which are accessed through Request.Params["p"], I expect a value from 1 to 5, not 0 or 256 or 99999.
I often end by writing a quite ugly code like:
page = Math.Max(0, Math.Min(2, page));
or even uglier:
percentage =
(inputPercentage < 0 || inputPercentage > 100) ?
0 :
inputPercentage;
Isn't there a smarter way to do such things within .NET Framework?
I know I can write a general method int LimitToRange(int value, int inclusiveMinimum, int inlusiveMaximum) and use it in every project, but maybe there is already a magic method in the framework?
If I need to do it manually, what would be the "best" (ie. less uglier and more fast) way to do what I'm doing in the first example? Something like this?
public int LimitToRange(int value, int inclusiveMinimum, int inlusiveMaximum)
{
if (value >= inclusiveMinimum)
{
if (value <= inlusiveMaximum)
{
return value;
}
return inlusiveMaximum;
}
return inclusiveMinimum;
}
This operation is called 'Clamp' and it's usually written like this:
public static int Clamp( int value, int min, int max )
{
return (value < min) ? min : (value > max) ? max : value;
}
A much cleaner method that will work with more than just integers (taken from my own library of shared code):
public static T Clamp<T>(T value, T min, T max) where T : IComparable<T>
{
if (value.CompareTo(min) < 0)
return min;
if (value.CompareTo(max) > 0)
return max;
return value;
}
I see Mark's answer and raise it by a this:
public static class InputExtensions
{
public static int LimitToRange(
this int value, int inclusiveMinimum, int inclusiveMaximum)
{
if (value < inclusiveMinimum) { return inclusiveMinimum; }
if (value > inclusiveMaximum) { return inclusiveMaximum; }
return value;
}
}
Usage:
int userInput = ...;
int result = userInput.LimitToRange(1, 5)
See: Extension Methods
I like Guffa's answer, but I am surprised that no one has yet posted a solution using Min/Max.
public int LimitInclusive(int value, int min, int max)
{
return Math.Min(max, Math.Max(value, min));
}
An alternative way to write your LimitToRange function is as follows.
public int LimitToRange(int value, int inclusiveMinimum, int inclusiveMaximum)
{
if (value < inclusiveMinimum) { return inclusiveMinimum; }
if (value > inclusiveMaximum) { return inclusiveMaximum; }
return value;
}
I think this is a little easier to understand while still being efficient.
No, there isn't any method for that built in the framework. I suppose that it was left out because you already have Min and Max, so you can accomplish it using them.
If you write your own method for it, it doesn't matter much how you write it. If you use if statements or the conditional operator ?, it will still compile to pretty much the same code anyway.
To clamp values without giving users any feedback that the value entered by them is wrong, in general, might not be a great idea (IMHO). This might lead to subtle bugs later, which are difficult to debug, especially when min/max values are determined at run time.
Think of this. You have $100 in your bank account, and you want to transfer $150 to your friend. Would you like your banking system to throw an InsufficientFundsException or get into a discussion with your friend that you transferred $150 but he received only $100 (assuming the bank clamped the transfer amount to 100 since your did not have sufficient funds)
That being said, you should also look at code contracts.
public void MyFunction (Type input)
{
Contract.Requires(input > SomeReferenceValue);
Contract.Requires (input < SomeOtherReferencValue);
}
This will force the user input to be within the range.
I like the Clamp name. I would suggest the following class
public class MathHelper
{
public static int Clamp (int value,int min,int max)
{
// todo - implementation
}
public static float Clamp (float value,float min,float max)
{
// todo - implementation
}
)
or if you want to use generics, then
public class MathHelper
{
public static T Clamp<T> (T value, T min, T max) where T : IComparable
{
// todo - implementation
T output = value;
if (value.CompareTo(max) > 0)
{
return max;
}
if (value.CompareTo(min) < 0)
{
return min;
}
return output;
}
}