- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
任务是将C整数数组的每个元素设置为其绝对值。我正在尝试尽可能有效地做到这一点。以下是我进行的优化过程。请告诉我这些是否真的是优化,以及是否可以进行更多优化!
该函数的第一个参数将是一个整数数组,第二个参数将是该数组的整数大小。
这是标准的实现:
void absolute (int array[], int n){
for(int i = 0; i < n; i++)
if(array[i] < 0)
array[i] = - array[i];
}
void absolute (int array[], int n){
for(int i = 0; i < n; i++){
uint32_t temp = array[i] >> 31; // make a mask of the sign bit
array[i] ^= temp; // toggle the bits if value is negative
array[i] += temp & 1; // add one if value was negative
}
}
void absolute (int array[], int n){
for(n--; n >= 0;){
uint32_t temp = array[n] >> 31;
array[n] ^= temp;
array[n] += temp & 1;
}
}
最佳答案
我个人比较喜欢这个问题。像这样的问题使您想知道是否有办法使自己的代码更好。
您的最终优化不正确,因为它会初始化n--,但是n永远不会再递减。要更正此问题,您需要for(n--; n >= 0; n--)
。尽管我发现结果减少或增加for循环都没有明显的好处。
如果数组的值不是真正随机分布的,我发现在第一个实现中使用的简单if(array[i] < 0)
实际上要快得多。
这是我用来进行基准测试的代码:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef _OPT3
#include <emmintrin.h>
#include <tmmintrin.h>
#endif
int main(int argc, char **argv)
{
int *array;
struct timespec tsstart, tsend;
int ncount = 500000000;
int i;
array = malloc(sizeof(int) * ncount);
for(i = 0; i < ncount; i++)
{
array[i] = rand();
#ifdef _DIST
if(rand() % 100 == 0) // make the values less likely to be negative.
#else
if(rand() % 2 == 0) // the values are equeally likely to be negaitve as positive.
#endif
array[i] = -rand();
}
clock_gettime(CLOCK_MONOTONIC, &tsstart);
#ifdef _OPT1
for(i = 0; i < ncount; i++)
{
uint32_t ntemp = array[i] >> 31;
array[i] ^= ntemp;
array[i] += ntemp & 1;
}
#elif _OPT2
for(ncount--; ncount >= 0; ncount--)
{
uint32_t ntemp = array[ncount] >> 31;
array[ncount] ^= ntemp;
array[ncount] += ntemp & 1;
}
#elif _OPT3
for(i = 0; i < ncount; i+=4)
{
__m128i a3_a2_a1_a0 = _mm_loadu_si128((__m128i*)&array[i]); //Load 4 int32 elements from array.
a3_a2_a1_a0 = _mm_abs_epi32(a3_a2_a1_a0); //Set absolute of 4 int32 elements in single instruction.
_mm_storeu_si128((__m128i*)(&array[i]), a3_a2_a1_a0); //Store 4 int32 elements of array.
}
#elif _OPT4
for(i = 0; i < ncount; i++)
{
array[i] = abs(array[i]); // abs() is actually an intrinsic on gcc and msvc
}
#else
for(i = 0; i < ncount; i++)
{
if(array[i] < 0)
{
array[i] = -array[i];
}
}
#endif
clock_gettime(CLOCK_MONOTONIC, &tsend);
printf("start: %ld.%09ld\n", tsstart.tv_sec, tsstart.tv_nsec);
printf("end: %ld.%09ld\n", tsend.tv_sec, tsend.tv_nsec);
tsend.tv_sec -= tsstart.tv_sec;
tsend.tv_nsec -= tsstart.tv_nsec;
if(tsend.tv_nsec < 0)
{
tsend.tv_sec--;
tsend.tv_nsec = 1000000000 + tsend.tv_nsec;
}
printf("diff: %ld.%09ld\n", tsend.tv_sec, tsend.tv_nsec);
free(array);
return 0;
}
// Implimentation One (No Optimizations)
$ gcc -O3 -march=native test.c
$ ./a.out
start: 9221396.418007954
end: 9221398.103490309
diff: 1.685482355
// Implimentation One Non Random Distrubution
$ gcc -D_DIST -O3 -march=native test.c
$ ./a.out
start: 9221515.889463124
end: 9221516.255742919
diff: 0.366279795
// Implementation Two (Branchless)
$ gcc -D_OPT1 -O3 -march=native test.c
$ ./a.out
start: 9221472.539690988
end: 9221472.787347636
diff: 0.247656648
// Implementation Three (Branchless Decrement)
$ gcc -D_OPT2 -O3 -march=native test.c
$ ./a.out
start: 9221930.068693139
end: 9221930.334575475
diff: 0.265882336
// Rotem's Implementation (SIMD)
$ gcc -D_OPT3 -O3 -march=native test.c
$ ./a.out
start: 9222076.001094679
end: 9222076.230432423
diff: 0.229337744
// Inuitive abs() Implementation
$ gcc -D_OPT4 -O3 -march=native test.c
$ ./a.out
start: 9222112.523690484
end: 9222112.754820240
diff: 0.231129756
// Inuitive abs() Implementation Without native
$ gcc -D_OPT4 -O3 test.c
$ ./a.out
start: 9223301.744006196
end: 9223301.974097927
diff: 0.230091731
gcc -O3
之类的编译器优化时,诸如更改for循环计数方式之类的微优化绝对无效。编译器最终生成程序集,该程序集对数组指针进行指针比较以测试我们是否到达末尾。
gcc -O3
运行时,优化Rotem提供的SSE代码也没有什么区别,因为它可以在16字节边界上正确对齐内存,从而消除了
_mm_loadu_si128()
/
_mm_storeu_si128()
的必要性。
abs()
功能的实现。事实证明,在gcc上
abs()
,而MSVC实际上是编译器固有的。我仅使用
gcc -O3
优化来重做所有测试结果。
abs()
实现是最快的,其次是两个XOR实现,最后是分支实现。
abs()
实现实际上都依赖于
PABSD
指令,并且都具有包含7条指令的循环。速度上的细微差异(SIMD稍快一些)来自以下事实:优化的SIMD实现假定内存将始终包含4个整数(128位)的倍数,而
abs()
实现需要额外的指令来测试内存的情况不包含4个整数的倍数。
abs()
,就可以通过调用C库函数的简单性实现几乎与SIMD相同的速度。不使用
abs()
的
-march=native
循环仅延长4条指令,而不使用
PABSD
,而是使用
PSRAD
,
PXOR
和
PSUBD
指令。
abs()
比XOR实现快?
abs()
程序集几乎与XOR实现的程序集完全相同。
abs()
:
psrad $31, %xmm0
pxor %xmm0, %xmm1
psubd %xmm0, %xmm1
psrad $31, %xmm1
movdqa %xmm1, %xmm2
pxor %xmm1, %xmm0
pand %xmm3, %xmm2
paddd %xmm2, %xmm0
abs()
:
int ntemp = array[i] >> 31;
array[i] ^= ntemp;
array[i] -= ntemp;
uint32_t ntemp = array[i] >> 31;
array[i] ^= ntemp;
array[i] += ntemp & 1;
abs()
! :D
关于c - 有效地获取C中整数 vector 的绝对值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38388689/
我正在尝试解决一个问题: 编写一个程序计算非负整数之间的差值。 输入: 输入的每一行都由一对整数组成。每个整数都在 0 到 10 之间提高到 15(含)。输入在文件末尾终止。 输出: 对于输入中的每一
我有一个这样的数据框: Current Dataframe: ID Price Price_List 0 Prodt1 1500 [-5.2, -4.6, -3.3,
很难解释...让我试试: 我构建了一个脚本来比较两个用户的兴趣(爱好) 假设用户 A 有 44 种爱好,并且与用户 B(有 19 种爱好)有 13 种共同爱好所以在伪代码中(其中 % 是我的公式):
我在 LINQ 查询中使用 EntityFunctions 类: var a = dbContext.Where(x=>EntityFunctions.DiffMinutes(dateA,dateB)
我正在做一项作业,我应该返回 3 个值中最小的一个(绝对值,如程序所述)。当只需要返回 2 个值时,它工作得很好,但是当我添加第三个值时,它开始在方法内的 Math.min 处显示“找不到符号”。 :
我写了一个名为 absD 的函数,我想返回它的参数的绝对值..我在 cygwin 中使用 GCC 内联汇编.. 我不明白为什么它不起作用。我正在加载到内存中。然后进入 st(0)我在哪里使用 fabs
以原始形式。 svm 中很少有 alpha 值为正,相应的 x 将是支持向量,如图所示 http://en.wikipedia.org/wiki/Support_vector_machine . 如果
我对 xcode 中 ABS(A) 和 abs(int) 这两者的区别感到困惑。似乎也无法在网上找到任何解释。我应该使用哪个?我实际上正在研究加速度计。使用 ABS(A) 和 abs(int) 给了我
我一直在努力尝试理解 pandas 时间戳和时间增量。我喜欢你使用它们的方式,但在尝试减法时我发现这有点奇怪: now = pd.Timestamp('now') then = now - pd.to
假设我有一个对称矩阵 M,它不是正(半)定的,我想计算它的 k 顶(绝对值)特征值(和相应的特征向量)。现在,可以使用截断的 SVD 来做到这一点,它将返回所述特征值的绝对值,然后必须检查符号并找到相
问题很简单。我需要一行命令,例如, Math.round((-Math.random() * 2)) , 输出 只是显示 1 和 -1 .我试图弄清楚,但这似乎不是一件容易的事!我可以使用 IF 命令
我有一个看起来像这样的表: Country | Item | Col1 | Col2 | Col3 | Col4 4 | 4 | .152 | .01 | .65 | 1
我是 Laravel 框架的新手,我正在寻找如何编写查询以获得绝对值(简而言之,忽略 + 和 - 符号,只显示数据库中的数字。我知道我们可以使用 Abs 来获得它。但我不知道该怎么做。看看我的代码:
Working jsfiddle 对 jQuery/javacript 来说还是个新手,但我有 2 个函数,它们在检查时对隐藏值求和,并且我需要生成它们差异的绝对值: $(document).read
我有这个数据框和代码。 from pandas import DataFrame import pandas as pd import numpy as np df = pd.DataFrame({'
我知道 - 过早的优化。 但是我有代码可以查明某个位置是否发生了变化,而不是缓存的位置。 当前代码是: if(abs(newpos-oldpos) > 1){ ..... } 使用下面的是不是
This question它的答案描述了为什么 i32 上的 abs() 返回 i32 而不是 u32。它说“似乎公认的解决方法是使用 as u32 进行转换”。但是,如果参数是 std::i32::
我是一名优秀的程序员,十分优秀!