Как задать точность в c
Для вывода на консоль в языке программирования Си зачастую применяется функция printf() . Но если с выводом простой строки особых проблем не возникает, то при выводе данных других типов есть свои особенности.
Формальное определение функции printf выглядит следующим образом:
printf(строка_форматирования, список_аргументов)
Первый параметр представляет строку, которая может содержать произвольный текст в двойных кавычках. Например:
#include int main(void)
Кроме стандартного текста мы можем передавать в строку специальные группы символов, которые называются управляющими последовательностями. Наиболее распространенные из них:
- \n : перевод на новую строку
- \t : табуляция
- \r : возврат каретки (курсора) в начало строки
- \\ : обратный слеш
- \’ : одинарная кавычка
- \» : двойная кавычка
#include int main(void)
The book "The C Programming Language" Brian Kernighan, Dennis Ritchie
Спецификации преобразования
Спецификации преобразования позволяют задать формат вывода различных типов данных. Формальное определение спецификаций преобразования выглядит следующим образом:
% флаги ширина_поля.точность модификатор спецификатор
Из этих компонентов обязательными являются только два % и спецификатор .
Какие спецификаторы мы можем использовать:
- %c : для вывода отдельных символов (тип char)
- %s : для вывода строк
- %d : для вывода целых чисел со знаком (тип int)
- %i : для вывода целых чисел со знаком (тип int)
- %u : для вывода целых положительных чисел (тип unsigned)
- %f : для вывода чисел с плавающей точкой (float, double)
- %F : для вывода чисел с плавающей точкой в верхнем регистре (float, double)
- %e : для вывода экспоненциального представления чисел с плавающей точкой (float, double)
- %E : для вывода экспоненциального представления чисел с плавающей точкой в верхнем регистре (float, double)
- %g : для вывода чисел используется более короткий из форматов %e или %f
- %G : для вывода чисел используется более короткий из форматов %E или %F
- %o : для вывода восьмеричных чисел без знака
- %x : для вывода шестнадцатеричных чисел
- %X : для вывода шестнадцатеричных чисел в верхнем регистре
- %% : для вывода знака процента
Применим несколько спецификаторов:
#include int main(void)
Значения для спецификаторов передаются через аргумент, который идет вторым параметром в функции printf.
x = 71.898598 x = 7.189860e+001 symbol = r number = 23 Hello Word 2013
Для вывода числовых значений с плавающей точкой мы можем использовать ширину поля и точность. Ширина поля представляет целое положительное число, которое определяет длину выводимого значения в символах. Точность — это также целое положительное число, которое определяет количество цифр в дробной части. Например:
float r = 71.8986; printf("x = %4.2f \n", r); // 71.90
Здесь спецификация преобразования представляет строку «%4.2f», где «4» — ширина поля (для вывода числа будут использоваться 4 цифры), а «2» — точность (2 цифры в дробной части).
Модификаторы позволяют конкретизировать выводимое значение. Используются следующие модификаторы:
- h : для вывода значений short int
- l : для вывода значений long int и unsigned long int
- ll : для вывода значений long long int и unsigned long long int
- L : для вывода значений long double
short r = 7100; printf("x = %hd", r);
Необязательно передавать по одному значению для вывода в функцию printf. Мы можем передавать множество значений:
printf("Name=%s \t Age=%d \t Weight=%3.2f", "Tom", 23, 63.3456);
Первый спецификатор в строке форматирования — «%s», и для него значение будет поставляться первым аргументом — строкой «Tom». Второй спецификатор — «%d», для него значение берется из второго аргумента — числа 23. И так далее.
Дополнительно можно использовать флаги, которые дополнительно позволяют управлять форматированием вывода:
- — : указывает, что выравнивание будет идти от левого края (по умолчанию используется выравнивае справа).
- + : если выводимое значение имеет знак (+ или -), то оно выводится. Без данного флага знак выводится только в случае отрицательного значения.
- пробел : вставляет пробел на месте знака перед положительными числами
- # : при использовании со спецификаторами «o», «x», «X» значение числа выводится с предшествующими символами 0, 0x или 0X. При использовании со спецификаторами «f», «g», «G» десятичная точка будет выводиться, даже если в числе нет дробной части
Пример использования флагов:
#include int main(void)
8 8 +8 010 8.000000 Tom 38 Tom 38
Точность вычислений. Си
Мне нужно, чтобы по завершению программы число было выведено с точностью до 10^(-6) символов. Но возникла проблема. Число не точное.
#include #include int main()
После завершения этой программы выдает значение 30.000002 , хотя должно выдавать 30.000000 (a = 60, r = 10) Я попытался ограничить количество цифр после запятой до 5, но это не помогло.
Отслеживать
13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков
задан 25 сен в 19:39
user561670 user561670
printf(«%.5f» . См. en.cppreference.com/w/c/io/fprintf. А для расчетов используйте double .
25 сен в 19:40
А я что говорил о double ? ideone.com/2CeAW0
25 сен в 19:48
И, кстати, делите на 2. , не на 2 , а то введете нечетное значение и будете удивляться.
25 сен в 19:49
Странная идея вводить a и r целыми.
25 сен в 19:57
Вы хорошо понимаете что делает запись «%d» «%d» ?
25 сен в 19:58
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Семи разрядов точности float не хватает для вашей задачи: 30.000000 — восемь знаков. Используйте double — 16 разрядов.
#include #include // В стандартном C нет константы M_PI, определяем на всякий случай #ifndef M_PI # define M_PI (3.14159265358979323846) #endif int main() < // разумно ввести угол и радиус как вещественные числа // всегда все вещественные вычисления делайте на double // у вас не причин использовать float double a, r; // ввод всегда следует проверять if (scanf("%lf %lf", &a, &r) != 2) < fputs("error\n", stderr); return 1; >// синус нужен два раза, запомним его // все константы в вещественных выражениях с точкой // целочисленное деление свело с ума не одного программиста const double s = sin(a / 2. * (M_PI / 180.)); const double x = r * (1. + s) / (1. - s); // после печати переведите строку // печать вещественных чисел выводит шесть знаков после запятой, // ничего не надо менять printf("%lf\n", x); >
Компилировать лучше на максимуме предупреждений. Компилятор замечает такие огрехи в коде, которые программисту и в голову не придут:
$ gcc -std=c11 -pedantic -Wall -Wextra -Werror -Wwrite-strings -Wconversion temp.c -lm $ echo 60 10 | ./a.out 30.000000
Точность при вычислении
Решаю олимпиадные задачи различного рода, когда работал в Паскале никогда и не задумывался над работой оператора»=» или «>=» в работе с вещественными числами, я думал, что с точностью сравнений и проблем не может быть. Но вот я перешел на C++ и один учитель мне сказал, что «==» или «> = < %.7lf", l); >int main() < freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); scanf("%lf\n", &a); scanf("%d", &n); solve(); return 0; >
Отслеживать
11.3k 5 5 золотых знаков 25 25 серебряных знаков 40 40 бронзовых знаков
задан 13 авг 2012 в 6:36
Евгений536 Евгений536
700 2 2 золотых знака 11 11 серебряных знаков 30 30 бронзовых знаков
не волнуйтесь, вы перешли на новый уровень сложности. скоро у вас будет level up 🙂
13 авг 2012 в 7:53
В Паскале правила игры точно такие же, т.к. все это рано или поздно упирается в IEEE754 (en.wikipedia.org/wiki/IEEE_floating_point)
26 янв 2016 в 7:47
5 ответов 5
Сортировка: Сброс на вариант по умолчанию
Проблема здесь не в «неточном» сравнении аппаратурой процессора, а в том, что некоторые десятичные дроби не могут быть точно преобразованы в двоичный формат чисел с плавающей точкой.
Еще одна проблема заключается в потере младших разрядов мантиссы при вычислениях в циклах.
Отслеживать
ответ дан 13 авг 2012 в 8:23
45.8k 6 6 золотых знаков 46 46 серебряных знаков 115 115 бронзовых знаков
Действительно ничего хорошего из сравнения типа == при операциях с вещественными числами не выйдет. Можно попробовать простой код:
double sum = 0; for ( int i = 0; i++; i
Гарантировать, что в итоге sum будет равным 1 в данном случаи невозможно. Может быть равен, а может и нет. Дело в машинной точности округления мат. операций. И ваш преподаватель все правильно говорит. Сравнение вида
fabs ( 1.0 - sum ) < 0.0000000000000001;
Даст верный результат всегда. ps Число 0.0000000000000001 взял просто так, но поверьте, такая ошибка вычислений очень мала, но все же точного результата ( sum == 1.0 ) вы не получите
Как задать точность в c
Требуется вывести double с максимальной точностью, при этом целую часть, которая не превышает 999 вывести с пробелами на месте отсутствующих цифр, типа 9,12.
Вывожу следующим образом
Возникло 2 проблемы:
1) везде читал, что точность double определяется как std::numeric_limits::digits10 , однако похоже, что можно вытащить больше значащих цифр, если задать точность в 20 цифр, то будут видны все 20 отличных от 0 цифр
2) не нашел, как можно задать размер целой части, чтобы заполнить отсутствующие цифры пробелами
Подскажите, что требуется сделать?
Всё, чего вам не хватало, это задать заполнитель setfill и ширину setw выводимого поля:
Можно также написать класс, с функциональностью выводить как угодно. Например:
И пример программы:
Можно и манипулятор написать, но такой класс, думаю, более полезен в том смысле, что может выдавать целую и дробную части
Во-первых, смысл величины digits10 для плавающего типа T заключается в том, что если вы возьмете десятичное строковое представление, преобразуете его в значение типа T , а затем преобразуете его из T обратно в десятичное строковое представление, то вы получите digits10 значащих цифр цифр, совпадающих с вашей исходной строкой. Например, если вы используете плавающий тип для хранения целых значений, то целые значения с таким количеством цифр будут представляться без потерь, как и соседние (+-1) целые значения.
Родственной величиной является величина max_digits10 , которая говорит, что если вы преобразуете плавающее значение типа T в десятичное строковое представление с сохранением max_digits10 старших значащих цифр, а затем преобразуете его обратно в тип T , то вы гарантированно получите исходное значение типа T .
Таким образом, величина digits10 описывает сохранение данных в преобразовании туда-обратно вида «строка10 -> плавающее -> строка10«. А величина max_digits10 описывает сохранение данных в преобразовании туда-обратно вида «плавающее -> строка10 -> плавающее».
Это, однако, совсем не означает, что десятичное строковое плавающее значение будет иметь только столько точных цифр. Огульно обзывать цифры за пределами этого количества «мусором» — очевидная профанация. Какие цифры являются точными, а какие нет — определяется спецификой ваших вычислений и известно только вам.
Очевидный пример: «традиционные» двоичные плавающие типы способны точно представлять степени двойки в пределах возможностей экспоненты. То есть std::pow(2, 512) даст вам точное значение типа double
в котором намного больше значащих цифр, чем digits10 или max_digits10 для double ( 15 и 17 соответственно). Никакого «мусора» в этом представлении нет (разумеется, если вы хотели вычислить именно 2 512 ) . Вас это не должно удивлять. Умение пользоваться такими возможностями плавающих представлений — это во многом и есть умение пользоваться плавающими типами в общем.
Во-вторых, что касается управления шириной поля при выводе — об этом вы уже получили ответы.
По ходу обсуждения оказалось, что имеет смысл остановиться подробнее на определении точности вещественного типа. Удивительно, но оказывается, что точность 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 «Точность выполнения арифметических действий в системе с плавающей точкой«.
Как увеличить точность double C++?
Пытаюсь сделать одинаковое вычисление с помощью C++ чтобы точность была как в языке Ruby, однако C++ жестче округляет значения а делать round() для каждого прохода не вариант так как чисел после запятой может быть от 1 до 16, что посоветуете?
- Вопрос задан более трёх лет назад
- 5020 просмотров
- Вконтакте
Не совсем корректно поставлен вопрос, тем что тебе нужно — ты понижаешь точность.
У float 23 мантисы, у double 52. Теоритически дабл имеет двухкратную точность в сравнении с float.
Это как понимать?
У тебя может быть до 16 чисел после запятой — это уже сильно округленно. Поставь себе конкретно вопрос — сколько именно чисел после запятой ты хочешь видеть в итоге? На столько и округляй.
Если же отвечать конкретно на формулировку твоего вопроса, а именно «как повысить точность», то 1 из ответов был бы long double
tolstiyman
Для начала установим режим вывода с фиксированной точкой, что делается модификатором std::fixed. Затем, с помощью модификатора std::setprecision(n), устанавливаем точность вывода n. Для работы последнего модификатора необходимо подключить заголовочный файл iomanip. Таким образом код будет выглядеть приблизительно так:
Или, чтобы не писать постоянно «std::«, так:
Почему в C++ для double в числе только 5 цифр после запятой
В языке C++ при определении переменных необходимо указать их тип, причём в дальнейшем тип менять нельзя.
Для числовых переменных распространёнными типами являются int, short, long, float и double.
К примеру, переменная с типом данных float — это число с плавающей точкой, для хранения которого используется 4 байта, а это 6-9 значимых цифр, обычно 7.
А переменная с типом данных double — это число с плавающей точкой, для хранения которого используется 8 байт, а это примерно 15-18 значимых цифр, обычно 16.
Зная это, рассмотрим следующий простейший код — для его выполнения, сохраните код в файл test.cpp:
Теперь скомпилируйте его:
Результат выполнения очень необычен:

Число 230.4732 обрезано до 230.473 — потерян одна цифра после запятой. А в числе типа double, значение которого 30949.12345678, обрезалось до 30949.1 — то есть вместо предполагаемых 15-18 значимых цифр получено только 6…
Отсюда возникает вопрос, почему в числе типа double можно использовать только 6 значимых цифр?
На самом деле, число double d содержит все цифры после запятой, которые присвоены этой переменной — всё дело в том, как выполняется проверка числа. У метода cout имеются свои настройки по умолчанию для вывода и форматирования чисел — если в числе больше 6 разрядов, то обрезаются цифры после запятой, если до запятой также больше 6 цифр, то используется научная запись числа, например 1.23457e+14.
Такое поведение по умолчанию cout можно исправить. Для этого, во-первых, необходимо добавить новый заголовок #include .
Во-вторых нужно использовать std::setprecision(n), где n — это новая величина точности.
При использовании в выражении out или in >> setprecision(n) устанавливает для параметра точности потока out или in значение ровное n.
Отредактирует код нашей программы:
Заново скомпилируем и выполним его. Результат:
Именно этот результат мы и ожидали:

Отметим ещё раз — в самой программе используются все возможные знаки и разряды чисел, цифры обрезались в момент вывода.
