itoa , _itoa , ltoa , _ltoa , ultoa , _ultoa , _i64toa , _ui64toa , _itow , _ltow , _ultow , _i64tow , _ui64tow
Преобразует целое число в строку. Доступны более безопасные версии этих функций, см. раздел _itoa_s , _itow_s функции.
Синтаксис
Параметры
value
Число, которое требуется преобразовать.
buffer
Буфер, содержащий результат преобразования.
radix
Основание, используемое для преобразования value , которое должно находиться в диапазоне 2-36.
size
Длина буфера в единицах символьного типа. Этот параметр выводится из buffer аргумента в C++.
Возвращаемое значение
Каждая из этих функций возвращает указатель на buffer . Ошибки не возвращаются.
Remarks
_itoa Функции, _ltoa , _ultoa _i64toa , и _ui64toa преобразуют цифры заданного value аргумента в строку символов, завершающуюся нулем, и сохраняют результат (до 33 символов для _itoa , _ltoa , _ultoa , и 65 для _i64toa и _ui64toa ) в buffer . Если radix равно 10, а значение отрицательное, первый символ хранимой строки является знаком «минус» ( — ). _itow Функции, _ltow _ultow _i64tow ,, и _ui64tow — это версии, _ltoa _ultoa ,, _i64toa и _ui64toa соответственно для _itoa расширенных символов.
Эти функции могут записывать после конца буфера, который слишком мал. Чтобы предотвратить переполнение буфера, убедитесь, что буфер достаточно велик, чтобы вместить преобразованные цифры, а также завершающий символ NULL и знак подписывания. Неправильное использование этих функций может привести к серьезным проблемам безопасности в коде.
Из-за возможных проблем безопасности эти функции по умолчанию приводят к нерекомендуемому предупреждению C4996. Эта функция или переменная может быть ненадежной. Вместо этого рекомендуется использовать safe_function . Чтобы отключить функцию устаревания, используйте _CRT_SECURE_NO_WARNINGS . Мы рекомендуем изменить исходный код для использования safe_function предложения, предложенного в сообщении с предупреждением. Более безопасные функции не записывают больше символов, чем заданный размер буфера. Дополнительные сведения см. в _itow_s разделе _itoa_s функции.
Чтобы использовать эти функции без предупреждения об устаревании, определите _CRT_SECURE_NO_WARNINGS макрос препроцессора перед включением всех заголовков CRT. Это можно сделать из командной строки в командной строке разработчика, добавив /D_CRT_SECURE_NO_WARNINGS параметр cl компилятора в команду. В противном случае определите макрос в исходных файлах. при использовании предварительно скомпилированных заголовков определите макрос в верхней части файла pch.h включения предкомпилированного заголовка ( stdafx.h в Visual Studio 2017 и более ранних версиях). Чтобы определить макрос в исходном коде, используйте #define директиву перед включением любого заголовка CRT, как показано в следующем примере:
В C++ эти функции имеют шаблонные перегрузки, которые вызывают их более безопасные аналоги. Дополнительные сведения см. в разделе Безопасные перегрузки шаблонов.
Имена itoa POSIX, ltoa и ultoa существуют как псевдонимы для _itoa функций, _ltoa и _ultoa . Имена POSIX являются устаревшими, так как они не соответствуют соглашениям об именах глобальных функций, связанных с реализацией ISO C. По умолчанию эти функции приводят к нерекомендуемому предупреждению C4996: имя POSIX для этого элемента является устаревшим. Вместо этого используйте имя, соответствующее стандарту ISO C и C++: new_name . Мы рекомендуем изменить исходный код для использования более ранних версий этих функций, _itoa_s _ltoa_s , или _ultoa_s . Дополнительные сведения см. в _itow_s разделе _itoa_s функции.
Для переносимости исходного кода можно хранить имена POSIX в коде. Чтобы использовать эти функции без предупреждения об устаревании, определите _CRT_NONSTDC_NO_WARNINGS и макросы препроцессора, и _CRT_SECURE_NO_WARNINGS перед включением любых заголовков CRT. Это можно сделать из командной строки в командной строке разработчика, добавив /D_CRT_SECURE_NO_WARNINGS Параметры cl компилятора и /D_CRT_NONSTDC_NO_WARNINGS в команду. В противном случае определите макросы в исходных файлах. При использовании предварительно скомпилированных заголовков определите макросы в верхней части файла, включаемого в предкомпилированный заголовок. Чтобы определить макросы в исходном коде, используйте #define директивы перед включением любого заголовка CRT, как показано в следующем примере:
Макрос максимального числа преобразований
Чтобы облегчить создание безопасных буферов для преобразований, CRT включает некоторые удобные макросы. Они определяют размер буфера, необходимого для преобразования наибольшего возможного значения каждого целочисленного типа, включая завершающий символ NULL и знак подписывания, для нескольких распространенных базовых типов. Чтобы гарантировать, что буфер преобразования достаточен для получения любого преобразования в базе, заданной параметром radix , используйте один из этих определенных макросов при выделении буфера. Это помогает предотвратить ошибки переполнения буфера при преобразовании целочисленных типов в строки. Эти макросы определяются при включении stdlib. h или WCHAR. h в источнике.
Чтобы использовать один из этих макросов в функции преобразования строк, объявите буфер преобразования соответствующего символьного типа и используйте значение макроса для целочисленного типа и Base в качестве измерения буфера. В этой таблице перечислены макросы, подходящие для каждой функции в перечисленных базовых базах:
| Функции | radix | Макросы |
|---|---|---|
| _itoa , _itow | 16 10 8 2 |
_MAX_ITOSTR_BASE16_COUNT _MAX_ITOSTR_BASE10_COUNT _MAX_ITOSTR_BASE8_COUNT _MAX_ITOSTR_BASE2_COUNT |
| _ltoa , _ltow | 16 10 8 2 |
_MAX_LTOSTR_BASE16_COUNT _MAX_LTOSTR_BASE10_COUNT _MAX_LTOSTR_BASE8_COUNT _MAX_LTOSTR_BASE2_COUNT |
| _ultoa , _ultow | 16 10 8 2 |
_MAX_ULTOSTR_BASE16_COUNT _MAX_ULTOSTR_BASE10_COUNT _MAX_ULTOSTR_BASE8_COUNT _MAX_ULTOSTR_BASE2_COUNT |
| _i64toa , _i64tow | 16 10 8 2 |
_MAX_I64TOSTR_BASE16_COUNT _MAX_I64TOSTR_BASE10_COUNT _MAX_I64TOSTR_BASE8_COUNT _MAX_I64TOSTR_BASE2_COUNT |
| _ui64toa , _ui64tow | 16 10 8 2 |
_MAX_U64TOSTR_BASE16_COUNT _MAX_U64TOSTR_BASE10_COUNT _MAX_U64TOSTR_BASE8_COUNT _MAX_U64TOSTR_BASE2_COUNT |
В этом примере используется макрос счетчика преобразования для определения буфера, достаточного для размещения unsigned long long в базовом 2:
Универсальное текстовое сопоставление функций
| Tchar.h ассемблер | _UNICODE и _MBCS не определено | _MBCS определяется | _UNICODE определяется |
|---|---|---|---|
| _itot | _itoa | _itoa | _itow |
| _ltot | _ltoa | _ltoa | _ltow |
| _ultot | _ultoa | _ultoa | _ultow |
| _i64tot | _i64toa | _i64toa | _i64tow |
| _ui64tot | _ui64toa | _ui64toa | _ui64tow |
Требования
| Подпрограмма | Обязательный заголовок |
|---|---|
| itoa , ltoa , ultoa | <stdlib.h> |
| _itoa , _ltoa , _ultoa , _i64toa , _ui64toa | <stdlib.h> |
| _itow , _ltow , _ultow , _i64tow , _ui64tow | <stdlib.h> или <wchar.h> |
Эти функции и макросы относятся только к Microsoft. Дополнительные сведения о совместимости см. в разделе Compatibility.
Пример
В этом примере демонстрируется использование некоторых целочисленных функций преобразования. Обратите внимание на использование _CRT_SECURE_NO_WARNINGS макроса для предупреждения C4996.
Как преобразовать int в строку в C?
Как преобразовать int (целое число) в строку? Я пытаюсь сделать функцию, которая преобразует данные struct в строку, чтобы сохранить их в файле.
РЕДАКТИРОВАТЬ: Как указано в комментарии, itoa() это не стандарт, поэтому лучше использовать подход sprintf (), предложенный в ответе соперника!
Вы можете использовать itoa() функцию для преобразования вашего целочисленного значения в строку.
Если вы хотите вывести свою структуру в файл, нет необходимости предварительно преобразовывать какое-либо значение. Вы можете просто использовать спецификацию формата printf, чтобы указать, как выводить ваши значения, и использовать любой из операторов семейства printf для вывода ваших данных.
Вы можете использовать sprintf для этого, или, может быть, snprintf если у вас есть:
Где количество символов (плюс завершающий символ) в str может быть рассчитано с помощью:
Чем дольше: для начала нужно выяснить достаточный размер. snprintf говорит вам длину, если вы называете это в NULL, 0 качестве первых параметров:
Выделите еще один символ для нулевого терминатора.
Если работает для каждой строки формата, поэтому вы можете конвертировать число с плавающей запятой или двойное в строку с помощью «%g» , вы можете преобразовать int в шестнадцатеричное с помощью «%x» , и так далее.
Изучив различные версии itoa для gcc, я обнаружил, что самая гибкая версия, способная обрабатывать преобразования в двоичные, десятичные и шестнадцатеричные, как положительные, так и отрицательные, — четвертая версия, найденная на http://www.strudel.org. .uk / itoa / . Хотя sprintf / snprintf имеют преимущества, они не будут обрабатывать отрицательные числа ни для чего, кроме десятичного преобразования. Так как ссылка выше отключена или больше не активна, я включил их 4-ю версию ниже:
Это старый, но вот другой способ.
Если вы используете GCC, вы можете использовать функцию asprintf расширения GNU.
Преобразование чего-либо в строку должно либо 1) выделить результирующую строку, либо 2) передать в char * адресат и размер. Пример кода ниже:
Оба работают для всех в int том числе INT_MIN . Они обеспечивают последовательный выход в отличие от snprintf() которого зависит от текущей локали.
Способ 1: возвращает нехватку NULL памяти.
Способ 2: возвращается, NULL если буфер был слишком маленьким.
[Редактировать] как запрос @Alter Mann
(CHAR_BIT*sizeof(int_type)-1)*10/33+3 это как минимум максимальное количество, char необходимое для кодирования некоторого целого типа со знаком в виде строки, состоящей из необязательного отрицательного знака, цифр и нулевого символа.
Количество не знаковых битов в знаковое целое число не более чем CHAR_BIT*sizeof(int_type)-1 . Основное-10 представление n -битного двоичного числа занимает до n*log10(2) + 1 цифр. 10/33 чуть больше чем log10(2) . +1 для знака char и +1 для нулевого символа. Другие фракции могут быть использованы как 28/93.
Метод 3: Если кто-то хочет жить на грани, и переполнение буфера не является проблемой, следует простое решение C99 или более поздней версии, которое обрабатывает все int .
Преобразуем в строку. Часть 1. Целые числа.

Задача преобразования числа в строку стоит всегда, когда нужно отобразить числовые результаты работы программы. Процессоры у нас оперируют двоичными данными, человеку-же подавай десятичные числа. Собственно задача состоит в преобразовании базы числа. Какие для этого есть способы? Целью данной статьи является описание и сравнение максимального количества способов преобразования числа в строку. Задачу, естественно, рассматриваем с точки зрения реализации на микроконтроллерах, по этому размер и скорость имеют значение. Для простоты рассматриваем только без-знаковые 32-х и 16-ти разрядные числа (со знаком не намного сложнее).
1. sprintf
Первое что приходит в голову это функция sprintf из стандартной библиотеки Си. Использовать её просто:
После чего в массиве buffer у нас лежит требуемая строка.
Но вот беда, sprintf это ведь функция форматированного вывода, которая много чего умеет и тянет за собой много другие функций стандартной библиотеки. Размер машинного кода при ее использовании увеличивается значительно. Например, даже минимальная версия sprintf из avr-libc (это то, что идет в составе WinAVR / AVR Toolchain) добавляет чуть менее 2 килобайт.
2. utoa, ultoa
В состав библиотек, поставляемых с компиляторами, часто включают функции преобразования числа в строку itoa, ltoa, utoa, ultoa. Вообще эти функции не стандартные, ног часто имеются в наличии и, в отличии от sprintf, не делают ничего лишнего.
3. Извлечение цифр делением на 10.
Готовые стандартные и не очень способы посмотрели. Теперь пришло время свои велосипеды изобретать. Первый самый очевидный способ это конечно деление на 10 и вычисление остатка в цикле.
Остаток от деления выдаёт нам десятичные цифры в обратном порядке, начиная с младшего, поэтому записываем из в буфер начиная с конца, чтоб потом не разворачивать полученную строку.
Всё вроде просто красиво, ничего лишнего, но есть одно но. Собственно деление, да еще и вычисление остатка. Если в процессоре нет аппаратного деления, то это очень медленно.
4. Извлечение цифр делением на 10 с помощью функции div
Может попробовать использовать стандартную функцию div, которая возвращает сразу частное и остаток?
Но деление всё равно остается. К преимуществам этого и предыдущего метода можно отнести то, что они могут преобразовывать число в строку по любому основанию (если ёх чуть доработать), не обязательно 10.
5. Деление на 10 сдвигами и сложениями.
Если у целевого процессора нет аппаратной поддержки 32-х разрядного деления, то предыдущие два метода будут довольно медленными. Деление на 10 можно заменить на серию сдвигов и сложений. Вдохновившись книжкой «Алгоритмические трюки для программистов» (она-же «Hacker’s delight»), берём оттуда функцию деления на 10 с помощью сдвигов и сложений, заменив имеющееся там умножение на 10 (оно тоже «дорогое», на AVR по крайней мере) также сдвигами и сложениями. Модифицируем ее, чтоб она возвращала и частное и остаток:
Выглядит страшно и непонятно, но на самом деле всё просто. Сначала умножаем исходное число на 0.8 или 0.1100 1100 1100 1100 1100 1100 1100 1100 в двоичном представлении. Очень удобно, что дробь периодическая и удалось обойтись всего пятью сдвигами и четырьмя сложениями. Далее делим то, что получилось на 8, сдвигая на 3 разряда вправо. Получается исходное число делённое на 10 с точностью до единицы из-за ошибок округления. После находим остаток умножая полученное частное на 10 и вычитая его из исходного числа. Если остаток больше 9, то корректируем его и частное.
Сама функция использующее «быстрое» деление не отличается по виду от своих предшественниц.
6. Вычитание степеней 10.
Еще один популярный способ преобразования числа в строку, заключается в последовательном вычитании из исходного числа степеней 10, начиная с максимальной. Для этого понадобится таблица с этими степенями 10:
40 байт размером. И сама функция:
Работает очень просто, пока число больше текущей степени 10 вычитаем эту степень 10 из числа и считаем сколько раз вычлось. Потом переходим на меньшую степень 10. И так пока не доберёмся до 1. Цифры получаются сразу в нужном порядке, нужно только удалить ведущие нули.
Методы на двоично-десятичных числах.
Следующие три метода основаны на операциях с упакованными двоично-десятичными числами — binary coded decimals (BCD). В этом представлении каждая тетрада (4 бита) хранит одну десятичную цифру. В 32-х разрядной переменной можно таким образом хранить 8 десятичных цифр. В двоичном представлении в 2-х разрядной переменной 10 десятичных цифр. Поэтому эти методы дают урезанные результаты для чисел больше 99999999. Двоично-десятичные числа очень легко преобразуются в строку:
Собственно из операций с BCD нам нужно сложение и умножение на 2, которое успешно заменяется сложением числа с самим собой. Поэтому нужно только сложение:
Выглядит страшно и непонятно — опять какое-то хитрое побитовое колдунство. На самом деле, чтоб сложить два BCD нужно просто сложить их как обычные двоичные числа — строчка a += b. А потом к каждой тетраде значение которой оказалось больше 9 нужно добавить корректирующее число 6 с переносом бита в старшую тетраду. И к каждой тетраде из которой был перенос бита в старшую тетраду, нужно также добавить корректирующее число 6. Все остальные строки функции — как раз эта коррекция. В первых двух строках мы определяем все биты суммы a + b + 0x66666666ul, которые изменили своё значение из-за переноса бита из младшего разряда. В третей строка складываем наши два числа. В четвёртой — выделяем младшие биты переноса для каждой тетрады. В остальных — прибавляем 6 к тем тетрадам из которых был перенос бита. Вот так вот — без единого условного перехода.
7. Сложение степеней двойки.
Первый способ, хорошо всем знакомый еще со школьных уроков информатики, — сложение десятичных представлений степеней двойки, соответствующих единичным битам в преобразуемом числе:
7. Сложение степеней двойки с таблицей.
В предыдущем методе используется два сложения двоично-десятичных чисел. От одного из них можно избавиться беря степень двойки из таблицы:
Таблица содержит 30 элментов — 120 байт.
8. Horner’s method
В этом методе на каждом шаге удваиваем накопленный десятичный результат, если старший бит двоичного числа единица, то добавляем к результату единицу, двоичное число при этом умножаем на 2 (сдвигаем на бит влево).
Здесь уже две операции сложения BCD, но одна из них сложение с 1 и от неё одной можно избавиться.
При этом первый аргумент bcd_add может оказаться не корректным BCD, где младшая тетрада содержит цифру больше 9. Однако наша bcd_add это нормально прожевывает выдавая правильный результат. А вот если добавлять эту лишнюю единицу ко второму аргументы, то результат будет уже не правильным.
Количество итераций в цикле этого метода всегда будет равно разрядности числа, в отличии от предыдущих, где цикл закончится, как только в числе не останется единичных бит.
9. Извлечение цифр умножением на 10.
Идея заключается в том, что десятичные цифры можно извлекать со стороны старших бит числа и использовать умножение на 10 для перехода к следующему десятичному разряду. Для этого придётся представить наше двоично число как дробную часть, мысленно перенести запятую на сколько-то разрядов влево, в нашем случае это будет 27. При этом число будет состоять из 2^-27 долей. Чтоб извлекать десятичные цифры эта дробь должна состоять из каких-то десятичных долей пусть это будет 10^-9. Его нужно для этого умножить на 2^-27/10^-9 = 1.34217728. После этого биты начиная с 27 разряда будут содержать старшую десятичную цифру. Но это если исходное число было меньше 2^27. Если оно было больше, то две цифры со значением не более 31. Это надо учесть. Еще один момент — это переполнение. Начиная с чисела 3199999999 ((2^32-1) / 1.34217728) у нас будет переполнение на 1 разряд, которое тоже надо учесть. А как-же всё-таки умножить челое число на 1.34217728 и без изпользования плавающей точки? Всё так-же сдвиками и сложениями. И так вот, что получилось:
Как ни странно но это работает. Если кто-нибудь видел этот способ раньше — скажите мне, а то я могу претендовать на авторство.
Как видно при умножении пришлось использовать 40-ка битную арифметику — дополнительный байт для дробной части. Если дробную часть отбросить и использовать 32-х битную арифметику, то возникают ошибки округления, который достигают 7 для больших чисел. К сожалению в языке Си нет доступа к биту переноса и по этому перенос в/из дробной части пришлось организовывать вручную. Для эффективного использования бита переноса можно использовать ассемблерные вставки. Поскольку первая тестируемая платформа у нас будет avr-gcc, для него их и напишем, чисто ради спортивного интереса. С ними цикл умножения будет выглядеть так:
Бенчмарк
Теперь собственно та часть ради которой всё затевалось — сравнение скорости работы. Первой испытанной платформой будет будет AVR с использованием компилятора GCC.
Для методов разных типов время работы будет зависеть от разных факторов, например для методов основанных на делении на 10 время будет зависеть в большей степени от количества десятичных цифр, о есть от абсолютной величины числа и очень мало от самих этих цифр. Вычитание степеней 10 в цикле будет тем быстрее работать чем меньше сумма десятичных цифр составляющих число. То есть 1000000 обработается гораздо быстрее чем 999999. Методы основанные на двоично-десятичных числах будут быстрее работать если в исходном числе мало единичных бит — быстрее всего со степенями двойки. Время работы последнего метода будет зависеть только от абсолютной величины преобразуемого числа, но в меньшей степени чем методы с делением на 10. Итак в наборе для тестирования должны быть маленькие чила, большие числа, степени двойки, степени десяти, числа где много девяток.
Всякие тесты для AVR удобно проводить на симуляторе Simulavr — не нужно никакого железа, и многочисленных перепрошивок.
Для замера времени выполнения наших функций воспользуемся 16-ти разрядным таймером, тикающем на частоте ядра. Вывод на консоль через отладочный порт эмулятора. Оптимизация кода максимальная по скорости.
Вот что получилось в результате для 32-х разрядных чисел:
* после плюса размер зависимостей — таблицы или функции деления
** в скобках указаны результаты для варианта с ассемблерными вставками.
Лидирует в этом бенчмарке с не большим отрывом метод на быстром делении на 10 сдвигами и сложениями. К нему близко подобралось вычитание степеней 10. Следом метод с умножением на 10. методы с честным делением (включая utoa), как и ожидалось, самые медленные, особенно тот, что использует функцию ldiv, но и самые компактные. Время выполнения метода Хорнера практически не зависит от конвертируемого числа. sprintf работает относительно быстро, по сравнению с utoa. И не удивительно — у неё внутри используется метод похожий на utoa_fast_div, но накладные на разбор форматной строки и медленный вывод в буффер через fputc дают о себе знать.
UPDATE.
Результат для 16-х разрядных чисел:
Здесь опять с заметным преимуществом лидирует быстрое деление сдвигами/сложениями. Худший результат теперь у sprintf, ведь внутри она всё равно использует 32- разрядные числа.
UPDATE #2. Результаты для MSP430.
Результат для 16-х разрядных чисел:
Поскольку кроме MSP430 Launcpad-а с камнем MSP430G2231 других MSP430 у меня нет, тестировать пришлось на нем. Все функции разумеется в него не помещаются, по этому заливаются и тестируются по одной с помощью скрипта.
Как видно честное деление здесь почти вдвое медленнее чем у AVR.
UPDETE #3
Результаты для STM32.
Обсуждение результатов
Аутсайдером везде является функция использующая библиотечную функцию деления div. Несмотря на то, что она возвращает за один вызов и остаток и частное от деления, даже на STM32 аппаратным делением, она реализована программно и работает очень медленно. Очевидно этот способ использовать не стоит. Однако функция использующая встроенный оператор деления utoa_builtin_div, плетущаяся в конце на AVR и MSP430, на STM32 — в лидерах. Ничего удивительного, ведь в Cortex M3 есть аппаратное деление скажут многие, и будут не совсем правы — деление-то там есть, но оно не такое уж и быстрое (в скобках для utoa_builtin_div указано время, если заставить компилятор сгенерировать честное деление). Дело в том, что хитрый GCC при делении на константу использует хитрый трюк — заменяет деление на умножение на константу такую, что старшие 32 бита в 64 разрядном произведении, содержат исходное делимое, делённое на 10.
Этот код эквивалентен примерно следующему:
uint32_t tmp = value;
Такой способ тоже описан в книжке «Алгоритмические трюки для программистов». Однако на AVR и MSP430 этот номер не пройдёт — там умножение 32*32 => 64 работает неприлично долго, дольше честного деления.
Еще utoa_builtin_div всегда имеет минимальный размер.
Всегда хороший, а зачастую лучший результат даёт деление на 10 сдвигами и сложениями utoa_fast_div. Это практически безусловный лидер по скорости и часто имеет вполне скромный размер. Этот метод всегда удачный выбор.
Любимое многими вычитание степеней десяти utoa_cycle_sub по размеру вместе с таблицей примерно совпадает сutoa_fast_div, но всегда немного уступает по скорости. Вобщем, тоже не плохой выбор.
Методы основанные на двоично десятичных числах работают не очень быстро, имеют не самый маленький размер и к тому-же выдают только 8 цифр результата (в моей реализации, можно получить все 10 цифр, но будет еще медленнее). Их лучше использовать не для преобразования двоичных чисел в строки, а для преобразования двоичных чисел в упакованные двоично десятичные, для последующей работы сними.
Особняком стоит метод с умножением на 10 utoa_fract. Он не выглядит очень привлекательным по среднему времени, однако его худшее время часто оказывается меньше, чем худшее время лидеров. У этого метода разница между лучшим и худшим относительно небольшая — он работает стабильно.
UPDATE.
Нашел еще один интересный и очень быстрый метод. Вот Вот здесь.
Описание того, как это работает по ссылке выше на английском. К сожалению, корректные результаты этот метод выдаёт только для 15-ти битных значений, зато очень быстро:
для AVR лучшее время — 133 такта, худшее — 167, среднее — 146.
Coming next.
Часть 2. Фиксированная и плавающая точка.
PS. Может быть кто знает еще какие нибудь методы преобразования чисел в строку?