Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
#include <stdio.h>
void main(int argc, char* argv[]) {
float sum1 = 0.f;
float sum2 = 0.f;
int n = 20000;
int i;
printf("%i numbers\n", n);
for ( i = 1; i <= n; ++i ) {
sum1 += 1.f / i;
sum2 += 1.f / (n + 1 - i);
}
printf("%f\n", sum1 - sum2);
}При подсчёте sum1 в неё сразу кладётся 1, фиксируя экспоненту, после чего начинают добавляться всё более мелкие числа. В итоге последние из них банально «обрубаются» (если не полностью, то частично), т.к. попросту не влазят в мантиссу.
Уильям Кэхэн написал программу на Си (есть версия и для Фортрана), которая позволяет проверить удовлетворяет ли связка «архитектура+компилятор+опции» IEEE754.
Что такое субнормальные денормализованные (subnormal) числа рассмотрим на простом примере. Пусть имеем нормализованное представление с длиной мантиссы P=3 (бита) и диапазоном значений экспоненты -1≤E≤2. В этом случае получим 16 чисел:
float a=0.5; int n = *((int*) &a); float b = *((int*) &(++n)); ...
s/float b = *((int*) &(++n));/float b = *((float*) &(++n));/... if (aInt < 0) aInt = 0x80000000 - aInt; ... if (bInt < 0) bInt = 0x80000000 - bInt; ...
0x80000000 <= aInt
0x80000000 <= bInt
aInt = 0x80000000 + aInt;
...
bInt = 0x80000000 + bInt;
aInt = aInt - 0x80000000;
...
bInt = bInt - 0x80000000;
...
/*
if (aInt < 0)
aInt = 0x80000000 - aInt;
...
*/
aInt &= 0x7fffffff;
...
/*
if (bInt < 0)
bInt = 0x80000000 - bInt;
...
*/
bInt &= 0x7fffffff;
if (aInt < 0)
aInt = 0x80000000 - aInt;
0x80000000 - aInt для отрицательных float.&= 0x7fffffff; приведет к тому, что функция будет считать равными числа отличающиеся знаком (например +1 будет равен -1)int intDiff должен быть unsigned int, тогда будет использоваться беззнаковое сравнение (по правилам сравнения С), иначе если в abs случится переполнение, её результат будет интерпретирован как отрицательный и if (intDiff <= maxUlps) вернет истину для совершенно разных чисел. add RAX,RBX
jc >label
Надо понимать, что «сложение» и «сложение xx-битных чисел в компьютере» вообще говоря разные операции. Эксепшен — это «все, финиш, приехали». А переполнение при том же сложении — это заранее оговоренная в документации особенность работы конкретного процессора.if (a!=a) printf("Оппа, NaN..."); union fl {
float f;
unsigned long l;
}; Тогда в отладчике можно увидеть, что fl.f=1.0 это на самом деле fl.l=0x3f800000.
Что нужно знать про арифметику с плавающей запятой