Цикл For в С# против цикла For в Python

Я писал метод, который вычислял бы значение e^x. То, как я реализовал это в python, было следующим.

import math

def exp(x):
    return sum([
        x**n/math.factorial(n)
        for n in range(0, 100)
    ])

Это очень хорошо вернет значение e^x. Но когда я попытался реализовать тот же метод на С#, он не выдал того же значения, что и на питоне. Далее была реализация на С#.

static double exp(int x)
{
    double FinalAnswer = 0;
    for (int j = 0; j <= 100; j++)
    {
        FinalAnswer += (Math.Pow(x, j))/Factorial(j);
    }
    return FinalAnswer;
}

Вывод для этого кода сначала был символом бесконечности. Чтобы решить эту проблему, я просто уменьшил количество запусков цикла. Вывод кода на С#, где цикл выполнялся только 10 раз, был довольно близок к выводу на питоне, где цикл выполнялся 100 раз. Мой вопрос в том, что происходит между двумя циклами на разных языках программирования. Сначала я подумал, что выражение, которое я использовал в своем методе для вычисления e^x, быстро сходится. Но как цикл, который выполняется 10 раз, дает результат, соответствующий результату цикла, который выполняется 100 раз?

Кроме того, когда я увеличил цикл for в С# до 20 и 30, значения e ^ x для x> 3 были далекими. Может ли кто-нибудь объяснить, что здесь происходит?

Я думаю, вам нужно j < 100, ваш диапазон питона останавливается на 99 ...92, 93, 94, 95, 96, 97, 98, 99]

Sayse 28.06.2022 09:17

Я попробовал оба фрагмента с 3 и 13 и не нашел существенной разницы. Пожалуйста, добавьте примеры (например, пары вход-выход), с которыми вы столкнулись. Также имейте в виду, что чистый python работает с числами с бесконечной точностью, где c# double — это аппаратный нативный тип с ограничениями точности (вы можете видеть это, когда 3**50 дает int 717897987691852588770249 в python, а в c# (long)Math.Pow(3,50) дает -9223372036854775808).

Ackdari 28.06.2022 09:33

Обратите внимание, что прямое вычисление математической формулы $\sum_{n=0}^k\frac{X^n}{n!}$ в том виде, в каком она написана, является особенно плохим способом ее вычисления практически на любом языке. Вычисление полинома с использованием Схема Хорнера не только использует намного меньше операций умножения и деления, но также позволяет избежать переполнения, которое здесь наблюдается, и, как правило, более снисходительно относится к ранним ошибкам округления.

Marc van Leeuwen 29.06.2022 18:29
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
13
3
1 111
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Скорее всего, вы столкнетесь здесь с целочисленное переполнение с версией C# функции Factorial (по крайней мере, с вашей ее реализацией или откуда она исходит).

В C# int — это числовой тип, хранящийся в 32 битах памяти, что означает, что он ограничен -2^31 <= n <= 2^31 - 1, что составляет около +/- 2,1 миллиарда. Вы можете попробовать использовать тип long, который является 64-битным числовым типом, однако для еще больших верхних границ в вашем цикле for, например, приближения к 100, вы также будете переполнять long.

Когда вы запускаете функцию Factorial в C#, сначала она запускается нормально, однако, если вы продолжите, вы увидите, что она внезапно переходит к отрицательным числам, и если вы продолжите двигаться дальше, он станет равным 0 и перестанет меняться. Вы видите вывод бесконечности из-за деления на 0, и C# имеет способ обработки этого с помощью удвоений; то есть просто вернуться double.PositiveInfinity.

Причина, по которой этого не происходит в python, заключается в том, что он использует переменное количество битов для хранения своих числовых значений.

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

Дополнительное примечание: Как упоминалось в комментариях, в C# есть тип с именем BigInteger, который предназначен для обработки огромных чисел, таких как значения, которые вы ожидаете от больших входных данных для функции факториала. Вы можете найти ссылку на документы BigInteger здесь


Я знаю, что это очень запоздалое добавление, но вы можете вычислить каждый компонент факториальной функции отдельно с той мощностью, которую вы используете. Вот что я имею в виду:

public decimal Exp(decimal power, int accuracy = 100)
{
    decimal runningTotal = 1;
    decimal finalValue = 1;
    for (int i = 1; i <= accuracy; i++)
    {
        runningTotal *= power/i;
        finalValue += runningTotal;
    }
    return finalValue;
}

Не могли бы вы уточнить эту часть: «Причина, по которой этого не происходит в python, заключается в том, что он использует переменное количество бит для хранения своих числовых значений».

Yonatan Nir 28.06.2022 10:17

@YonatanNir Я не особо разбираюсь в тонкостях, но на высоком уровне способ хранения чисел в python использует нефиксированное количество байтов. если число, которое вы пытаетесь представить, требует больше, чем количество байтов, которое в настоящее время содержит переменная, оно просто выделяет больше и использует это. Вы можете найти лучшее сравнение здесь: pythontutorial.net/advanced-python/python-целые числа

Aggragoth 28.06.2022 11:04

В C# также есть класс BigIntegerSystem.Numerics), который можно использовать для хранения сколь угодно больших чисел за счет более медленных вычислений и несколько более сложного кода. (Вы не сможете использовать Math.Factorial() или Math.Pow(), но вы можете достаточно легко написать свои собственные реализации BigInteger.) У BigInteger есть своя собственная функция Pow(), которая того стоит.

Darrel Hoffman 28.06.2022 18:40

Для справки, последний термин math.factorial(n) (n=99) эквивалентен 942689044888324774562618574305724247380969376407895166349423‌​87772947070700232237‌​98882976159207729119‌​82360585058860846042‌​94126475673600000000‌​00000000000000 — в качестве целого числа без знака для этого потребуется 519 бит, намного больше, чем даже long.

MisterMiyagi 28.06.2022 18:46

FWIW здесь Целочисленная реализация Python. По сути, он хранит длину (ob_size, поле общего назначения, которым слегка злоупотребляют для целых чисел) и блок uint32_t этой длины, биты которого представляют число.

David Z 28.06.2022 19:03

Я бы предложил double f = 1.0; for (int j = 0; j < 100; j++) { FinalAnswer += (Math.Pow(x, j))/f; f = f * (j + 1);} Или, на самом деле, избавиться от Math.Pow таким же образом.

Carsten S 28.06.2022 21:27

Если вам нужно получить действительно большие числа, очень маленькие числа или числа с большим количеством знаков по обе стороны от десятичной точки для C#, проверьте порт заголовков/классов gmplib

ivanivan 28.06.2022 23:54

Другие вопросы по теме