LINUX.ORG.RU

Горение от libc в Minix

 , ,


1

2

Код:

#define TEST_SPEED_FABS_LOOPS  ((U32_MAX >> 3) + bxi_randu8())

static void check_fabs_speed(void)
{
    u32 i;
    f64 iterator = 1.1;
    f64 value    = 0.0;
    f64 sum_org   = 0;
    f64 sum_new   = 0;
    u32 loops = TEST_SPEED_FABS_LOOPS;

    test_time_start();
    {
        for (i = 0; i < loops; i++)
        {
            iterator *= -1.5;
            value    += iterator;
            sum_org  += fabs(value - 50.0);
            if (value > 1e8)
                value = 0.0;
            if (iterator > 1e8)
                iterator = 1.1;
        }
    }
    test_time_finish();
    test_time_print("fabs");

    iterator = 1.1;
    value    = 0.0;
    test_time_start();
    {
        for (i = 0; i < loops; i++)
        {
            iterator *= -1.5;
            value    += iterator;
            sum_new  += bxi_fabs(value - 50.0);
            if (value > 1e8)
                value = 0.0;
            if (iterator > 1e8)
                iterator = 1.1;
        }
    }
    test_time_finish();
    test_time_print("bxi_fabs");

    printf("%f\n%f\n", sum_org, sum_new);

    if (sum_org != sum_new)
        test_failed();
}
+ rand добавлен для того, чтобы компилятор это не свернул в `mov eax 24355184302566256`.

Суть кода - проверяет скорость и точность самописного fabs. Два блока кода почти идентичны, за исключением имени функции. Запускаем на Ubuntu 16.04, libc-2.23, x86_64:

24355184302566256.000000
24355184302566256.000000
То есть функция работает точно, различия только в скорости. Теперь переносим это на машину с Minix, libc-12-187, x86:
24355184305680488.000000
24355184302566256.000000
А теперь собственно, вопрос - А КАКОГО ФИГА? Первое число - сумма вычисленная системным fabs. Самописный посчитал одинаково на обоих платформах. Что там можно было сделать не так? Там нет математических вычислений, fabs(x) = |x|! Там 2 условия должно быть:
if (isnan(x)) return -x; 
return x > 0 ? x : -x;

В общем у меня подгорает - автоматические тесты фейлятся, система говорит что я дурак, а баг на самом деле в разработчиках Minix.

Что делать? Как это решить? Почему разный результат?

★★★★★

Последнее исправление: PPP328 (всего исправлений: 1)

Это что ли?

ENTRY(fabs)
	fldl	4(%esp)
	fabs
	ret
END(fabs)
А вообще отладчиком проще посмотреть.

И почему горение от glibc, если у них похоже своя?

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Это

Скорее всего нет. Потому что на blame пишет «Import unmodified NetBSD libc in trunk». То есть баг еще и в NetBSD?

И почему горение от glibc

Поменял заголовок. По привычке написал glibc и не заметил.

Сейчас попробую собрать MWE, выложу.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от xaizek

Вот, MWE:

#include <stdio.h>
#include <stdlib.h>
#include <math.h> /* Compile me with -lm */

int main(int argc, char * argv[])
{
    unsigned int i;
    double sum = 0;
    double iterator = 1.1;
    double value    = 0.0;

    for (i = 0; i < atoi(argv[1]); i++)
    {
        iterator *= -1.5;
        value    += iterator;
        sum      += fabs(value);
            
        if (value > 1e8)
            value = 0.0;
        if (iterator > 1e8)
            iterator = 1.1;
    }

    printf("%f\n", sum);

    return 0;
}
./a.out 1000

Linux: 43824602808.364777
Minix: 43824602808.364784

Судя по всему оно по разному умножает.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Отладчик не поможет. Под -O0 разницы нет.

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

И ещё, при сборке указывается флаг -fno-builtin?

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Нет, флаг не указывается. Большой проект под асм трудно смотреть, сейчас MWE посмотрю

PPP328 ★★★★★
() автор топика

В общем у меня подгорает - автоматические тесты фейлятся, система говорит что я дурак

Так и есть. Нельзя проверять float на равенство, результат может зависеть от оптимизаций, версии компилятора, флагов fpu и бог весть чего ещё. В FPU вещи типа a + b + c != a + (b + c) и 3.0 + 4.0 != 7.0 вполне ожидаемы чуть более чем всегда.

slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 1)
Ответ на: комментарий от PPP328

Да, под линуксом sse и там, видимо fabs вообще не нужен, он как-то прибавляет как беззнаковое и всё. Скорее как slovozap говорит, сходиться так точно и не должно, так как кастомная функция сильно влияет на возможности по оптимизации.

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)

Платиновые треды.

anonymous
()
Ответ на: комментарий от slovazap

Ну спишем на это тогда. Просто в изначальном тесте последовательность действий одна и та же, плюс дробной части нет совсем. Ок, спишем на это.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Дробная часть есть всегда. По-моему IEEE 754, да? Сравнивай через эпсилон, но там тоже возможны варианты.

anonymous
()

На 32-битных intel gcc по умолчанию пытается использовать 80-разрядные регистры FPU для float и double без усечения промежуточных операций до 32/64 бит: https://gcc.gnu.org/wiki/x87note

Результат может зависеть например от уровня оптимизации (если промежуточный результат компилятору приходится сохранять в память). Или от следуемого стандарта.

Флаг gcc -fexcess-precision=standard вставляет усечение.

$ gcc a.c -o a -m32 -O2 -fexcess-precision=standard && ./a
24355184136881860.000000
$ gcc a.c -o a -m32 -O2 -fexcess-precision=fast && ./a
24355184139996084.000000
$ gcc a.c -o a -m32 -O2 -std=c99 && ./a
24355184136881860.000000
$ uname -m
x86_64

От minix не зависит.

sf ★★★
()
Ответ на: комментарий от sf

Под minix у меня clang, но видимо работает так же. Спасибо за информацию.

PPP328 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.