2010-05-04 4 views
28

Я пытаюсь сравнить два числа в R как часть условия, если-заявление:Числовое сравнение трудности в R

(a-b) >= 0.5

В данном конкретном случае, а = 0,58 и Ь = 0,08. .. и все же (a-b) >= 0.5 является ложным. Я знаю об опасности использования == для точного сравнения чисел, и это, кажется, связаны:

(a - b) == 0.5) является ложным, а

all.equal((a - b), 0.5) верно.

Единственное решение, о котором я могу думать, состоит в том, чтобы иметь два условия: (a-b) > 0.5 | all.equal((a-b), 0.5). Это работает, но это действительно единственное решение? Должен ли я просто поклясться в семействе операторов сравнения = навсегда?

Редактировать для пояснения: Я знаю, что это проблема с плавающей точкой. Более принципиально, что я спрашиваю: что я должен делать? Какой разумный способ справиться с сравнениями более или равными с R, поскольку на >= нельзя действительно доверять?

+0

я мог быть далеко, но это могло быть проблема с плавающей точкой? – Dan

+0

Действительно. Я просто не знаю, что с этим делать. –

+0

Вернее, я не знаю, что люди более сообразительны, чем я. –

ответ

30

Я никогда не был фанатом от all.equal за такие вещи. Мне кажется, что толерантность действует загадочно. Почему бы не просто проверить что-то большее, чем допуск менее 0,05

tol = 1e-5 

(a-b) >= (0.05-tol) 

В общем, без округления и только с обычной логикой я нахожу прямую логику лучше, чем all.equal

If x == y затем x-y == 0. Возможно x-y это не совсем так 0 для таких случаев я использую

abs(x-y) <= tol 

Вы должны установить толерантность в любом случае для all.equal и это является более компактным и простым, чем all.equal.

9

Вы можете создать это как отдельный оператор или перезаписать исходный> = функция (вероятно, не очень хорошая идея), если вы хотите использовать этот подход: Окрашенные

# using a tolerance 
epsilon <- 1e-10 # set this as a global setting 
`%>=%` <- function(x, y) (x + epsilon > y) 

# as a new operator with the original approach 
`%>=%` <- function(x, y) (all.equal(x, y)==TRUE | (x > y)) 

# overwriting R's version (not advised) 
`>=` <- function(x, y) (isTRUE(all.equal(x, y)) | (x > y)) 

> (a-b) >= 0.5 
[1] TRUE 
> c(1,3,5) >= 2:4 
[1] FALSE FALSE TRUE 
+1

Лично я считаю, что это лучший подход, потому что вам не нужно самостоятельно решать вопрос. Вы даже можете взять страницу с Perl и дать им имена типа 'ge',' le' и 'ne'. –

5

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

round(0.58 - 0.08, 2) == 0.5 
+2

Я думаю, что это лучшее решение, и для оригинальной проблемы я буду использовать 'round (a-b, 10)> = 0.5' (10 цифр должно быть достаточно для будущих расширений). – Marek

3

Выберите определенный уровень допуска:

epsilon <- 1e-10 

Затем используйте

(a-b+epsilon) >= 0.5 
2

Но, если вы используете допуски в любом случае, почему вы все равно, что абы == 0,5 (на самом деле) не получить оценку? Если вы используете допуски в любом случае, вы говорите, что меня точно не интересуют конечные точки.

Вот что такое if ((a-b)> = .5) if ((a-b) <.5)

один из них должен всегда оценивать истину на каждой паре двойников. Любой код, который использует один, неявно определяет, нет операции на другой, по крайней мере. Если вы используете допуски для получения фактического .5, включенных в первую, но ваша проблема определена в непрерывном домене, вы не многого добиваетесь. В большинстве проблем, связанных с непрерывными значениями в лежащей в основе проблемы, это будет очень мало, так как значения произвольно выше .5 всегда будут оцениваться так, как должны. Значения, произвольно близкие к .5, пойдут на «неправильное» управление потоком, но в непрерывных проблемах, где вы используете соответствующую точность, которая не имеет значения.

Единственный раз, когда допуски имеют смысл, когда вы имеете дело с проблемами типа если ((аb) == с) если ((аb)! = С)

Здесь никакое количество " соответствующая точность "может помочь вам. Причина в том, что вы должны быть готовы к тому, что второй всегда будет оценивать true, если вы не установите бит a-b на очень низком уровне вручную, если на самом деле вы, вероятно, хотите, чтобы первое иногда было истинным.

1

Еще один комментарий. all.equal является общим. Для числовых значений используется all.equal.numeric. Осмотр этой функции показывает, что она используется .Machine$double.eps^0.5, где .Machine$double.eps определяется как

double.eps: the smallest positive floating-point number ‘x’ such that 
      ‘1 + x != 1’. It equals ‘double.base^ulp.digits’ if either 
      ‘double.base’ is 2 or ‘double.rounding’ is 0; otherwise, it 
      is ‘(double.base^double.ulp.digits)/2’. Normally 
      ‘2.220446e-16’. 

(стр .Machine эксплуатации).

Другими словами, это было бы приемлемым выбором для вашей толерантности:

myeq <- function(a, b, tol=.Machine$double.eps^0.5) 
     abs(a - b) <= tol 
Смежные вопросы