如何找到环绕的两个数字的平均值?

How to find average of two numbers that wrap around?

我有一个 int 表示范围 [0, 8[ 环绕的数字:

       2      
  1         3


0             4


  7         5
       6

现在我需要像这样求两个数字的平均值,例如 7 和 0 的平均值为 7.5,7 和 2 的平均值为 0.5,0 和 4 的平均值为2或6等

我找到了 this ("How do you calculate the average of a set of angles?") related question, but it's about angles and I don't see how it could help here. There's also "How to subtract two unsigned ints with wrap around or overflow" 但它是关于减法,而不是求平均值。有什么指点吗?

我还有一个wrap函数,如果能在这里用到的话:

template <class type>
inline type Wrap(type Value, type Minimum, type Maximum)
{
  Value = ((Value - Minimum) % (Maximum + 1 - Minimum));
  return (Value >= 0 ? Minimum : Maximum + 1) + Value;
}

编辑: 尝试更正式地定义规则:

如果abs(a - b) <= 4那么avg = (a + b) / 2.
否则,avg = (a + b) / 2. + 4; if (avg >= 8) avg -= 8;.

粗糙但有效:

float foo(int a, int b)
{
  int c;
  if(a>b)
    {
      c=a;
      a=b;
      b=c;
    }

  if( b-a > 3)
    {
      c=a+8;
      a=b;
      b=c;
    }

  float f = 0.5*(a+b);
  if(f>7.6)
    f-=8.0;
  return(f);
}

我认为第一个 return 表达式就是您所追求的:

def av(a,b):
    mi = min(a,b)
    ma = max(a,b)
    if ma - mi > 4:
        return (((mi + 8) + ma) / 2.) % 8
    else:
        return (mi+ma)/2.

mi是两者中的最小值; ma 是最大值

另一种解决方案是先将您的数字转换为角度,从而使用您 cited 的答案:

  1. 将数字转换为角度。

    angle_a = a * pi / 4
    angle_b = b * pi / 4
    
  2. 计算每个角度的单位向量

    unit_a
    unit_b
    
  3. 计算单位向量平均值

    unit_average = (unit_a + unit_b) / 2
    
  4. 计算unit_average

    的角度
    angle_average
    
  5. 将angle_average转换为数字

    number_average = angle_average * 4 / pi
    

那么number_average就是我们的答案

float wAvg(int m, int n)
{
    int minimum = min(m, n);
    int maximum = max(m, n);

    int d1 = minimum + 8 - maximum; // difference between m and n
                                    // when wrapped around
    int d2 = max - min;             // normal difference

    float avg = 0.0f;

    if (d1 < d2)    // if wrapped around distance is shorter than normal distance
    {
        avg = d1 / 2.0f + maximum;

        if (avg >= 8.0f)
            avg -= 8.0f;
    }
    else
    {
        avg = (m + n) / 2.0f;
    }

    return avg;
}

我认为这可能有效

看到@Beta 的“粗略”回答后,仅供娱乐:) :

float wAvg(int m, int n)
{
    static float results[8][8] =
    {
        {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 6.5f, 7.0f, 7.5f},
        {0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 7.5f, 0.0f},
        {1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 0.5f},
        {1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f},
        {2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.5f},
        {6.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.5f, 6.0f},
        {7.0f, 7.5f, 4.0f, 4.5f, 5.0f, 5.5f, 6.0f, 6.5f},
        {7.5f, 0.0f, 0.5f, 5.0f, 5.5f, 6.0f, 6.5f, 7.0f}
    };

    return results[m % 8][n % 8];
}

推测以下将起作用(与角度相同):

function meanWrappingValue(values: Array<number>, range: number): number {
    return meanAngle(values.map(value => value * (Math.PI * 2) / range)) / (Math.PI * 2) * range;
}

function meanAngle(angles: Array<number>): number {
    let sinSum = angles.reduce((sum, cur) => sum + Math.sin(cur), 0);
    let cosSum = angles.reduce((sum, cur) => sum + Math.cos(cur), 0);
    return normalizeAngle(Math.atan2(sinSum / angles.length, cosSum / angles.length));
}

function normalizeAngle(angle: number): number {
    let range = Math.PI * 2;
    return ((angle % range) + range) % range;
}

在你的情况下它将是:

let result = meanWrappingValue([7, 2], 8);
console.log(result); // => 0.5