2014-08-28 2 views
1

Для удовольствия я пытался оценить гауссовский интеграл от 0 до 1, используя разложение в ряд. По этой причине, я написал функцию факториала, которая хорошо работает до 20 (я проверил), а затем я написал это:Гауссовское интегральное и двойное деление

int main(){ 
    int n; 
    long double result=0; 
    for(n=0; n<=5; n++){ 
     if(n%2==0){ 
      result+=(((long double) 1/(long double)(factorial(n)*(2*n+1)))); 
     } else { 
      result-=(((long double) 1/(long double)(factorial(n)*(2*n+1)))); 
     } 
    }   
    printf("The Gaussian integral from 0 to 1 is %Lf\n", result); 
} 

Это дает мне странное отрицательное число, которое, очевидно, даже не близко. Я подозреваю, что проблема связана с актерским составом, но я не знаю, что это такое. Есть предположения? Это не первое, что я пробовал. Я попытался преобразовать что-либо в выражение и поставить явное действие в начале, но это не сработало.

+2

Что является результатом 'factorial (0)'? – mch

+1

Работает для меня: http://ideone.com/VLgnoS – interjay

+0

Это 1, я обратился к проблеме, когда писал функцию. –

ответ

3

Вы используете компилятор MinGW (порт gcc для Windows), который имеет проблемы с типом long double. Это связано с конфликтами между реализацией GCC long double и библиотекой Microsoft C. См. Также this question.

Согласно this question, определение __USE_MINGW_ANSI_STDIO может решить эту проблему. Если нет, то вместо этого будет работать double.

+0

Впечатляющий подвиг вычета. –

2

В (long double)(factorial(n)*(2*n+1) умножения являются целыми умножениями, и первый может переполняться, если результат factorial уже близок к пределу используемого целочисленного типа.

Напишите ((long double)(factorial(n))*(2*n+1), чтобы первое умножение было умножением с плавающей запятой.

+0

'n <= 5' здесь, поэтому он не должен переполняться. – interjay

+0

@interjay Да. Я должен предположить, что код, показанный в вопросе, не совсем тот, который переполняется. Однако, принимая факториальную функцию, которая работает для переданных ей значений и возвращает некоторый целочисленный тип (не заданный в вопросе), целочисленное умножение на '2 * n + 1' является очевидным красным флагом в вопросе и немедленно преобразуется с плавающей точкой - это самое простое средство. –

+1

OP утверждает, что «факториальная функция работает до 20!». Я сомневаюсь, что он переполнит даже 64-битное целое число. Поэтому я согласен с Паскалем - это не SSCCE. Итак, +1 ответ (даже если мой симпатичный). – Bathsheba

1

Вы почти наверняка переполняете свой целочисленный тип. В C это технически неопределенное поведение.

Для 32-разрядного целого числа без знака, 13! будет переполняться. На 64 бит, 21! будет переполняться.

Ваш алгоритм сохранится немного дольше, если вы используете тип с плавающей точкой или расширение, например __uint128 (дает вам, я думаю, до 34!), Если ваш компилятор его поддерживает.

Еще одна проблема, с которой вы сталкиваетесь, заключается в том, что вы постепенно добавляете условия уменьшения размера в общую сумму. Это никогда не бывает хорошей идеей при работе с типами с плавающей запятой. Если вы запустите цикл for в обратном порядке, результат будет более точным.

+0

Он работает с двойным, хотя и с 6 цифрами точности. Как я могу сделать немного больше? –

+1

предложение об улучшении добавлено в ответ – Bathsheba

Смежные вопросы