# Clamp function for primitive types

**URL:** <https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999>\
**Category:** language design\
**Created:** [March 25, 2017, 9:25pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999 "2017-03-25T21:25:45Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Xaeroxe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/xaeroxe/32/2209_2.png) [@Xaeroxe](https://internals.rust-lang.org/u/Xaeroxe)\
**Post date:** [March 25, 2017, 9:25pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/1 "2017-03-25T21:25:45Z")

</div>

This is a small change to the primitive types for Rust so I wasn’t sure if an RFC was appropriate. There is a constant need for the ability to restrict values to be between a certain minimum and maximum in several libraries. Some syntax patterns I’ve observed to accomplish this are

```rust
if input > max {
    max
}
else if input < min {
    min
} else {
    input
}

```

and

```rust
input.max(min).min(max);

```

and even

```rust
match input {
        c if c > max => max,
        c if c < min => min,
        c => c,
    }

```

This is a very common task but there isn’t an idiomatic way to do this. Thus I propose clamp whose general form is:

```rust
pub fn clamp(self, min: Self, max: Self) -> Self {
    if self < min {
        min
    }
    else if self > max {
        max
    }
    else {
        self
    }
}

```

I’ve added this function to the applicable primitive types in a branch on my own Rust repo. I’d like to have them incorporated into the main compiler but I’m not entirely sure what my next step should be to accomplish that.

[https://github.com/Xaeroxe/rust/tree/clamp\_patch](https://github.com/Xaeroxe/rust/tree/clamp_patch)

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [March 26, 2017, 1:12am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/2 "2017-03-26T01:12:59Z")

</div>

Default answer for a new API is to make an RFC: [https://github.com/rust-lang/rfcs/blob/master/libs\_changes.md#is-an-rfc-required](https://github.com/rust-lang/rfcs/blob/master/libs_changes.md#is-an-rfc-required). I don’t know whether this is a case where a PR would suffice; that doc implies you could just submit one and find out.

I do think it sounds like a useful thing to have; I know I’ve made similar things before.

Some questions to ponder, regarding the implementation:

- Why only on [ui]N? Why not on anything `Ord`? (like `std::cmp::min`)
- Should one of the `Range` types be involved, since the parameters are in essence a range?
- fN aren’t Ord, so the custom method on them needs to talk about NaN behaviour, justify it, and test it.
- If there’s a good answer for NaN, can that be extended to a good answer for PartialOrd?
- What happens if the requested range is uninhabitable? `4.clamp(11, 9)`, for example.

Edit: I probably should have said [RangeInclusive](https://doc.rust-lang.org/std/ops/enum.RangeInclusive.html), not just Range. Though part of me thinks that `assert_eq!( (3.14f64).clamp(0.0..1.0), 0.9999999999999999)` is awesome (if probably not that useful).

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [March 26, 2017, 1:17am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/3 "2017-03-26T01:17:20Z")

</div>

> [@scottmcm](#):
>
> Why not on anything Ord? (like std::cmp::min)

`Ord` doesn't work with floats ☹

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [March 26, 2017, 1:19am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/4 "2017-03-26T01:19:05Z")

</div>

> [@kornel](#):
>
> Ord doesn't work with floats ☹

Yes, hence the note about "the custom method on fN", also like `min`/`max`.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [March 26, 2017, 1:23am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/5 "2017-03-26T01:23:04Z")

</div>

I write a version of `clamp()` in almost every program I write, but most often I use it when converting to a smaller type, e.g. `f32.clamp() -> u8`.

What are your use-cases for it?

---

<div class="post-metadata">

**Author:** ![Xaeroxe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/xaeroxe/32/2209_2.png) [@Xaeroxe](https://internals.rust-lang.org/u/Xaeroxe)\
**Post date:** [March 26, 2017, 1:52am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/6 "2017-03-26T01:52:26Z")

</div>

Thanks for your advice on the PR. I’ll give this a second pass based on your feedback then submit the PR and see what happens.

Use cases are very wide and varied but it typically has to do with interfacing with APIs that take normalized values or when sending output to hardware that expects values to be in a certain range, such as audio samples or painting to pixels on a display.

I had not considered using one of the Range types but I will certainly look into it.

I thought of implementing this for a trait such as PartialOrd but prior precedence showed similar functions lived at these locations so I decided to go with that. That being said a historical reason is not a good reason so I’ll see if there’s a better home for these that makes them more broadly applicable.

There is no good answer for NaN types other than panicking or returning some kind of error value. Returning an error value would complicate the signature, and we also have prior precedence from invalid indexes into arrays demonstrating that panicking on unusual inputs is acceptable so I’m of the belief that panicking would be preferable.

If it’s going to be implemented based on a trait I’d rather not use Ord but PartialOrd instead, as floats are a type that needs to be restricted often as well.

There is also a case to be made that if this can only handle Ord types correctly then maybe it should only be implemented for Ord with a special case for floats.

---

<div class="post-metadata">

**Author:** ![Xaeroxe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/xaeroxe/32/2209_2.png) [@Xaeroxe](https://internals.rust-lang.org/u/Xaeroxe)\
**Post date:** [March 26, 2017, 3:06am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/7 "2017-03-26T03:06:15Z")

</div>

I’ve decided not to use the range type, as it being exclusive on the upper bound is problematic for the clamp function.

---

<div class="post-metadata">

**Author:** ![Fylwind](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fylwind/32/2117_2.png) [@Fylwind](https://internals.rust-lang.org/u/Fylwind)\
**Post date:** [March 26, 2017, 6:25am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/8 "2017-03-26T06:25:45Z")

</div>

There’s a [RangeToInclusive](https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html) BTW.

---

<div class="post-metadata">

**Author:** ![Xaeroxe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/xaeroxe/32/2209_2.png) [@Xaeroxe](https://internals.rust-lang.org/u/Xaeroxe)\
**Post date:** [March 26, 2017, 6:32am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/9 "2017-03-26T06:32:38Z")

</div>

I appreciate the thought but it’s also not fit for this for two reasons, the first being that it is unstable, the second being that it doesn’t define a beginning, only an end.

---

<div class="post-metadata">

**Author:** ![colin\_kiegel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/colin_kiegel/32/1345_2.png) [@colin\_kiegel](https://internals.rust-lang.org/u/colin_kiegel)\
**Post date:** [March 26, 2017, 8:41am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/10 "2017-03-26T08:41:54Z")

</div>

Also not stable, but it has the lower bound too [RangeInclusive](https://doc.rust-lang.org/std/ops/enum.RangeInclusive.html). I also believe `std` can and does use unstable features internally. So it should be possible to use ranges. Users will be able to construct ranges via `a...b` on stable, but only `std` can then access the unstable API on that range, destructure, etc. After all, it’s defined in `std`. 🙂

---

<div class="post-metadata">

**Author:** ![hanna-kruppe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hanna-kruppe/32/6540_2.png) [@hanna-kruppe](https://internals.rust-lang.org/u/hanna-kruppe)\
**Post date:** [March 26, 2017, 12:28pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/11 "2017-03-26T12:28:54Z")

</div>

> [@Xaeroxe](#):
>
> There is no good answer for NaN types other than panicking or returning some kind of error value. Returning an error value would complicate the signature, and we also have prior precedence from invalid indexes into arrays demonstrating that panicking on unusual inputs is acceptable so I'm of the belief that panicking would be preferable.

A sensible alternative is to return NaN when the value to be clamped is NaN. ~~This matches what `fN::min` and `fN::max` do, and the more general principle that NaN should be propagated rather than swallowed by most operations. A NaN min or max is much stranger, I'm not sure whether `x.clamp(NaN, y)` should return NaN, or if it should panicks just as if the lower bound is larger than the upper bound.~~ I mixed this up, thanks @bluss

In any case, this would require making a dedicated clamp method that works slightly differently from the clam or `Ord` types, but this too matches the `min`/`max` situation.

---

<div class="post-metadata">

**Author:** ![bluss](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bluss/32/2264_2.png) [@bluss](https://internals.rust-lang.org/u/bluss)\
**Post date:** [March 26, 2017, 1:31pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/12 "2017-03-26T13:31:06Z")

</div>

fN::min and max are actually always propagating the non-NaN operand, so they do the inverse of that.

---

<div class="post-metadata">

**Author:** ![Xaeroxe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/xaeroxe/32/2209_2.png) [@Xaeroxe](https://internals.rust-lang.org/u/Xaeroxe)\
**Post date:** [March 26, 2017, 3:25pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/13 "2017-03-26T15:25:16Z")

</div>

So I decided to make clamp a more general purpose function that lives in std::cmp::clamp and uses Ord with RangeInclusive. Since it is also oftentimes desirable to clamp floats as well I left the current float implementation but modified it to use RangeInclusive. RangeInclusive also contains an “Empty” variant whose purpose I believe to be for iteration, but I’m not iterating the range so I created code branches for Empty values that should never be executed.

Clamp and NaN: Here is the behavior the current implementation guarantees:

If an upper bound of NaN is used then no maximum is applied. If a lower bound of NaN is used then no minimum is applied. If this function is called on NaN then NaN will be returned.

Commit for review: [https://github.com/Xaeroxe/rust/commit/e1f90513e6cd525f1bd75e5557ef53d470a9251c](https://github.com/Xaeroxe/rust/commit/e1f90513e6cd525f1bd75e5557ef53d470a9251c)

---

<div class="post-metadata">

**Author:** ![bluss](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bluss/32/2264_2.png) [@bluss](https://internals.rust-lang.org/u/bluss)\
**Post date:** [March 26, 2017, 3:27pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/14 "2017-03-26T15:27:51Z")

</div>

numpy has a function called `np.clip` that clamps all the values in an array. It leaves NaNs in place.

it accepts min and max, and passing NaN for either of those behaves as if passing None (no clip at the corresponding lower/upper boundary).

---

<div class="post-metadata">

**Author:** ![Xaeroxe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/xaeroxe/32/2209_2.png) [@Xaeroxe](https://internals.rust-lang.org/u/Xaeroxe)\
**Post date:** [March 26, 2017, 4:18pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/15 "2017-03-26T16:18:53Z")

</div>

This clamp code should behave in a similar way. If a value can’t be compared (such as NaN) the comparison will return false. That means that if NaN is passed for min no minimum is enforced. The same is true of max. If NaN is passed as self then NaN will be returned because it can’t be compared.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [March 26, 2017, 7:29pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/16 "2017-03-26T19:29:32Z")

</div>

The semantics should probably match:

```rust
maxsd %xmm0, %xmm1
minsd %xmm1, %xmm2
movaps %xmm2, %xmm0

```

otherwise the implementation may be much slower than it needs to be.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [March 26, 2017, 8:09pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/17 "2017-03-26T20:09:41Z")

</div>

Oh man, floating point and its billion NaNs 😭[These](https://is.gd/hcbWJL) all give totally different ASM:

```rust
     if x < start { return start; }
     if x > end { return end; }
     return x;

```

```rust
    x.max(start).min(end)

```

```rust
    // this gives @kornel's instructions
    if x < start { x = start }
    if x > end { x = end }
    x

```

Unimportant aside: they _also_ give different instructions for integers, but not meaningfully (just different combinations of `cmov(l|le|g|ge)`).

---

<div class="post-metadata">

**Author:** ![Xaeroxe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/xaeroxe/32/2209_2.png) [@Xaeroxe](https://internals.rust-lang.org/u/Xaeroxe)\
**Post date:** [March 26, 2017, 9:38pm UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/18 "2017-03-26T21:38:22Z")

</div>

The exact assembly produced is one area in which my knowledge is definitely lacking. Assuming the code is functionally equivalent I’ll take whatever is decided to be the most optimal by you people.

---

<div class="post-metadata">

**Author:** ![bluss](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bluss/32/2264_2.png) [@bluss](https://internals.rust-lang.org/u/bluss)\
**Post date:** [March 27, 2017, 1:39am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/19 "2017-03-27T01:39:55Z")

</div>

If I put exactly this into ndarray’s mapv\_inplace, the loop autovectorizes pretty well (Element type is f64). But it can also be ndarray’s own responsibility to provide an array wide clamp.

```rust
a.mapv_inplace(|mut x| {
    if x < min { x = min };
    if x > max { x = max };
    x
})

```

(AVX instructions)

```rust
│140:┌─→vmovup xmm2,XMMWORD PTR [rcx-0x20]
│ │ vmovup xmm3,XMMWORD PTR [rcx]
│ │ vinser ymm2,ymm2,XMMWORD PTR [rcx-0x10],0x1
│ │ vinser ymm3,ymm3,XMMWORD PTR [rcx+0x10],0x1
│ │ vmaxpd ymm2,ymm0,ymm2                     
│ │ vmaxpd ymm3,ymm0,ymm3                    
│ │ vminpd ymm2,ymm1,ymm2                   
│ │ vminpd ymm3,ymm1,ymm3                  
│ │ vextra XMMWORD PTR [rcx-0x10],ymm2,0x1
│ │ vmovup XMMWORD PTR [rcx-0x20],xmm2   
│ │ vextra XMMWORD PTR [rcx+0x10],ymm3,0x1
│ │ vmovup XMMWORD PTR [rcx],xmm3        
│ │ add rcx,0x40                     
│ │ add rdx,0xfffffffffffffff8      
│ └──jne 140

```

---

<div class="post-metadata">

**Author:** ![Xaeroxe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/xaeroxe/32/2209_2.png) [@Xaeroxe](https://internals.rust-lang.org/u/Xaeroxe)\
**Post date:** [March 27, 2017, 5:34am UTC](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999/20 "2017-03-27T05:34:46Z")

</div>

Clearly I underestimated the amount of discussion this function warrants, so I created an RFC here: [https://github.com/rust-lang/rfcs/pull/1961](https://github.com/rust-lang/rfcs/pull/1961)

[Next page](https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999.md?page=2)
