Разные результаты журнала и экспоненты в Linux и Windows в R, почему и какой обходной путь?

Вот ситуация: у меня есть вектор 0:4, который я использую log1p для преобразования и обратного преобразования с помощью exp(x) - 1. Я классифицировал исходный вектор 0:4 и вектор обратного преобразования, используя одни и те же критерии, но результаты различаются для Windows и Linux. Ниже приведен минимальный пример, который я подготовил:

vec_original <- 0:4
log_vec <- log1p(vec_original)
vec_bktrans <- exp(log_vec) - 1
cat_original <- cut(vec_original, c(0, 1, 2, 4, Inf), include.lowest = TRUE)
cat_bktrans <- cut(vec_bktrans, c(0, 1, 2, 4, Inf), include.lowest = TRUE)

data.frame(
  original = format(vec_original, digits = 20),
  bk_trans = format(vec_bktrans, digits = 20),
  cat_original = cat_original,
  cat_bktrans = cat_bktrans
)

При запуске того же кода в Linux я получаю следующий результат (см. строку номер 3):

  original              bk_trans cat_original cat_bktrans
1        0 0.0000000000000000000        [0,1]       [0,1]
2        1 1.0000000000000000000        [0,1]       [0,1]
3        2 1.9999999999999995559        (1,2]       (1,2]
4        3 3.0000000000000000000        (2,4]       (2,4]
5        4 3.9999999999999991118        (2,4]       (2,4]

В Windows я получаю следующие результаты (см. строку номер 3):

  original              bk_trans cat_original cat_bktrans
1        0 0.0000000000000000000        [0,1]       [0,1]
2        1 1.0000000000000000000        [0,1]       [0,1]
3        2 2.0000000000000004441        (1,2]       (2,4]
4        3 3.0000000000000000000        (2,4]       (2,4]
5        4 3.9999999999999991118        (2,4]       (2,4]

Может ли кто-нибудь объяснить, в чем причина этого?

Да, я понял проблему с неточностями чисел с плавающей запятой в машинах, но в посте все еще не объясняются различия в Windows и Linux.

TheRimalaya 04.06.2024 00:35

Я полагаю, что обходной путь — округлить окончательные значения до нескольких десятичных знаков, что имеет смысл в контексте вашего анализа. Я предполагаю, что 1,999999 и 2,000000, вероятно, теоретически одинаковы.

thelatemail 04.06.2024 00:44

Чтобы ответить на вопрос «любое обходное решение», было бы полезно иметь больше контекста: какая часть вашего текущего кода/рабочего процесса ломается из-за того, что эти результаты не совсем совпадают?

Ben Bolker 04.06.2024 01:29

Различные алгоритмы для вычисления значений, выполняющие разные вычисления, дают немного разные результаты?

Shawn 04.06.2024 05:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
4
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это предположение, но я предполагаю, что разница между платформами (которая может зависеть от деталей параметров компилятора и фактической архитектуры ЦП, а также ОС) связана с необязательным использованием где-то 80-битных регистров расширенной точности. в вычислительном пути, например. см. этот вопрос или этот вопрос . Гораздо больше информации о повышенной точности здесь:

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

Ответ более высокого уровня на этот вопрос (к сожалению) «никогда не полагайтесь на точное равенство в вычислениях с плавающей запятой на разных платформах». «Любым обходным путем» было бы округление результатов, как предлагает @thelatemail, или использование чего-то вроде all.equal() для проверки приблизительного равенства (точный ответ будет зависеть от того, какое использование вы хотите использовать в дальнейшем, и почему важно, чтобы они быть в точности эквивалентны...)

Другие вопросы по теме