Перенос программ с одной архитектуры на другую

Сразу предупреждаю, что это сложная задача.

Есть тест. Тест стал результатом разбора большой проблемы на баг, с которым мы столкнулись в работе. Конструкция __ attribute__((noinline)) запрещает компилятору делать подстановочную функцию (для оптимизации, чтобы что-то там не взорвалось). Это самый простой способ оптимизации, гарантированно не убивающий интересную ситуацию.

#include <stdio.h>

double d = 5436277361664796672.000000;
long long ll = 5436277361664796253LL;

int __attribute__((noinline))
func1 (void)
{
  double d1 = (double)ll;

  if (d > d1)
    return 1;
  else
    return 0;
}

int __attribute__((noinline))
func2 (void)
{
  if (d > (double)ll)
    return 1;
  else
    return 0;
}

int
main (void)
{
  printf ("%d %d\n", func1(), func2());
  return 0;
}

Я провел этот тест на intel и sparc. Gcc используется в режиме с оптимизацией и без оптимизации. Получил следующие результаты:

sparc: "gcc" printed "0 0"
sparc: "gcc -O2" printed "0 0"
intel: "gcc" printed "0 1"
intel: "gcc -O2" printed "1 1"

В чем причина различий? Так или иначе при разборе ситуации было бы полезно иметь возможность все это повторить самому, но, конечно, практически ни у кого нет возможности запустить этот код на sparc. Вместо этого sparc можно попробовать запустить под Windows с помощью microsoft or borland C compiler. Я не знаю, какие им будут выданы результаты, но в любом случае что-то ни с чем не совпадает (потому что мы видим три разных результата)

Редактировать 1 _атрибут_ ((noinline)) — расширение компилятора gcc (забыл написать об этом). Поэтому VisualStudio не может его скомпилировать.


person Dima Kozyr    schedule 18.02.2014    source источник
comment
То, что оптимизация меняет результат, указывает на наличие неопределенного поведения, но я пока не могу определить, где вы получите UB.   -  person    schedule 19.02.2014
comment
Вы можете проверить размер переменных. Проверьте этот вопрос: stackoverflow.com/questions/ 7279504/   -  person Snake Sanders    schedule 19.02.2014
comment
Вы верите, что указано, как целые числа преобразуются в числа с плавающей запятой? Если да, то где и как? Дело в том, что с оптимизациями результат согласован, как и следовало ожидать.   -  person Kerrek SB    schedule 19.02.2014
comment
@delnan Я не думаю, что это правда. Возможно, не указано.   -  person David Heffernan    schedule 19.02.2014
comment
@DavidHeffernan Вполне возможно, что есть и другая причина, но наиболее вероятной причиной является UB. Кроме того, не указан ли технический термин из стандарта? Потому что неопределенное поведение есть, и то, что не указано в стандарте (в неформальном смысле), вызывает неопределенное поведение (в формальном смысле).   -  person    schedule 19.02.2014
comment
@delnan stackoverflow.com/questions/2397984/   -  person David Heffernan    schedule 19.02.2014
comment
@DavidHeffernan Спасибо, я наткнулся на это однажды, но забыл об этом.   -  person    schedule 19.02.2014


Ответы (2)


Я отмечаю, что объявление двойной константы имеет 19 значащих цифр, что является большей точностью, чем может быть представлено двойным значением IEEE (которое допускает от 15 до 17 значащих цифр). Так что d не может точно содержать 5436277361664796672.000000.

Две строки определения константы становятся разными на 16-м разряде, поэтому вы находитесь в области, где неточности в двойном значении имеют ту же величину, что и разница между этими двумя числами. Поэтому на сравнение нельзя полагаться.

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

person Tim Bergel    schedule 18.02.2014

Кажется решил проблему. В целом все правильно написал. Но на самом деле корректно работает sparc версия. Потому что стандарт для преобразования int64-> float64 должен быть с потерей точности. А в коде при конвертации (под интел) происходит int64-> float80 потеря. Т.е. код на основе Intel работает с большей точностью, но это противоречит стандарту.

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

person Dima Kozyr    schedule 18.02.2014