有一个大数组(~100,000)的浮动点变量,并且有一个阈值(也是浮动点)。
问题是,我必须将数组中的每个变量与阈值进行比较,但是霓虹灯标志的传输需要很长的时间(根据分析器大约20个周期)。
有什么有效的方法来比较这些值吗?
注意:作为舍入错误并不重要,我尝试了以下方法:
float arr[10000];
float threshold;
....
int a = arr[20]; // e.g.
int t = threshold;
if (t > a) {....}但在本例中,我获得了以下处理器命令序列:
vldr.32 s0, [r0]
vcvt.s32.f32 s0, s0
vmov r0, s0 <--- takes 20 cycles as `vmrs APSR_nzcv, fpscr` in case of
cmp r0, r1 floating point comparison由于转换发生在霓虹灯,无论我比较整数,通过描述的方式或浮动。
发布于 2012-04-30 11:24:52
如果浮点数为32位IEEE-754,而ints也是32位,并且如果不存在+无穷大、-infinity和NaN值,我们可以将浮点数作为ints进行比较,并给出一些小技巧:
#include <stdio.h>
#include <limits.h>
#include <assert.h>
#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1]
C_ASSERT(sizeof(int) == sizeof(float));
C_ASSERT(sizeof(int) * CHAR_BIT == 32);
int isGreater(float* f1, float* f2)
{
int i1, i2, t1, t2;
i1 = *(int*)f1;
i2 = *(int*)f2;
t1 = i1 >> 31;
i1 = (i1 ^ t1) + (t1 & 0x80000001);
t2 = i2 >> 31;
i2 = (i2 ^ t2) + (t2 & 0x80000001);
return i1 > i2;
}
int main(void)
{
float arr[9] = { -3, -2, -1.5, -1, 0, 1, 1.5, 2, 3 };
float thr;
int i;
// Make sure floats are 32-bit IEE754 and
// reinterpreted as integers as we want/expect
{
static const float testf = 8873283.0f;
unsigned testi = *(unsigned*)&testf;
assert(testi == 0x4B076543);
}
thr = -1.5;
for (i = 0; i < 9; i++)
{
printf("%f %s %f\n", arr[i], "<=\0> " + 3*isGreater(&arr[i], &thr), thr);
}
thr = 1.5;
for (i = 0; i < 9; i++)
{
printf("%f %s %f\n", arr[i], "<=\0> " + 3*isGreater(&arr[i], &thr), thr);
}
return 0;
}输出:
-3.000000 <= -1.500000
-2.000000 <= -1.500000
-1.500000 <= -1.500000
-1.000000 > -1.500000
0.000000 > -1.500000
1.000000 > -1.500000
1.500000 > -1.500000
2.000000 > -1.500000
3.000000 > -1.500000
-3.000000 <= 1.500000
-2.000000 <= 1.500000
-1.500000 <= 1.500000
-1.000000 <= 1.500000
0.000000 <= 1.500000
1.000000 <= 1.500000
1.500000 <= 1.500000
2.000000 > 1.500000
3.000000 > 1.500000当然,在不改变阈值的情况下,在比较操作符中使用的isGreater()中的最终整数值的预计算是有意义的。
如果您害怕上述代码中C/C++中的未定义行为,则可以在程序集中重写代码。
发布于 2012-04-30 10:31:23
如果您的数据是浮动的,那么您应该使用浮点数进行比较。
float arr[10000];
float threshold;
....
float a = arr[20]; // e.g.
if (threshold > a) {....}否则,您将有昂贵的浮点转换。
发布于 2012-05-02 07:49:02
您的示例显示了编译器生成的代码可能是多么糟糕:
它加载一个数值与霓虹灯只是转换成int,然后做一个霓虹灯->臂转移,导致管道冲洗造成11~14个周期浪费。
最好的解决方案是将函数完全写在手头的程序集中。
但是,有一个简单的技巧可以在不进行类型转换和截断的情况下进行快速浮点比较:
阈值正(与int比较一样快):
void example(float * pSrc, float threshold, unsigned int count)
{
typedef union {
int ival,
unsigned int uval,
float fval
} unitype;
unitype v, t;
if (count==0) return;
t.fval = threshold;
do {
v.fval = *pSrc++;
if (v.ival < t.ival) {
// your code here
}
else {
// your code here (optional)
}
} while (--count);
}阈值负(每个周期比int比较多1个周期):
void example(float * pSrc, float threshold, unsigned int count)
{
typedef union {
int ival,
unsigned int uval,
float fval
} unitype;
unitype v, t, temp;
if (count==0) return;
t.fval = threshold;
t.uval &= 0x7fffffff;
do {
v.fval = *pSrc++;
temp.uval = v.uval ^ 0x80000000;
if (temp.ival >= t.ival) {
// your code here
}
else {
// your code here (optional)
}
} while (--count);
}我认为这比上面所接受的要快得多。再说一次,我有点晚了。
https://stackoverflow.com/questions/10381927
复制相似问题