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

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

  • автор:

Типы данных

Вывод действительных чисел на C++ Перед выводом действительных чисел (float, double, long double) следует указать выходному потоку точность вывода. Например:

float x; x = 123.456789; cout.setf(ios::fixed); // вывод в фиксированном формате cout.precision(6); // вывод до 6 знака после точки, включительно cout

Вы используете гостевой доступ (Вход)

Эта страница: General type: incourse. Context Страница: Вывод действительных чисел на C++ (context id 276028). Page type mod-page-view.

c++: задать точность числа при выводе через printf

Подскажите, как задать точность вывода float / double числа через printf ? У меня сейчас вывод выглядит следующим образом:

printf("a: %20.16f, b: %20.16f, c: %20.16f", a, b, c); 

и настроен под точность double , но иногда я использую float числа (для ускорения расчётов) и тогда мне нужна float точность без вывода дополнительных чисел Как корректнее реализовать выбор соответствующей точность? Есть варианты 1) определять тип данных и для каждого типа использовать свой вариант вывода

template void myprint()

2) формировать строку в зависимости от точности

const int prec = std::numeric_limits::digits10 + 1; const std::string format = "%" + std::to_string(4 + prec) + "." + std::to_string(prec); . 

оба варианта с недостатками (во втором как-то приходится правильно сформировать строку $x.y , что требует относительно много кода для такой задачи, а в первом варианте слишком много if придется наставить) как можно оптимальнее разрешить эту проблему?

Тип с точностью до 4 знаков C++?

Я знаю, что есть типы данных float, double и long double. Все они могут хранить кучу знаков после запятой, но не могут хранить числа типа 0.03, они будут записаны как 0.02(9). Мне нужна точность в вычислениях, но в то же время мне не нужны 4+ знаки после запятой. Есть ли тип в C++, который может хранить небольшое кол-во знаков после запятой, но без погрешностей?

  • Вопрос задан более года назад
  • 262 просмотра

1 комментарий

Простой 1 комментарий

Есть даже специальные библиотеки, которые позволяют символьные вычисления любого уровня точности, например, NTL https://libntl.org/

И в целом, как уже указали в ответе, ничто немешает реализовать свой кастомный класс с перегруженными операторами.

Решения вопроса 0
Ответы на вопрос 1
Wataru @wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.

Есть. Называется int. Вам надо хранить количество десятитысячных в числе. Иными словами, вы вместо x храните в int x*10000. При выводе делите на 10000 (и установите выводить 4 знака).

Такие числа можно просто складывать и вычитать. При умножении надо будет результат поделить нацело на 10000 (или округлить к ближайшему, делящемуся на 10000 и потом отбросить 4 нуля). При делении — наоборот. Надо сначала домножить числитель на 10000, а потом поделить нацело на знаменатель (возможно стоит подумать об округлении к ближайшему целому).

Upd: И вообще, раз уж разговор о C++, то можно реализовать свой класс. Там можно даже отдельно хранить целую часть и 4 знака после запятой. Если вам встроенной точности int/int64_t не хватает. Все математические операции можно переопределить и работать, как со встроенным типом. Вообще, по-умному, это называется fixed point numbers.

Ответ написан более года назад
Комментировать
Нравится 10 Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

cpp

  • C++
  • +1 ещё

Как исправить ошибку undefined reference to при коспиляции кода с++ в VS?

  • 1 подписчик
  • 18 часов назад
  • 68 просмотров

Точность и точность вычислений с плавающей запятой

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

  1. При вычислении с одной и двойной точностью результат обычно не будет более точным, чем одиночная точность. Если требуется двойная точность, убедитесь, что все термины в вычислении, включая константы, указываются с двойной точностью.
  2. Никогда не предполагайте, что простое числовое значение точно представлено на компьютере. Большинство значений с плавающей запятой нельзя точно представить как конечное двоичное значение. Например, .1 является .0001100110011. двоичным (он повторяется навсегда), поэтому его нельзя представить с полной точностью на компьютере с помощью двоичной арифметики, которая включает все компьютеры.
  3. Никогда не предполагайте, что результат является точным до последней десятичной запятой. Всегда существуют небольшие различия между «истинным» ответом и тем, что можно вычислить с конечной точностью любой единицы обработки с плавающей запятой.
  4. Никогда не сравнивайте два значения с плавающей запятой, чтобы узнать, равны ли они. Это является следствием правила 3. Почти всегда будут небольшие различия между числами, которые «должны» быть равными. Вместо этого всегда проверка, чтобы узнать, являются ли числа почти равными. Иными словами, проверка, чтобы увидеть, мала ли разница между ними или незначительна.

Дополнительные сведения

Как правило, описанные выше правила применяются ко всем языкам, включая C, C++ и ассемблер. В приведенных ниже примерах демонстрируются некоторые правила, использующие FORTRAN PowerStation. Все примеры были скомпилированы с помощью FORTRAN PowerStation 32 без каких-либо параметров, за исключением последнего, написанного на языке C.

Пример 1

В первом примере демонстрируются две вещи:

  • По умолчанию константы FORTRAN имеют одну точность (по умолчанию константы C имеют двойную точность).
  • Вычисления, содержащие какие-либо одноточные термины точности, не намного более точны, чем вычисления, в которых все термины имеют единую точность.

После инициализации с 1.1 (одной константой точности) значение y будет таким же неточным, как и одна переменная точности.

x = 1.100000000000000 y = 1.100000023841858 

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

true = 1.320000000000000 (multiplying 2 double precision values) y = 1.320000052452087 (multiplying a double and a single) z = 1.320000081062318 (multiplying 2 single precision values) 
Пример кода
C Compile options: none real*8 x,y,z x = 1.1D0 y = 1.1 print *, 'x =',x, 'y =', y y = 1.2 * x z = 1.2 * 1.1 print *, x, y, z end 

Пример 2

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

Root = -1.1500000000 

Вместо этого возникает следующая ошибка:

  • sqrt: ошибка ДОМЕНА
Пример кода
C Compile options: none real*8 a,b,c,x,y a=1.0D0 b=2.3D0 c=1.322D0 x = b**2 y = 4*a*c print *,x,y,x-y print "(' Root =',F16.10)",(-b+dsqrt(x-y))/(2*a) end 

Пример 3

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

В этом примере два значения равны и не равны. В первом случае значение Z по-прежнему находится в стеке сопроцессора и имеет ту же точность, что и Y. Таким образом, X не равен Y и выводится первое сообщение. Во время второго if, Z должен был быть загружен из памяти и, следовательно, имел ту же точность и значение, что и X, и второе сообщение также печатается.

Пример кода
C Compile options: none real*8 y y=27.1024D0 x=27.1024 z=y if (x.ne.z) then print *,'X does not equal Z' end if if (x.eq.z) then print *,'X equals Z' end if end 

Пример 4

В первой части примера кода 4 вычисляется наименьшая возможная разница между двумя числами, близкими к 1.0. Это делается путем добавления одного бита в двоичное представление 1.0.

x = 1.00000000000000000 (one bit more than 1.0) y = 1.00000000000000000 (exactly 1.0) x-y = .00000000000000022 (smallest possible difference) 

Некоторые версии FORTRAN округляют числа при их отображении, чтобы присущая числовая точность не была столь очевидной. Поэтому при отображении x и y выглядят одинаково.

Вторая часть примера кода 4 вычисляет наименьшую возможную разницу между двумя числами, близкими к 10,0. Опять же, это делается путем добавления одного бита в двоичное представление 10.0. Обратите внимание, что разница между числами около 10 больше, чем разница рядом с 1. Это демонстрирует общий принцип, согласно которому чем больше абсолютное значение числа, тем менее точно оно может храниться в заданном количестве битов.

x = 10.00000000000000000 (one bit more than 10.0) y = 10.00000000000000000 (exactly 10.0) x-y = .00000000000000178 

Двоичное представление этих чисел также отображается, чтобы показать, что они отличаются только на 1 бит.

x = 4024000000000001 Hex y = 4024000000000000 Hex 

В последней части примера кода 4 показано, что простые неповторяющиеся десятичные значения часто могут быть представлены в двоичном формате только повторяющейся дроби. В этом случае x=1,05, для которого требуется повторяющийся коэффициент CCCCCCCC. (Шестнадцатеричный) в мантиссе. В FORTRAN последняя цифра «C» округляется до «D» для поддержания максимально возможной точности:

x = 3FF0CCCCCCCCCCCD (Hex representation of 1.05D0) 

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

x-1 = .05000000000000004 
Пример кода
C Compile options: none IMPLICIT real*8 (A-Z) integer*4 i(2) real*8 x,y equivalence (i(1),x) x=1. y=x i(1)=i(1)+1 print "(1x,'x =',F20.17,' y=',f20.17)", x,y print "(1x,'x-y=',F20.17)", x-y print * x=10. y=x i(1)=i(1)+1 print "(1x,'x =',F20.17,' y=',f20.17)", x,y print "(1x,'x-y=',F20.17)", x-y print * print "(1x,'x =',Z16,' Hex y=',Z16,' Hex')", x,y print * x=1.05D0 print "(1x,'x =',F20.17)", x print "(1x,'x =',Z16,' Hex')", x x=x-1 print "(1x,'x-1=',F20.17)", x print * end 

Пример 5

В C по умолчанию плавающие константы имеют значение doubles. Используйте «f», чтобы указать значение с плавающей точкой, как в «89,95f».

/* Compile options needed: none */ #include void main() < float floatvar; double doublevar; /* Print double constant. */ printf("89.95 = %f\n", 89.95); // 89.95 = 89.950000 /* Printf float constant */ printf("89.95 = %f\n", 89.95F); // 89.95 = 89.949997 /*** Use double constant. ***/ floatvar = 89.95; doublevar = 89.95; printf("89.95 = %f\n", floatvar); // 89.95 = 89.949997 printf("89.95 = %lf\n", doublevar); // 89.95 = 89.950000 /*** Use float constant. ***/ floatvar = 89.95f; doublevar = 89.95f; printf("89.95 = %f\n", floatvar); // 89.95 = 89.949997 printf("89.95 = %lf\n", doublevar); // 89.95 = 89.949997 >

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

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