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

Как повысить точность в c

  • автор:

Вычисления с повышенной точностью в C#

Здравствуйте! Нужно выполнить вычисления с высокой точностью. Мне не достаточно точности double (15-16 digits), мне нужна точность не мене 18 цифр за запятой, поддерживает ли такую точность какой-нибудь тип данных в C#?
Пробовала использовать Decimal но функция Math.Cos либо не поддерживает этот тип данных, либо я просто не знаю как это реализовать. Может в С# для вычисления Cos можно использовать другую функцию?
Через ряд Тейлора получается с точностью 16 знаков, не больше, а мне этого мало.

static decimal f(decimal x, decimal y)
decimal fx;
fx = 10 * Math.Cos(5 * x) — 2 * y;
return fx;
>

При комплиляции выдается ошибка: Наиболее подходящий перегруженный метод для «System.Math.Cos(double)» имеет несколько недопустимых аргументов.
Применив Math.Cos((double)5*x) возникает ошибка: Оператор «*» не может применяться к операндам типа «double» и «decimal».

4 ответа

15 марта 2010 года
1.2K / / 11.10.2004

Классическая ошибка перемножения яблок на груши. Внимательно посмотрите, какими типами орудуете.

если так, то все работает

static double f(double x, double y)
double fx;
fx = 10 * Math.Cos(5d * x) — 2 * y;
return fx;
>

Кстати, вместо Math.Cos((double)5*x), правильнее написать Math.Cos(5.00d*x)

15 марта 2010 года
4.5K / / 09.08.2005

если так, то все работает

Но становится бессмысленным использование типа decimal.

15 марта 2010 года
1.2K / / 11.10.2004
Но становится бессмысленным использование типа decimal.

Вот так всегда, моя невнимательность меня губит:)
Не прочел первую часть вопроса.

В любом случае, стандартную функцию Math.Cos напрямую для типа decimal использовать не получится.

При конвертации всеравно точность потеряется.

fx = 10m * (decimal)Math.Cos(5d * (double)x) — 2m * y;

А вообще, я тут почитал это

И получил нечто похожее на то, что нужно автору

using System;
using System.Globalization;

namespace Test
class Program

static void Main(string[] args)
double i = 1, j = 3d;

Console.WriteLine(f(i, j).ToString(«E50», CultureInfo.InvariantCulture));

Console.Write(«\nPress any key to exit»);
Console.ReadKey();
>

static double f(double x, double y)
double fx;
fx = 10d * Math.Cos(5d * x) — 2d * y;
return fx;
>
>
>

31 марта 2010 года
301 / / 16.09.2008

Здравствуйте! Нужно выполнить вычисления с высокой точностью. Мне не достаточно точности double (15-16 digits), мне нужна точность не мене 18 цифр за запятой, поддерживает ли такую точность какой-нибудь тип данных в C#?
Пробовала использовать Decimal но функция Math.Cos либо не поддерживает этот тип данных, либо я просто не знаю как это реализовать. Может в С# для вычисления Cos можно использовать другую функцию?
Через ряд Тейлора получается с точностью 16 знаков, не больше, а мне этого мало.

C# не предполагает высокоточных вычислений. И вообще машинная погрешность в операциях * / ^ над числами с плавающей точкой дает такую погрешность, что смысла расширять точность double еще на несколько цифр просто нет.
А decimal внутри состоит из 2х int64 )))

Хотите высокую точность — используйте либо лучше всего — символьные пакеты, либо как минимум — дробный тип данных )))

Как увеличить точность double C++?

Пытаюсь сделать одинаковое вычисление с помощью C++ чтобы точность была как в языке Ruby, однако C++ жестче округляет значения а делать round() для каждого прохода не вариант так как чисел после запятой может быть от 1 до 16, что посоветуете?

a = 3.2 b = 4.2 p = 8.3 puts ((a+b) * (p / 100)) # 0.6142000000000001
#include #include using namespace std; int main(void) < long double a = 3.2; long double b = 4.2; long double p = 8.3; cout 
a = 9.809999999999999 b = 11.1 p = 8.3 puts ((a+b) * (p / 100)) # 1.7355299999999998
#include #include using namespace std; int main(void) < long double a = 9.809999999999999; long double b = 11.1; long double p = 8.3; cout 
  • Вопрос задан более трёх лет назад
  • 5726 просмотров

Комментировать
Решения вопроса 0
Ответы на вопрос 1

Therapyx

Data Science

Не совсем корректно поставлен вопрос, тем что тебе нужно - ты понижаешь точность.
У float 23 мантисы, у double 52. Теоритически дабл имеет двухкратную точность в сравнении с float.

C++ жестче округляет значения

Это как понимать?

У тебя может быть до 16 чисел после запятой - это уже сильно округленно. Поставь себе конкретно вопрос - сколько именно чисел после запятой ты хочешь видеть в итоге? На столько и округляй.
Если же отвечать конкретно на формулировку твоего вопроса, а именно "как повысить точность", то 1 из ответов был бы long double

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

где P , Q , T - константы. У этого выражения есть особенность: при s==1 получаем 0 в знаменателе. Однако, при abs(s-1)

C(s->1, t) = P + Q*(1 - t/T) (2) 

Собственно мой вопрос: как максимально точно посчитать выражение (1) в окрестностях, близких к s==1 ? Использовать его непосредственно в виде (1), или лучше как-то преобразовать его? Например в форме (3):

C(s,t) = P + Q*((s - pow(s,t/T)/(s - 1))/pow(s,t/T) (3) 

В последнем случае, чем ближе знаменатель к нулю, тем ближе и числитель к нулю, а значит, интуитивно полагаю, погрешность вычислений должна быть меньше, чем если считать по формуле (1). Но я в этом не уверен, по-этому решил спросить совета. Просьба к математикам и продвинутым знатокам FPU не судить меня строго и не спешить минусовать.

Отслеживать
задан 22 авг 2021 в 18:01
2,157 5 5 серебряных знаков 10 10 бронзовых знаков

Почему бы не разложить (1) в рад Тэйлора, относительно (s-1). Или интересует не только окрестность точки s==1?

22 авг 2021 в 18:34

@Chorkov Да, интересует не только окрестность точки s==1 , а вся полуось s>0 . Для значений abs(s-1)
22 авг 2021 в 18:42

s2 -> (s - 1) , p - q/s2 + (q + q/s2)/((1+s2)^(t/T)) , lim s2 -> 0 => p - q/s2 + (q + q/s2)/(1+s2*(t/T))

22 авг 2021 в 19:57

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Это не ответ, а расширенный комментарий.

Вы уверены, что вам нужна "точная" формула? Я тут прикинул, разложив функцию возведения в степень в ряд Тейлора.

Ваша функция представляется таким рядом:

введите сюда описание изображения

введите сюда описание изображения

Здесь в скобках стоит обобщённый биномиальный коэффициент:

Это разложение сходится при |s-1| < 1

Я сделал прототип на Python

P=2.0 Q=1.0 T=1.0 def C(s,t): return P - Q/(s-1) + (Q + Q/(s-1))/pow(s,t/T) # Обобщённый биномиальный коэффициент def binom(a,n): res = 1 for k in range(1,n+1): res *= (a-k+1)/k return res # Вычисление разложением в ряд. По умолчанию ряд вычисляется до 4 степени def C2(s,t, n=4): d = s - 1 f = 0 for i in range(1,n+1): f += binom(-t/T, i)*(d**(i-1)) return P + Q + Q*(1+d)*f # Сравнение исходной формулы и разложения в ряд до 20 степени (оверкил) # Перебираем epsilon от 0.1 до 1e-14 for p in range(1, 15): s = 1+pow(10,-p) c1 = C(s,0.5) c2 = C2(s,0.5, n=20) print(f"e = 1e-

: s = , c1 = , c2 = , abs(c2-c1) = ")

Вот что получилось

e = 1e-1: c1 = 2.4880884817015154, c2 = 2.4880884817015154, abs(c2-c1) = 0.0 e = 1e-2: c1 = 2.4987562112089137, c2 = 2.4987562112089026, abs(c2-c1) = 1.1102230246251565e-14 e = 1e-3: c1 = 2.4998750624608874, c2 = 2.4998750624609647, abs(c2-c1) = 7.72715225139109e-14 e = 1e-4: c1 = 2.4999875006251386, c2 = 2.499987500624961, abs(c2-c1) = 1.7763568394002505e-13 e = 1e-5: c1 = 2.4999987500195857, c2 = 2.4999987500062497, abs(c2-c1) = 1.333599897179738e-11 e = 1e-6: c1 = 2.499999874853529, c2 = 2.4999998750000625, abs(c2-c1) = 1.4653345203896606e-10 e = 1e-7: c1 = 2.499999986961484, c2 = 2.4999999875000007, abs(c2-c1) = 5.385167867189011e-10 e = 1e-8: c1 = 2.5, c2 = 2.49999999875, abs(c2-c1) = 1.2500001034254637e-09 e = 1e-9: c1 = 2.5, c2 = 2.499999999875, abs(c2-c1) = 1.2500001034254637e-10 e = 1e-10: c1 = 2.5, c2 = 2.4999999999874998, abs(c2-c1) = 1.2500223078859563e-11 e = 1e-11: c1 = 2.5, c2 = 2.49999999999875, abs(c2-c1) = 1.2501111257279263e-12 e = 1e-12: c1 = 2.5, c2 = 2.4999999999998748, abs(c2-c1) = 1.2523315717771766e-13 e = 1e-13: c1 = 2.5, c2 = 2.4999999999999876, abs(c2-c1) = 1.2434497875801753e-14 e = 1e-14: c1 = 2.515625, c2 = 2.4999999999999987, abs(c2-c1) = 0.015625000000001332 

Видно, что почти для всех эпсилонов расхождение между исходной формулой и разложением в ряд не хуже чем 1e-9

Заметная разница только для 1e-14 , но это и так предел точности представления вещественных чисел в double .

Если для вас точность девять знаков после запятой достаточна, то не парьтесь с приблизительной формулой.

UPD: сравнение с приближённой формулой

Сравнил приближённую формулу C(s->1, t) = P + Q*(1 - t/T) с результатом разложения в ряд. В выводе ниже c2 результат разложения в ряд, c3 - значение приближенной формулы.

e = 1e-1: c3 = 2.5, c2 = 2.4880884817015154, abs(c2-c3) = 0.01191151829848458 e = 1e-2: c3 = 2.5, c2 = 2.4987562112089026, abs(c2-c3) = 0.0012437887910974332 e = 1e-3: c3 = 2.5, c2 = 2.4998750624609647, abs(c2-c3) = 0.00012493753903530802 e = 1e-4: c3 = 2.5, c2 = 2.499987500624961, abs(c2-c3) = 1.2499375038999005e-05 e = 1e-5: c3 = 2.5, c2 = 2.4999987500062497, abs(c2-c3) = 1.2499937502852276e-06 e = 1e-6: c3 = 2.5, c2 = 2.4999998750000625, abs(c2-c3) = 1.2499993751191596e-07 e = 1e-7: c3 = 2.5, c2 = 2.4999999875000007, abs(c2-c3) = 1.2499999257897798e-08 e = 1e-8: c3 = 2.5, c2 = 2.49999999875, abs(c2-c3) = 1.2500001034254637e-09 e = 1e-9: c3 = 2.5, c2 = 2.499999999875, abs(c2-c3) = 1.2500001034254637e-10 e = 1e-10: c3 = 2.5, c2 = 2.4999999999874998, abs(c2-c3) = 1.2500223078859563e-11 e = 1e-11: c3 = 2.5, c2 = 2.49999999999875, abs(c2-c3) = 1.2501111257279263e-12 e = 1e-12: c3 = 2.5, c2 = 2.4999999999998748, abs(c2-c3) = 1.2523315717771766e-13 e = 1e-13: c3 = 2.5, c2 = 2.4999999999999876, abs(c2-c3) = 1.2434497875801753e-14 e = 1e-14: c3 = 2.5, c2 = 2.4999999999999987, abs(c2-c3) = 1.3322676295501878e-15 

Получается, что ошибки округления начинают сказываться только для epsilon порядка 1e-14 , а при выбранной вами точности 0.00001 ошибка приближенной формулы на пять порядков хуже, чем у точной. Поэтому я могу лишь повторить "посыл" - не беспокойтесь о потери точности из-за малости отклонения от 1.

Как повысить точность вещественного деления в среде C++?

При реализации логики калькулятора на языке С++ столкнулся с различием в точности с референсом.
В качестве референса был использован стандартный win32 (не UWP) калькулятор Windows 7 / 10.

Пример: деление 100 на 6.
Калькулятор Windows: 16,66666666666667
Стандартные средства C++: 16,6667

Использовалось и приведение и объявление double и long doule.

Вопрос: Какие есть методы приведение в эквивалентную точность в рамках стандартной библиотеки?

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

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

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