обновление: судя по тому, что другие нашли в исходном коде, я ошибался — sum()
не сортирует. Паттерны согласованности, которые я обнаружил ниже, связаны с тем фактом, что сортировка (как это делается в некоторых случаях ниже) и использование промежуточных значений повышенной точности (как это делается в sum()
) могут иметь аналогичные эффекты на точность...
@ user2357112 комментарии ниже:
src/main/summary.c . .. не выполняет никакой сортировки. (Это потребовало бы больших затрат на операцию суммирования.) Это даже не использование попарного или компенсированного суммирования; он просто наивно складывает все слева направо в LDOUBLE (либо long double, либо double, в зависимости от HAVE_LONG_DOUBLE).
Я изнурил себя поисками этого в исходном коде R (безуспешно - sum
трудно найти), но я могу экспериментально показать, что при выполнении sum()
R сортирует входной вектор от наименьшего к наибольшему, чтобы максимизировать точность; разница между результатами sum()
и Reduce()
ниже связана с использованием расширенной точности. Я не знаю, что делает accu
...
set.seed(101)
vec <- runif(100, 0, 0.00001)
options(digits=20)
(s1 <- sum(vec))
## [1] 0.00052502325481269514554
Использование Reduce("+",...)
просто добавляет элементы по порядку.
(s2 <- Reduce("+",sort(vec)))
## [1] 0.00052502325481269514554
(s3 <- Reduce("+",vec))
## [1] 0.00052502325481269503712
identical(s1,s2) ## TRUE
?sum()
также говорит
Там, где это возможно, используются аккумуляторы повышенной точности, но это зависит от платформы.
Выполнение этого в RcppArmadillo
для отсортированного вектора дает тот же ответ, что и в R; выполнение этого на векторе в исходном порядке дает еще один ответ (я не знаю почему; я предполагаю, что это будут вышеупомянутые аккумуляторы повышенной точности, которые больше повлияют на числовой результат, когда данные не отсортированы).
suppressMessages(require(inline))
code <- '
arma::vec ax = Rcpp::as<arma::vec>(x);
return Rcpp::wrap(arma::accu(ax));
'
## create the compiled function
armasum <- cxxfunction(signature(x="numeric"),
code,plugin="RcppArmadillo")
(s4 <- armasum(vec))
## [1] 0.00052502325481269525396
(s5 <- armasum(sort(vec)))
## [1] 0.00052502325481269514554
identical(s1,s5) ## TRUE
Но, как указано в комментариях, это работает не для всех семян: в этом случае результат Reduce()
ближе к результатам sum()
set.seed(123)
vec2 <- runif(50000,0,0.000001)
s4 <- sum(vec2); s5 <- Reduce("+",sort(vec2))
s6 <- Reduce("+",vec2); s7 <- armasum(sort(vec2))
rbind(s4,s5,s6,s7)
## [,1]
## s4 0.024869900535651481843
## s5 0.024869900535651658785
## s6 0.024869900535651523477
## s7 0.024869900535651343065
Я в тупике здесь. Я ожидал, что по крайней мере s6
и s7
будут идентичны...
Я укажу, что в целом, когда ваш алгоритм зависит от такого рода крошечных числовых различий, вы, вероятно, будете очень разочарованы, так как результаты, вероятно, будут отличаться на основе множества мелких и, возможно, не в ваших силах. управляющие факторы, такие как конкретная операционная система, компилятор и т. д., с которыми вы работаете.
person
Ben Bolker
schedule
26.07.2016
.Machine
полезным а> - person patrickmdnet   schedule 26.07.2016set.seed
передrunif
, чтобы другие могли проверить тот же тестовый пример. И можете ли вы также включить код для вашей функцииlog
? - person nrussell   schedule 26.07.2016sum
действительно, по-видимому, сохраняет суммирование в типе, определенном здесь - person alexis_laz   schedule 26.07.2016