百科问答小站 logo
百科问答小站 font logo



最快的 atoi、atof 实现是什么样的? 第1页

  

user avatar   jing-wei-zhang-huai-39 网友的相关建议: 
      

曾经在写解析json的时候,写过一个字符串转数字,看到这个问题后,把这部分代码摘出来,放到C语言基础库Morn里面,测试了一下,比标准库要快,但是不敢说最快。

简单说就是:尽量不算,尽量查表。

源代码比较简单,放在这里了:

       static int morn_atoi[9][10]={     {0,100000000,200000000,300000000,400000000,500000000,600000000,700000000,800000000,900000000},     {0, 10000000, 20000000, 30000000, 40000000, 50000000, 60000000, 70000000, 80000000, 90000000},     {0,  1000000,  2000000,  3000000,  4000000,  5000000,  6000000,  7000000,  8000000,  9000000},     {0,   100000,   200000,   300000,   400000,   500000,   600000,   700000,   800000,   900000},     {0,    10000,    20000,    30000,    40000,    50000,    60000,    70000,    80000,    90000},     {0,     1000,     2000,     3000,     4000,     5000,     6000,     7000,     8000,     9000},     {0,      100,      200,      300,      400,      500,      600,      700,      800,      900},     {0,       10,       20,       30,       40,       50,       60,       70,       80,       90},     {0,        1,        2,        3,        4,        5,        6,        7,        8,        9} };  int mAtoi(char *str) {     int flag=0;unsigned char *s=(unsigned char *)str;          if(*str=='-') {flag=1;s++;}     else if(*str=='+')         s++;     int data=morn_atoi[0][s[0]-'0'];if((s[1]<'0')||(s[1]>'9')) {data=data/100000000;return (flag)?(0-data):data;}     data +=  morn_atoi[1][s[1]-'0'];if((s[2]<'0')||(s[2]>'9')) {data=data/10000000; return (flag)?(0-data):data;}     data +=  morn_atoi[2][s[2]-'0'];if((s[3]<'0')||(s[3]>'9')) {data=data/1000000;  return (flag)?(0-data):data;}     data +=  morn_atoi[3][s[3]-'0'];if((s[4]<'0')||(s[4]>'9')) {data=data/100000;   return (flag)?(0-data):data;}     data +=  morn_atoi[4][s[4]-'0'];if((s[5]<'0')||(s[5]>'9')) {data=data/10000;    return (flag)?(0-data):data;}     data +=  morn_atoi[5][s[5]-'0'];if((s[6]<'0')||(s[6]>'9')) {data=data/1000;     return (flag)?(0-data):data;}     data +=  morn_atoi[6][s[6]-'0'];if((s[7]<'0')||(s[7]>'9')) {data=data/100;      return (flag)?(0-data):data;}     data +=  morn_atoi[7][s[7]-'0'];if((s[8]<'0')||(s[8]>'9')) {data=data/10;       return (flag)?(0-data):data;}     data +=               s[8]-'0' ;if((s[9]<'0')||(s[9]>'9')) {                    return (flag)?(0-data):data;}     data=data*10+s[9]-'0';return (flag)?(0-data):data; }  static double morn_atof[17][10]={     {0.0,0.1000000000000000,0.2000000000000000,0.3000000000000000,0.4000000000000000,0.5000000000000000,0.6000000000000000,0.7000000000000000,0.8000000000000000,0.9000000000000000},     {0.0,0.0100000000000000,0.0200000000000000,0.0300000000000000,0.0400000000000000,0.0500000000000000,0.0600000000000000,0.0700000000000000,0.0800000000000000,0.0900000000000000},     {0.0,0.0010000000000000,0.0020000000000000,0.0030000000000000,0.0040000000000000,0.0050000000000000,0.0060000000000000,0.0070000000000000,0.0080000000000000,0.0090000000000000},     {0.0,0.0001000000000000,0.0002000000000000,0.0003000000000000,0.0004000000000000,0.0005000000000000,0.0006000000000000,0.0007000000000000,0.0008000000000000,0.0009000000000000},     {0.0,0.0000100000000000,0.0000200000000000,0.0000300000000000,0.0000400000000000,0.0000500000000000,0.0000600000000000,0.0000700000000000,0.0000800000000000,0.0000900000000000},     {0.0,0.0000010000000000,0.0000020000000000,0.0000030000000000,0.0000040000000000,0.0000050000000000,0.0000060000000000,0.0000070000000000,0.0000080000000000,0.0000090000000000},     {0.0,0.0000001000000000,0.0000002000000000,0.0000003000000000,0.0000004000000000,0.0000005000000000,0.0000006000000000,0.0000007000000000,0.0000008000000000,0.0000009000000000},     {0.0,0.0000000100000000,0.0000000200000000,0.0000000300000000,0.0000000400000000,0.0000000500000000,0.0000000600000000,0.0000000700000000,0.0000000800000000,0.0000000900000000},     {0.0,0.0000000010000000,0.0000000020000000,0.0000000030000000,0.0000000040000000,0.0000000050000000,0.0000000060000000,0.0000000070000000,0.0000000080000000,0.0000000090000000},     {0.0,0.0000000001000000,0.0000000002000000,0.0000000003000000,0.0000000004000000,0.0000000005000000,0.0000000006000000,0.0000000007000000,0.0000000008000000,0.0000000009000000},     {0.0,0.0000000000100000,0.0000000000200000,0.0000000000300000,0.0000000000400000,0.0000000000500000,0.0000000000600000,0.0000000000700000,0.0000000000800000,0.0000000000900000},     {0.0,0.0000000000010000,0.0000000000020000,0.0000000000030000,0.0000000000040000,0.0000000000050000,0.0000000000060000,0.0000000000070000,0.0000000000080000,0.0000000000090000},     {0.0,0.0000000000001000,0.0000000000002000,0.0000000000003000,0.0000000000004000,0.0000000000005000,0.0000000000006000,0.0000000000007000,0.0000000000008000,0.0000000000009000},     {0.0,0.0000000000000100,0.0000000000000200,0.0000000000000300,0.0000000000000400,0.0000000000000500,0.0000000000000600,0.0000000000000700,0.0000000000000800,0.0000000000000900},     {0.0,0.0000000000000010,0.0000000000000020,0.0000000000000030,0.0000000000000040,0.0000000000000050,0.0000000000000060,0.0000000000000070,0.0000000000000080,0.0000000000000090},     {0.0,0.0000000000000001,0.0000000000000002,0.0000000000000003,0.0000000000000004,0.0000000000000005,0.0000000000000006,0.0000000000000007,0.0000000000000008,0.0000000000000009},     {0.0,0.0000000000000000,0.0000000000000000,0.0000000000000000,0.0000000000000000,0.0000000000000000,0.0000000000000000,0.0000000000000000,0.0000000000000000,0.0000000000000000}, };  static double morn_atof_k[20]={1.0,0.1,0.01,0.001,0.0001,0.00001,0.000001,0.0000001,0.00000001,0.000000001,0.0000000001,0.00000000001,0.000000000001,0.0000000000001,0.00000000000001,0.000000000000001,0.0000000000000001,0.00000000000000001,0.000000000000000001,0.0000000000000000001}; double mAtof(char *p) {     int flag=0;double d=0;          if(*p=='-') {flag=1;p++;}     else if(*p=='+')         p++;     for(;(*p>='0')&&(*p<='9');p++) d=d*10.0+(*p-'0');     if(*p=='.')     {         p++;int i;double v=0;         for(i=0;i<20;i++) {if(p[i]!='0') break;} double k=morn_atof_k[i]; p=p+i;         for(i=0;(p[i]>='0')&&(p[i]<='9');i++) {v=v+morn_atof[MIN(i,16)][p[i]-'0'];} p=p+i;         d=v*k+d;     }     if((*p=='e')||(*p=='E'))     {         p++;         int f=0;if(*p=='-') {f=1;p++;} else if(*p=='+') {p++;}         int e=0;for(;(*p>='0')&&(*p<='9');p++) e=e*10+(*p-'0');         d=d*pow(10.0,((f==1)?(0-e):e));     }          return (flag)?(0-d):d; }     

做个测试:

       #include "morn_util.h"  #define N 10000 #define T 1000      void test_atoi() {     char str[N][16];     for(int i=0;i<N;i++)     {         int v=mRand();         sprintf(&str[i][0],"%d",v);     }     int sum=0;      mTimerBegin("atoi");     for(int t=0;t<T;t++)     {         sum=0;         for(int i=0;i<N;i++)             sum += atoi(&str[i][0]);     }     mTimerEnd("atoi");     printf("sum=%d
",sum);          mTimerBegin("mAtoi");     for(int t=0;t<T;t++)     {         sum=0;         for(int i=0;i<N;i++)             sum += mAtoi(&str[i][0]);     }     mTimerEnd("mAtoi");     printf("sum=%d
",sum); }  void test_atof() {     char str[N][16];     for(int i=0;i<N;i++)     {         double v=(double)mRand()/(double)mRand();         sprintf(&str[i][0],"%.16f",v);         str[i][15]=0;     }     double sum=0;      mTimerBegin("atof");     for(int t=0;t<T;t++)     {         sum=0;         for(int i=0;i<N;i++)             sum += atof(&str[i][0]);     }     mTimerEnd("atof");     printf("sum=%f
",sum);          mTimerBegin("mAtof");     for(int t=0;t<T;t++)     {         sum=0;         for(int i=0;i<N;i++)             sum+= mAtof(&str[i][0]);     }     mTimerEnd("mAtof");     printf("sum=%f
",sum); }  int main() {     test_atoi();     test_atof();     return 0; }     

以上,分别随机生成10000个整数和浮点数,转成字符串存放在二维数组里,然后分别使用Morn和标准库把字符串数字解出来。计时1000次(也即总共计时1000万次转换)。为了验证准确性,计算10000个数字的和,看看两个方法的结果是否一致。

测试的编译器、编译命令和结果如下:

可以看到:①两种库算得的结果一致,②atoi快大概5倍,③atof快大概18倍。




  

相关话题

  PRML为何是机器学习的经典书籍中的经典? 
  为什么很多新型编程语言都抛弃了 C 语言风格的 for 语句? 
  写C with class很丢人么? 
  如何看待软件工程师觉得学习算法没用? 
  左移40位为什么不能写成1<<40ll? 
  如何看待字节跳动算法工程师猝死,妻子怀孕两个月?当前情况如何? 
  如何看待 2021 年图灵奖授予美国计算机科学家 Jack J. Dongarra? 
  C++的CRTP所带来的静态多态功能具体有什么用? 
  C和C++的适用场合?如何创建C++实现的动态库?动态库如何保证向后兼容,即二进制兼容性? 
  二分查找有几种写法?它们的区别是什么? 

前一个讨论
为什么黄金几乎在所有文明里都是贵重金属,并且作为了货币?
下一个讨论
为何电脑HDMI接电视机效果没VGA舒服?





© 2024-12-26 - tinynew.org. All Rights Reserved.
© 2024-12-26 - tinynew.org. 保留所有权利