Мне кажется, что вы хотите построить (вручную) то, что составляет конечный автомат, где каждое состояние обрабатывает N-ую входную цифру или цифры экспоненты; этот конечный автомат будет иметь форму дерева (без петель!). Цель состоит в том, чтобы делать целочисленную арифметику везде, где это возможно, и (очевидно) запоминать переменные состояния («ведущий минус», «десятичная точка в позиции 3») в состояниях неявно, чтобы избежать присваиваний, хранения и последующей выборки / проверки таких значений , Реализуйте конечный автомат с простыми старыми операторами «if» только на входных символах (чтобы ваше дерево стало набором вложенных ifs). Встроенный доступ к символам буфера; Вы не хотите, чтобы вызов функции getchar
замедлял вас.
Ведущие нули могут быть просто подавлены; Вам может понадобиться цикл для обработки смехотворно длинных ведущих нулевых последовательностей. Первая ненулевая цифра может быть собрана без обнуления аккумулятора или умножения на десять. Первые 4-9 ненулевых цифр (для 16-битных или 32-битных целых чисел) можно собрать с помощью целочисленных умножений на постоянное значение десять (большинство компиляторов превращают их в несколько сдвигов и сложений). [Вверху: нулевые цифры не требуют никакой работы, пока не будет найдена ненулевая цифра, а затем требуется умножить 10 ^ N на N последовательных нулей; Вы можете подключить все это в конечный автомат]. Цифры, следующие за первыми 4-9, могут быть получены с использованием 32- или 64-битных умножений в зависимости от размера слова вашей машины. Поскольку вам не важна точность, вы можете просто игнорировать цифры после того, как вы собрали 32- или 64-битные значения; Я предполагаю, что вы действительно можете остановиться, когда у вас есть фиксированное число ненулевых цифр на основе того, что ваше приложение на самом деле делает с этими числами. Десятичная точка, найденная в строке цифр, просто вызывает ветвь в дереве конечного автомата. Эта ветвь знает неявное местоположение точки и, следовательно, как правильно масштабировать ее до десяти. Приложив усилия, вы сможете комбинировать некоторые поддеревья конечного автомата, если вам не нравится размер этого кода.
[Вверху: целые и дробные части следует хранить как отдельные (маленькие) целые числа. Это потребует дополнительной операции с плавающей точкой в конце для объединения целых и дробных частей, вероятно, не стоит].
[Вверху: соберите 2 символа для пар цифр в 16-битное значение, найдите 16-битное значение.
Это позволяет избежать увеличения количества регистров в обмене на доступ к памяти, вероятно, не является выигрышем на современных машинах].
При обнаружении "E", получить показатель степени как целое число, как указано выше; найдите в таблице предварительно вычисленных множителей точно рассчитанные / масштабированные степени десяти (обратные значения, если знак «-» присутствует в показателе степени) и умножьте собранную мантиссу. (никогда не делайте поплавок). Поскольку каждая подпрограмма сбора показателей находится в отдельной ветви (листе) дерева, она должна корректироваться с учетом явного или фактического расположения десятичной точки, смещая степень десяти индекса.
[Сверху: вы можете избежать стоимости ptr++
, если знаете, что символы для числа хранятся в буфере линейно и не пересекают границу буфера. В состоянии k вдоль ветви дерева вы можете получить доступ к символу k как *(start+k)
. Хороший компилятор обычно может скрыть "... + k" в индексированном смещении в режиме адресации.]
Совершенно верно, эта схема делает примерно одно дешевое умножение-добавление на ненулевую цифру, одно приведение к плавающей запятой мантиссы и одно умножение с плавающей запятой для масштабирования результата по экспоненте и расположению десятичной точки.
Я не реализовал вышеизложенное. Я реализовал его версии с помощью циклов, они довольно быстрые.