具有环绕溢出的浮点约束函数的最简洁实现

发布于 2024-10-21 19:22:25 字数 1196 浏览 5 评论 0 原文

我正在寻找以下函数的最简洁和通用的实现:

float Constrain(float value, float min, float max);

Constrain() 将 value 限制在 [min, float) 范围内。即,范围包括 min 但不包括 max 和大于 max 或小于 minvalues 环绕在一个圆圈。即,以与整数上溢/下溢类似的方式。

该函数应通过以下测试:

Constrain(  0.0,  0.0,  10.0) ==  0.0
Constrain( 10.0,  0.0,  10.0) ==  0.0
Constrain(  5.0,  0.0,  10.0) ==  5.0
Constrain( 15.0,  0.0,  10.0) ==  5.0
Constrain( -1.0,  0.0,  10.0) ==  9.0
Constrain(-15.0,  0.0,  10.0) ==  5.0

Constrain(  0.0, -5.0,   5.0) ==  0.0
Constrain(  5.0, -5.0,   5.0) == -5.0
Constrain(  0.0, -5.0,   5.0) ==  0.0
Constrain( 10.0, -5.0,   5.0) ==  0.0    
Constrain( -6.0, -5.0,   5.0) ==  4.0
Constrain(-10.0, -5.0,   5.0) ==  0.0
Constrain( 24.0, -5.0,   5.0) ==  4.0

Constrain(  0.0, -5.0,   0.0) == -5.0
Constrain(  5.0, -5.0,   0.0) == -5.0
Constrain( 10.0, -5.0,   0.0) == -5.0
Constrain( -3.0, -5.0,   0.0) == -3.0     
Constrain( -6.0, -5.0,   0.0) == -1.0
Constrain(-10.0, -5.0,   0.0) == -5.0

请注意,可以假定 min 参数在数值上始终小于 max

可能有一个非常简单的公式可以解决这个问题,但是我非常愚蠢,不知道它的通用解决方案。

I'm looking for the most succinct and general implementation of the following function:

float Constrain(float value, float min, float max);

Where Constrain() bounds value in the range [min, float). Ie, the range includes min but excludes max and values greater than max or less than min wrap around in a circle. Ie, in a similar way to integers over/underflow.

The function should pass the following tests:

Constrain(  0.0,  0.0,  10.0) ==  0.0
Constrain( 10.0,  0.0,  10.0) ==  0.0
Constrain(  5.0,  0.0,  10.0) ==  5.0
Constrain( 15.0,  0.0,  10.0) ==  5.0
Constrain( -1.0,  0.0,  10.0) ==  9.0
Constrain(-15.0,  0.0,  10.0) ==  5.0

Constrain(  0.0, -5.0,   5.0) ==  0.0
Constrain(  5.0, -5.0,   5.0) == -5.0
Constrain(  0.0, -5.0,   5.0) ==  0.0
Constrain( 10.0, -5.0,   5.0) ==  0.0    
Constrain( -6.0, -5.0,   5.0) ==  4.0
Constrain(-10.0, -5.0,   5.0) ==  0.0
Constrain( 24.0, -5.0,   5.0) ==  4.0

Constrain(  0.0, -5.0,   0.0) == -5.0
Constrain(  5.0, -5.0,   0.0) == -5.0
Constrain( 10.0, -5.0,   0.0) == -5.0
Constrain( -3.0, -5.0,   0.0) == -3.0     
Constrain( -6.0, -5.0,   0.0) == -1.0
Constrain(-10.0, -5.0,   0.0) == -5.0

Note that the min param can be assumed to be always numerically less than max.

There is probably a very simple formula to solve this question but and I'm being spectacularly dumb not knowing the generalised solution to it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

轮廓§ 2024-10-28 19:22:25

几乎正在寻找fmod函数。 fmod(x,y) 返回 x 除以 y 的余数,两者均为 double。结果的符号与x相同(相当于,相应的整数部分函数是向零舍入的函数),这就是为什么它只是几乎你想要什么。因此,如果 x>=lolo+fmod(x-lo,hi-lo) 是正确的,但如果 x > 那么 hi+fmod(x-lo,hi-lo) 几乎是正确的事情,除了当 x 时,结果可能是 < code>lohi 您会得到 hi 而不是 lo

所以。您可以分为三种方式:

double Constrain(x,lo,hi) {
  double t = fmod(x-lo,hi-lo);
  return t<0 ? t+hi : t+lo;
}

或者您可以使用 floor 代替 [已编辑,因为第一个版本根本不是我的意思]:

double Constrain(x,lo,hi) {
  double t = (x-lo) / (hi-lo);
  return lo + (hi-lo) * (t-floor(t));
}

如果您关心的是可理解性,请选择;如果您关心的是性能,请尝试两者。

You're almost looking for the fmod function. fmod(x,y) returns the remainder on dividing x by y, both being doubles. The sign of the result is the same as that of x (equivalently, the corresponding integer-part function is the one that rounds towards zero), and that's why it's only almost what you want. So, if x>=lo then lo+fmod(x-lo,hi-lo) is the Right Thing, but if x<lo then hi+fmod(x-lo,hi-lo) is oh-so-nearly the Right Thing except that when x<lo and the result could be either lo or hi you get hi instead of lo.

So. You can split three ways:

double Constrain(x,lo,hi) {
  double t = fmod(x-lo,hi-lo);
  return t<0 ? t+hi : t+lo;
}

or you can use floor instead [EDITED because the first version of this wasn't what I meant at all]:

double Constrain(x,lo,hi) {
  double t = (x-lo) / (hi-lo);
  return lo + (hi-lo) * (t-floor(t));
}

Take your pick if what you care about is comprehensibility; try them both if what you care about is performance.

贱人配狗天长地久 2024-10-28 19:22:25

lrint() 可能会更快。

inline double fwrap(double x, double y)
{
  return x - y * lrint(x / y - 0.5);
}

double constrain(double x, double lo, double hi)
{
  return fwrap(x, hi - lo);
}

lrint() may be faster.

inline double fwrap(double x, double y)
{
  return x - y * lrint(x / y - 0.5);
}

double constrain(double x, double lo, double hi)
{
  return fwrap(x, hi - lo);
}
秋心╮凉 2024-10-28 19:22:25

lrint() 可能会更快。

inline double fwrap(double x, double y)
{
  return x - y * lrint(x / y - 0.5);
}

double constrain(double x, double lo, double hi)
{
  return fwrap(x - lo, hi - lo) + lo;
}

lrint() may be faster.

inline double fwrap(double x, double y)
{
  return x - y * lrint(x / y - 0.5);
}

double constrain(double x, double lo, double hi)
{
  return fwrap(x - lo, hi - lo) + lo;
}
残疾 2024-10-28 19:22:25

这也有效:

double constrain(double value, double min, double max)
{
    double Range = max - min;

    if (value < min)
        value = max - (max - value ) % (Range + 1); // Range+1 for inclusive

    if (value > max)
        value = (value - min) % (Range) + min; // Range(+0) for exclusive

    return value;
}

This also works:

double constrain(double value, double min, double max)
{
    double Range = max - min;

    if (value < min)
        value = max - (max - value ) % (Range + 1); // Range+1 for inclusive

    if (value > max)
        value = (value - min) % (Range) + min; // Range(+0) for exclusive

    return value;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文