Классическая реализация - Дэвид Гэй dtoa
. Точные детали несколько загадочны (см. Почему «dtoa.c» содержит так много кода? ), но в целом он работает, выполняя базовое преобразование, используя большую точность, чем та, которую вы можете получить из 32- разрядное, 64-разрядное или даже 80-разрядное число с плавающей запятой. Для этого он использует так называемые числа больших чисел или числа произвольной точности, которые могут содержать столько цифр, сколько вы можете уместить в памяти. Код Gay был с изменениями скопирован в бесчисленное множество других библиотек, включая общие реализации стандартной библиотеки C (так что она может питать ваши printf
), Java, Python, PHP, JavaScript и т. Д.
(В качестве примечания ... не все эти копии кода dtoa для Gay были обновлены, так как PHP использовал старую версию strtod, которую он зависал при разборе 2.2250738585072011e-308. )
В общем, если вы будете делать вещи «очевидным» и простым способом, например, умножением на степень 10 и последующим преобразованием целого числа, вы потеряете небольшую степень точности, а некоторые результаты будут неточными ... но возможно, вы получите правильные первые 14 или 15 цифр. Гей-реализация dtoa () утверждает, что все цифры верны ... но в результате код довольно сложен для отслеживания. Перейдите к нижней части, чтобы увидеть сам strtod, вы можете увидеть, что он начинается с «быстрого пути», который просто использует обычную арифметику с плавающей точкой, но затем он обнаруживает, что этот результат неверен, и использует более надежный алгоритм с использованием bigints, который работает в все случаи (но медленнее).
Реализация имеет следующую цитату, которая может вас заинтересовать:
* Inspired by "How to Print Floating-Point Numbers Accurately" by
* Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
Алгоритм работает, вычисляя диапазон десятичных чисел, которые производят данное двоичное число, и, используя больше цифр, диапазон становится все меньше и меньше, пока вы не получите точный результат или не сможете правильно округлить до запрошенного числа цифр. .
В частности, из раздела 2.2 Алгоритм
Алгоритм использует точную рациональную арифметику для выполнения своих вычислений, чтобы не было потери точности. Для генерации цифр алгоритм масштабирует число так, чтобы оно имело форму 0.d 1 d 2 ..., где d 1 , d 2 , ..., цифры основания B. Первая цифра вычисляется путем умножения масштабированного числа на выходную базу B и взятия целочисленной части. Остаток используется для вычисления остальных цифр с использованием того же подхода.
Затем алгоритм может продолжаться до тех пор, пока не получит точный результат (что всегда возможно, поскольку числа с плавающей запятой являются основанием 2, а коэффициент 2 равен 10) или пока он не будет иметь столько цифр, сколько требуется. Статья продолжает доказывать правильность алгоритма.
Также обратите внимание, что не все реализации printf
основаны на dtoa Гея, это просто очень распространенная реализация, которая часто копируется.