#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 "Точность выполнения арифметических действий в системе с плавающей
точкой".