Почему в зависимости от ОС вывод asinh отличается от numpy? - PullRequest
0 голосов
/ 31 октября 2018

Я пытаюсь сохранить согласованные результаты вычислений с плавающей запятой для разных операционных систем, и я столкнулся с странной регрессией в отношении numpy и arcsinh при тестировании на более новых системах. Вот минимальный рабочий пример, который ведет себя по-разному в разных системах.

#!/usr/bin/env python
import struct

from numpy import (array, arcsinh, float32)


def float_to_hex(f):
    return hex(struct.unpack('<I', struct.pack('<f', f))[0])


numpy_result = arcsinh(array([3.0], dtype=float32))[0]
print("asinh(3.0):", numpy_result, float_to_hex(numpy_result))

На Centos 7 и Ubuntu 16.04 я получаю следующий результат: asinh(3.0): 1.8184464 0x3fe8c2da

На Ubuntu 18.04 (и Windows, по словам коллеги) я получаю следующий результат: asinh(3.0): 1.8184465 0x3fe8c2db

Было бы здорово понять, почему это происходит, и как получить согласованный результат в разных системах. Идеально придерживается 32-битного решения с плавающей запятой. Есть ли какая-то непонятная опция, которую я пропускаю, которая меняется в разных операционных системах?

Примечательно, что я не могу воспроизвести это с помощью C-программы. С помощью asinh GLIBC (32-разрядного числа с плавающей запятой 3.0) я всегда получаю новый результат 1.8184465 и его шестнадцатеричное представление 0x3fe8c2db независимо от того, в какой системе я работаю. Это, кажется, специфично для numpy.

Мой рабочий пример C:

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

int main() {
    float value = asinhf(3.0f);
    unsigned int hexValue = *(unsigned int *)&value;
    printf("Plain value: %.7f\n", value);
    printf("Hex value: 0x%8x\n", hexValue);
    return 0;
}

Я также могу убедиться, что в системах используется одна и та же клочковатая версия. В этом случае это 1.15.3. Пакет numpy был установлен с колес повсюду, поэтому установлены одни и те же библиотеки общих объектов. Для здравого смысла я дважды проверил библиотеки, выполнив операцию file на всех из них во всех системах.

Я полагаю, что согласно IEEE 754 последняя значащая цифра 5 (для arcsinh из 3.0) является правильной, поскольку она должна округляться от нуля. Тем не менее, решение, в котором результат является согласованным, для меня важнее.

Спасибо за ваше время.

1 Ответ

0 голосов
/ 31 октября 2018

Итак, я выяснил , почему ответ в разных системах разный, и как я его раньше не видел. Тем не менее, я все еще не уверен, как получить последовательные результаты.

Как отметил Марк Дикинсон в комментариях, я упустил из виду, что gcc выполняет оптимизацию во время компиляции с использованием MPFR (с плавающей точкой с множественной точностью и правильным округлением). Запуск ldd в моем полученном двоичном файле показал, что libm вообще не загружался динамически. Я перекомпилировал мой пример C с помощью clang и динамического связывания в libm, и вот, я получил те же самые результаты, которые я получил бы через python / numpy для всех систем. В результате asinhf(3.0f); округляется в более старых системах и округляется в более новых.

Так что в какой-то момент это выглядит как libm обновление библиотеки.

В частности, произошло изменение, которое произошло по крайней мере между 2,23 и 2,27 GLIBC.

Если у кого-нибудь есть какие-либо предложения для получения последовательного округления по системам, я был бы очень признателен. Я подозреваю, что может быть неправильное округление независимо от точности на старых системах.

Спасибо, что уделили время.

...