Intereting Posts
использование catch (…) (эллипсис) для посмертного анализа C ++ – Сплит-строка по регулярному выражению удаление элементов объекта std-вектора с использованием стирания: a) обработка памяти и b) лучший способ? Как открыть файлы COMXX (serial port) C ++: объявить глобальный class и получить доступ к нему из других classов? c ++, несколько экземпляров dll, singleton ошибка с gpumat и mat экранирование #include в пространстве имен {} block? Создание двух отдельных исполняемых файлов из make-файла (g ++) Сравнение строковых данных, полученных от сокета в C Является ли левое и правое смещение отрицательных целых чисел определенным поведением? Использование массива char внутри объединения Инициализация структуры typedef из библиотеки C в C ++ Где неопределенное поведение при использовании const_cast ? Как отсортировать набор координат в порядке возрастания по расстоянию от точки (x1, y1)?

C ++ обработка избыточной точности

В настоящее время я просматриваю код, который выполняет многоточную арифметику с плавающей запятой . Чтобы правильно работать, этот код требует, чтобы значения были уменьшены до конечной точности в четко определенных точках. Таким образом, даже если промежуточный результат был рассчитан на 80-битный расширенный регистр с плавающей запятой с высокой точностью , в какой-то момент он должен быть округлен до 64 бит для последующих операций.

В коде используется макрос INEXACT для описания этого требования, но не имеет идеального определения. В руководстве gcc упоминается стандарт -fexcess-precision=standard как способ заставить четко определенную точность для операций литья и присваивания. Однако он также пишет:

‘-fexcess-precision = standard’ не применяется для языков, отличных от C

Теперь я думаю о переносе этих идей на C ++ (комментарии приветствуются, если кто-то знает существующую реализацию). Похоже, я не могу использовать этот переключатель для C ++. Но что такое поведение g ++ по умолчанию при отсутствии какого-либо переключателя? Есть ли еще C ++-подобные способы контроля над избыточной точностью?

Я предполагаю, что для моего текущего -mfpmath=sse использования, я, вероятно, буду использовать -mfpmath=sse в любом случае, что, насколько мне известно, не должно подвергаться какой-либо избыточной точности. Но мне все еще интересно.

    Есть ли еще C ++-подобные способы контроля над избыточной точностью?

    В стандарте C99 определяется FLT_EVAL_METHOD , макрос компилятора, определяющий, как должна FLT_EVAL_METHOD избыточная точность в программе на C (многие компиляторы C по-прежнему ведут себя так, что точно не соответствуют наиболее разумной интерпретации значения FP_EVAL_METHOD которое они определяют: более старые версии GCC, генерирующие код 387, Clang при генерации кода 387, …). Тонкие точки по отношению к эффектам FLT_EVAL_METHOD были уточнены в стандарте C11.

    Начиная со стандарта 2011 года, C ++ отдает предпочтение C99 для определения FLT_EVAL_METHOD (header cfloat).

    Поэтому GCC должен просто разрешить -fexcess-precision=standard для C ++, и, надеюсь, в конечном итоге это произойдет. Те же семантики, что и для C, уже находятся в стандарте C ++, их нужно только реализовать в компиляторах C ++.


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

    Это обычное решение.

    Имейте в FP_CONTRACT что C99 также определяет FP_CONTRACT в math.h, на который вы можете захотеть взглянуть: он относится к той же проблеме, когда некоторые выражения вычисляются с большей точностью, ударяясь от совершенно другой стороны (современная команда с объединенным умножением-добавлением вместо старого набора команд 387). Это прагма для принятия решения о том, разрешено ли компилятору заменять дополнения и умножения исходного уровня с помощью инструкций FMA (это приводит к тому, что умножение фактически вычисляется с бесконечной точностью, потому что так работает эта инструкция, а не округляется до точность такого типа, как это было бы с отдельными инструкциями умножения и добавления). Эта прагма, по-видимому, не была включена в стандарт C ++ (насколько я вижу).

    Значение по умолчанию для этого параметра определяется реализацией, и некоторые люди утверждают, что по умолчанию должно быть разрешено создавать инструкции FMA (для компиляторов C, которые иначе определяют FLT_EVAL_METHOD как 0). Вы должны, в C, обеспечить будущее своим кодом с помощью:

     #include  #pragma STDC FP_CONTRACT off 

    И эквивалентное заклинание в C ++, если ваш компилятор документирует один.


    что такое поведение g ++ по умолчанию при отсутствии какого-либо переключателя?

    Я боюсь, что ответ на этот вопрос заключается в том, что поведение GCC, скажем, при генерации кода 387, бессмысленно. См. Описание ситуации, которая побудила Джозефа Майерса исправить ситуацию для C. Если g ++ не реализует -fexcess-precision=standard , это, вероятно, означает, что 80-разрядные вычисления случайным образом округляются до точности типа, когда произошел компилятор чтобы пролить в регистр некоторые регистры с плавающей запятой, введя программу ниже, чтобы напечатать «foo» в некоторых случаях вне контроля программиста:

     if (x == 0.0) return; ... // code that does not modify x if (x == 0.0) printf("foo\n"); 

    … потому что код в эллипсисе вызвал x , который содержался в 80-битном регистре с плавающей запятой, чтобы пролить его на 64-разрядный слот в стеке.

    Но что такое поведение g ++ по умолчанию при отсутствии какого-либо переключателя?

    Я сам нашел один ответ через эксперимент, используя следующий код:

     #include  #include  int main(int argc, char** argv) { double a = atof("1.2345678"); double b = a*a; printf("%.20e\n", b - 1.52415765279683990130); return 0; } 

    Если b округляется ( -fexcess-precision=standard ), результат равен нулю. В противном случае ( -fexcess-precision=fast ) это что-то вроде 8e-17 . Компиляция с -mfpmath=387 -O3 , я мог бы воспроизвести оба случая для gcc-4.8.2 . Для g++-4.8.2 Я получаю сообщение об ошибке для -fexcess-precision=standard если я пытаюсь это сделать, и без флага я получаю то же поведение, что и -fexcess-precision=fast дает для C. Добавление -std=c++11 не помогает. Итак, теперь подозрение, уже озвученное Паскалем, является официальным: g ++ не обязательно кругом повсюду.