2 / 2 / 1
Регистрация: 30.06.2021
Сообщений: 31

Где теряется точность?

04.09.2022, 20:40. Показов 3671. Ответов 23

Студворк — интернет-сервис помощи студентам
Здравствуйте, сразу к делу:

C
1
2
3
4
5
6
7
8
9
10
11
12
double x;
double z;
printf("Input x: ");
scanf("%lf",&x);
if(x<=0){
        z=0;
    }else if(x<0||x<=1){
        z=pow(x,2)-x;
    }else{
        z=pow(x,2)-(sin(M_PI*pow(x,2)));
    }
printf("If x=%lf, then z=%lf\n",x,z);
Вводим x=7 и получаем ответ: z=49.0000

А если написать так:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
double x;
double z;
float y;
printf("Input x: ");
scanf("%lf",&x);
y=M_PI*pow(x,2);
if(x<=0){
        z=0;
    }else if(x<0||x<=1){
        z=pow(x,2)-x;
    }else{
        z=pow(x,2)-(sin(y));
    }
printf("If x=%lf, then z=%lf\n",x,z);
Вводим x=7 и получаем ответ: z=48.999994
причём, если 'y' сделать double, опять получаем округление до 49.0000
Где теряется точность?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
04.09.2022, 20:40
Ответы с готовыми решениями:

Теряется точность
Видимо в этой проге теряетмя точность. Не проходит только 1 тест. #include &lt;iostream&gt; #include &lt;iomanip&gt; using...

Куда теряется точность?
Для примера, есть формула (a+b)3 - a3. В расчетах с хранением промежуточных результатов и без него получаются разные ответы. #include...

Теряется точность в сравнении с exel
Точность измерений на С++ меньше чем на exel. Нужно это исправить. Код проги #include &lt;iostream&gt; #include &lt;cmath&gt; ...

23
599 / 421 / 137
Регистрация: 02.10.2008
Сообщений: 1,798
Записей в блоге: 1
08.09.2022, 10:51
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от мама Стифлера Посмотреть сообщение
Или его процессор, получается вычисляет более точно.
Проц - это вряд ли.
Много зависит от реализации printf()
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
 Аватар для easybudda
12843 / 7592 / 1766
Регистрация: 25.07.2009
Сообщений: 13,981
08.09.2022, 14:48
Цитата Сообщение от drfaust Посмотреть сообщение
Много зависит от реализации printf()
мама Стифлера, ну да, скорее всего. У меня на довольно древнем компе с более другой (как любит говорить один форумчанин) ОС и gcc, и clang выдают ровно такой же результат, какой получился на относительно новом компе с вин 10 и компилятором cl от последней студии.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
[andrew@srv /usr/home/andrew/prog/c/num]$ gcc -Wall 0501.c 
[andrew@srv /usr/home/andrew/prog/c/num]$ ./a.out 
a = 0.50000000000000000000
b = 0.10000000000000000555
c = 0.50000000000000000000
d = 0.10000000149011611938
[andrew@srv /usr/home/andrew/prog/c/num]$ uname -sr
FreeBSD 13.0-RELEASE-p11
[andrew@srv /usr/home/andrew/prog/c/num]$ sysctl hw.model
hw.model: Pentium(R) Dual-Core  CPU      E5500  @ 2.80GHz
[andrew@srv /usr/home/andrew/prog/c/num]$ gcc -dumpversion
11.3.0
[andrew@srv /usr/home/andrew/prog/c/num]$
Видимо, разработчики вашего
Цитата Сообщение от мама Стифлера Посмотреть сообщение
TDM-GCC
посчитали, что 17 знаков после запятой "за глаза" всем хватит...
0
Нарушающий
417 / 305 / 46
Регистрация: 13.04.2022
Сообщений: 1,759
09.09.2022, 20:38
Вспомнил про эту тему, вот мои результаты (gcc/linux, Float, Double, Long double):
Адрес байтов растет влево.
Code
1
2
3
4
5
6
7
8
// для присваивания 0.5
f: 3f 00 00 00
d: 3f e0 00 00 00 00 00 00
l: 00 00 55 cf 53 0b 3f fe 80 00 00 00 00 00 00 00
// для присваивания 0.1 (присваивание для long double требует константы правильного типа, 0.1 не прокатит)
f: 3d cc cc cd
d: 3f b9 99 99 99 99 99 9a
l: 00 00 55 84 d9 19 3f fb cc cc cc cc cc cc cc cd
99 и cc соответствуют повтору битов 1100, представляющих бесконечную двоичную дробь для числа 0.6 представленного в мантиссе согласно представлению IEEE. (1.6B-4, единица не хранится).
0.6 в двоичном это 0.(1001). В зависимости от границы байта это может быть 0х33, 0х66, 0х99 или 0xcc

Во всех случаях выше округление правильно выполняется вверх, поэтому погрешность для 0.1 тоже вверх.
Погрешность для представления 0.1 равна значению нижнего бита мантиссы, минус отброшенный остаток.
Float мантисса 23 бита, -100 1100 1101, значение нижнего бита 2-23, экспонента 2-4, т.е. 2-27.
Величина отброшенного хвоста 1100 1100... начиная с 24 бита это 1.6*2-24, и экспонента 2-4, всего 1.6*2-28.

Разница между двумя: 0.4*2-28, или 0.000000001490116119384765625, десятичная дробь конечной длины.
Если написать printf() очень аккуратно, то printf( "%.30f", (float)0.1 ) должен вывести 0.100000001490116119384765625000.

У меня ровно столько и выводит.

Если кому-то интересно поиграться, код ниже.

Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
 
#define DUMP(x) for( int i = (printf( "%s: ", #x ), sizeof( x )) ; i-- ; ) \
                    printf( i ? "%02x " : "%02x\n", ((const unsigned char*)&(x))[i] )
 
int main()
{
  float  f = 0.1;
  double d = 0.1;
  long double l = 0.1l;
 
  DUMP( f );
  DUMP( d );
  DUMP( l );
 
  printf( "0.000000001490116119384765625--\n%.30f\n", (float)0.1 );
 
  return 0;
}
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13215 / 6847 / 1826
Регистрация: 18.10.2014
Сообщений: 17,343
10.09.2022, 20:00
Лучший ответ Сообщение было отмечено Zicrys как решение

Решение

Цитата Сообщение от Zicrys Посмотреть сообщение
Где теряется точность?
Потеря точности при таком изменении кода происходит/может происходить как минимум под двум причинам:

1. Использование float в качестве промежуточного типа, в то время как с точки зрения языка все выражение вычисляется в типе double. Это приводит к "огрублению" промежуточного результата. Об этом вам уже рассказали.

2. Сам факт выноса подвыражения M_PI*pow(x,2) из целого выражения pow(x,2)-sin(M_PI*pow(x,2)), даже (!) если бы промежуточный результат сохранялся в типе double, то есть даже если бы с тривиальной точки зрения потери точности "не могло быть".

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

Будет ли иметь место этот эффект зависит от используемой реализацией модели плавающих вычислений. Мы все прекрасно помним это явление, когда плавающие вычисления на платформе x86 выполнялись средствами FPU. С переходом на использование SSE2 это явление становится менее актуальным.

Другими словами, даже при использовании "правильных" типов

C
1
2
3
4
double a, b, c, d;
...
double x = a * b + c / d;
double y1 = a * b, y2 = c / d, y = y1 + y2;
финальные значения (x и y в примере) могут быть разными (см. FP_CONTRACT).
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
10.09.2022, 20:00

Теряется точность переменной типа double
Вот код: double StepC = 0.001, g_C; for ( double c = StepC; c &lt;= 3; c += StepC ) { //...

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

Умножение преобразованием Фурье. Теряется точность
Добрый день ребятки. У кого есть какие мысли? Поделитесь. Само преобразование Фурье: #define K2PI...

Где то теряется post
Всем привет. Есть форма: &lt;form method=&quot;post&quot; action=&quot;http://localhost/wp-login.php&quot; id=&quot;loginform&quot; name=&quot;loginform&quot;&gt; &lt;p&gt; ...

Где теряется кодировка ?
Непонятная проблемка внутри процедуры путь программы в нормальном виде , при передаче в другую процедуру уже кракозябры . где копать ? ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
24
Ответ Создать тему
Опции темы

Новые блоги и статьи
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru