Как иметь дело с избыточной точностью в вычислениях с плавающей точкой?

Правильно ли мое понимание законности sc = s?

blockquote>

Да, только некоторые детали последней части нужны.

... но любое присвоение (или ссылка?) на *s или sc было бы незаконным.

blockquote>

(я подозреваю, что OP означает «... или *sc было бы незаконно.»)

Ссылка на то, на что указывает s или sc, в порядке, как в char ch = *sc;

Попытка изменить значение *s или *sc представляет собой неопределенное поведение (UB), а не «недопустимо», как в *sc = 'x';
(См. хорошую дополнительную информацию по @rici )

С UB назначение может работать, оно может не работать по вторникам, код может аварийно завершиться и т. Д. C не определяет, что происходит. Код достоверности не должен пытаться это сделать.

9
задан Stephan 3 February 2009 в 09:39
поделиться

5 ответов

В Вашем вопросе Вы заявили то использование volatile будет работать, но что будет огромный хит производительности. Что относительно того, чтобы использовать volatile переменная только во время сравнения, позволяя x быть сохраненным в регистре?

double x; /* might have excess precision */
volatile double x_dbl; /* guaranteed to be double precision */
do {
  x = /* some computation */;
  x_dbl = x;
} while (x_dbl <= 0.0);

Необходимо также проверить, можно ли ускорить сравнение с самым маленьким субнормальным значением при помощи long double явно и кэш это значение, т.е.

const long double dbl_denorm_min = static_cast<long double>(std::numeric_limits<double>::denorm_min());

и затем сравните

x < dbl_denorm_min

Я предположил бы, что достойный компилятор сделает это автоматически, но каждый никогда не знает...

2
ответ дан 4 December 2019 в 21:12
поделиться

Поскольку Arkadiy заявил в комментариях, явном броске ((double)x) <= 0.0 должен работать - по крайней мере, согласно стандарту.

C99:TC3, 5.2.4.2.2 §8:

За исключением присвоения и броска (которые удаляют весь дополнительный диапазон и точность), значения операций с плавающими операндами и значения, подвергающиеся обычным арифметическим преобразованиям и плавающих констант, оценены к формату, диапазон которого и точность могут быть больше, чем необходимый типом. [...]


При использовании GCC на x86 можно использовать флаги -mpc32, -mpc64 и -mpc80 для установки точности операций с плавающей точкой к единственному, удваиваются и расширенная двойная точность.

7
ответ дан 4 December 2019 в 21:12
поделиться

Обязательно осуществите ту проверку абсолютное значение. Это должен быть эпсилон вокруг нуля, выше и ниже.

0
ответ дан 4 December 2019 в 21:12
поделиться

Ну, GCC имеет флаг, - fexcess-точность, которая вызывает проблему, которую Вы обсуждаете. Это также имеет флаг, - ffloat-хранилище, которое решает проблему, которую Вы обсуждаете.

"Не храните переменные с плавающей точкой в регистрах. Это предотвращает нежелательную избыточную точность на машинах, таких как 68000, где плавающие регистры (68881) сохраняют больше точности, чем двойное, как предполагается, имеет".

Я сомневаюсь, что решение не оказывает влияния производительности, но влияние является, вероятно, не чрезмерно дорогим. Случайный поиск с помощью Google предполагает, что стоит приблизительно 20%. На самом деле я не думаю, что существует решение, которое является и портативным и не оказывает влияния производительности, начиная с того, чтобы вынуждать микросхему не использовать избыточную точность часто собирается включить некоторую небесплатную операцию. Однако это - вероятно, решение, которое Вы хотите.

0
ответ дан 4 December 2019 в 21:12
поделиться

Интересно, есть ли у Вас правильный критерий остановки. Это кажется, что x <= 0 является условием исключений, но не завершающимся условием и что завершающееся условие легче удовлетворить. Возможно, должен быть оператор завершения в Вашем цикле с условием продолжения, который останавливает повторение, когда некоторый допуск встречен. Например, много алгоритма завершается, когда два последовательных повторения достаточно друг близко к другу.

1
ответ дан 4 December 2019 в 21:12
поделиться