自 (我IRC) 286以来,BCD指令就没有在硬件中实现了,现在只是微码化的。它们不太可能特别高效.
AAM
等)甚至在64位模式下都不存在,这是不使用它们的另一个原因。 - Peter Cordeshttps://github.com/matiu2/yajp
您感兴趣的文件为:
https://github.com/matiu2/yajp/blob/master/tests/test_number.cpp
此外,您可能会对执行转换的状态机感兴趣:getchar
函数使速度变慢。[越过顶端:如果您知道数字字符线性存储在缓冲区中并且不跨越缓冲区边界,则可以避免ptr ++
的成本。 在树枝的第k个状态下,您可以将第k个字符访问为*(start+k)
。 一个好的编译器通常可以隐藏寻址模式中的“... + k”索引偏移量。]
如果正确完成,此方案每个非零数字大约需要一次廉价的乘加法操作,一个浮点数强制转换操作和一个浮点数乘法操作以按指数和小数点位置进行比例缩放结果。
我没有实现上述内容。 我已经实现了循环版本,它们非常快速。
我实现了一些你可能会发现有用的东西。
与atof相比,它大约快了5倍,如果与__forceinline
一起使用,则大约快了10倍。
另一个好处是它似乎具有与crt实现完全相同的算术。
当然,它也有一些缺点:
__forceinline bool float_scan(const wchar_t* wcs, float* val)
{
int hdr=0;
while (wcs[hdr]==L' ')
hdr++;
int cur=hdr;
bool negative=false;
bool has_sign=false;
if (wcs[cur]==L'+' || wcs[cur]==L'-')
{
if (wcs[cur]==L'-')
negative=true;
has_sign=true;
cur++;
}
else
has_sign=false;
int quot_digs=0;
int frac_digs=0;
bool full=false;
wchar_t period=0;
int binexp=0;
int decexp=0;
unsigned long value=0;
while (wcs[cur]>=L'0' && wcs[cur]<=L'9')
{
if (!full)
{
if (value>=0x19999999 && wcs[cur]-L'0'>5 || value>0x19999999)
{
full=true;
decexp++;
}
else
value=value*10+wcs[cur]-L'0';
}
else
decexp++;
quot_digs++;
cur++;
}
if (wcs[cur]==L'.' || wcs[cur]==L',')
{
period=wcs[cur];
cur++;
while (wcs[cur]>=L'0' && wcs[cur]<=L'9')
{
if (!full)
{
if (value>=0x19999999 && wcs[cur]-L'0'>5 || value>0x19999999)
full=true;
else
{
decexp--;
value=value*10+wcs[cur]-L'0';
}
}
frac_digs++;
cur++;
}
}
if (!quot_digs && !frac_digs)
return false;
wchar_t exp_char=0;
int decexp2=0; // explicit exponent
bool exp_negative=false;
bool has_expsign=false;
int exp_digs=0;
// even if value is 0, we still need to eat exponent chars
if (wcs[cur]==L'e' || wcs[cur]==L'E')
{
exp_char=wcs[cur];
cur++;
if (wcs[cur]==L'+' || wcs[cur]==L'-')
{
has_expsign=true;
if (wcs[cur]=='-')
exp_negative=true;
cur++;
}
while (wcs[cur]>=L'0' && wcs[cur]<=L'9')
{
if (decexp2>=0x19999999)
return false;
decexp2=10*decexp2+wcs[cur]-L'0';
exp_digs++;
cur++;
}
if (exp_negative)
decexp-=decexp2;
else
decexp+=decexp2;
}
// end of wcs scan, cur contains value's tail
if (value)
{
while (value<=0x19999999)
{
decexp--;
value=value*10;
}
if (decexp)
{
// ensure 1bit space for mul by something lower than 2.0
if (value&0x80000000)
{
value>>=1;
binexp++;
}
if (decexp>308 || decexp<-307)
return false;
// convert exp from 10 to 2 (using FPU)
int E;
double v=pow(10.0,decexp);
double m=frexp(v,&E);
m=2.0*m;
E--;
value=(unsigned long)floor(value*m);
binexp+=E;
}
binexp+=23; // rebase exponent to 23bits of mantisa
// so the value is: +/- VALUE * pow(2,BINEXP);
// (normalize manthisa to 24bits, update exponent)
while (value&0xFE000000)
{
value>>=1;
binexp++;
}
if (value&0x01000000)
{
if (value&1)
value++;
value>>=1;
binexp++;
if (value&0x01000000)
{
value>>=1;
binexp++;
}
}
while (!(value&0x00800000))
{
value<<=1;
binexp--;
}
if (binexp<-127)
{
// underflow
value=0;
binexp=-127;
}
else
if (binexp>128)
return false;
//exclude "implicit 1"
value&=0x007FFFFF;
// encode exponent
unsigned long exponent=(binexp+127)<<23;
value |= exponent;
}
// encode sign
unsigned long sign=negative<<31;
value |= sign;
if (val)
{
*(unsigned long*)val=value;
}
return true;
}
decexp
值,pow(10.0,decexp)
是不精确的。而且你好像把次标准结果发送到0,而不是它们的值。如果我错了,请纠正我。 - R.. GitHub STOP HELPING ICE我记得我们有一个Winforms应用程序,在解析一些数据交换文件时表现非常缓慢,我们都认为是数据库服务器出现了问题,但我们聪明的老板实际上发现瓶颈在于将解析的字符串转换为十进制数的调用!
最简单的方法是循环遍历字符串中的每个数字(字符),保持一个运行总数,将总数乘以10,然后加上下一个数字的值。继续这样做,直到您到达字符串的末尾或遇到一个点。如果遇到一个点,请将整数部分与小数部分分开,然后有一个乘法器,每个数字都会将自己除以10。随着你的前进不断地添加它们。
例如:123.456
累加总数=0,加1(现在是1) 累加总数=1 * 10 = 10,加2(现在是12) 累加总数=12 * 10 = 120,加3(现在是123) 遇到小数点,准备处理小数部分 乘数=0.1,乘以4,得到0.4,加到累加总数中,变成了123.4 乘数=0.1 / 10 = 0.01,乘以5,得到0.05,加到累加总数中,变成了123.45 乘数=0.01 / 10 = 0.001,乘以6,得到0.006,加到累加总数中,变成了123.456
当然,测试数字的正确性以及负数会使它更加复杂。但是,如果您可以“假设”输入是正确的,那么您可以使代码更简单、更快速。
你有没有考虑让GPU来处理这个任务?如果你可以将字符串加载到GPU内存中并让它们进行处理,你可能会发现一个好的算法可以比你的处理器运行得更快。
或者,你可以使用FPGA来完成这项工作——有一些FPGA PCI-E板可以用来制作任意协处理器。使用DMA将FPGA指向包含要转换的字符串数组的内存部分,让它快速地完成转换并留下转换后的值。
你有考虑过四核处理器吗?在大多数情况下,真正的瓶颈都是内存访问...
-Adam
isdigit
的区域设置更改?也许他们应该查看 ISO C 标准。isdigit
没有区域设置相关的行为;它必须检查字符是否是集合0
到9
中的元素,仅此而已。 - Kaz