2013-07-08 2 views
1

Поэтому я представлен со следующей проблемой:тригонометрические Точность R

«О параболы у = х2/к, три точки А (а, а2/к), В (Ь, b2/к) и C (c, c2/k).

Пусть F (K, X) - число целых квадруплетов (k, a, b, c) таких, что хотя бы один угол треугольника ABC 45 градусов, с 1 ≤ K ≤ K ≤ и -X < < Ь с ≤ Х.

Например, F (1, 10) = 41 и Р (10, 100) = 12492. Найти F (106, 109). "

В целях его решения я использовал геометрическое определение точечного произведения: theta = cos^-1 ((точка B)/(| A | * | B |)), где A и B являются евклидовыми векторами, | A | представляет собой величину A, а theta - угол между ними.

Я прочитал свой сценарий несколько раз, и насколько я вижу единственную причину, в результате которой 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 
     } 
     } 
    } 
    } 
} 
+1

Это может быть проблема с плавающей точкой; см. http://stackoverflow.com/questions/9508518/why-are-these-numbers-not-equal – Aaron

+0

Это было. Спасибо за эту ссылку. – fowlslegs

+0

И, не задумываясь, я написал алгоритм грубой силы, который займет слишком много времени, чтобы вычислить F (10^6,10^9). Да, мне не хватало этих каротин! Вернуться к доске для рисования. – fowlslegs

ответ

4

Не сравнивать для точного равенства с плавающей точкой. Всегда включайте фактор пуха.

 .... 
     .... 
     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 
+0

Это решает! Большое спасибо. – fowlslegs

+0

Более точный способ сделать это: 'if (isTRUE (all.equal (angA, pi/4)) || isTRUE (all.equal (angB, pi/4)) || isTRUE (all.equal (angC, пи/4))) '. См. Ссылку Aaron рекомендуется: stackoverflow.com/questions/9508518/. – fowlslegs

2

Я нахожу эту игрушку мой полезной при работе с плавающей точкой равенства: (бесплатно как в пиве, свободно изменять, как вам нравится, и т.д.)

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, который имеет свои собственные возможности.

Смежные вопросы