我正在阅读K&R的"The C Programming Language"并且发现了这个声明[Introduction,p.3]:
由于大多数计算机都直接支持C提供的数据类型和控制结构,因此实现自包含程序所需的运行时库很小.
粗体陈述是什么意思?是否存在计算机不直接支持的数据类型或控制结构的示例?
左右移位运算符(<<和>>)已在C++中可用.但是,我无法找到如何执行循环移位或旋转操作.
如何执行"向左旋转"和"向右旋转"等操作?
在这里向右旋转两次
Initial --> 1000 0011 0100 0010
Run Code Online (Sandbox Code Playgroud)
应该导致:
Final --> 1010 0000 1101 0000
Run Code Online (Sandbox Code Playgroud)
一个例子会有所帮助.
(编者注:如果旋转计数为零,许多常见的表达方式在C中旋转会受到未定义的行为的影响,或者编译为不止一个旋转机器指令.这个问题的答案应记录最佳实践.)
有汇编指令ADC.我发现这意味着"随身携带".但我不知道这意味着什么.或者如何用C++编写这个指令.我知道它不一样ADD.所以做一个简单的求和是不正确的.
信息:
在Windows中编译.我正在使用32位Windows安装.我的处理器是Intel的Core 2 Duo.
GCC具有128位整数.使用这些我可以让编译器使用mul(或imul只有一个操作数)指令.例如
uint64_t x,y;
unsigned __int128 z = (unsigned __int128)x*y;
Run Code Online (Sandbox Code Playgroud)
生产mul.我用它来创建一个128x128到256的函数(在更新之前,请参阅此问题的结尾,如果您感兴趣,请参阅此代码).
现在我想要进行256位加法,ADC除了使用汇编之外,我还没有找到让编译器使用的方法.我可以使用汇编程序,但我想要内联函数以提高效率.编译器已经生成了一个有效的128x128到256函数(因为我在这个问题的开头解释了)所以我不明白为什么我应该在汇编中重写它(或者编译器已经有效实现的任何其他函数) .
这是我提出的内联汇编函数:
#define ADD256(X1, X2, X3, X4, Y1, Y2, Y3, Y4) \
__asm__ __volatile__ ( \
"addq %[v1], %[u1] \n" \
"adcq %[v2], %[u2] \n" \
"adcq %[v3], %[u3] \n" \
"adcq %[v4], %[u4] \n" \
: [u1] "+&r" (X1), [u2] "+&r" (X2), [u3] "+&r" (X3), [u4] "+&r" (X4) \
: [v1] "r" (Y1), [v2] "r" (Y2), [v3] "r" (Y3), [v4] …Run Code Online (Sandbox Code Playgroud) 我的问题是关于试验部门的条件测试.关于采用什么条件测试似乎存在争议.我们来看看RosettaCode的代码 .
int is_prime(unsigned int n)
{
unsigned int p;
if (!(n & 1) || n < 2 ) return n == 2;
/* comparing p*p <= n can overflow */
for (p = 3; p <= n/p; p += 2)
if (!(n % p)) return 0;
return 1;
}
Run Code Online (Sandbox Code Playgroud)
车轮分解或使用预定的素数列表不会改变我的问题的本质.
我可以想到三种情况来进行条件测试:
案例1:适用于所有n但它必须在每次迭代时进行额外的除法(编辑:实际上它不需要额外的除法但它仍然较慢.我不知道为什么.请参阅下面的汇编输出).我发现它的速度是情况2的两倍,因为大的n值是素数(在我的Sandy Bridge系统上).
案例2:明显快于案例1,但它有一个问题,它溢出大n并进入一个不定式循环.它可以处理的最大值是
(sqrt(n) …Run Code Online (Sandbox Code Playgroud) 因为似乎没有ADC的固有内容而且我不能使用Visual C++的x64架构使用内联汇编程序,如果我想使用add with carry编写函数但是将它包含在C++命名空间中,我该怎么办?
(使用比较运算符进行仿真不是一种选择.这256兆位的添加对性能至关重要.)
MSVC和ICC都支持内在函数_addcarry_u64和_addcarryx_u64.
根据英特尔的内在指南和白皮书,这些应分别映射到adcx和adox.但是,通过查看生成的程序集,很明显它们分别映射到adc并且adcx没有映射到的内在函数adox.
另外,告诉编译器
我不确定如何使用MSVC和ICC启用ADX./arch:AVX2在MSVC中启用AVX2 或-march=core-avx2在Linux上启用ICC没有任何区别.
MSVC的文档列出_addcarryx_u64了ADX技术,_addcarry_u64但没有列出的技术.但是,MSVC针对这些内在函数的文档中的链接直接指向Intel Intrinsic指南,该指南与MSVC自己的文档和生成的程序集相矛盾.
由此我得出结论,英特尔的内在指南和白皮书是错误的.
这对于MSVC感觉有一定意义,它不允许内联汇编它应该提供一种使用adc它的方式_addcarry_u64.
其中的一大优点adcx,并adox为他们在不同的标志(进操作CF和溢出OF),这使得两个独立平行进位链.但是,由于没有内在的adox可能性如何?对于ICC,至少有一个可以使用内联汇编,但在64位模式下使用MSVC是不可能的.
微软和英特尔的文档(白皮书和在线内在指南)都同意了.
该_addcarry_u64征的文件说只生产adc.该_addcarryx_u64征可以产生两种adcx或adox.然而,在MSVC 2013和2015中,_addcarryx_u64只生产adcx.ICC同时生产.
几年前,我需要一种方法来使用 Cuda 进行一些基本的 128 位整数数学运算: cuda 上的 128 位整数?. 现在我遇到了同样的问题,但这次我需要在不支持任何类型的 128 位的 32 位嵌入式系统(英特尔爱迪生)上运行一些基本的 128 位算术(求和、位移和乘法)。但是,有直接支持的 64 位整数(unsigned long long int)。
我天真地尝试使用上次在CPU上回答我的asm代码,但是我得到了一堆错误。我真的没有使用 asm 的经验,所以:使用 64 位整数实现 128 位加法、乘法和位移的最有效方法是什么?
是否存在ARM C编译器的内在函数来执行随身携带操作,或者是否需要使用汇编语言?
在x86上,有_addcarry_u64for-carry-carry.(_addcarryx_u64特殊目的还有更新的.)