Почему при нахождении сум в прямом и обратном порядке ответ разный?

Почему при нахождении сумм в прямом (значение в переменной s1) и обратном порядке (s2) ответ разный?

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

int main() {
    float s1, s2; 
    long long int n;

    s1 = 0.; 
    for (n = 1; n <= 100000000; n++) s1 += 1. / (n * n);
    s2 = 0.; 
    for (n = 100000000; n >= 1; n--) s2 += 1. / (n * n);
    
    printf("%.17lf\n", s1); 
    printf("%.17lf\n\n", s2);
    system("pause"); 
    return 0;
}

Ответы (1 шт):

Автор решения: Zhihar

ситуация следующая (все как говорит @avp) у float ограничена точность определённым кол-вом знаком после запятой, поэтому

1 + 10000000000000000000 = 10000000000000000000 (1e19)

точность у float в районе 7 знаков после запятой, поэтому у того же числа 10000000000000000000 в float входят только первые 7 цифр 1000000*************, а остальные не влияют никак на число, т.е.

999999999999 + 10000000000000000000 = 10000000000000000000 (1e19)

теперь что делают 2 ваших цикла:

первый цикл начинает складывать от большего числа к меньшему, в какой-то момент уже не имеет значения, что вы складываете - это не повлияет на результат

для float в вашем коде после n = 4096 все остальные слагаемые настолько малы относительно суммы, что не влияют на сумму

второй цикл начинает складывать от меньших чисел к большим, поэтому не учтенные в первом случае слагаемые после n = 4096 все таки в сумме образуют величину, которая влияет на итоговую сумму

поэтому и видим отличие

    s1  1.64472532  float
    s2  1.64493406  float

в первом случае поменьше, во втором побольше на ту самую сумму от n = 4096 до n = 100000000, а на самом деле где-то до n = 370728

Кстати у double мантисса гораздо больше (весь тип занимает 8 байт вместо 4 для float), поэтому результаты тоже будут разными по описанным выше причинам, но отличаться будут на меньшую величину

    s1  1.6449340578345750  double
    s2  1.6449340568482265  double

и в первом цикле слагаемые не учитываются уже только с n = 94906266

→ Ссылка