Рассмотрим достаточно частый случай, когда функция представляет собой две ветви, заданные по-разному, например:
Задание 6. Запрограммировать функциюW(x), заданную системой:
и построить ее график на отрезке .
Решение. На первый взгляд, задача для нас уже не представляет проблемы. Действительно, используя оператор if () {} else {} можно получить вполне корректный код функции:
W<- function(x) {# Объявление имени функции W(x)
if (x>= 0) {Res<- x^2} else{Res<- sin(2*x)} # Вычислениеправой и левой ветвей
return(Res)
}
W(2) # Возвращает 2^2 - правая ветвь
W(-pi/4) # Возвращает sin(-2pi/4) - левая ветвь
Однако, у этого кода есть существенный недостаток! Так написанная функция W(x) не будет воспринимать векторизованные обращения. Иными словами, привычным способом построить график этой функции нам не удастся: компилятор R выдаст ошибку на второй строчке кода при попытке подставить в функцию не число, а целый вектор:
x <- seq(-10,5,length.out = 101) # Разбиваем отрезок [-10; 5] на 100 частей
y <- W(x) # Вычисляем значения функции W(x) во всех точках
|
|
plot(x,y,type = "l",lwd = 2,col="blue") # Строимграфикy=W(x)
Дело в том, что в языке Rусловный операторif () {} else {} не работает с векторизованными величинами. Здесь необходимо использовать специальные конструкции.
Самой простой и понятной является схема с привлечением специального оператора ifelse (A, expr1,expr2), который при выполнении условия A, реализует действия, составленные в expr1, а при невыполнении условия A, соответственно – в expr2. В нашем случае функция будет запрограммирована так:
W<- function(x)
{
Res <- ifelse(x>=0,x^2,sin(2*x))
return(Res)
}
x<- seq(-10,5,length.out = 1001) # Разбиваем отрезок [-10; 5] на 1000 частей
y<- W(x) # Вычисляем значения функции W(x) во всех точках
plot(x,y,type = "l",lwd = 2,col="blue") # Строимграфик y=W(x)
Это позволяет построить график функции привычным образом с использованием векторизованных обращений к W(x)
Использование векторизованных процедур: оператор […]
Для построения функций, заданных по-разному на трех и более промежутках, вместо вложенных конструкций ifelse лучше использовать оператор квадратных скобок […] – самый мощный для векторизованных процедур.
Задание 7*. Запрограммировать в RфункциюS(x), заданную системой:
,
и построить ее график на отрезке .
Решение. Введем следующий код, задающий функцию S(x) на трех промежутках:
S<- function(x)
{
A<- (x<0) # Создаем массив из "TRUE/да" и "FALSE/нет" для x< 0
B<- (x>=0)&(x<=2) # Создаем массив из "TRUE/да" и "FALSE/нет" для (x>= 0) и (x<= 2)
D<- (x>2) # Создаем массив из "TRUE/да" и "FALSE/нет" для x> 2
x[A] <- sin(2*x[A]) # Вычисляем левую ветвь функции
x[B] <- x[B]^2 # Вычисляем середину функции
x[D] <- 6 - x[D] # Вычисляем правую ветвь функции
|
|
Res<- x
return(Res)
}
Идея здесь следующая: весь массив аргументов функции разделить на три группы A,B и D, в которых функция задана соответственно одной из трех ветвей. Здесь A– это массив из последовательности «да» и «нет». Если в каком-либо месте стоит «да», то на этом месте подходящий аргумент функции для левой ветви, если нет – неподходящий. Аналогично для B и D.
В следующих трех строках значения соответствующих аргументов x[A], x[B] и x[D] переопределяются в значения самой функции.
Теперь можно построить графикS(x):
x <- seq(-10,5,length.out = 1001) # Разбиваем отрезок [-10; 5] на 1000 частей
y <- S(x) # Вычисляем значения функции S(x) во всех точках
plot(x,y,type = "l",lwd = 2,col="red") # Строимграфик y=S(x)
abline(h = 0, v = 0, col = "gray40") # Рисуемосикоординат