如何找到环绕的两个数字的平均值?
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 的答案:
将数字转换为角度。
angle_a = a * pi / 4
angle_b = b * pi / 4
计算每个角度的单位向量
unit_a
unit_b
计算单位向量平均值
unit_average = (unit_a + unit_b) / 2
计算unit_average
的角度
angle_average
将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
我有一个 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 的答案:
将数字转换为角度。
angle_a = a * pi / 4 angle_b = b * pi / 4
计算每个角度的单位向量
unit_a unit_b
计算单位向量平均值
unit_average = (unit_a + unit_b) / 2
计算unit_average
的角度angle_average
将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