Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
0 / 0 / 0
Регистрация: 13.11.2009
Сообщений: 13

Расходящиеся ряды или как правильно задать проверку

13.11.2009, 15:31. Показов 1788. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте,
наткнулся на проблему, которая не дает покоя мозгу.
Ситуация следующая:
Работаю в среде MS Visual Studio 2005(C++), написал программу вычисления функции методом рядов Тейлора. Функция разложения : f=ln(1-x), Раскладывается она следующим образом:
http://i36.tinypic.com/20fysfp.gif
При входе в цикл первое значение вычисляется после 10,000,000 операций (если E задать 1e-7),
если же задать E = 1e-8, то первое значение вычисляется уже после 100,000,000 операций (это видно в выводе)
Причем если задать дополнительную проверку на максимальное кол-во итераций (допустим 1000), то точность теряется где-то уже после 3-4 знака..
Вообще говоря, происходит какое-то непонятное переполнение, после которого точность сильно повышается, а кол-во итераций снижается на несколько порядков!
Как и с чем это может быть связано и возможен ли другой способ проверки значения во втором цикле for?(может быть, y2-y1 < E? Как это можно реализовать?)
По-идее, функция(ряд Тейлора) расходится при больших n... Вот здесь то и вопрос: Как быть в таком случае?


Код программы (C++):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include "iostream"
#include "stdafx.h"
#include <conio.h>
#include <stdio.h>
#include <windows.h>
#include <math.h> 
 
//using CharToOemA func to convert ANSI to OEM
char bufRus[256];
char* Rus(const char* text)
    {
        CharToOemA(LPCSTR(text), bufRus);
        return bufRus;
    }
 
char* Rus(const char* text);
 
int _tmain(int argc, _TCHAR* argv[])
{
    double dXbegin, dXend, dXstep, N, E;//, N1=1, i=1.0;
    printf(Rus("Программа вычисления функции ln(1-x), заданной рядами Тейлора\n"));
    printf(Rus("и вывода в столбец значений ф-ии на интервале [x1;x2]\n"));
    printf(Rus("x лежит в диапазоне (-1 <= x < 1)\n"));
    printf(Rus("с шагом dx и заданной точностью E.\n"));
    printf(Rus("Введите начало интервала, конец интервала, число шагов(N), точность вычислений.\n"));
    printf("x1, x2, N, E = ?\n");
    scanf("%lf%lf%lf%lf", &dXbegin, &dXend, &N, &E);
    
    if (    dXbegin < -1e300    // Проверка на диапазон значений вводимых чисел
        ||  dXbegin > 1e300
        ||  dXend < -1e300
        ||  dXend > 1e300
        ||  N < 1
        ||  N > 1e300
        ||  E < 0
        ||  E > 1e300)
    {
        printf(Rus("Вне диапазона\n"));
        getch();
        return 0;
    }
    if ( dXbegin > dXend )
    {
        printf(Rus("Начало интервала больше чем его конец, корректирую...\n"));
        dXbegin = -dXbegin;
        dXend = -dXend;
    }
    dXstep=(dXend-dXbegin)/N;
//  N=1.0; // экономим место в памяти(вместо объявления новой переменной), используем ненужную далее переменную N
    
    for (double x=dXbegin, i, y; x <= dXend; x+=dXstep)
    {
        if ( x < -1 || x >= 1)
        {
            printf(Rus("Значение функции в точке x=(%lf) не существует\n"), x);
            continue;
        }
    
    for (i=1, y=0, N=1; E < fabs(N/i); i++)
        {
            N*=x;   //следующий член ряда
            y-=(N/i);   //сумма
        }
    printf("i=%lf\n", i);
    printf(Rus("В точке x=[%.10lf]\ty=[%.10lf]\n"), x, y);
    }
    printf("E=[%lf]\nN=[%lf]\ndXbegin=[%lf]\ndXend=[%lf]\n", E, N, dXbegin, dXend);
    getch();
    return 0;
}
Вывод:
Программа вычисления функции ln(1-x), заданной рядами Тейлора
и вывода в столбец значений ф-ии на интервале [x1;x2]
x лежит в диапазоне (-1 <= x < 1)
с шагом dx и заданной точностью E.
Введите начало интервала, конец интервала, число шагов(N), точность вычислений.
x1, x2, N, E = ?
-1 -0.9 2 1e-8
i=100000000.000000
В точке x=[-1.0000000000] y=[0.6931471856]
i=253.000000
В точке x=[-0.9500000000] y=[0.6678293679]
E=[0.000000]
N=[0.000002]
dXbegin=[-1.000000]
dXend=[-0.900000]
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
13.11.2009, 15:31
Ответы с готовыми решениями:

Как правильно организовать проверку на отсутствие или существование записи в mysql
Вопрос в следующем как организовать проверку на отсутствие или существование записи в mysql? Есть таблица: И нужно перенаправлять...

Как правильно задать http запрос, если нужно задать reqest header?
В программе нужно перезагрузить роутер, исспользуя httpanalazer получилось определить какой запрос я должен отослать - он на фото ...

Подскажите как задать проверку
Можете помочь, я ещё начинающий кодер, мне нужно задать проверку: если у объекта угол вращения по Z больше чем к примеру 20 градусов, то......

4
║XLR8║
 Аватар для outoftime
1212 / 909 / 270
Регистрация: 25.07.2009
Сообщений: 4,360
Записей в блоге: 5
13.11.2009, 18:45
здесь
C++
1
for (i=1, y=0, N=1; E < fabs(N/i); i++)
при отрицательных х вы производите на 1 итерацию больше, надо брать по модулю.
здесь
C++
1
2
3
4
dXstep=(dXend-dXbegin)/N;
//      N=1.0; // экономим место в памяти(вместо объявления новой переменной), используем ненужную далее переменную N
        
        for (double x=dXbegin, i, y; x <= dXend; x+=dXstep)
вы опять потеряли -, т.к. при начале -0,5 и конце -0,3 шаг -0,2, потом вы к началу -0,5 прибавляете -0,2 до тех пор пока.. короче он должен зациклиться..
Это касательно мелочи..

Если что конкретно не ясно, спрашивайте..
0
0 / 0 / 0
Регистрация: 13.11.2009
Сообщений: 13
13.11.2009, 22:43  [ТС]
Цитата Сообщение от outoftime Посмотреть сообщение
здесь
C++
1
for (i=1, y=0, N=1; E < fabs(N/i); i++)
при отрицательных х вы производите на 1 итерацию больше, надо брать по модулю.
Если что конкретно не ясно, спрашивайте..
Что конкретно по модулю брать? х? или N?
0
 Аватар для manfeese
133 / 132 / 29
Регистрация: 04.01.2009
Сообщений: 415
14.11.2009, 03:01
В случае, когда x = -1, боюсь, что ничего нельзя сделать. Ряд является знакочередующимся, поэтому и накладываються ограничения на значения X.

Добавлено через 44 минуты
Хотя, можно использовать следующее условие:
Если значение x<0, то вместо него можно использовать обратное ему значение для данной функции, а именно x=x/(x-1);
Например ln(1-(-1))=-ln(1-(1/2)).
В таком случае ряд перестает быть знакочередующимся, и операция выполняется намного быстрее.
Например для значений X = -1 и eps = 1e-7 количество итераций составляет 21, а для eps = 1e-8, всего лишь 22.
На примере своей программы приведу дополнительные условия:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <math.h>
#include <stdio.h>
#include <conio.h>
 
int main()
{
float x, eps;               
float Sum=0;                 
float Prev,temp=1;          
int n=1;                    
 
Start:
        printf("x="); scanf("%f",&x);
        if ( x<1 || x>=1)
    {
       clrscr();
       printf("X must be in -1<=X<1\n");
       goto Start;
    }
        printf("eps="); scanf("%f",&eps);
 
if ( x<0 ) x=x/(x-1);        // Проверка значения x
 
do
{
  Prev = Sum;                           
  temp *= x;                            
  Sum -= temp/n++;
}while(fabs(Sum-Prev)>eps);
 
if ( (x/(x-1)) < 0 ) Sum=-Sum;  //Меняем значение на противоположное
 
printf("Sum=%f  iteracii: %i",Sum,n);
getch();
 
return 0;
}
Добавлено через 47 минут
Немного ошибся в условиях, вот правильный
код
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <math.h>
#include <stdio.h>
#include <conio.h>
 
int main()
{
float x, eps;               
float Sum=0;                 
float Prev,temp=1;          
int n=1;
bool Inv = false;                    
 
Start:
        printf("x="); scanf("%f",&x);
        if ( x<1 || x>=1)
        {
           clrscr();
           printf("X must be in -1<=X<1\n");
           goto Start;
        }
        printf("eps="); scanf("%f",&eps);
 
if ( x<0 )  // Проверка значения x
{
   x=x/(x-1);         
   Inv = true;
}
 
do
{
  Prev = Sum;                           
  temp *= x;                            
  Sum -= temp/n++;
}while(fabs(Sum-Prev)>eps);
 
if (Inv) Sum=-Sum;  //Меняем значение на противоположное
 
printf("Sum=%f  iteracii: %i",Sum,n);
getch();
 
return 0;
}
0
0 / 0 / 0
Регистрация: 13.11.2009
Сообщений: 13
30.11.2009, 10:56  [ТС]
Всем спасибо за поддержку и советы!

В итоге отладив программу пошагово, я понял наконец, где я теряю минус и преобразовал программу к такому виду(работает вполне сносно!):

code
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include "iostream"
#include "stdafx.h"
#include <conio.h>
#include <stdio.h>
#include <windows.h>
#include <math.h> 
 
//using CharToOemA func to convert ANSI to OEM
char bufRus[256];
char* Rus(const char* text)
    {
        CharToOemA(LPCSTR(text), bufRus);
        return bufRus;
    }
 
char* Rus(const char* text);
 
int _tmain(int argc, _TCHAR* argv[])
{
    double dXbegin, dXend, dXstep, N, E;//, N1=1, i=1.0;
    printf(Rus("Программа вычисления функции ln(x+1), заданной рядами Тейлора\n"));
    printf(Rus("и вывода в столбец значений ф-ии на интервале [x1;x2]\n"));
    printf(Rus("с шагом dx и заданной точностью E.\n"));
    printf(Rus("x лежит в диапазоне (-1;1]\n"));
    printf(Rus("Введите начало интервала, конец интервала, число шагов(N), точность вычислений.\n"));
    printf("x1, x2, N, E = ?\n");
    scanf("%lf%lf%lf%lf", &dXbegin, &dXend, &N, &E);
    
    if (    dXbegin < -1e300    // Проверка на диапазон значений вводимых чисел
        ||  dXbegin > 1e300
        ||  dXend < -1e300
        ||  dXend > 1e300
        ||  N < 1
        ||  N > 1e300
        ||  E < 0
        ||  E > 1e300)
    {
        printf(Rus("Вне диапазона\n"));
        getch();
        return 0;
    }
    if ( dXbegin > dXend )
    {
        printf(Rus("Начало интервала больше чем его конец, корректирую...\n"));
        //обойдемся без дополнительного ввода новой переменной
        dXbegin = dXbegin + dXend;  // {a = a0 + b0, b = b0}
        dXend   = dXbegin - dXend;  // {a = a0 + b0, b = a0}
        dXbegin = dXbegin - dXend;  // {a = b0, b = a0}
 
    }
    dXstep=fabs(dXend-dXbegin)/N;
    for (double x=dXbegin, i, y; x <= dXend; x+=dXstep)
    {
        if ( x <= -1 || x > 1)
        {
            printf(Rus("Значение функции в точке x=(%lf) не существует(задано условием)\n"), x);
            continue;
        }
 
        for (double i=1, minus=-1, y=0, N=1; E < fabs(N/i); i++)
        {
                if (i == 1)         //т.к. знакочередующаяся последовательность, пришлось пропустить
                    {           //программу через последовательное выполнение
                        N*=x;       //чтобы понять причину некорректного результата ...
                        y+=(N/i);   //итог: проверка условия в случае i == 1
                        continue;   //далее знак меняется нормально
                    }
                else
                    {
                    //minus*=-1.0;      //после первой итерации становится +, потом -...
                    N*=minus*x;     //следующий член ряда
                    y+=(N/i);       //сумма
                    if (E > fabs(N/i))
                        {
                            printf("i=%lf\n", i);
                            printf(Rus("В точке x=[%.10lf]\ty=[%.10lf]\n"), x, y);
                        }
                    if (i > 10000000)
                        {
                            printf(Rus("Количество итераций превысило 10,000,000 - прерываем цикл\n"));
                            printf(Rus("В точке x=[%.10lf]\ty=[%.10lf]\n"), x, y);
                            break;
                        }
                    }
        }
    }
    printf("E=[%e]\nN=[%lf]\ndXbegin=[%lf]\ndXend=[%lf]\n", E, N, dXbegin, dXend);
    getch();
    return 0;
}

P.S. функция немного другая правда: ln(x+1)
Но сути это не меняет, она такая же знакопеременная(не нужен только минус за скобкой как в первом примере)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
30.11.2009, 10:56
Помогаю со студенческими работами здесь

Как задать проверку на дробную часть?
Что исправить когда ввожу число без дроби например 49 пишет сорок девять сантиметра ноль милиметров а нужно просто сорок девять...

Ряды. Как правильно записать выражение?
Подскажите, как в маткаде правильно записать выражение? 3*5*.....*(2n+1).

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

Как правильно делать проверку
Сори за название, не смог его правильно сформулировать. Не пойму как правильно сделать такую проверку: Есть html код вида &lt;div...

Как задать условие выхода из цикла, проверку на использование каждого элемента в массиве?
Есть функция: void naznachenie (string FIO, string dol) { int a; while (FIO != 5 &amp;&amp; dol != 3) { ...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь(не выше 3-го порядка) постоянного тока с элементами R, L, C, k(ключ), U, E, J. Программа находит переходные токи и напряжения на элементах схемы классическим методом(1 и 2 з-ны. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru