Как округляется результат этой операции одинарной точности? [Или почему этот бит 1, а не 0?] - PullRequest
5 голосов
/ 28 октября 2011

Я работаю над процедурой оптимизации функций (вариант алгоритма Нелдера-Мида), которая не может сходиться в очень специфических условиях.

Я определил, что переменная float, давайте назовемему a присваивается среднее значение между a и другой переменной b, которая отличается от нее только битом.

Точнее, значения каждой переменной следующие:

float a = 25.9735966f; // 41CFC9ED
float b = 25.9735947f; // 41CFC9EC

И теперь я пытаюсь присвоить a среднее значение от a до b:

a = 0.5 * (a+b);

Когда я пишу этот код в тестовой программе, я получаюрезультат, который я хочу, а именно 25.9735947.Но в отладчике моего исходного библиотечного кода я вижу, что значение остается 25.9735966.Я почти уверен, что у меня одинаковые флаги компилятора в обеих программах. Есть ли какая-то причина, по которой это вычисление с одинарной точностью даст разные результаты?

ОБНОВЛЕНИЕ

Как и запрашивал @PascalCuoq, вот что я думаюэто сборка для рассматриваемой линии.Строка делает еще несколько вещей, и я не уверен, где происходит умножение.

.loc 1 53 0 discriminator 2
movl    -60(%rbp), %eax
cltq
salq    $3, %rax
addq    -88(%rbp), %rax
movq    (%rax), %rax
movl    -44(%rbp), %edx
movslq  %edx, %rdx
salq    $2, %rdx
leaq    (%rax,%rdx), %rcx
movl    -44(%rbp), %eax
cltq
salq    $2, %rax
addq    -72(%rbp), %rax
movl    -60(%rbp), %edx
movslq  %edx, %rdx
salq    $3, %rdx
addq    -88(%rbp), %rdx
movq    (%rdx), %rdx
movl    -44(%rbp), %esi
movslq  %esi, %rsi
salq    $2, %rsi
addq    %rsi, %rdx
movss   (%rdx), %xmm1
movl    -52(%rbp), %edx
movslq  %edx, %rdx
salq    $3, %rdx
addq    -88(%rbp), %rdx
movq    (%rdx), %rdx
movl    -44(%rbp), %esi
movslq  %esi, %rsi
salq    $2, %rsi
addq    %rsi, %rdx
movss   (%rdx), %xmm0
addss   %xmm1, %xmm0
movss   .LC6(%rip), %xmm1
mulss   %xmm1, %xmm0
movss   %xmm0, (%rax)
movl    (%rax), %eax
movl    %eax, (%rcx)

УТОЧНЕНИЕ

Мой код - ripoff вариант кода Нелдера-Мида из Числовых Рецептов.Вот эта строка:

p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);

В этой строке p[i][j] == 25.9735966f и p[ilo][j] == 25.9735947f.Результирующее значение в p[i][j] равно 25.9735966f.

1 Ответ

2 голосов
/ 29 октября 2011

Я просто перечитал соответствующую часть IEEE 754-1985, предполагая, что ваша реализация с плавающей точкой соответствует этому стандарту.Единственное, что приходит на ум, - это то, что в ваших двух средах существуют разные режимы округления.Это следующие возможности:

  • раунд до ближайшего, и в случае равного расстояния: установить младший значащий бит в ноль => 25.9735947f
  • раунд в направлении +INF =>25.9735966f
  • в направлении 0 => 25.9735947f
  • в направлении -INF => 25.9735947f

Так что единственная возможность состоит в томваша среда отладки имеет режим округления в направлении + INF .Для меня нет другого правдоподобного объяснения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...