4

我需要一个可以手动步进的变化值,它可以在 a和 a之间step()来回移动,每个.minmaxspeedstep()

这是我当前的代码:

template<typename T> struct PingPongValue {
        T value, min, max, speed, dir{1};

        PingPongValue(T mMin, T mMax, T mSpeed) 
           : value(mMin), min(mMin), max(mMax), speed(mSpeed) { }

        void step()
        {
            value += speed * dir;
                 if(value > max) { value = max; dir = -1; }
            else if(value < min) { value = min; dir = +1; }
        }
};

例子:

PingPongValue v{0, 5, 1};
v.step(); // v.value == 1
v.step(); // v.value == 2
v.step(); // v.value == 3
v.step(); // v.value == 4
v.step(); // v.value == 5
v.step(); // v.value == 4
v.step(); // v.value == 3
v.step(); // v.value == 2
// etc...

我想有一种数学方法可以将其表示为无分支函数,但我无法弄清楚。我尝试使用模,但我仍然需要一个dir变量来改变步进方向。

4

7 回答 7

5

您可以使用数组来执行此操作,如下所示(警告:可能有大量错误!):

int total_steps = 2*(max - min + 1)/speed; // this may be wrong -- have to double check
T steps[total_steps];
for(int i = 0; i < max - min; ++i)
    steps[total_steps - i] = steps[i] = min + i*speed;

然后你可以使用模数total_steps来永远遍历数组。

于 2013-09-24T10:06:26.053 回答
4

我不喜欢“无分支”算法,因为很多时候它们只是“因为分支很慢”而被使用,在这种情况下,IMO 优化器的工作就是寻找更快的方法。

不过,您可以使用比较,因为 bool在转换为整数类型01转换为整数类型时会产生。这是否是无分支的取决于架构 AFAIK。

value += speed*dir;                           // allowing over-/underflow
value += (min-value)*(value<min) + (max-value)*(value>max);  // clamp
dir   += 2* ((value==min) - (value==max));    // set dir

SSCCE:

template<typename T> struct PingPongValue {
        T value, min, max, speed, dir{1};

        PingPongValue(T mMin, T mMax, T mSpeed) 
           : value(mMin), min(mMin), max(mMax), speed(mSpeed) { }

        void step()
        {
            // allowing over-/underflow
            value += speed*dir;

            // clamp
            value += (min-value)*(value<min) + (max-value)*(value>max);

            // set dir
            dir   += 2* ((value==min) - (value==max));
        }
};


#include <iostream>

template<class T>
void step(PingPongValue<T>& v)
{
    v.step();
    std::cout << "stepped to: " << v.value << std::endl;
}

int main()
{
    PingPongValue<int> p{-3, 6, 2};
    std::cout << "initial: " << p.value << std::endl;
    for(int i = 0; i < 10; ++i)
    {
        step(p);
    }
}

输出:

初始:-3
步入:-1
步入:1
步入:3
步数:5
步数:6
步入:4
步入:2
步入:0
步入:-2
步入:-3
于 2013-09-24T10:22:08.343 回答
2

实际上,您必须使用一些周期性函数,如 sin(x) 并将其标准化为您想要的比例。例如三角波:http ://en.wikipedia.org/wiki/Triangle_wave

另一种方法(对于简单的情况可能更优选)是使用预先计算的结果数组并遍历它们(并在 mod 函数的帮助下处理索引溢出)。

于 2013-09-24T10:05:43.937 回答
1
        int min = 2;
        int max = 7;
        int step = 1;

        int d = max - min;
        int n = d;

        for( int i = 0; min<1000; ++i)
        {
            int x = min + abs(d - n); // the result
            n = (n + step) % (2 * d); // the step
        }
于 2013-09-24T13:55:13.630 回答
0

假设您尝试在 6 点到 11 点之间打乒乓球:

您正在尝试重复以下顺序:

f4(i) = 6 7 8 9 10 11 10 9 8 7

假设它是通过将 6 添加到另一个序列的值而形成的:

f3(i) = 0 1 2 3 4 5 4 3 2 1

假设它是通过取另一个序列的绝对值形成的。

f2(i) = 0 1 2 3 4 5 -4 -3 -2 -1

现在假设您通过从另一个序列的值中减去 4 得到这些数字。

f1(i) = 4 5 6 7 8 9 0 1 2 3

然后你有:

f1(i) = (i + 4) % 10;
f2(i) = f1(i) - 4;
f3(i) = abs(f2(i));
f4(i) = f3(i) + 6

代替:

min = 6
2*(max - min) = 10
max - min - 1 = 4

你得到:

f1(i) = (i + max - min - 1) % 2*(max - min);
f2(i) = f1(i) - (max - min - 1);
f3(i) = abs(f2(i));
f4(i) = f3(i) + min;
于 2013-09-24T13:00:33.043 回答
0

这是我在伪代码中的想法,但不能保证:) 这应该模仿您的示例所做的,而不是您的代码所做的。也就是说,它应该创建一个系列 1, 2, 3, 4, 5, 4, 3, 2, 1, 2, ... 而您的代码将创建 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1, 2, ...

注释说明了 min=1、max=5、speed=1 的行为

size = max-min; // 4
internalValue = (internalValue + speed) % (size*2); // 0, 1, ..., 7, 0, 1, ...
reverse = internalValue / size; // 0 for internalValue in [0, 3], 1 for [4, 7]
value = min + internalValue - 2*reverse*(internalValue - size);

internalValue 是这里唯一的实际状态变量。

于 2013-09-24T10:25:46.090 回答
0

如果你有一个无分支 -function abs你可以使用这个:

template<typename T> struct PingPongValue {
    T value, inner, min, max, speed;

    PingPongValue(T mMin, T mMax, T mSpeed) 
       : value(mMin), inner(0), min(mMin), max(mMax), speed(mSpeed) { }

    void step()
    {
        inner = (inner + speed) % ((mMax - mMin) * 2);
        value = mMax - abs(inner - mMax + 1) + mMin - 1;
    }
};
于 2013-09-24T10:33:18.867 回答