Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 12.05.2016, 14:41   #1
Motoroller
 
Регистрация: 12.05.2016
Сообщений: 5
По умолчанию Поиск решения упражнения по вычислению значения числа pi с помощью бесконечного ряда из книги Дейтелов "Как программировать на C"

Изучаю C по книге Харви и Пола Дейтелов "Как программировать на C", IDE Code::Blocks, OS Win7x64.
В упражнениях для самоконтроля есть такое задание:

Вычислите значение pi с помощью бесконечного ряда pi = 4 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + k.
Выведите таблицу, которая показывает значение pi, аппроксимированное одним членом этого ряда, двумя членами, тремя членами и т.д. Сколько членов этого ряда нужно использовать, прежде чем вы впервые получите 3.14? 3.141? 3.1415? 3.14159?

Написал основу программы:
Код:
#include <stdio.h>
#include <math.h>

int main(void)
{
	int iSign = 1; // значение 0 - знак минус, 1 - знак плюс
	long int liOddNumbers;
	double dPi = 0.0;

	for (liOddNumbers = 1; liOddNumbers <= 2147483647; liOddNumbers += 2)
	{
		if (iSign == 0)
		{
			dPi -= 4 / (double)liOddNumbers;
			iSign = 1;
		}
		else
		{
			dPi += 4 / (double)liOddNumbers;
			iSign = 0;
		}
		...
	}
		return 0;
}
Как реализовать вывод значения ряда, при котором dPi == 3.14, 3.141 и т.д., если в логической операции участвуют данные вещественного типа?

Конструкция if (dPi == 3.14) ... напрямую не работает, т.к. значение dPi каждый раз в цикле будет отличаться от 3.14 и вряд ли когда совпадёт.

Реализация if (fabs(dPi - 3.14) < 0.009999) ... также не даёт желаемого результата, т.к. существует ряд значений dPi, удовлетворяющих условию, но не содержащих в себе 3.14.

Прошу подтолкнуть на правильный алгоритм решения этой задачи.

В процессе поиска решения возник более общий вопрос: как на C осуществляется сравнение данных вещественного типа, какие для этого существуют механизмы?
Motoroller вне форума Ответить с цитированием
Старый 12.05.2016, 14:58   #2
netpolice
Форумчанин
 
Аватар для netpolice
 
Регистрация: 14.02.2013
Сообщений: 222
По умолчанию

А слабо вывести в один столбик номер члена, а во второй значение, и тупо глазками посмотреть... Или задача рассчитать количество членов программно?

Цитата:
Сообщение от Motoroller Посмотреть сообщение

Реализация if (fabs(dPi - 3.14) < 0.009999) ... также не даёт желаемого результата, т.к. существует ряд значений dPi, удовлетворяющих условию, но не содержащих в себе 3.14.
Конечно, тебе нужно искать разницу между Pi(k) и Pi(k-1).... Дальше понятно?

Последний раз редактировалось Аватар; 12.05.2016 в 15:47.
netpolice вне форума Ответить с цитированием
Старый 12.05.2016, 15:43   #3
Motoroller
 
Регистрация: 12.05.2016
Сообщений: 5
По умолчанию

Анализировал вывод так:
...
printf("%ld\t%f\t%f\n", liOddNumbers, dPi, fabs(dPi - 3.14));
...

И так:
...
printf("%ld\t%e\t%e\n", liOddNumbers, dPi, fabs(dPi - 3.14));
...

Значение в списке присутствует, оно очевидно , но как это всё реализовать программно? По какому критерию выделить из списка именно это значение?

Каким образом C-программисты сравнивают две вещественные переменные?
Motoroller вне форума Ответить с цитированием
Старый 12.05.2016, 15:48   #4
Motoroller
 
Регистрация: 12.05.2016
Сообщений: 5
По умолчанию

... тебе нужно искать разницу между Pi(k) и Pi(k-1) ...

Спасибо, есть пища для размышлений.
Motoroller вне форума Ответить с цитированием
Старый 13.05.2016, 04:38   #5
Motoroller
 
Регистрация: 12.05.2016
Сообщений: 5
По умолчанию

Ввёл дополнительную переменную для сохранения предыдущего значения ряда, код получился такой:
Код:
#include <stdio.h>
#include <math.h>

int main(void)
{
    int iSign = 1; // значение 0 - знак минус, 1 - знак плюс
    long int liOddNumbers;
    double dPi = 0.0;
    double dPiPrev = 0.0;

    for (liOddNumbers = 1; liOddNumbers <= 300; liOddNumbers += 2) // 2147483647
    {
        if (iSign == 0)
        {
            dPi -= 4 / (double)liOddNumbers;
            iSign = 1;
        }

        else
        {
            dPi += 4 / (double)liOddNumbers;
             iSign = 0;
        }

        printf("%ld\t%f\t%f\n", liOddNumbers, dPi, fabs(dPi - dPiPrev));
        dPiPrev = dPi;
    }

    return 0;
}
Вывод программы до первого вхождения 3.14:
...
231 3.132972 0.017316
233 3.150140 0.017167
235 3.133118 0.017021
237 3.149996 0.016878
239 3.133259 0.016736
241 3.149857 0.016598
243 3.133396 0.016461
...

Т.е. , 237 ряд даёт значение dPi = 3.149996, разница с предыдущим значением dPi составляет 0.016878.

Какое условие отделит 237 ряд от других значений?
Motoroller вне форума Ответить с цитированием
Старый 13.05.2016, 10:40   #6
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,238
По умолчанию

что-то у меня с вами результаты не сходятся.

я набросал такую программку на Паскале:
Код:
var sum, next, prev : double;
 i,i2,i3,i4,i5:integer;
 
 procedure pr;
 begin writeLn(i,' ', sum:1:15,' next= ',next:1:15,' prev= ',prev:1:15 ); end;
 
begin
  i:=0;
  sum:=0; 
  prev:=0;
  i2 := 0;
  i3 := 0;
  i4 := 0;
  i5 := 0;
  repeat
    inc(i);
    next:=4/(2.0*i - 1);
    if odd(i) 
      then sum := sum + next
      else sum := sum - next;
    if i2=0 then
       begin if trunc(sum*100)=314 then begin i2:=i; pr; end; end
    else    
    if i3=0 then
       begin if trunc(sum*1000)=3141 then begin i3:=i; pr; end; end
    else    
    if i4=0 then
       begin if trunc(sum*10000)=31415 then begin i4:=i; pr; end; end
    else    
    if i5=0 then
       begin if trunc(sum*100000)=314159 then begin i5:=i; pr; end; end;
    prev:=next
  until i5>0;
end.
получил такие ответы:
Код:
119 3.149995866593470 next= 0.016877637130802 prev= 0.017021276595745
1688 3.141000236580160 next= 0.001185185185185 prev= 0.001185887933590
10794 3.141500009528470 next= 0.000185296706351 prev= 0.000185313875376
136121 3.141599999994790 next= 0.000014692864043 prev= 0.000014692971984

а вот для сравнения первые 30 членов ряда:
Код:
1 4.000000000000000 next= 4.000000000000000 prev= 0.000000000000000
2 2.666666666666670 next= 1.333333333333330 prev= 4.000000000000000
3 3.466666666666670 next= 0.800000000000000 prev= 1.333333333333330
4 2.895238095238100 next= 0.571428571428571 prev= 0.800000000000000
5 3.339682539682540 next= 0.444444444444444 prev= 0.571428571428571
6 2.976046176046180 next= 0.363636363636364 prev= 0.444444444444444
7 3.283738483738480 next= 0.307692307692308 prev= 0.363636363636364
8 3.017071817071820 next= 0.266666666666667 prev= 0.307692307692308
9 3.252365934718880 next= 0.235294117647059 prev= 0.266666666666667
10 3.041839618929400 next= 0.210526315789474 prev= 0.235294117647059
11 3.232315809405590 next= 0.190476190476190 prev= 0.210526315789474
12 3.058402765927330 next= 0.173913043478261 prev= 0.190476190476190
13 3.218402765927330 next= 0.160000000000000 prev= 0.173913043478261
14 3.070254617779190 next= 0.148148148148148 prev= 0.160000000000000
15 3.208185652261940 next= 0.137931034482759 prev= 0.148148148148148
16 3.079153394197430 next= 0.129032258064516 prev= 0.137931034482759
17 3.200365515409550 next= 0.121212121212121 prev= 0.129032258064516
18 3.086079801123830 next= 0.114285714285714 prev= 0.121212121212121
19 3.194187909231940 next= 0.108108108108108 prev= 0.114285714285714
20 3.091623806667840 next= 0.102564102564103 prev= 0.108108108108108
21 3.189184782277600 next= 0.097560975609756 prev= 0.102564102564103
22 3.096161526463640 next= 0.093023255813954 prev= 0.097560975609756
23 3.185050415352530 next= 0.088888888888889 prev= 0.093023255813954
24 3.099944032373810 next= 0.085106382978723 prev= 0.088888888888889
25 3.181576685435030 next= 0.081632653061225 prev= 0.085106382978723
26 3.103145312886010 next= 0.078431372549020 prev= 0.081632653061225
27 3.178617010999220 next= 0.075471698113208 prev= 0.078431372549020
28 3.105889738271950 next= 0.072727272727273 prev= 0.075471698113208
29 3.176065176868440 next= 0.070175438596491 prev= 0.072727272727273
30 3.108268566698950 next= 0.067796610169492 prev= 0.070175438596491
Serge_Bliznykov вне форума Ответить с цитированием
Старый 13.05.2016, 11:41   #7
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,515
По умолчанию

первые знаки =3.14 это попадание в диапазон [3.14; 3.15) 3.14<= p(i) <3.15 =3.14 +0.01
или учесть переменность знакоряда (+/-) (аппроксимация сверху/снизу)
i=2k p(i)<3.14 +0.01
i=2k+1 3.14 <=p(i)
программа — запись алгоритма на языке понятном транслятору
evg_m вне форума Ответить с цитированием
Старый 13.05.2016, 15:02   #8
min@y™
Цифровой кот
Старожил
 
Аватар для min@y™
 
Регистрация: 29.08.2014
Сообщений: 7,656
По умолчанию

Чо-то мне подумалось, что искаться должно как-то так:

Вложения
Тип файла: 7z pf_293340.7z (952.8 Кб, 8 просмотров)
Расскажу я вам, дружочки, как выращивать грибочки: нужно в поле утром рано сдвинуть два куска урана...

Последний раз редактировалось min@y™; 13.05.2016 в 15:14.
min@y™ вне форума Ответить с цитированием
Старый 13.05.2016, 15:10   #9
Motoroller
 
Регистрация: 12.05.2016
Сообщений: 5
По умолчанию

Рабочий вариант программы получился таким:

Код:
#include <stdio.h>
#include <math.h>

int main(void)
{
	int iSign = 1;
	int iFlag1, iFlag2, iFlag3, iFlag4;
	iFlag1 = iFlag2 = iFlag3 = iFlag4 = 0;
	long int liMemNum = 0;
	long int liOddNumbers;
	double dPi = 0.0;

	for (liOddNumbers = 1; liOddNumbers <= 1000000; liOddNumbers += 2)
	{
		if (iSign == 0)
		{
			dPi -= 4 / (double)liOddNumbers;
			iSign = 1;
		}
		else
		{
			dPi += 4 / (double)liOddNumbers;
			iSign = 0;
		}

		liMemNum++;

		if (iFlag1 == 0)
		{
			if (dPi >= 3.14 && dPi < 3.15)
			{
				printf("%ld\t%f\n", liMemNum, dPi);
				iFlag1++;
			}
		}

		if (iFlag2 == 0)
		{
			if (dPi >= 3.141 && dPi < 3.142)
			{
				printf("%ld\t%f\n", liMemNum, dPi);
				iFlag2++;
			}
		}

		if (iFlag3 == 0)
		{
			if (dPi >= 3.1415 && dPi < 3.1416)
			{
				printf("%ld\t%f\n", liMemNum, dPi);
				iFlag3++;
			}
		}

		if (iFlag4 == 0)
		{
			if (dPi >= 3.14159 && dPi < 3.14160)
			{
				printf("%ld\t%f\n", liMemNum, dPi);
				iFlag4++;
			}
		}
	}

	return 0;
}
Вывод программы:

119 3.149996
1688 3.141000
10794 3.141500
136121 3.141600

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


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
"Поиск решения" для больше чем 100 ограничений Анастасия25 Microsoft Office Excel 3 01.04.2016 23:11
решение задачи методом "поиск решения" в Excel FullhDi Microsoft Office Excel 19 03.03.2015 16:20
Не компилируется программа из книги Дейтела "Как программировать на с++" Aaron Cash Помощь студентам 0 11.10.2011 15:16
Решение задачи, используя "Поиск решения" MilaSlava Microsoft Office Excel 4 03.04.2011 14:08
"Транспортная задача", "Поиск решения" Perroman Microsoft Office Excel 3 12.12.2007 17:12