快读快写

源码

此处展示的是 2.5 版本源码:

#ifdef __linux__
#define gc getchar_unlocked
#define pc putchar_unlocked
#else
#define gc _getchar_nolock
#define pc _putchar_nolock
#endif
inline bool blank(const char x) {return !(x^32)||!(x^10)||!(x^13)||!(x^9);}
template<typename Tp> inline void read(Tp &x) {x=0; register bool z=true; register char a=gc(); for(;!isdigit(a);a=gc()) if(a=='-') z=false; for(;isdigit(a);a=gc()) x=(x<<1)+(x<<3)+(a^48); x=(z?x:~x+1);}
inline void read(double &x) {x=0.0; register bool z=true; register double y=0.1; register char a=gc(); for(;!isdigit(a);a=gc()) if(a=='-') z=false; for(;isdigit(a);a=gc()) x=x*10+(a^48); if(a!='.') return x=z?x:-x,void(); for(a=gc();isdigit(a);a=gc(),y/=10) x+=y*(a^48); x=(z?x:-x);}
inline void read(char &x) {for(x=gc();blank(x)&&(x^-1);x=gc());}
inline void read(char *x) {register char a=gc(); for(;blank(a)&&(a^-1);a=gc()); for(;!blank(a)&&(a^-1);a=gc()) *x++=a; *x=0;}
inline void read(string &x) {x=""; register char a=gc(); for(;blank(a)&&(a^-1);a=gc()); for(;!blank(a)&&(a^-1);a=gc()) x+=a;}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y) {read(x),read(y...);}
template<typename Tp> inline void write(Tp x) {if(!x) return pc(48),void(); if(x<0) pc('-'),x=~x+1; register int len=0; register char tmp[64]; for(;x;x/=10) tmp[++len]=x%10+48; while(len) pc(tmp[len--]);}
inline void write(const double x) {register int a=6; register double b=x,c=b; if(b<0) pc('-'),b=-b,c=-c; register double y=5*powl(10,-a-1); b+=y,c+=y; register int len=0; register char tmp[64]; if(b<1) pc(48); else for(;b>=1;b/=10) tmp[++len]=floor(b)-floor(b/10)*10+48; while(len) pc(tmp[len--]); pc('.'); for(c*=10;a;a--,c*=10) pc(floor(c)-floor(c/10)*10+48);}
inline void write(const pair<int,double>x) {register int a=x.first; if(a<7) {register double b=x.second,c=b; if(b<0) pc('-'),b=-b,c=-c; register double y=5*powl(10,-a-1); b+=y,c+=y; register int len=0; register char tmp[64]; if(b<1) pc(48); else for(;b>=1;b/=10) tmp[++len]=floor(b)-floor(b/10)*10+48; while(len) pc(tmp[len--]); a&&(pc('.')); for(c*=10;a;a--,c*=10) pc(floor(c)-floor(c/10)*10+48);} else cout<<fixed<<setprecision(a)<<x.second;}
inline void write(const char x) {pc(x);}
inline void write(const bool x) {pc(x?49:48);}
inline void write(char *x) {fputs(x,stdout);}
inline void write(const char *x) {fputs(x,stdout);}
inline void write(const string &x) {fputs(x.c_str(),stdout);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y) {write(x),write(y...);}

代码长度 \(2.5k\),如果您不想让自己的代码开局上百行的话建议保持这种每个函数压成一行的形式。

写在前面

  • 如果您希望更加舒适无误的使用此快读快写,请仔细阅读如下内容。

  • 有更加简洁的 1.0 版本,但是只支持对于整形的输入输出,读入效率与 2.5 版本完全相同,输出效率略低于 2.5 版本,详见 一些工具

  • 2.5 版本的存在意义在于在保证了相对较高的效率同时更加方便使用,以避免了需要输出非整形时还需要使用其他读写方式从而降低了效率且不方便使用的问题,而非最求最快,所以在极端卡常环境下作用可能没有一些“超级快读”显著。

  • 绝大多数函数基于 getchar_unlockedputchar_unlocked 实现,没有采用 freadfwrite 的原因是不想让输入输出占用格外的空间,所以效率方面有一定的保证但难以达到最快。

    上述仅针对于 linux 环境,对于 windows 环境则基于 _getchar_nolock_putchar_nolock,此函数与 getchar_unlockedputchar_unlocked 类似,效率均高于 getcharputchar

    不管什么评测环境,请勿将其和解绑 cincout 同时使用,原因可自行上网查询。

    同时,对于每一个函数,请保证您的传参是合法的,否则出现死循环等问题一概不负责。

  • 对于 double 的输出是存在精度误差的,但是在保留小数点后 \(6\) 位及以内的数据正确率约为 \(100\%\),但是在 \(7\) 位及以上时,即使使用 printf 也会存在精度问题,但为了避免不必要的麻烦,对于 \(7\) 位及以上的,我使用了 cout<<fixed<<setprecision(a)<<b\(a\) 为保留位数,\(b\) 为输出的数,这个 cout 是没法解绑的,但是效率没有比解绑的低太多,所以当其出现精度问题时并不是快写的问题。

  • 如果将浮点数输入到一个整形或 bool 类型的变量中,使用 cin 会自动将其向零取整作为结果,使用 scanf 后果比较严重,此快读为了保证效率,在该方面不支持类似自动取整的功能且可能出现输入结果异常的问题,如有该方面需要请先输入为 double 类型再转为整形。

  • 经过调试,目前应该没有大的问题,若存在问题请及时指出,我会尽快改正,后续可能要优化代码所以可能会更新版本。

功能介绍

  • 支持对于整形的输入,您可以使用 read(x) 读入一个整形 \(x\),效率保证通过 P10815【模板】快速读入

  • 支持对于 double 的输入,不支持对于 float 的输入,您可以使用 read(x) 输入一个 double 类型的 \(x\),效率与对整形输入类似。

  • 支持对于 bool 的输入,您可以使用 read(x) 输入一个整形 \(x\),若您输入的 \(x\) 为合法的整形,其将自动识别为 bool 类型,若为 \(0\)\(-0\) 则识别为 false,否则为 true,效率与对整形输入效率类似。

  • 支持对于字符的输入,自动过滤空格与换行,您可以使用 read(x) 读入一个字符 \(x\),如果您想读入一个空格或换行请使用 gatchar 等自带函数。

  • 支持对于字符串的输入,包括一维 char 数组(char*)和 string,您可以使用 read(x) 输入一个字符串 \(x\)

    效率方面,基于 \(O(len)\) 次的 getchar_unlocked,约为 scanf\(2\) 倍,约为不解绑 cin\(10\) 倍,但只有解绑 cin\(\dfrac{1}{2}\),目前没有想到更好的解决方案,欢迎大家指出。同时不管什么读入方式对于字符串的输入效率都是极高的,不必担心输入字符串被卡常,实测 \(10^9\) 个字符的量只需要 \(0.5s\) 左右。

  • 支持多个类型同时输入,具体的,您可以使用 read(a,b,c,...) 依次进行 \(a,b,c\) 等若干个任意类型的输入。

    特殊的,对于一个 char* 类型的 \(s\),您可以正常的将 \(s\) 传入该函数,但不支持将其类似与 \(s+1\) 的类型传入上述函数,因为我对于输入类型均进行了取地址,而 \(s+1\) 本身就是一个地址,不能够重复两次取地址,存在解决方案但是并不优美,因为我并不想在每个变量前都手动加一个取地址,所以在不影响其他类型输入的手感的前提下,请单独使用 read(s+1)

  • 支持对于整形的输出,您可以使用 write(x) 输出一个整形 \(x\),相对于 1.0 版本的提升在于将其从递归改为递推,从而提高了效率,效率高于解绑的 cout

  • 支持对于 double 的输出,不支持对于 float 的输出。

    • 您可以使用 write(x) 输出一个保留小数点后 \(6\) 位的 double 类型的 \(x\)

    • 您可以使用 write(make_pair(a,b)) 输出一个保留小数点后 \(a\) 位的 double 类型的 \(b\),推荐将 definemake_pair 以避免过于麻烦。

    • 如果您想输出小数点后不是保留 \(6\) 位的浮点数,可以使用上述的第二种方案;或者将源码中将 void write(double x) 函数中 \(a\) 的值进行修改,如果整个程序需要输出的浮点数保留位数均相同,推荐使用后者从而更加方便和效率。

    效率方面,因为 double 不可以进行取模运算,所以采用了 floor 以实现 \(\bmod 10\) 的效果,所以效率不如整形的输出,这是无法避免的,但是效率依然高于 printf 和解绑的 cout

    精度问题已在前面阐述。

  • 支持对于 bool 的输出,您可以使用 write(x) 输出一个 bool 类型的 \(x\),若 \(x=true\) 输出 1,若 \(x=false\) 输出 0

  • 支持对于字符的输出,您可以使用 write(x) 输出一个字符 \(x\),本质就是把 \(x\) 直接 putchar_unlocked 出去。

  • 支持对于字符串的输出,包括一维 char 数组(char*)和 string,您可以使用 write(x) 输出一个字符串 \(x\)

    此函数不基于 getchar_unlocked 而是基于 fputs,因为对于一个一个字符的输出效率是严格低于整个输出的,使用 fputs 的效率极高,和解绑的 cout 几乎相同。

    也正因为使用了 fputs,若您想要输出的是一个 char*,请保证其末尾字符为 \0,此处输出的字符串中可以有空格等特殊字符。

    另外,我对字符串的输出进行了取地址操作,不会占用格外的空间。

  • 支持对于 const char*const string 的输出,您可以使用 write(x) 输出一个上述类型的 \(x\)

    例如,您可以使用 write("Charlie") 输出一个 Charlie,此处的 Charlieconst char* 类型。

    效率与实现方面与对 char*string 的输出相同。

  • 支持多个类型同时输出,具体的,您可以使用 write(a,b,c,...) 依次进行 \(a,b,c\) 等若干个任意类型的输出。

    此函数不存在取地址问题,可以放心使用。

  • 原则上可以还可以加入输入一整行包括空格字符串、输入一整个数组等其他功能,但我认为那是没有什么意义的,例如若有输入一整行字符串的要求,请自行使用 fgets 等函数。

更新说明

  • 2.1 版本,增加了对于 const char*const string 的输出,经过测试发现 2.0 版本不支持类似 write("Charlie") 的操作,因为此处的 Charlieconst char* 类型,同时发现对于 const string 有着同样的问题,现已修复,对于其余类型的变量没有此类问题。

    ——更新时间:2025年01月11日。

  • 2.2 版本,通过 define 解决了不兼容 windows 的问题。

    ——更新时间:2025年01月23日。

  • 2.4 版本,感谢 @LionBlaze、@yangfengzhao 等人的提醒,共做出了以下五点修改:

    • 对于 windows 环境下采用了更快速的 _getchar_nolock_putchar_nolock,解决了在 windows 环境下效率低下的问题。

    • 对于大多数输出函数的参数添加了 const,更加符合规范并提高安全性。

    • 修复了对于 charchar*string 类型的输入无法识别 \t 的问题。

    • 对于 char* 的输入进行了一些效率方面的优化,小幅度提升效率,但尚未解决无法与其他类型同时传入的问题。

    • 进行了一些写法上的优化,去除部分冗余函数,减少代码长度。

    因为在同一天进行了多次修改,故跳过 2.3 进入 2.4 版本。

    ——更新时间:2025年02月05日。

  • 2.5 版本,共做出以下三点修改:

    • 修复了对于有前导零情况下 bool 输入结果异常的问题,并发现针对 bool 的输入函数是没有意义的,现对于 bool 的输入和整形共用一个函数,正常使用时返回值正常。

    • 去除对于 double 的输出函数中的冗余部分,提高了效率,简短了代码长度。

    • 在「写在前面」中更新了有关将浮点数输入到整形或 bool 类型的变量中可能出现的问题,请仔细观看

    ——更新时间:2025年02月10日。

posted @ 2025-01-10 10:24  卡布叻_周深  阅读(121)  评论(9)    收藏  举报