Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Проблема с точностью


Автор: Ares4322 3.9.2011, 12:49
Доброго времени суток!
Есть программа. Она должна выводить число с точностью 10 знаков после запятой. Но для 100000 циклов она выводит inf. 
Что за inf т как сделать, чтобы она выводила в итоге число с точностью 10 знаков после запятой?
Код

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char** argv) {
    int i;
    long double s=0;
    for( i=1; i<100000; i++ ){
        s += powl((i*i),-1);
    }
    printf("%11.10lf\n", s);
    return (EXIT_SUCCESS);
}


Автор: boostcoder 3.9.2011, 12:57
Цитата(Ares4322 @  3.9.2011,  12:49 Найти цитируемый пост)
как сделать, чтобы она выводила в итоге число с точностью 10 знаков после запятой?

использовать http://gmplib.org/ ;)
вы наверное не знаете, что при использовании double, на другой платформе/ОС вы получите немного(а может и много) другой результат ;)

Автор: Ares4322 3.9.2011, 13:03
Я поясню. Решаю сейчас задачи из учебника на точность. И там такой код:
Код

   int i;
    double s=0;
    for( i=1; i<1000000; i++ ){
        s += 1/(i*i);
    }
    printf("%f\n", s);

По заданию его нужно исправить, чтобы он выводил значение s += 1/(i*i) от 1 до 10000 с точностью до 10 знаков после запятой. Этот код выводит inf. Я его переделал в вышепредставленный. Он тоже выводит  inf. И я не могу понять, как мне выполнить задание.

Автор: boostcoder 3.9.2011, 13:30
ааа, понял)

Автор: Ares4322 3.9.2011, 13:35
И все-таки, не подскажете, где ошибка и как решить задачу?

Автор: rodnover 3.9.2011, 13:57
http://ru.wikipedia.org/wiki/%D0%A1%D1%83%D0%BC%D0%BC%D0%B0_%D1%80%D1%8F%D0%B4%D0%B0

user posted image

Оно? 

----
А не. сейчас. 

---
Да мозги уже не те. Перепутал степенной ряд с  рядом дирихле. И формулу частичной суммы этого ряда в инете оказалось непросто найти. Попробуйте, может получится?

Автор: Void 3.9.2011, 14:58
Цитата(Ares4322 @  3.9.2011,  14:49 Найти цитируемый пост)
for( i=1; i<100000; i++ ){

Цитата(Ares4322 @  3.9.2011,  15:03 Найти цитируемый пост)
for( i=1; i<1000000; i++ ){

Цитата(Ares4322 @  3.9.2011,  15:03 Найти цитируемый пост)
от 1 до 10000

Определитесь уже. В первом и втором случае переполнение 32-битного int в i * i.

Автор: volatile 3.9.2011, 15:37
Код

    for( i=1; i<1000000; i++ )
    {
        s += 1/(double(i)*i);
    }
    printf("%.10f\n", s);

Автор: Фантом 3.9.2011, 15:54
Что-то Вы странное наворотили. Во-первых, для точности 10 в знаков типа double вполне достаточно. Во-вторых, не надо пользоваться powl(), результат достигается намного проще:
Код

s += 1.0/i/i;

(но именно так - 1.0 нужно для смены типа, (i*i) нельзя, чтобы не вылезти за пределы int).

В принципе, для вящей правильности следовало бы поменять порядок суммирования (от больших i к меньшим), но поскольку запас точности double - еще порядков пять лишних, в данном случае это ни на чем не скажется.

P.S. Про "странное" - это к исходному сообщению, а не к предыдущему.  smile 

Автор: Skevalt 3.9.2011, 16:08
Цитата(Фантом @  3.9.2011,  15:54 Найти цитируемый пост)
(но именно так - 1.0 нужно для смены типа, (i*i) нельзя, чтобы не вылезти за пределы int).
 Вы правы, но mingw и liveworkspace корректно обрабатывают и 1.0/(i*i):
Код

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char** argv) 
{
    double s = 0.0;
    for(int i = 1; i < 10000; i++)
    {
        s += 1.0/(i*i);
    }
    printf("\n%e", s);
   
    return 0;
}


Автор: volatile 3.9.2011, 16:40
Цитата(Skevalt @  3.9.2011,  16:08 Найти цитируемый пост)
mingw и liveworkspace корректно обрабатывают и 1.0/(i*i):

Но это вовсе не означает что все компиляторы будут корректно обрабатывать данное выражение.
По стандарту порядок вычисления может быть любым. И не исключено что сначала будет высислено (i*i), и произойдет переполнение.

наиболее переносисый код, все-же
Цитата(volatile @  3.9.2011,  15:37 Найти цитируемый пост)
s += 1/(double(i)*i);


Автор: Ln78 4.9.2011, 08:45
Цитата(Void @  3.9.2011,  14:58 Найти цитируемый пост)
Определитесь уже. В первом и втором случае переполнение 32-битного int в i * i

Приближённо заменим ряд интегралом. Получим, что остаток будет примерно равен 1/N. Так что, если нужно обеспечить точность 10 в минус десятой, то N должно быть не меньше 10 в десятой. Квадрат – 10 в 20-й. А точность даблов – на несколько порядков меньше. Ещё и погрешность суммирования. Таким способом требуемую точность получить не удастся. 


P.S. не так понял задачу. Здесь требуется конечная сумма для относительно небольших N. Тогда просто заменить int на double, степенные функции не нужны, только время зря расходуют.

Автор: mes 4.9.2011, 10:44
Цитата(Ln78 @  4.9.2011,  07:45 Найти цитируемый пост)
 А точность даблов – на несколько порядков меньше. 

нужна не "точность расчета", а "точность вывода" :
Цитата(Ares4322 @  3.9.2011,  11:49 Найти цитируемый пост)
 выводить число с точностью 10 знаков


Автор: Ares4322 4.9.2011, 11:58
Да, нужна именно точность вывода. 
У меня gcc 4.4.5 и 1/i*i отрабатывает не так, как ожидаешь. В этом и была проблема.
Версии http://forum.vingrad.ru/index.php?showtopic=337389&view=findpost&p=2397219 и http://forum.vingrad.ru/index.php?showtopic=337389&view=findpost&p=2397221 работают.
Теперь знаю, что порядок вычисления арифметических выражений может быть не таким, каким ты его ожидаешь.
И что желательно явно приводить типы.
Спасибо!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)