Страницы

Поиск по вопросам

понедельник, 30 декабря 2019 г.

Вывод double с нужной точностью и в нужном формате

#cpp #строки #stl #double #format


Требуется вывести double с максимальной точностью, при этом целую часть, которая
не превышает 999 вывести с пробелами на месте отсутствующих цифр, типа 9,12...

Вывожу следующим образом

std::cout << std::fixed << std::setprecision(std::numeric_limits::digits10
+ 1) << value << std::endl;


Возникло 2 проблемы:

1) везде читал, что точность double определяется как std::numeric_limits::digits10,
однако похоже, что можно вытащить больше значащих цифр, если задать точность в 20 цифр,
то будут видны все 20 отличных от 0 цифр

2) не нашел, как можно задать размер целой части, чтобы заполнить отсутствующие цифры
пробелами

Подскажите, что требуется сделать?
    


Ответы

Ответ 1



Всё, чего вам не хватало, это задать заполнитель setfill и ширину setw выводимого поля: #include #include #include void print(double value) { const auto digits = std::numeric_limits::digits10; std::cout << std::setfill(' ') << std::setw(digits + 4); std::cout << std::fixed << std::setprecision(digits) << value << std::endl; } int main() { double value = 9.12; print(value); } Результат выполнения

Ответ 2



Можно также написать класс, с функциональностью выводить как угодно. Например: #include #include #include using namespace std; class IM { double d; size_t ww; char c; public: IM(double val, size_t whole_size, char imbue = ' ') : d(val), ww(whole_size), c(imbue) {} int get_whole() const { return d; } int get_fraction() const { stringstream s; s << d - get_whole(); int k; s.ignore(2); // пропускаем '0' и '.' s >> k; return k; } friend ostream& operator <<(ostream& os, const IM& m) { os << setw(m.ww) << setiosflags(ios_base::left) <

Ответ 3



Во-первых, смысл величины digits10 для плавающего типа T заключается в том, что если вы возьмете десятичное строковое представление, преобразуете его в значение типа T, а затем преобразуете его из T обратно в десятичное строковое представление, то вы получите digits10 значащих цифр цифр, совпадающих с вашей исходной строкой. Например, если вы используете плавающий тип для хранения целых значений, то целые значения с таким количеством цифр будут представляться без потерь, как и соседние (+-1) целые значения. Родственной величиной является величина max_digits10, которая говорит, что если вы преобразуете плавающее значение типа T в десятичное строковое представление с сохранением max_digits10 старших значащих цифр, а затем преобразуете его обратно в тип T, то вы гарантированно получите исходное значение типа T. Таким образом, величина digits10 описывает сохранение данных в преобразовании туда-обратно вида "строка10 -> плавающее -> строка10". А величина max_digits10 описывает сохранение данных в преобразовании туда-обратно вида "плавающее -> строка10 -> плавающее". Это, однако, совсем не означает, что десятичное строковое плавающее значение будет иметь только столько точных цифр. Огульно обзывать цифры за пределами этого количества "мусором" - очевидная профанация. Какие цифры являются точными, а какие нет - определяется спецификой ваших вычислений и известно только вам. Очевидный пример: "традиционные" двоичные плавающие типы способны точно представлять степени двойки в пределах возможностей экспоненты. То есть std::pow(2, 512) даст вам точное значение типа double 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096 в котором намного больше значащих цифр, чем digits10 или max_digits10 для double (15 и 17 соответственно). Никакого "мусора" в этом представлении нет (разумеется, если вы хотели вычислить именно 2512) . Вас это не должно удивлять. Умение пользоваться такими возможностями плавающих представлений - это во многом и есть умение пользоваться плавающими типами в общем. Во-вторых, что касается управления шириной поля при выводе - об этом вы уже получили ответы.

Ответ 4



По ходу обсуждения оказалось, что имеет смысл остановиться подробнее на определении точности вещественного типа. Удивительно, но оказывается, что точность double совсем не жалкие 15 цифр, а намного, намного больше! И в подтверждение приводятся числа 2^(-100) и 2^512, которые действительно представляются точно. Так что же, получается что и в самом деле точность double больше, чем 15 цифр? К сожалению нет, такие заявления говорят лишь о непонимании вещественной арифметики. Давайте посмотрим на представление чисел вещественным типом. Точность представления определяется его мантиссой, которая в случае числа двойной точности имеет длину 52 бита и соответственно может представить 2^52 значений. Теперь возьмем некое число, у которого в двоичном представлении биты мантиссы 53, 54, и т.д. являются нулями. Нетрудно видеть, что такое число будет представлено абсолютно точно. С бесконечной точностью! И таких чисел существует ровно 2^52. Попробуем теперь немного уменьшить требования к точности. Возьмем, скажем, тысячу знаков после запятой - есть ли числа, которые представляются с такой точностью? Да, такие числа в самом деле есть, и из свойств множества действительных чисел видно, что их бесконечно много. Какую бы точность мы ни задали - сто, тысячу, миллион знаков после запятой, - оказывается, что существует бесконечно много чисел, представимых именно с такой точностью. Получается, что точность вещественного типа это какая-то странная характеристика, которая произвольно меняется в зависимости от числа вплоть до бесконечности? Нет, именно в этом месте и происходит путаница! Точность представления отдельно взятого числа не имеет никакого отношения к точности вещественного типа. Слово одно, но под ним подразумеваются совершенно разные вещи. А собственно точность представления числа, хотя и кажется очень важной с бытовой точки зрения, в вещественной арифметике никакого значения не имеет. По той простой причине, что она непредсказуема - мы не можем определить точность представления по результату вычислений. Для этого надо этот результат сравнить с эталонным значением, а если мы и так его знаем, то зачем нам что-то вычислять? Так что же такое точность вещественного типа? Представим, что у нас есть два числа, у которых первые 52 бита мантиссы совпадают, а различается бит 53. Эти два числа будут представлены одной и той же мантиссой, и соответственно, тем же самым числом двойной точности. Мы говорим, что точность double составляет 52 бита, и это означает простую вещь: double различает только числа, у которых отличаются первые 52 бита. Числа, у которых отличаются только биты 53 и последующие, представляются одной и той же мантиссой. Вот это и есть точность! Соответственно,в десятичном виде точность double составляет 15.45 десятичных цифр. Это означает, что числа, отличающиеся первыми 15 знаками всегда представляются разными значениями double. Числа с отличиями в 16-ом знаке могут представляться разными значениями (в 45% случаев), а могут и не отличаться (соответственно, в 55% случаев). Числа с отличием в 17-ом и более младших знаках имеют одинаковое представление в числе двойной точности. Разумеется, тема точности вещественной арифметики немного сложнее этого простого определения. Для более серьезного ознакомления можно посоветовать Д. Кнут, том 2 "Получисленные алгоритмы", глава 4.2.2 "Точность выполнения арифметических действий в системе с плавающей точкой".

Комментариев нет:

Отправить комментарий