Вопрос

Я всегда использовал потоки, printf, string(x) или любой другой язык, предлагаемый для преобразования числовых типов в строку или обратно.Однако я никогда особо не задумывался о том, как это на самом деле делается.Я искал в Google, но все результаты касаются только использования этих разных методов, а не того, как на самом деле происходит преобразование :(

Для целых чисел, использующих двоичные, восьмеричные и шестнадцатеричные числа, это кажется довольно простым, поскольку каждая «цифра» в строке представляет собой набор битов (например, для двух шестнадцатеричных цифр я знаю, что это xxxxyyyy), поэтому я мог бы сделать это с битовыми сдвигами и взять один по цифре, например, для шестнадцатеричной строки 0xFA20 значение равно «(15 << 12) | (10 << 8) | (2 << 4) | (0 << 0)».

Десятичные целые числа сложнее, поскольку основание 10 не отображается в основание 2 таким образом, и поэтому один бит может влиять на более чем одну десятичную цифру, что делает преобразование в обоих направлениях более сложным...

Что касается чисел с плавающей запятой, я понятия не имею.Я думаю, целую и дробную части можно рассматривать отдельно или что-то в этом роде?А как насчет экспоненты, заданного количества значащих цифр или заданного количества десятичных знаков?

Это было полезно?

Решение

Десятичные преобразования немного медленнее, но не намного сложнее.Давайте посмотрим на шестнадцатеричное преобразование подробнее, как если бы мы, вероятно, написали его в реальном коде.Например, в C++ вы можете выполнить преобразование примерно так:

char digits[] = "0123456789abcdef";
std::string result;

int input = 0xFA20;

while (input) {
    int digit = input & 0xf; // or: digit = input % 0xf;
    input >>= 4;             // or: input /= 16;
    result.push_front(digits[digit]);
}

Однако сейчас это имеет некоторые магические цифры.Давайте избавимся от них:

const int base = 16;

while (input) { 
    int digit = input % (base - 1);
    input /= base;
    result.push_front(digits[digit]);
}

Избавившись от этих магических чисел, мы также сделали процедуру почти универсальной: если мы изменим значение «base», остальная часть процедуры все равно будет работать и преобразует входные данные в указанную базу.По сути, единственное другое изменение, которое нам нужно сделать, — это добавить больше к массиву «цифр», если мы хотим поддерживать систему счисления по основанию больше 16.

Это также игнорирует некоторые вещи для простоты.Очевидно, что если число отрицательное, вы обычно устанавливаете флаг, преобразуете его в положительное число и в конце, если флаг установлен, вставляете в строку знак «-»).При дополнении до 2 существует угловой случай для максимально отрицательного числа, которое невозможно преобразовать в положительное число (без преобразования в тип с большим диапазоном).Обычно вы справляетесь с этим, продвигая большинство типов.Для вашего самого большого целочисленного типа (который вы не можете продвигать) обычно проще всего просто жестко запрограммировать это одно значение.

В принципе, плавающая запятая не сильно отличается — вы по-прежнему выполняете математические манипуляции, чтобы генерировать по одной цифре за раз.На самом деле все становится сложнее просто потому, что вам обычно приходится иметь дело с парой разных форматов (по крайней мере, с «базовым» форматом с плавающей запятой и своего рода «научным» форматом), а также с переменными для ширины и точности поля.К тому времени, как вы разберетесь с этим, у вас будет несколько сотен строк кода или около того — не особенно возмутительное количество, но, вероятно, немного больше, чем имеет смысл включать сюда.

Другие советы

Я искал в Google, но все результаты просто используют эти варьируются методы, а не как преобразование действительно сделано за кулисами :(

По причинам эффективности преобразование из одного представления в другую (особенно преобразования с плавающей точкой / целочисленными) часто является инструкцией по эксплуатации низкого уровня и реализуется на уровне процессора. Вот почему вы обычно не видите его повторно реализованы в библиотеках или на уровне языка.

Это особенно распространено в мире обработки сигналов, например, в том случае, если вы хотите взять форму волны и преобразовать его в дискретное целочисленное значение в некоторых диапазоне.

Для целых чисел вы можете найти оставшуюся часть дивизии, это последняя цифра, разделить на 10, нашел модульный остаток - это одна, но последняя цифра, и так далее. Числа с плавающей запятой построены из двух частей - значимых цифр и экспоненты, т. Е. Номер = значимые.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top