在我看来,您想(手动)构建相当于每个状态处理第 N 个输入数字或指数数字的状态机;这个状态机的形状像一棵树(没有循环!)。目标是尽可能进行整数运算,并且(显然)隐式记住状态中的状态变量(“前导减号”、“位置 3 的小数点”),以避免分配、存储和以后获取/测试这些值. 仅在输入字符上使用普通的旧“if”语句实现状态机(因此您的树将成为一组嵌套的 if)。对缓冲区字符的内联访问;您不希望函数调用getchar
减慢您的速度。
可以简单地抑制前导零;你可能需要一个循环来处理非常长的前导零序列。无需将累加器归零或乘以十即可收集第一个非零数字。前 4-9 个非零数字(对于 16 位或 32 位整数)可以通过整数乘以常数值 10 来收集(大多数编译器将其转换为几次移位和加法)。[在顶部:零位不需要任何工作,直到找到一个非零位,然后需要 N 个连续零的乘法 10^N;您可以将所有这些连接到状态机]。前 4-9 之后的数字可以使用 32 位或 64 位乘法来收集,具体取决于您机器的字长。由于您不关心准确性,因此您可以在收集 32 或 64 位价值后简单地忽略数字;一世' 根据您的应用程序对这些数字的实际操作,猜测当您有一些固定数量的非零数字时,您实际上可以停止。在数字字符串中找到的小数点只会导致状态机树中的分支。该分支知道该点的隐含位置,因此以后如何适当地按 10 的幂进行缩放。如果您不喜欢这段代码的大小,您可以通过努力组合一些状态机子树。
[在顶部:将整数和小数部分保留为单独的(小)整数。这将需要在最后进行额外的浮点运算来组合整数和小数部分,可能不值得]。
[在顶部:将数字对的 2 个字符收集到一个 16 位值中,查找 16 位值。这避免了寄存器中的乘法以换取内存访问,这在现代机器上可能不是一个胜利]。
在遇到“E”时,如上所述将指数收集为整数;在预先计算的乘数表中查找准确的预先计算/缩放的 10 次幂(如果指数中存在“-”符号,则为倒数)并将收集的尾数相乘。(永远不要做浮点除法)。由于每个指数收集例程都位于树的不同分支(叶)中,因此它必须通过偏移 10 指数的幂来调整小数点的明显或实际位置。
ptr++
[顶部:如果您知道数字的字符线性存储在缓冲区中并且不跨越缓冲区边界,则可以避免成本。在沿着树枝的第 k 个状态中,您可以将第 k 个字符访问为*(start+k)
. 一个好的编译器通常可以在寻址模式下将“...+k”隐藏在索引偏移中。]
如果做得对,该方案对每个非零数字进行大约一次廉价的乘加,尾数转换为浮点数,以及通过指数和小数点位置缩放结果的浮点乘法。
我还没有实现上述。我已经用循环实现了它的版本,它们非常快。