Как обрабатывать арифметические операции с чрезвычайно большими числами?

Вопрос или проблема

Я пытаюсь найти кумулятивную функцию распределения для особого типа порядковых статистик; постепенное цензурирование равномерных порядковых статистик. Я разработал следующий код на R:

# Кумулятивная функция распределения для r-й порядковой статистики с постепенным цензурированием
n <- 30 # Общее количество экспериментальных единиц
m <- 15 # Желаемое количество отказов
R <- c(rep(0, m - 1), n - m) # Схема постепенного цензурирования
order <- m # Порядок цензурированных порядковых статистик (здесь максимальный порядок)

gam <- NA
Cr <- NA
for(i in 1 : order)
{
  gam[i] <- m - i + 1 + sum(R[i : m])
}
for(i in 1 : order)
{
  Cr[i] <- prod(gam[1 : i])
}
air <- array(dim = c(order, order))

for(i in 1 : order)
{
  for (j in 1 : order) {

    if(i != j)
    {
      air[i, j] <- 1/(gam[j] - gam[i])
    }
  }
}
A <- NA
for(i in 1 : order)
{
  A[i] = prod(na.omit(air[i,]))
}
# Кумулятивная функция распределения для постепенного цензурирования равномерных порядковых статистик
progU_CDF <- function(u)
{
  CDF = NA
  for(i in 1 : length(u))
  {
    CDF[i] <- 1 - (Cr[order] * sum((A/gam) * ((1 - u[i])^(gam))))
  }
  return(CDF)
}

Теперь progU_CDF(0) должен давать 0, а progU_CDF(1) должен давать 1. Тем не менее, в этом случае progU_CDF(0) выдает число, очень близкое к 0, но не совсем 0. Математически, идея заключается в том, что когда u = 0, Cr[order] * sum(A/gam) = 1.

Кроме того, когда я строю график CDF, форма оказывается приемлемой, т.е. монотонно не убывающей.

plot(seq(0, 1, 0.01), progU_CDF(seq(0, 1, 0.01)), type = "l")

График CDF порядковых статистик n = 30, m = 15

Однако ситуация начинает приходить в беспорядок, когда я беру n = 50 и m = 25. Ничего не изменилось, но Cr[order] * sum(A/gam) ни разу не приближается к 1, когда u = 0. И график CDF выглядит так:

График CDF порядковых статистик n = 50, m = 25

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

Что еще более сбивает с толку, так это то, что Cr[order] * sum(A/gam) и sum(Cr[order] * A/gam) дают два разных числа, что противоречит интуиции, так как Cr[order] является константой.

Мой вопрос: почему это работает для n = 30, m = 15, но не для n = 50, m = 25? Есть ли способ справиться с такими большими числами, чтобы Cr[order] * sum(A/gam) всегда находилось близко к 1, когда u = 0, независимо от значений n и m?

A приводит к вектору очень малых чисел чередующихся знаков. Ошибки накапливаются так быстро, что при выполнении расчетов в логарифмическом масштабе все равно возникают большие ошибки. Множественная точность с Rmpfr кажется верным решением.

Векторизованный с помощью Rmpfr:

library(Rmpfr)

fprogU_CDF <- function(n, m, precBits = 128) {
  R <- c(numeric(m - 1), n - m) # Схема постепенного цензурирования
  order <- m # Порядок цензурированных порядковых статистик (здесь максимальный порядок)

  gam <- mpfr(rev(cumsum(R[m:order])) + m:(m - order + 1), precBits)
  Cr <- cumprod(gam[1:order])
  air <- 1/outer(gam, gam, "-")
  diag(air) <- 1
  A <- apply(air, 1, prod)
  diag(air) <- NA
  # Кумулятивная функция распределения для постепенно цензурированных равномерных порядковых статистик
  function(u) {
    as.numeric(1 - Cr[order]*colSums(A/gam*outer(gam, 1 - u, \(x, y) y^x)))
  }
}

Тестирование с n = 30 и m = 15.

progU_CDF <- fprogU_CDF(30, 15)
progU_CDF(0)
#> [1] 2.15461e-27
progU_CDF(1)
#> [1] 1
curve(progU_CDF(x), 0, 1)

введите описание изображения здесь

Тестирование с n = 50 и m = 25.

progU_CDF <- fprogU_CDF(50, 25, 1024)
progU_CDF(0)
#> [1] 4.050669e-288
progU_CDF(1)
#> [1] 1
curve(progU_CDF(x), 0, 1)

введите описание изображения здесь

Ответ или решение

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

  1. Признаки большой арифметики: Когда вы работаете с большими числами, такие данные могут превышать диапазон стандартного числового типа R (обычно double), что может вызвать потери точности. Этим объясняются неожиданные результаты, которые вы наблюдаете, такие как CDF, возвращающая значения, далёкие от 0 или 1, или несовпадающие суммы, когда n = 50 и m = 25.

  2. Логарифмические преобразования: Один из способов обработки больших чисел заключается в использовании логарифмов. Производя вычисления в логарифмическом масштабировании, вы можете избежать верхних границ и избежать переполнения или потеря точности. Ваша функция для A и других сумм может быть адаптирована для работы с логарифмами, а затем преобразовывать результаты обратно в экспоненциальный масштаб.

  3. Многоразрядные числовые библиотеки: Как вы уже заметили, использование библиотеки Rmpfr для работы с высокоточным арфметикой — это подходящее решение. Эта библиотека позволяет вам выполнять арифметику с произвольной точностью, что особенно полезно при работе с большими числами.

Пример реализации с использованием Rmpfr

Вот как можно адаптировать вашу функцию с использованием Rmpfr для повышения точности:

library(Rmpfr)

fprogU_CDF <- function(n, m, precBits = 128) {
  R <- c(numeric(m - 1), n - m) # Прогрессивная схему цензурирования
  order <- m # Порядок цензурованных порядковых статистик

  gam <- mpfr(rev(cumsum(R[m:order])) + m:(m - order + 1), precBits)
  Cr <- cumprod(gam[1:order])
  air <- 1 / outer(gam, gam, "-")
  diag(air) <- 1
  A <- apply(air, 1, prod)
  diag(air) <- NA

  # CDF прогрессивных цензурованных порядковых статистик
  function(u) {
    as.numeric(1 - Cr[order] * colSums(A / gam * outer(gam, 1 - u, \(x, y) y^x)))
  }
}

# Тестирование с n = 30 и m = 15
progU_CDF <- fprogU_CDF(30, 15)
print(progU_CDF(0)) # Ожидаемое значение близкое к 0
print(progU_CDF(1)) # Ожидаемое значение ровно 1

# Тестирование с n = 50 и m = 25
progU_CDF <- fprogU_CDF(50, 25, 1024)
print(progU_CDF(0)) # Ожидаемое значение близкое к 0
print(progU_CDF(1)) # Ожидаемое значение ровно 1

Заключение

Работа с очень большими числами в R требует внимательности к деталям и правильных математических методов для предотвращения потери точности. Использование библиотек, позволяющих большую точность, таких как Rmpfr, совместно с логарифмическими преобразованиями, поможет вам избежать сложностей при вычислениях и обеспечит ожидаемые результаты вашей кумулятивной функцию распределения для любых значений n и m.

Оцените материал
Добавить комментарий

Капча загружается...