GCC自带位运算系列函数

谈到GCC的黑科技,大家想到的一定是这句:

#pragma GCC optimize (3)//吸氧

抑或是这句:

#pragma GCC diagnostic error "-std=c++11"//C++11

然而又有多少人知道__builtin_xxx()这群神奇的存在?

举个栗子:树状数组的核心思想就是一个叫做lowbit()的函数,它是这样写的:

inline int lowbit(const int &x)
{
    return x & -x;
}

什么,你说长?你嫌慢?

#define lowbit(x) ((x) & -(x))

什么,你还是不想自己写?非得用内置函数?

那么恭喜你,这是你新的出路:

lowbit(x) == (1 << __builtin_ctz(x))

当然,对于lowbit()函数,大家看不到什么好处(喜欢这样用的才有问题吧(-_-))

再举一个栗子:P2704, 一道状压DP入门题目,它要求输出:

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

那么,DP的时候,对于每一行的状态,若它在二进制下的第i位以0表示不放,以1表示放的话,我们就得统计它二进制下1的个数,于是考虑用一个inline的函数count()来统计:

inline int count(int x)//摘自本人AC代码
{
    int ret = 0;
    while(x)
    {
        ret += x & 1;
        x >>= 1;
    }
    return ret;
}

统计一下,这里一共有135字节的内容。

使用它的代码长这样:sum[tot] = count(i);,改一下,变成这样:sum[tot] = __builtin_popcount(i);

有人又要钻牛角尖:就算你把函数定义的码量给省了,但是你每次调用函数都会增加strlen("__builtin_pop") == 13字节的码量啊?

那还不简单define下就好了

除了上述函数,本人另外还整理了一部分用得到的__builtin_系列函数:

  • __builtin_ffs(x) 返回x的二进制下第一位1的位置(从1开始)
  • __builtin_clz(x) 返回x二进制下最高有效位到最高位的1上一位的长度(即最高位开始连续0的个数)
  • __builtin_ctz(x) 与上一个函数相反,返回x的二进制下最低位开始连续0的个数(即第一个函数 - 1)
  • __builtin_parity(x) 返回x二进制下1的个数的奇偶性
  • __builtin_popcount(x) 返回x二进制下1的个数

另外以上函数的唯一参数都为unsigned int类型,并且都有unsigned long long版本,即在函数名后面加上ll,Like __builtin_popcountll(x)

对于其他的__builtin_系列函数,可以自行查阅GNU C所提供的文档

又双叒叕及:感谢@ComeIntoPower 管理员大大普及:可以在程序开头加入这样一行:

#pragma GCC target ("popcnt")

根据大大的说法,这条GCC指令可以让__builtin_popcount被编译器识别为一条指令。

什么用呢?就是加速!时 间 减 半!它本身就够快了,还可以加速%%%,鄙人真是孤陋寡闻。

注意:有些计算机可能不支持popcnt指令,然后GCC就会GG。(大部分计算机都有)

还有一点注意,有一种说法是NOI系列赛事中禁止使用以下划线开头的函数,因此在NOI系列比赛中使用有风险,这只是给平时做题提供一些便利



此外,既然是黑科技自然有地方不给用,我已经测试了各大OJ对于该系列函数的支持情况:(务必选用G++/GCC作为编译器)

  • 洛谷: OJBK
  • Poj: OJBK
  • Lydsy: OJBK
  • Hdu: A+B 莫名WA,但是编译应该OJBK
  • CodeVS: OJBK
  • Vijos: OJBK
  • Uoj: OJBK
  • Codeforces: OJBK
  • JoyOI: 评测机炸了,待更新
  • ContestHunter: OJBK
  • Zoj: 编译过了,也是莫名WA
  • SPOJ: OJBK
  • UVa: OJBK
  • AtCoder: OJBK
  • LibreOJ: OJBK
  • 比赛: 这个请问官方
  • ...待补充

原文地址:https://www.cnblogs.com/alpha1022/p/9692116.html

时间: 2024-10-19 14:09:05

GCC自带位运算系列函数的相关文章

位运算总结&amp;拾遗

JavaScript 位运算总结&拾遗 最近补充了一些位运算的知识,深感位运算的博大精深,此文作为这个系列的总结篇,在此回顾下所学的位运算知识和应用,同时也补充下前文中没有提到的一些位运算知识. 把一个数变为大于等于该数的最小的2的幂 一个数为2的幂,那么该数的二进制码只有最高位是1. 根据这个性质,我们来举个栗子,比如有数字10,转为二进制码后为: 1 0 1 0 我们只需把 0 bit的位置全部用1填充,然后再把该二进制码加1就ok了.而x | (x + 1)正好可以把最右边的0置为1,可是

2015.8.5 循环与函数、位运算

注意点: 1.只有整形才可以用switch. 2.case后面的常量不可以重复 3.default语句可以放在任意位置,但是后面不可以省略break: while: 1.用来处理一些重复执行的操作 2.确定循环终止的条件 (1)在循环开始之前,需要定义一个循环控制变量并将其初始 (2)确定循环的约束条件 (3)在每一次循环结束的时候,在循环中,要去改变循环控制变量的值,让它不间断接近约束条件 注意点: 1.在c语言总任何树枝都有真假性,只有0为 假,其它都为真 2.注意不把==和=混淆了,为了避

位运算+引用+const+new/delete+内联函数、函数重载、函数缺省参数

一.位运算 应用: 1.判断某一位是否为1 2.只改变其中某一位,而保持其它位都不变 位运算操作: 1.& 按位与(双目): 将某变量中的某些位清0(与0位与)且同时保留其它位不变(与1位与):获取某变量中某一位(与其位与后判断是否为该数) 2.|  按位或(双目): 将某变量中的某些位置1(与1位或)且保留其它位不变 3.^  按位异或(双目): 将某变量中的某些位取反(与1异或)且保留其它位不变 异或运算特点: 如果 a^b=c,那么就有 c^b = a以及c^a=b.(穷举法可证---用于

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

【老刘谈算法001】这位运算玩的真溜—strlen函数的汇编实现分析

首先挂下代码, ;原函数作者为不知名老外,出处为MASM32开发包,在此表示感谢. ;中文注释修改&添加 By 老刘. .486 .model flat, stdcall option casemap :none .code OPTION PROLOGUE:NONE OPTION EPILOGUE:NONE align 4 StrLen proc item:DWORD mov eax, [esp+4] ;获得参数item,即字符串指针 lea edx, [eax+3] ;edx=指针+3 pus

位运算 使用技巧

位运算简介及实用技巧(一):基础篇 什么是位运算? 程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算说穿了,就是直接对整数在内存中的二进制位进行操作.比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算.举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理): 110 AND 1011 ---------- 0010  -->  2 由于位运算

64位gcc编译32位汇编

由于使用as和ld来编译链接汇编程序,在使用C库的时候比较麻烦,需要输入比较多的指令,所以使用gcc进行编译链接.由于书中内容是32位汇编程序,但是机器使用的是64位操作系统,自带的gcc也是64位的,导致编译生成的程序,一运行就会Segment Fault.经过查询之后,发现是调用printf函数的时候,总是报错,查询之后发现是32位汇编和64位汇编在调用C库的时候,32位使用pushl指令来压栈传递参数,而64位汇编是使用通用寄存器来传递参数的. 32汇编的代码是: 1 .code32 2

exec系列函数(execl,execlp,execle,execv,execvp)使用

本节目标: exec替换进程映像 exec关联函数组(execl.execlp.execle.execv.execvp) 一,exec替换进程映像 在进程的创建上Unix采用了一个独特的方法,它将进程创建与加载一个新进程映象分离.这样的好处是有更多的余地对两种操作进行管理. 当我们创建了一个进程之后,通常将子进程替换成新的进程映象,这可以用exec系列的函数来进行.当然,exec系列的函数也可以将当前进程替换掉. 例如:在shell命令行执行ps命令,实际上是shell进程调用fork复制一个新

linux tricks 之VA系列函数.

VA函数(variable argument function),参数个数可变函数,又称可变参数函数.C/C++编程中,系统提供给编程人员的va函数很少.*printf()/*scanf()系列函数,用于输入输出时格式化字符串:exec*()系列函数,用于在程序中执行外部文件(main(int argc, char* argv[]算不算呢,与其说main()也是一个可变参数函数,倒不如说它是exec*()经过封装后的具备特殊功能和意义的函数,至少在原理这一级上有很多相似之处).由于参数个数的不确