1

Тема: Обчислити добуток членів послідовності (P)

Попередня назва: Допоможіть знайти помилку

https://replace.org.ua/uploads/images/9488/7636ddcfa75c678814777d8d2d84f7a6.png 
Компілятор помилок не показує, але проблема в тому, що при будь-якому n сума завжди рівна n+1.
Для мене умова дуже складна і не зрозуміла, ось все, що в мене вийшло. І чи правильно я підніс до степеня?
(Я початківець, не судіть строго)

#include "pch.h"
#include <iostream>
#include <stdio.h> 
int main()
{
    float s = 0, x, y;
    unsigned int z, i, n;
    printf("n=");
    scanf_s("%li", &n);
    for (i = 1;i <= n;i++)
    {
        y = z = (1 + 1.0 / i);
        for (x = 2;x <= i;x++)y *= z;
        s += y;
    }
     
    printf("s=%f", s);
    return 0;
}

Результат:
n=5
s=6.000000

2 Востаннє редагувалося koala (02.11.2019 11:14:53)

Re: Обчислити добуток членів послідовності (P)

Уважно стежте за типами.
y та z у вас цілі, а вираз (1 + 1.0 / i) - дійсний. Відповідно, дрібна частина відкидається, і лишається 2 (при i==1) чи 1 (при більших). Звідси і сума така - 2+1+1+...+1.

І у вас зайвий <iostream> (ви ж printf використовуєте), але в "pch.h" і так забагато всього напхано, так що воно не впливає.

Подякували: leofun01, grinyuk3092

3

Re: Обчислити добуток членів послідовності (P)

Ну і вводите ви "%li" (long int), а тип змінної - unsigned int. В принципі, в розумних межах це не має значення, але непорядок. Вас компілятор не попереджає про таке?

Подякували: grinyuk3091

4

Re: Обчислити добуток членів послідовності (P)

Ще дрібна порада - проголошуйте змінні якомога пізніше. Це убезпечує від купи подібних помилок.

    printf("n=");
    unsigned int n;
    scanf_s("%u", &n);
    float s = 0; //s має існувати до циклу і після нього
    for (unsigned int i = 1;i <= n;i++) //i діє лише всередині циклу
    {
        float z = (1 + 1.0 / i);
        float y = z; // можна було через кому в попередньому рядку, але так зрозуміліше
        for (unsigned int x = 2;x <= i;x++) //x діє лише всередині внутрішнього циклу
            y *= z;
        s += y;
    }
    printf("s=%f", s);
Подякували: grinyuk3091

5

Re: Обчислити добуток членів послідовності (P)

koala написав:

Ну і вводите ви "%li" (long int), а тип змінної - unsigned int. В принципі, в розумних межах це не має значення, але непорядок. Вас компілятор не попереджає про таке?

Ні, в прикладах до даної лабораторної роботи ,яку я виконую,
всі змінні unsigned int вводяться через %li. Я спитаю викладача на рахунок цього.

6 Востаннє редагувалося koala (02.11.2019 12:17:24)

Re: Обчислити добуток членів послідовності (P)

http://www.cplusplus.com/reference/cstdio/scanf/
Фокус у тому, що long int та int в поширених системах зазвичай мають розмір 32 біти та кодуються доповненим кодом, що збігається для додатних signed та unsigned. Тобто для значень від 0 до 2147483647 %li, %lu, %i та %u (а також %d та %ld) працюють однаково, відмінності будуть на чомусь специфічному.
Але краще, раз це все ж таки C++, а не C, використовувати <iostream>, там контроль типів вбудований.

std::cout<<"n=";
std::cin>>n; //конкретна функція, яку буде викликано для перетворення, залежить від типу n, а не додаткового специфікатора
Подякували: grinyuk3091

7 Востаннє редагувалося koala (03.11.2019 11:06:33)

Re: Обчислити добуток членів послідовності (P)

Звісно, можна в лоба:

        double total_product = 1.;
        for(int i=1; i<=n; ++i)
        {
            double product = 1.;
            for(int j=1; j<=i; ++j)
                product *= (1+1./i);
            total_product *= product;
        }

Чи навіть без проміжного значення - все ж і так домножується

        double product = 1.;
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=i; ++j)
                product *= (1.+1./i);

Але можна це все покращити за допомогою математики.
Ми маємо добуток (я позначу рядки літерами, щоб було видно, що куди іде):

A →(1 + 1/1) ×
B →(1 + 1/2)(1 + 1/2) ×
C →(1 + 1/3)(1 + 1/3)(1 + 1/3) ×
...
D →(1 + 1/n)(1 + 1/n)×...×(1 + 1/n)

Звісно, не має значення, в якій послідовності ми будемо обчислювати елементи добутку; переставимо їх (по літерах видно, що нічого не втрачено і не з'явилося):

(1 + 1/n) ×
(1 + 1/n)(1 + 1/(n-1)) ×
...
(1 + 1/n)(1 + 1/(n-1))×...×(1 + 1/3) ×
(1 + 1/n)(1 + 1/(n-1))×...×(1 + 1/3)(1 + 1/2) ×
(1 + 1/n)(1 + 1/(n-1))×...×(1 + 1/3)(1 + 1/2)(1 + 1/1)
     D                         С        B        A

А тепер стає видно, що i+1-й рядок можна отримати з i-го множенням його на (1+1/(n-i+1)), якщо нумерувати рядки з 1. Можна їх нумерувати з 0, тоді множити треба на (1+1/(n-i)). Але простіше, гадаю, все ж зробити i спадним від n до 1. Отже:

        double product = 1., current = 1.;
        for(int i=n;i>0;--i)
        {
          current *= (1.+1./i);
          product *= current;
        }

Порівняти результати і швидкість можете тут: https://ideone.com/WY96xJ

Подякували: grinyuk309, leofun012

8

Re: Обчислити добуток членів послідовності (P)

Любителі скорочувати можуть довести до

        for(int i=n;i>0;--i)
          product *= (current *= (1.+1./i);

Але я не раджу такий спосіб, так погано читається.

Подякували: grinyuk3091