Извлечение отдельных цифр из числа с плавающей точкой
-
19-08-2019 - |
Вопрос
Я весь день ломал над этим голову.Проект на C ++, над которым я сейчас работаю, требует отображения редактируемого значения.Выбранная в данный момент цифра отображает увеличенное значение выше и уменьшенное значение ниже для указанной цифры.Полезно иметь возможность ссылаться на редактируемое значение как на число, так и на набор цифр.Что было бы потрясающе, так это если бы существовала какая-то индексируемая форма числа с плавающей запятой, но я не смог найти такого решения.Я задаю этот вопрос, чтобы посмотреть, есть ли что-то очевидное, чего мне не хватает, или мне следует просто создать свой собственный.
Спасибо за совет!Я надеялся на решение, которое не будет преобразовываться из float -> string -> int, но я подумай это лучший способ уйти от проблем квантования с плавающей запятой.В итоге я выбрал boost::format и просто ссылался на отдельные символы строки.Я не вижу в этом огромной разницы в производительности по сравнению с использованием комбинаций modf и fmod для попытки получить цифру из числа с плавающей точкой (вероятно, это происходит именно за кулисами, только более надежно, чем моя реализация).
Решение
Внутреннее представление чисел с плавающей точкой не такое, как вы видите. Вы можете бросить только на перемешивание.
Чтобы разыграть, сделайте это:
char string[99];
sprintf(string,"%f",floatValue);
Или посмотрите это: http: // www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.1 р>
Статья в Википедии может объяснить больше о представлении: http://en.wikipedia.org/wiki/ Floating_point
Другие советы
О, есть много способов преобразовать в строку. (Хотя я действительно предпочитаю snprintf() я сам.)
Или вы могли бы преобразовать в int и извлечь цифры с помощью модуля и целочисленного деления.Вы можете подсчитать количество цифр с помощью log{base10}.
(Помните:log{baseA}_X / log{baseA}_B = log{BaseB}_X.)
Пример:
#define SHOW(X) cout << # X " = " << (X) << endl
int
main()
{
double d = 1234.567;
SHOW( (int(d)%10000) / 1000 );
SHOW( (int(d)%1000) / 100 );
SHOW( (int(d)%100) / 10 );
SHOW( (int(d)%10) );
SHOW( (int(d*10) % 10) );
SHOW( (int(d*100) % 10) );
SHOW( (int(d*1000)% 10) );
SHOW( log(d)/log(10) );
}
Хотя вам следовало бы использовать static_cast ...
Следите за экспоненциальными обозначениями.При очень больших или очень маленьких числах у вас может возникнуть проблема.
Числа с плавающей запятой также имеют проблемы с округлением, которые могут вас огорчить.(Это та же причина, по которой мы не используем operator== между двумя дублями.Или почему вы не можете полагаться на a * b == b * a.В зависимости от точных значений a и b, они могут очень незначительно отличаться примерно на 10^-25.)
Вы можете выполнять преобразование между string и float только с помощью boost::lexical_cast .Однако вы не можете напрямую проиндексировать форму с плавающей запятой - она внутренне не хранится в виде десятичных цифр.Вероятно, это не такая уж большая проблема.Для вашего пользовательского интерфейса вы, скорее всего, в любом случае сохраните строковую форму числа с преобразованиями в float и из float в getter / setter.