Тригонометрическая точность в R
Итак, мне поставлена следующая проблема:
"На параболе y = x2/k выбраны три точки A(a, a2/k), B(b, b2/k) и C(c, c2/k).
Пусть F(K, X) - число целочисленных четверок (k, a, b, c), такое, что хотя бы один угол треугольника ABC составляет 45 градусов, с 1 ≤ k ≤ K и -X ≤ a < b
Например, F(1, 10) = 41 и F(10, 100) = 12492. Найти F(106, 109)."
В целях ее решения я использовал геометрическое определение точечного произведения: theta = cos^-1((A dot B)/(|A|*|B|)), где A и B - евклидовы векторы, |A| представляет величину А, а тета - угол между ними.
Я перечитывал свой сценарий несколько раз, и насколько я вижу, единственная причина, по которой он приводит к FoKX=22 вместо FoKX=41, заключается в том, что существует ошибка в тригонометрической точности или преобразовании из радиан в градусы. Дайте мне знать, если это так, или я где-то допустил ошибку, которая может объяснить это. Спасибо всегда за помощь!
K<-1
X<-10
FoKX<-0
for(l in 1:K){
for(i in (-X):(X-2)){
for(j in (i+1):(X-1)){
for(k in (j+1):X){
vecAB<-c(j-i,(j^2-i^2)/l)
vecAC<-c(k-i,(k^2-i^2)/l)
vecBA<--vecAB
vecBC<-c(k-j,(k^2-j^2)/l)
vecCA<--vecAC
vecCB<--vecBC
magAB<-sqrt(sum(vecAB^2))
magAC<-sqrt(sum(vecAC^2))
magBA<-magAB
magBC<-sqrt(sum(vecBC^2))
magCA<-magAC
magCB<-magBC
ABdotAC<-sum(vecAB*vecAC)
BAdotBC<-sum(vecBA*vecBC)
CAdotCB<-sum(vecCA*vecCB)
angA<-acos(ABdotAC/(magAB*magAC))
angB<-acos(BAdotBC/(magBA*magBC))
angC<-acos(CAdotCB/(magCA*magCB))
if(angA==pi/4||angB==pi/4||angC==pi/4){
FoKX<-FoKX+1
}
}
}
}
}
2 ответа
Не сравнивайте для точного равенства с плавающей точкой. Всегда включайте фактор нечеткости.
....
....
if(abs(angA - pi/4) < 1e-9 ||
abs(angB - pi/4) < 1e-9 ||
abs(angC - pi/4) < 1e-9){
FoKX<-FoKX+1
}
}
}
}
}
FoKX
[1] 41
Я нахожу эту игрушку полезной при работе с равенством с плавающей точкой: (бесплатно, как в пиве, свободно модифицировать, как вам нравится, и т. Д.)
approxeq <- function(x, y, tolerance = .Machine$double.eps ^ 0.5,...) {
#input validation
if (length(x) != length(y)) warning('x,y lengths differ. Will recycle.')
#don't care about dimensions so long as you're smart about inputs
checkit <- abs(x-y) < tolerance
return(invisible(checkit))
}
Это возвращает логический вектор, в отличие от встроенного all.equal
который имеет свои собственные применения.