Как задать точность в c
Перейти к содержимому

Как задать точность в c

Точность чисел с плавающей точкой в C ++ (floor (), ceil (), trunc (), round () и setprecision ())

Десятичный эквивалент 1/3 равен 0,33333333333333…. Число бесконечной длины потребовало бы бесконечной памяти для хранения, и у нас обычно есть 4 или 8 байтов. Следовательно, числа с плавающей запятой хранят только определенное количество значащих цифр, а остальные теряются. Точность числа с плавающей запятой определяет, сколько значащих цифр оно может представлять без потери информации. При выводе чисел с плавающей запятой, cout имеет точность по умолчанию, равную 6, и после этого усекает все, что угодно.

Ниже приведены несколько библиотек и методов, которые используются для обеспечения точности чисел с плавающей запятой в C ++:

пол():
Этаж округляет заданное значение до ближайшего целого числа, которое меньше заданного значения.

// C ++ программа для демонстрации работы floor ()
// в C / C ++
#include<bits/stdc++.h>

using namespace std;

double x =1.411, y =1.500, z =1.711;

double a =-1.411, b =-1.500, c =-1.611;

CEIL ():
Ceil округляет заданное значение до ближайшего целого числа, которое больше заданного значения.

// C ++ программа для демонстрации работы ceil ()
// в C / C ++
#include<bits/stdc++.h>

using namespace std;

double x = 1.411, y = 1.500, z = 1.611;

double a = -1.411, b = -1.500, c = -1.611;

TRUNC ():
Trunc round удаляет цифры после десятичной точки.

// C ++ программа для демонстрации работы trunc ()
// в C / C ++
#include<bits/stdc++.h>

using namespace std;

double x = 1.411, y = 1.500, z = 1.611;

double a = -1.411, b = -1.500, c = -1.611;

круглый():
Округляет заданное число до ближайшего целого числа.

// C ++ программа для демонстрации работы round ()
// в C / C ++
#include<bits/stdc++.h>

using namespace std;

double x = 1.411, y = 1.500, z = 1.611;

double a = -1.411, b = -1.500, c = -1.611;

setprecision ():
Setprecision при использовании вместе с «fixed» обеспечивает точность чисел с плавающей запятой, соответствующих десятичным числам, указанным в скобках setprecison.

// C ++ программа для демонстрации работы setprecision ()
// в C / C ++
#include<bits/stdc++.h>

using namespace std;

double pi = 3.14159, npi = -3.14159;

Примечание. Если значение, указанное в setprecision (), превышает количество цифр с плавающей запятой в исходном числе, то 0 добавляется к цифре с плавающей запятой, чтобы соответствовать точности, указанной пользователем.

Существуют и другие методы для обеспечения точности чисел с плавающей запятой. Вышеупомянутые являются немногими из наиболее часто используемых методов для обеспечения точности чисел с плавающей запятой во время конкурентного кодирования.

Эта статья предоставлена Адитьей Гуптой . Если вы как GeeksforGeeks и хотели бы внести свой вклад, вы также можете написать статью с помощью contribute.geeksforgeeks.org или по почте статьи contribute@geeksforgeeks.org. Смотрите свою статью, появляющуюся на главной странице GeeksforGeeks, и помогите другим вундеркиндам.

Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.

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

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

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

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

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

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

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

user avatar

user avatar

Всё, чего вам не хватало, это задать заполнитель setfill и ширину setw выводимого поля:

user avatar

Можно также написать класс, с функциональностью выводить как угодно. Например:

И пример программы:

Можно и манипулятор написать, но такой класс, думаю, более полезен в том смысле, что может выдавать целую и дробную части

user avatar

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

Math. Round Метод

Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

Округляет значение до ближайшего целого или указанного количества десятичных знаков.

Перегрузки

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

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

Округляет значение с плавающей запятой двойной точности до целого числа, используя указанное соглашение округления.

Округляет значение с плавающей запятой двойной точности до указанного числа знаков после запятой; значения посередине округляются до ближайшего четного числа.

Округляет десятичное значение до указанного числа знаков после запятой; значения посередине округляются до ближайшего четного числа.

Округляет значение с плавающей запятой двойной точности до ближайшего целого значения; значения посередине округляются до ближайшего четного числа.

Округляет десятичное значение до ближайшего целого значения; значения посередине округляются до ближайшего четного числа.

Округляет десятичное значение целым числом, используя указанное соглашение округления.

Примеры

В дополнение к примерам в разделе "Примечания" в этой статье приведены примеры, иллюстрирующие следующие перегрузки Math.Round метода:

Комментарии

Какой метод вызывается?

Для выбора подходящего метода округления можно использовать следующую таблицу. Math.Round Помимо методов, он также включает Math.Ceiling и Math.Floor.

Кому Вызов
Округление числа до целого числа с помощью соглашения округления до ближайшего. Round(Decimal)
-или-
Round(Double)
Округление числа до целого числа с помощью указанного соглашения округления. Round(Decimal, MidpointRounding)
-или-
Round(Double, MidpointRounding)
Округление числа до указанного числа дробных цифр с помощью округления до ближайшего соглашения. Round(Decimal, Int32)
-или-
Round(Double, Int32)
Округление числа до указанного числа дробных цифр с помощью указанного соглашения округления. Round(Decimal, Int32, MidpointRounding)
-или-
Round(Double, Int32, MidpointRounding)
Single Округление значения до указанного числа дробных цифр с помощью указанного соглашения округления и минимизации потери точности. Преобразуйте Single объект в Decimal объект и вызов Round(Decimal, Int32, MidpointRounding).
Округление числа до указанного числа дробных цифр при минимизации проблем точности в округляющих средних значениях. Вызовите метод округления, реализующий сравнение "больше или приблизительно равно". См. округление и точность.
Округление дробного значения до целого числа, превышающего дробное значение. Например, округление от 3,1 до 4. Ceiling
Округление дробного значения до целого числа, которое меньше дробного значения. Например, округление от 3,9 до 3. Floor

Средние значения и соглашения округления

Округление включает преобразование числового значения с указанной точностью в значение с меньшей точностью. Например, метод можно использовать для Round(Double) округления значения от 3,4 до 3,0, а Round(Double, Int32) метод округляет значение 3,579 до 3,58.

В среднем значении значение после наименьшей значительной цифры в результате составляет ровно половину пути между двумя числами. Например, 3,47500 — это среднее значение, если оно округляется до двух десятичных разрядов, а 7,500 — это среднее значение, если оно округляется до целого числа. В таких случаях, если используется стратегия округления до ближайшего, ближайшее значение не может быть легко идентифицировано без соглашения округления.

Этот Round метод поддерживает два соглашения округления для обработки значений среднего уровня:

Округление от нуля

Значения среднего уровня округляются до следующего числа от нуля. Например, 3,75 округляется до 3,8, 3,85 округляется до 3,9, -3,75 округляется до -3,8 и -3,85 округляется до -3,9. Эта форма округления представлена элементом MidpointRounding.AwayFromZero перечисления.

Округление до ближайшей четной или округления банкира

Значения среднего уровня округляются до ближайшего четного числа. Например, как 3,75, так и 3,85 округления до 3,8 и -3,75 и -3,85 округления до -3,8. Эта форма округления представлена элементом MidpointRounding.ToEven перечисления.

В .NET Core 3.0 и более поздних версиях через перечисление доступны MidpointRounding три дополнительные стратегии округления. Эти стратегии используются во всех случаях, а не только для значений среднего уровня как MidpointRounding.ToEven и MidpointRounding.AwayFromZero являются.

Округление от нуля является наиболее широко известной формой округления, а округление до ближайшего даже является стандартом в финансовых и статистических операциях. Он соответствует стандарту IEEE 754, раздел 4. При использовании в нескольких операциях округления округление до ближайшего уменьшает ошибку округления, которая вызвана последовательно округляющими значениями средней точки в одном направлении. В некоторых случаях эта ошибка округления может быть значительной.

В следующем примере показана предвзятость, которая может быть результатом последовательного округления значений средней точки в одном направлении. В примере вычисляется истинное среднее значение массива значений Decimal , а затем вычисляется среднее значение, если значения в массиве округляются с помощью двух соглашений. В этом примере истинное среднее значение и среднее значение, что результаты при округлениях до ближайшего совпадают. Тем не менее, это означает, что результаты при округлениях от нуля отличаются на 05 (или на 3,6%) от истинного среднего.

По умолчанию Round метод использует округление до ближайшего четного соглашения. В следующей таблице перечислены перегрузки Round метода и соглашения округления, которые используются каждым из них.

Перегрузка Соглашение округления
Round(Decimal) ToEven
Round(Double) ToEven
Round(Decimal, Int32) ToEven
Round(Double, Int32) ToEven
Round(Decimal, MidpointRounding) Определяется параметром mode .
Round(Double, MidpointRounding) Определяется параметром mode
Round(Decimal, Int32, MidpointRounding) Определяется параметром mode
Round(Double, Int32, MidpointRounding) Определяется параметром mode

Округление и точность

Чтобы определить, связана ли операция округления со средним значением, Round метод умножает исходное значение на округление на 10n , где n — требуемое число дробных цифр в возвращаемом значении, а затем определяет, больше ли оставшаяся дробная часть значения больше или равна 5. Это небольшой вариант теста на равенство, и, как описано в разделе "Тестирование на равенство" в справочном разделе Double , тесты на равенство со значениями с плавающей запятой являются проблемными из-за проблем формата с плавающей запятой с двоичным представлением и точностью. Это означает, что любая дробная часть числа, которая немного меньше 5 (из-за потери точности), не округляется вверх.

В следующем примере показана эта проблема. Он неоднократно добавляет .1 к 11,0 и округляет результат до ближайшего целого числа. 11,5 должен округляется до 12, используя одно из соглашений о округлениях по середине ( ToEven или AwayFromZero ). Однако, как показано в выходных данных из примера, это не так. В примере используется строка стандартного числового формата R для отображения полной точности значения с плавающей запятой и показывает, что значение, которое нужно округить, потеряло точность во время повторяющихся добавлений, а его значение фактически равно 11,49999999999998. Так как .499999999999998 меньше 5, соглашения по середине округления не вступают в игру, и значение округляется вниз. Как показано в примере, эта проблема не возникает при назначении константного значения 11,5 переменной Double .

Проблемы точности округления значений среднего уровня, скорее всего, возникают в следующих условиях:

Если дробное значение не может быть выражено точно в двоичном формате типа с плавающей запятой.

Если округление значения вычисляется из одной или нескольких операций с плавающей запятой.

Если значение, которое должно быть округлено, является Single а не значением Double или Decimal. Дополнительные сведения см. в следующем разделе: округление и одноточие с плавающей запятой.

В тех случаях, когда отсутствие точности в операциях округления проблематично, можно сделать следующее:

Если операция округления вызывает перегрузку, округляющую Double значение, можно изменить Double значение Decimal и вызвать перегрузку, округляющую Decimal значение. Decimal Хотя тип данных также имеет проблемы с представлением и потерей точности, эти проблемы гораздо менее распространены.

Определите пользовательский алгоритм округления, выполняющий тест "почти равно", чтобы определить, является ли значение округлением приемлемо близко к среднему значению. В следующем примере определяется RoundApproximate метод, который проверяет, достаточно ли дробное значение достаточно близко к среднему значению для округления среднего уровня. Как показано в выходных данных из примера, она исправляет проблему округления, показанную в предыдущем примере.

Округление и одноточие с плавающей запятой

Этот Round метод включает перегрузки, принимаюющие аргументы типа Decimal и Double. Нет методов, которые округляют значения типа Single. Если передать Single значение в одну из перегрузок Round метода, он приводится (в C#) или преобразуется (в Visual Basic) в объектDouble, и вызывается соответствующая Round перегрузка с параметромDouble. Хотя это расширение преобразования, оно часто включает потерю точности, как показано в следующем примере. Single Если значение 16,325 передается методу Round и округляется до двух десятичных разрядов с помощью округления до ближайшего соглашения, результат равен 16,33, а не ожидаемому результату 16,32.

Этот непредвиденный результат связан с потерей точности при преобразовании Single значения в значение Double. Поскольку полученное Double значение 16,325000762939453 не является средним значением и больше 16,325, оно всегда округляется вверх.

Во многих случаях, как показано в примере, потеря точности может быть свернута или устранена путем приведения или преобразования Single значения в значение Decimal. Обратите внимание, что, поскольку это сужающее преобразование, он требует использования оператора приведения или вызова метода преобразования.

Round(Double, Int32, MidpointRounding)

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

Параметры

Округляемое число двойной точности с плавающей запятой.

Количество дробных разрядов в возвращаемом значении.

Одно из значений перечисления, указывающее, какую стратегию округления следует использовать.

Возвращаемое значение

Число с digits дробными цифрами, value до которых округляется. Если value имеет меньшее количество цифр дробной части, чем digits , то value возвращается без изменений.

Исключения

Параметр digits имеет значение меньше 0 или больше 15.

mode не является допустимым значением MidpointRounding.

Комментарии

Значение аргумента digits может варьироваться от 0 до 15. Максимальное число целочисленных и дробных цифр, поддерживаемых типом Double , равно 15.

Сведения о округлениях чисел со средними значениями см. в разделе " Средние значения" и соглашения округления .

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

Если аргумент имеет Double.NaNзначение value , метод возвращает .Double.NaN Если value значение равно Double.PositiveInfinity или Double.NegativeInfinity, метод возвращает Double.PositiveInfinity или Double.NegativeInfinityсоответственно.

Пример

В следующем примере показано, как использовать Round(Double, Int32, MidpointRounding) метод с перечислением MidpointRounding .

Примечания для тех, кто вызывает этот метод

Из-за потери точности, которая может привести к представлению десятичных значений в виде чисел с плавающей запятой или выполнению арифметических операций со значениями с плавающей запятой, в некоторых случаях Round(Double, Int32, MidpointRounding) метод может не округлить значения в середине точки, как указано в параметре mode . Это показано в следующем примере, где 2.135 округляется до 2,13 вместо 2,14. Это происходит потому, что внутри метода умножается value на 10digits , а операция умножения в этом случае страдает от потери точности.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *