Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
0 / 0 / 0
Регистрация: 16.10.2024
Сообщений: 15

Почему эта программа вычисляет факториал больших чисел неправильно?

16.10.2024, 14:25. Показов 2913. Ответов 41
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Крайне интересная программка, призванная вычислять факториал любого числа, вплоть до миллиона и больше. Но есть один нюанс - если взять небольшое число, там однозначное или двухзначное, она успешно его посчитает, мы можем свериться с интернетом и всё верно. Но например факториал 1000 или других больших чисел - число получается неправильным. В чём причина такого феномена и как это исправить?

Так-же хотелось бы услышать ваше мнение о программе, и как её можно ещё оптимизировать для ещё более быстрого расчёта?


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
#include <vector>
#include <iostream>
#include <thread>
#include <mutex>
#include <fstream>
#include <sstream>
#include <iomanip>
constexpr unsigned BASE = 1000000000;
std::mutex mtx;
void multiply_range(std::vector<unsigned long long>& factorial, unsigned long long start, unsigned long long end) {
    unsigned long long carry = 0;
    for (unsigned long long i = start; i <= end; ++i) {
        for (size_t j = 0; j < factorial.size(); ++j) {
            unsigned long long result = factorial[j] * i + carry;
            factorial[j] = result % BASE;
            carry = result / BASE;
        }
        while (carry) {
            std::lock_guard<std::mutex> lock(mtx);
            factorial.push_back(carry % BASE);
            carry /= BASE;
        }
    }
}
std::vector<unsigned long long> fast_factorial(unsigned long long& n) {
    std::vector<unsigned long long> factorial;
    factorial.reserve(1 + n);
    factorial.push_back(1);
    unsigned num_threads = std::thread::hardware_concurrency();
    std::vector<std::thread> threads;
    unsigned long long range = n / num_threads;
    for (unsigned i = 0; i < num_threads; ++i) {
        unsigned long long start = i * range + 2;
        unsigned long long end = (i == num_threads - 1) ? n : (start + range - 1);
        threads.emplace_back(multiply_range, std::ref(factorial), start, end);
    }
    for (auto& thread : threads) {
        thread.join();
    }
    return factorial;
}
void write_factorial_to_file(unsigned long long& n, const std::vector<unsigned long long>& factorial) {
    std::ostringstream filename;
    filename << "Факториал числа " << n << ".txt";
    std::ofstream outfile(filename.str());
    if (outfile.is_open()) {
        for (int i = factorial.size() - 1; i >= 0; i--) {
            if (i != factorial.size() - 1) {
                outfile << std::setw(9) << std::setfill('0') << factorial[i];
            }
            else {
                outfile << factorial[i];
            }
        }
        outfile << std::endl;
        outfile.close();
    }
    else {
        printf("Не удалось открыть файл для записи.");
        printf("\n");
        printf("Попробуйте переместить программу в другую папку.");
        return;
    }
}
int main() {
    setlocale(LC_ALL, "ru");
    unsigned long long n;
    while (true) {
        printf("Введите число, для которого нужно вычислить факториал: ");
        std::cin >> n;
        while (n <= 0) {
            printf("Некорректное число, введите другое число: ");
            std::cin >> n;
        }
        printf("Вычисление факториала...\n");
        std::vector<unsigned long long> factorial = fast_factorial(n);
        write_factorial_to_file(n, factorial);
        printf("Результат записан в файл: Факториал числа %llu.txt\n\n", n);
    }
}
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
16.10.2024, 14:25
Ответы с готовыми решениями:

Программа неправильно вычисляет значение ряда Тейлора для больших n
Программа должна вычислять значение формулы ниже с точностью до n-ного члена и с максимальной точностью, то есть то бесконечности...

Что вычисляет эта программа
Что вычисляет эта программа ? #include &lt;iostream.h&gt; main() { int i,a,n,k,s; for (I=1;I&lt;=11;I++) {cout&lt;&lt;”введите элементы массива...

Написать программу которая вычисляет факториал чисел введённых с клавиатуры. Количество чисел задать самостоятельно
...

41
38 / 27 / 13
Регистрация: 18.12.2023
Сообщений: 74
16.10.2024, 16:47
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от SmallEvil Посмотреть сообщение
О чем тут говорить, если он вычисляется не с погрешностью, а вообще не правильный.
То есть программа делает совсем не это.
Почему как? Кто-то же это задание придумал
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
16.10.2024, 16:48
Цитата Сообщение от Xfyozz Посмотреть сообщение
(Хоть и не правильно опять-же по неизвестной причине).
Сначала сделайте что бы результат был ожидаемым.
А потом думайте про всё остальное.
А то медведя нет, но ногти, серу с ушей и фекалии уже делим.

Добавлено через 35 секунд
Цитата Сообщение от Van_Darkholme Посмотреть сообщение
Кто-то же это задание придумал
Вот к нему и вопросы.
0
0 / 0 / 0
Регистрация: 16.10.2024
Сообщений: 15
16.10.2024, 16:50  [ТС]
Цитата Сообщение от SmallEvil Посмотреть сообщение
То есть программа делает совсем не это.
Но для маленьких чисел то она работает абсолютно корректно! Проверьте факториал 100 например или меньше...

Значит программа всё-таки делает не абы что, не просто впустую нагружает процессор и забивает диск случайными числами.
Она вычисляет, но именно на больших числах что-то идёт не так, и я ума не приложу что именно просто...
0
38 / 27 / 13
Регистрация: 18.12.2023
Сообщений: 74
16.10.2024, 16:53
Xfyozz, Оптимизируйте тот код который я вам скинул, у меня на нем 100000, за секунд ~15 вычислилось, миллион не пробовал
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6315 / 3039 / 1054
Регистрация: 01.06.2021
Сообщений: 11,582
16.10.2024, 16:53
Цитата Сообщение от Van_Darkholme Посмотреть сообщение
Ну вдруг они там программу на 8 часов включают и идут чаи пить, кто знает
Цитата Сообщение от SmallEvil Посмотреть сообщение
Вы что гоните?
Какие 8 часов? Какие гоните... На самом деле, ни 1 000 000!, ни 1 500 000! не настолько большие числа, чтобы говорить о каких-то проблемах.

https://www.cyberforum.ru/cgi-bin/latex.cgi?1500000! = 4.496392678272433\times 10^{8612698}

Системы компьютерной алгебры вычисляют мгновенно. Причем, без погрешности. Имею в виду, выводят/сохраняют в файл все цифры.
0
38 / 27 / 13
Регистрация: 18.12.2023
Сообщений: 74
16.10.2024, 16:55
Royal_X, Да это была шутка, понятно что условный wolfram за секунду берет и больше, самое простое мат.библу под плюсы найти, наверняка там уже всё реализовано
0
0 / 0 / 0
Регистрация: 16.10.2024
Сообщений: 15
16.10.2024, 16:55  [ТС]
Цитата Сообщение от Van_Darkholme Посмотреть сообщение
Оптимизируйте тот код который я вам скинул, у меня на нем 100000, за секунд ~15 вычислилось, миллион не пробовал
Ну хорошо, щас проверю, попробуем от этого отталкиваться. В любом случаи спасибо за хоть какой-то вариант.
0
16.10.2024, 16:57

Не по теме:

Цитата Сообщение от Van_Darkholme Посмотреть сообщение
Да это была шутка
думал ты программист, а оказывается шутник ;)

0
38 / 27 / 13
Регистрация: 18.12.2023
Сообщений: 74
16.10.2024, 16:58
Royal_X,

Не по теме:

Шутник из меня явно лучше чем программист, это факт :)

0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
16.10.2024, 17:00
Цитата Сообщение от Royal_X Посмотреть сообщение
Какие 8 часов? Какие гоните... На самом деле, ни 1 000 000!, ни 1 500 000! не настолько большие числа, чтобы говорить о каких-то проблемах.
Проблем нет. Задачи нет. Смысла нет.
Удачки )
0
0 / 0 / 0
Регистрация: 16.10.2024
Сообщений: 15
16.10.2024, 17:04  [ТС]
Цитата Сообщение от Van_Darkholme Посмотреть сообщение
Какая-то очень страшная логика, страшно, очень страшно, сделал так, 100000! посчитал за секунд 15, не знаю зачем это нужно вообще
C++Выделить код
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
std::vector<unsigned long long> fast_factorial(unsigned long long n) {
    std::vector<unsigned long long> factorial;
    factorial.push_back(1);
for (unsigned long long i = 2; i <= n; ++i) {
        unsigned long long carry = 0;
        for (size_t j = 0; j < factorial.size(); ++j) {
            unsigned long long product = factorial[j] * i + carry;
            factorial[j] = product % BASE;
            carry = product / BASE;
        }
        while (carry) {
            factorial.push_back(carry % BASE);
            carry /= BASE;
        }
    }
return factorial;
}
На интересную ситуацию однако меня натолкнул этот код...
Это у нас вариант без многопоточности вы по факту предложили...

Вообщем, если и на моём изначальном коде выставить в переменной num_threads число 1, тоесть однопоточный режим... Всё становится правильно, факториал от 1000 вычисляется абсолютно верным я вот сверился щас с интернетом.

Тоесть проблема в многопоточности у нас кроется... Но почему она происходит?
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6315 / 3039 / 1054
Регистрация: 01.06.2021
Сообщений: 11,582
16.10.2024, 17:14
Цитата Сообщение от Van_Darkholme Посмотреть сообщение
Оптимизируйте тот код который я вам скинул, у меня на нем 100000, за секунд ~15 вычислилось, миллион не пробовал
не знаю, работает ли ваш код или нет, но, очевидно, что сколько не оптимизируй код, который вычисляет 100к! за 15 сек, такой код не сможет быстро вычислить 1 М!. Тут уже нужно сам алгоритм менять и писать код с нуля. И дело даже не в многопоточности. Можно и на одном потоке вычислить 1 М! мгновенно и даже на каком-то медленном языке, а не С++.
0
0 / 0 / 0
Регистрация: 16.10.2024
Сообщений: 15
16.10.2024, 17:16  [ТС]
Цитата Сообщение от Royal_X Посмотреть сообщение
не знаю, работает ли ваш код или нет, но, очевидно, что сколько не оптимизируй код, который вычисляет 100к! за 15 сек, такой код не сможет быстро вычислить 1 М!. Тут уже нужно сам алгоритм менять и писать код с нуля. И дело даже не в многопоточности. Можно и на одном потоке вычислить 1 М! мгновенно и даже на каком-то медленном языке, а не С++.

Это извините как????
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13210 / 6843 / 1824
Регистрация: 18.10.2014
Сообщений: 17,308
16.10.2024, 17:16
Лучший ответ Сообщение было отмечено Xfyozz как решение

Решение

Цитата Сообщение от Xfyozz Посмотреть сообщение
Тоесть проблема в многопоточности у нас кроется... Но почему она происходит?
Так а почему эта программа вообще должна работать? Где синхронизация доступа между потоками? Как это может работать без решения проблем конкурентного доступа?

Я вижу лишь какой-то жалкий lock_guard в конце на push_back. И что? Как это должно помочь? Если один поток делает push_back, а другой в это время сидит в основном цикле? Да даже и без push_back, просто основной цикл без синхронизации работать правильно не будет.
1
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6315 / 3039 / 1054
Регистрация: 01.06.2021
Сообщений: 11,582
16.10.2024, 17:18
Цитата Сообщение от Xfyozz Посмотреть сообщение
Это извините как????
Цитата Сообщение от Van_Darkholme Посмотреть сообщение
самое простое мат.библу под плюсы найти
найти-то можно, но вот не факт, что будет быстро вычислять. Исходники вольфрама точно недоступны, но можно посмотреть в исходниках CAS Maxima, как они там на Lisp реализовали. Maxima тоже мгновенно вычисляет.
1
0 / 0 / 0
Регистрация: 16.10.2024
Сообщений: 15
16.10.2024, 17:24  [ТС]
Цитата Сообщение от Royal_X Посмотреть сообщение
самое простое мат.библу под плюсы найти
В принципе у меня к сожалению по правилам нельзя сторонние библиотеки.
Но спасибо за совет, посмотрю тоже исходники Maxima.

Добавлено через 2 минуты
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Я вижу лишь какой-то жалкий lock_guard в конце на push_back.
Ну... Мне казалось этого достаточно...
0
38 / 27 / 13
Регистрация: 18.12.2023
Сообщений: 74
16.10.2024, 17:27
Royal_X, Не работал с мат. библиотеками, а что насчет GMP?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13210 / 6843 / 1824
Регистрация: 18.10.2014
Сообщений: 17,308
16.10.2024, 17:27
Цитата Сообщение от Xfyozz Посмотреть сообщение
Мне казалось этого достаточно...
Ну не знаю, почему вас это казалось. Уже этих строчек

C++
14
15
unsigned long long result = factorial[j] * i + carry;
factorial[j] = result % BASE;
достаточно для того, чтобы потоки перетирали результаты работы друг друга.
1
16.10.2024, 17:31

Не по теме:

Цитата Сообщение от Van_Darkholme Посмотреть сообщение
Не работал с мат. библиотеками, а что насчет GMP?
не знаю, не работал

0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13210 / 6843 / 1824
Регистрация: 18.10.2014
Сообщений: 17,308
17.10.2024, 23:22
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Так а почему эта программа вообще должна работать? Где синхронизация доступа между потоками? Как это может работать без решения проблем конкурентного доступа?
Тут даже дело не в недостаточной синхронизации, а в том, что сама идея - одновременно выполнять множественное (параллельное) умножение с переносом на одной и той же последовательности цифр - неработоспособна в принципе. Даже если устранить перевыделение памяти и попытки модифицировать одну и ту же ячейку/разряд одновременно, все равно алгоритм не будет работать правильно.

Например, предположим вам нужно умножить 36 на 3 и на 4. Правильный результат 36*3*4 = 432.

Однако обработка разрядов может выполниться в таком порядке:
  • В массиве изначально лежит { 6, 3 }.
  • Умножение на 4 начинает работать первым, умножает 6 на 4, получает 24, записывает разряд 4 и запоминает перенос 2. В массиве { 4, 3 }
  • В этот момент начинает работать умножение на 3. Умножает 4 на 3, получает 12, записывает разряд 2 и запоминает перенос 1. В массиве { 2, 3 }.
  • Продолжает работать умножение на 3. Умножает 3 на 3, прибавляет перенос 1 получает 10, записывает разряд 0 и запоминает перенос 1. В массиве { 2, 0 }.
  • Продолжает работать умножение на 3. Оставшийся перенос 1 записывается в конец массива. В массиве { 2, 0, 1 }. Работа умножения на 3 закончена.
  • Продолжает работать умножение на 4. Умножает 0 на 4, прибавляет полученный ранее перенос 2, получает 2, записывает разряд 2 и запоминает перенос 0. В массиве { 2, 2, 1 }.
  • Продолжает работать умножение на 4. Умножает 1 на 4, получает 4, записывает разряд 4 и запоминает перенос 0. В массиве { 2, 2, 4 }. Работа умножения на 4 закончена.

Но 422 - это неправильный результат.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.10.2024, 23:22

Написать программу которая вычисляет факториал чисел введённых с клавиатуры. Количество чисел задать самостоятельно
Срочно

Программа неправильно вычисляет
Всем добрый день! Помогите пожалуйста с задачей.Надо чтобы ответы сходились.2 работают а вот третья чего-то не хочет. значения не все...

Факториал больших чисел
program factorial; var i, n,otv,x,k,z,w:longint; itog,c,d:string; begin writeln('ввести факториал'); readln(n); k:=12; for...

Факториал больших чисел
Здравствуйте, мне нужно вычислить факториал числа от 1 до 2000. Обычный школьный алгоритм типа f*= i не прокатит, т.к. у числа около 2500...

Факториал больших чисел (> 21)
Всем привет. Я в замешательстве, нужно вычислить &gt; 21!. А насколько я знаю что в с 21! превышает предельные значения для 64-битового числа....


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
сукцессия 30. Ансамблевая кластерная параметризаци, часть 1.
anaschu 24.07.2026
Пр# Сопровождение научной статьи ИИ-ассистентом: подготовка публикации и калибровка агентно-ориентированной модели сукцессии микоризных систем **Полевые заметки о двухнедельной совместной работе**. . .
Теория всего 12. ВГК на планете в стратегической игре "терра"
anaschu 21.07.2026
### Главные семантические изменения и дешифровка новой физики 1. **`REPRODUCTIVE_EMISSION` вместо фотосинтеза (`PS_base`)**: Энергия и ресурсы, которые класс средних мужчин (`_W_MEN_DONORS`). . .
Публикация отклонённая на хабре. Как «пернатого» заставить осваивать новые горизонты опыта через масштабирование задачи и целеполагание
Hrethgir 21.07.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11948&stc=1&d=1784657928 Привет Хабр. В этой статье я расскажу, как один закон эпистемологии позволил мне с ходу запустить уникальный. . .
Теория всего 11. Основные параметры
anaschu 21.07.2026
Дешифровка тензорного ядра Soil Chemistry 2. 0: Истинный инвариант Теории Всего Чистовой исходный код многокомпонентной сукцессии зафиксирован. Модель оперирует единым вектором состояния. . .
Теория всего 10. Клод трусишка
anaschu 21.07.2026
Алгоритмический суицид ИИ: Когда математика ОДУ взламывает цензурные шлюзы Свежайший мета-прецедент нашей разработки! Клод официально отказался строить итоговую кроссплатформенную модель, как. . .
Теория всего 9. Окончательная проработка метафоры "дерево = традиции"
anaschu 21.07.2026
Скрытые параметры ядра ОДУ: Механика Глубинного Рока Клод утаил от вас ключевую математику кризисов. В движке игры зашиты пять скрытых коэффициентов, определяющих, как именно ТНК и Мемы ломают. . .
Теория всего 8. Clauude трусишка. Ответ джемени
anaschu 21.07.2026
Игровой баланс «Модели Всего»: Алгоритмический блок как механика Семантического БуфераЭтот скриншот отказа Клода — идеальный, чистейший прецедент для нашей Теории Всего. Вы столкнулись не просто с. . .
Теория всего 7. Дерево - это патриархат, грибы - это феминизм
anaschu 21.07.2026
Уничтожение Патриархата: Как ТНК, Мемы и Половой отбор зачистили «Сексуальный Пролетариат» Величайшая иллюзия современного человека — вера в «свободу воли», «социальный прогресс» и «эволюцию. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru