Является ли жесткое кодирование наименее значимого байта двойника хорошей стратегией округления?

Вместо использования

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

, как в принятом ответе, было бы более надежно использовать:

import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

, поскольку использование __file__ вернет файл, из которого модуль был загружен, если он был загружен из файла, поэтому, если файл со сценарием вызывается из другого места, возвращаемый каталог будет неправильным.

Эти ответы дают более подробную информацию: https://stackoverflow.com/a/31867043/5542253 и https://stackoverflow.com/a/50502/5542253

0
задан jpo38 18 January 2019 в 20:37
поделиться

4 ответа

Является ли unsigned char * temp = (unsigned char *) & округлено безопасным или здесь есть неопределенное поведение, и почему?

Это хорошо определено как псевдоним через unsigned char разрешено разрешено .

является ли такая круглая функция безопасной и точной для всех входных данных?

Нет. Вы не можете идеально решить эту проблему с усечением / округлением. Учтите, что одна реализация дает 0x.....0ff, а другая 0x.....100. Установка lsb на 0x00 приведет к тому, что исходная разница в 1 ульп составит 256 ульпов.

Никакой алгоритм округления не может это исправить.

У вас есть два варианта:

  • не использовать с плавающей запятой, используйте другой способ (например, с фиксированной запятой)
  • встроить библиотеку с плавающей запятой в ваше приложение, который использует только базовую арифметику с плавающей запятой (+, -, *, /, sqrt), и не использует -ffast-math, или любую эквивалентную опцию. Таким образом, если вы работаете на платформе, совместимой с IEEE-754, результаты с плавающей запятой должны быть такими же, как в IEEE-754, согласно которым базовые операции должны рассчитываться «идеально». Это означает, что операция рассчитана с бесконечной точностью, а затем округлена до полученного представления.

Кстати, если разница на входе 1e-17 означает огромную разницу на выходе, то ваша проблема / алгоритм плохо обусловлены , чего, как правило, следует избегать, поскольку обычно оно не дает Вы значимые результаты.

0
ответ дан geza 18 January 2019 в 20:37
поделиться

То, что вы делаете, совершенно неверно.

Ваша проблема не в том, что вы получаете разные результаты (2,36 против 2,47). Ваша проблема в том, что, по крайней мере, один из этих результатов, и, вероятно, оба, имеют серьезные ошибки. Ваши результаты для Windows и Android не просто отличаются, они НЕПРАВИЛЬНЫ. (По крайней мере, один из них, и вы не знаете, какой из них).

Узнайте, почему вы получаете эти огромные ошибки, и измените свои алгоритмы, чтобы не увеличивать крошечные ошибки округления. Или у вас есть проблема, которая по своей сути хаотична, и в этом случае разница между результатами на самом деле очень полезная информация.

То, что вы пытаетесь, просто увеличивает ошибки округления в 256 раз, и если два разных результата заканчиваются шестнадцатеричным .... 1ff и .... 200, то вы меняете их на .... 180 и .... 280, так что даже разница между слегка отличающимися числами может возрасти в 256 раз.

И на бигендовской машине твой код просто перейдет в kaboom !!!

0
ответ дан gnasher729 18 January 2019 в 20:37
поделиться

Ваша функция не будет работать из-за псевдонимов.

double roundByCast( double d )
{
    double rounded = d;
    unsigned char* temp = (unsigned char*) &rounded;
    // changing least significant byte to be always the same
    temp[0] = 128;
    return rounded;
}

Приведение к unsigned char * для temp разрешено, поскольку приведение char * является исключением из правил наложения имен. Это необходимо для таких функций, как read, write, memcpy и т. Д., Чтобы они могли копировать значения в и из байтовых представлений.

Однако, вам не разрешено писать в temp [0], а затем предполагать, что округленное изменилось. Вы должны создать новую двойную переменную (в стеке все нормально) и memcpy temp вернуться к ней.

0
ответ дан Zan Lynx 18 January 2019 в 20:37
поделиться

Нет, округление не является стратегией для устранения мелких ошибок или гарантии согласия с расчетами, выполненными с ошибками.

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

В вашем конкретном случае жесткого кодирования младшего значащего байта самые близкие значения

0x1.mmmmmmm100

и

0x1.mmmmmmm0ff

имеют отклонение только одного ULP ... но после вашего округляя, они отличаются на 256 ULP. Oops!

0
ответ дан Ben Voigt 18 January 2019 в 20:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: