| |||||||||||||||||||||||||||
Замечание. 10-байтовые плавающие числа являются «родными» для Intel-овских
процессоров. То есть сам процессор работает лишь с такими числами. Даже если ваша
программа работает с 4-х или с 8-ми байтовыми числами, при загрузке в процессор
из памяти они преобразовываются в 10-байтовые и все операци выполняются именно
с ними. И лишь при записи в память числа снова преобразовываются к требуемому
(8-ми или 4-х байтовому) виду.
По не совсем понятным причинам Microsoft ведет борьбу с 10-байтовыми числами. Начиная с конца 90-х годов все микрософтовские компиляторы делают вид, что ничего о таких числах не знают. В последние годы все большее развитие получают графические сопроцессоры и некоторые другие аналогичные приспособления (SSE* и др.). Для них «родными» являются уже как 4-х, так и 8-ми байтовые числа. |
Сколько получится, если сложить 50 единиц?
50.
А 50 миллионов?
50 000 000.
А если это переменная типа float? Проверим, на всякий случай.
float s=0; for( int k=0; k<50; k++ ) s++; printf("%f\n", s);
50.000000
Здесь всё нормально.
float s=0; for( int k=0; k<50000000; k++ ) s++; printf("%f\n", s);
16777216.000000
Переменная типа float занимает в памяти 4 байта, её значение можно
представить в виде (мантисса)*2(степень), причем мантисса - трехбайтовое число.
Поэтому, если s≥16 777 216, то 1 оказывается так мала по сравнению с s, что
s+1 не примерно равно s, а точно:
Конечно, единицы складывать не очень интересно. Давайте рассмотрим
более реальный пример.
Яркость каждой точки на изображении является целым числом от 0 до 255.
Допустим, нам даны 100 миллионов точек с яркостями
int N=100000000, int_s=0; for( int k=0; k<N; k++ ) int_s+=f(k); int_s /= N; printf("%d\n", int_s);
Попробуем использовать числа типа float:
int N=100000000; float s=0; for( int k=0; k<N; k++ ) s+=f(k); s /= N; printf("%d\n", s);
И только при использовании double результат будет именно тот, который и должен быть.
Вывод: нельзя использовать float для нахождения суммы более, чем 10 млн. слагаемых.
А на сколько безопасен в этом случае double? Ведь наверное, если слагаемых будет побольше,
то и он «сломается»?
Конечно, сломается. Но если слагаемых будет больше 256 ≈ 0.7•1017.
Если считать, что мы складываем по 2 млрд. слагаемых в секунду (оптимистичный вариант), то
до этого предела мы будем добираться более года. Так что если ожидаемое время работы программы
меньше года, то об этой проблеме можете забыть.