8  PIEP y POA en R

En esta sección se hará una revisión de los elementos básicos de programación imperativa estructurada procedimental (PIEP) y de programación orientada a arreglos (POA) de una implementación en R (obviamente, R como lenguaje de programación y NO como herramienta de cálculo o de análisis de datos).

En esta revisión se hace una pequeña introducción a R, a sus elementos básicos, a sus principales estructuras de control, a la creación de subprogramas, y al manejo de sus tipos de datos compuestos.

Se espera que al finalizar las actividades de esta sección, el estudiante entienda y tenga clara la manera en que un algoritmo, diseñado bajo los paradigmas de programación imperativa estructurada procedimental y orientado a arreglos, se puede implementar mediante el uso del lenguaje de programación R.

Preparación de clase
  • Para la siguiente sección, lea todo y ejecute todo el código que allí se incluye, haciendo todas las pruebas, cambios y experimentos que se les puedan ocurrir sobre dicho código.

En sus propias palabras, explique lo que le transmitió y lo que le enseño cada parte de lo que leyó, ejecutó, probó y experimentó; incluya su discusión, reflexiones y conclusiones al respecto; exponga lo que no entendió e intente encontrar por su cuenta respuestas a las preguntas que le surgieron, para poder compartirlas en clase.

8.1 Elementos básicos de PIEP y POA en R

Cuaderno computacional en Google Colaboratory:
Elementos básicos, estructuras de control, creación de subprogramas y tipos de datos compuestos en R

8.2 Ejemplos

Ejemplo 8.1 Haga un adecuado análisis, diseño e implementación en R de un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban un número entero y que devuelvan el factorial del número recibido. Implemente una prueba rápida (una serie de instrucciones) que le permita probar los subprogramas requeridos para varios valores distintos. Por último, implemente una serie de instrucciones que permita realiar una comparación de tiempos entre las dos soluciones solicitadas y la función factorial() de R.

El factorial de un número entero positivo k, denotado k! se puede definir como el producto de todos los números enteros positivos menores o iguales que k: k! = (2)(3) \cdots (k-2)(k-1)(k) o lo que es lo mismo, k! = (k)(k-1)(k-2) \cdots (3)(2)

Además, es necesario tener en cuenta que, 0! = 1 y es buena idea tener en cuenta que, 1! = 1 \qquad 2! = 2

# Solamente sirve para un parámetro vector con un solo elemento:
mi_fact_klength1_PIEP <- function(klength1){
  if(length(klength1) == 1){
    if(klength1 > 2){
      res <- klength1
      while(klength1 > 2){
        klength1 <- klength1 - 1
        res <- res * klength1
      }
      return(res)
    }else{
      if(klength1 >= 0){
        return(ifelse(klength1 == 0, 1, klength1))
      }
    }
  }
  return(NaN)
}

# Factorial elemento a elemento de un vector dado:
mi_fact_PIEP <- function(k){
  n <- length(k)
  res <- NULL
  for(i in 1:n){
    res[i] = mi_fact_klength1_PIEP(k[i])
  }
  return(res)
}
# Solamente sirve para un parámetro vector con un solo elemento:
mi_fact_klength1_POA <- function(klength1){
  if(length(klength1)==1){
    if(klength1 > 2){
      return(prod(2:klength1))
    }else{
      if(klength1 >= 0){
        return(ifelse(klength1 == 0, 1, klength1))
      }
    }
  }
  return(NaN)
}

# `Vectorize()` toma una función y devuelve una función capaz de devolver 
# el mismo resultado pero elemento a elemento de un vector dado:
mi_fact_POA_Vectorize <- Vectorize(mi_fact_klength1_POA)

# Implementación propia (con la ayuda de `sapply()`) capaz de devolver el 
# factorial elemento a elemento de un vector dado:
mi_fact_POA_sapply <- function(k){
  sapply(k, mi_fact_klength1_POA)
}
v <- c(-14, -8, 0, 1, 2, 8, 14)
for(i in v){
  cat("(", sprintf(i, fmt='%3.0f'), ")!\t", 
      sprintf(mi_fact_klength1_PIEP(i), fmt='%12.0f'), "\t", 
      sprintf(mi_fact_klength1_POA(i), fmt='%12.0f'), "\t", 
      sprintf(factorial(i), fmt='%12.0f'), "\n", sep = "")
}
(-14)!           NaN             NaN             NaN
( -8)!           NaN             NaN             NaN
(  0)!             1               1               1
(  1)!             1               1               1
(  2)!             2               2               2
(  8)!         40320           40320           40320
( 14)!   87178291200     87178291200     87178291200
v <- c(-14, -8, 0, 1, 2, 8, 14)
resul <- c(mi_fact_PIEP(v), mi_fact_POA_Vectorize(v), 
           mi_fact_POA_sapply(v), factorial(v))
resul <- matrix(resul, ncol = 4) 
colnames(resul) <- c("mi_fact_PIEP(v)", "mi_fact_POA_Vectorize(v)", 
                     "mi_fact_POA_sapply(v)", "factorial(v)")
rownames(resul) <- paste0("(", v, ")!")
resul
       mi_fact_PIEP(v) mi_fact_POA_Vectorize(v) mi_fact_POA_sapply(v)
(-14)!             NaN                      NaN                   NaN
(-8)!              NaN                      NaN                   NaN
(0)!                 1                        1                     1
(1)!                 1                        1                     1
(2)!                 2                        2                     2
(8)!             40320                    40320                 40320
(14)!      87178291200              87178291200           87178291200
       factorial(v)
(-14)!          NaN
(-8)!           NaN
(0)!              1
(1)!              1
(2)!              2
(8)!          40320
(14)!   87178291200
# `require()` intenta cargar la librería, si no la puede cargar devuelve FALSE
if (!require(microbenchmark)){
  install.packages("microbenchmark") # Instala librería
  library(microbenchmark) # Carga librería
}
Loading required package: microbenchmark
set.seed(10310506)
k <- sample(8:14, 1)
cat("k =", k)
k = 13
mbm <- microbenchmark("mi_fact_klen1_PIEP"={mi_fact_klength1_PIEP(k)},
                      "mi_fact_klen1_POA"={mi_fact_klength1_POA(k)},
                      "mi_fact_PIEP"={mi_fact_PIEP(k)},
                      "mi_fact_POA_Vectorize"={mi_fact_POA_Vectorize(k)},
                      "mi_fact_POA_sapply"={mi_fact_POA_sapply(k)},
                      "factorial"={factorial(k)},
                      times=1e3)
mbm # Tabla
Unit: nanoseconds
                  expr   min      lq      mean  median      uq     max neval
    mi_fact_klen1_PIEP   958  1127.5  1311.191  1237.0  1373.0   14896  1000
     mi_fact_klen1_POA   746  1002.0  1187.126  1147.0  1291.5    6041  1000
          mi_fact_PIEP  1891  2594.0  3144.303  3128.0  3406.0   20533  1000
 mi_fact_POA_Vectorize 30691 33200.0 35104.018 33988.5 35106.0  363835  1000
    mi_fact_POA_sapply 11398 12944.0 15274.747 13668.0 14341.5 1285978  1000
             factorial   372   499.0   598.559   568.5   644.0    9912  1000
boxplot(mbm, bty="n") # Gráfico boxplot

Loading required package: ggplot2
autoplot(mbm) # gráfico parecido al boxplot

# `require()` intenta cargar la librería, si no la puede cargar devuelve FALSE
if (!require(microbenchmark)){
  install.packages("microbenchmark") # Instala librería
  library(microbenchmark) # Carga librería
}
set.seed(10310506)
k <- sample(0:15, 25, replace=TRUE)
print(k)
 [1]  5  0  6 14 15  7 10 13  6  4 15 13  4  2 15 13 13  5 12  8  7  2  2  9  1
mbm <- microbenchmark("mi_fact_PIEP"={mi_fact_PIEP(k)},
                      "mi_fact_POA_Vectorize"={mi_fact_POA_Vectorize(k)},
                      "mi_fact_POA_sapply"={mi_fact_POA_sapply(k)},
                      "factorial"={factorial(k)},
                      times=1e3)
mbm # Tabla
Unit: microseconds
                  expr    min      lq      mean  median      uq      max neval
          mi_fact_PIEP 34.162 39.3040 45.107212 41.2065 42.9405 2767.120  1000
 mi_fact_POA_Vectorize 66.424 71.5705 77.771241 74.5260 77.8560  171.114  1000
    mi_fact_POA_sapply 43.561 48.1915 54.999933 50.1345 52.4745 3083.187  1000
             factorial  1.574  1.9230  2.218272  2.1460  2.3370   12.964  1000
if (!require(ggplot2)){
  install.packages("ggplot2")
  library(ggplot2)
}
autoplot(mbm) # gráfico parecido al boxplot

Ejemplo 8.2 Haga un adecuado análisis, diseño e implementación en R de un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que devuelvan una aproximación de la función coseno evaluada en un número real dado entre 0 y \frac{\pi}{4}. Los subprogramas solicitados deben tener en cuenta que:

  • \sum\limits_{k = 0}^{n} \frac{(-1)^k}{(2k)!} c^{2k} \xrightarrow[n \to \infty]{} \cos(c)
  • En esta ocasión, fije la cantidad de términos a usar de la serie. Es decir, primero analice y determine, a lo sumo, cuántos términos son mayores que 1 \times 10^{-15} para c entre 0 y \frac{\pi}{4}, y luego en la implementación use siempre esa misma cantidad de términos.

Adicionalmente, implemente una prueba rápida (una serie de instrucciones) que le permita probar los subprogramas requeridos para varios valores distintos. Por último, implemente una serie de instrucciones que permita realizar una comparación de tiempos entre las dos soluciones solicitadas y la función cos() de R.

Para c entre 0 y \frac{\pi}{4}, \frac{1}{(2k)!} c^{2k} < \frac{1}{(2k)!} \left(\frac{\pi}{4}\right)^{2k} o sea que si se encuentra k_0 tal que para todo k > k_0 se tiene que, \frac{1}{(2k)!} \left(\frac{\pi}{4}\right)^{2k} < 1 \times 10^{-15} entonces \frac{1}{(2k)!} c^{2k} < 1 \times 10^{-15} para todo k > k_0 y para todo c entre 0 y \frac{\pi}{4}.

Reescribiendo,

\begin{align*} \frac{1}{(2k)!} \left(\frac{\pi}{4}\right)^{2k} &< 1 \times 10^{-15} \\ \left(\frac{\pi}{4}\right)^{2k} &< \frac{(2k)!}{1 \times 10^{15}} \\ \left(\frac{\pi}{4}\right)^{2k} - \frac{(2k)!}{1 \times 10^{15}} &< 0 \end{align*}

Encontrando numéricamente una raíz para la función f(k) = \left(\frac{\pi}{4}\right)^{2k} - \frac{(2k)!}{1 \times 10^{15}}, concluimos que \frac{1}{(2k)!} \left(\frac{\pi}{4}\right)^{2k} < 1 \times 10^{-15} para todo k > 8.000312.

Es decir, para un c entre 0 y \frac{\pi}{4}, los términos k = 0, 1, \dots, 8 de la serie serán los únicos que podrían llegar a ser mayores que 1 \times 10^{-15}. En otras palabras, los términos k = 0, 1, \dots, 8 serán más que suficientes para cualquier c entre 0 y \frac{\pi}{4}, ya que, para todo c entre 0 y \frac{\pi}{4}, los términos k = 9 en adelante serán menores que 1 \times 10^{-15}.

# Unicamente para $0 \leq c \leq \frac{\pi}{4}$
mi_cos_serie_clen1_PIEP <- function(clen1){
  res <- 1.0
  if(clen1 != 0){
    cCuadr <- clen1 * clen1
    magnTerm <- cCuadr / 2
    restar <- TRUE
    res <- res - magnTerm
    iMax <- 16
    for(i in seq(4, iMax, 2)){
      magnTerm <- magnTerm * cCuadr / (i * (i - 1))
      if(restar){
        restar <- FALSE
        res <- res + magnTerm
      }
      else{
        restar <- TRUE
        res <- res - magnTerm
      }
    }
  }
  res
}

mi_cos_serie_PIEP <- function(c){
  len <- length(c)
  res <- NULL
  for(i in 1:len){
    res[i] = mi_cos_serie_clen1_PIEP(c[i])
  }
  res
}
# Solamente sirve para un parámetro vector con un solo elemento:
mi_cos_serie_clen1_POA <- function(clen1){
  kMax <- 8
  iMax <- 16
  res <- 1
  if(clen1 != 0){
    num <- cumprod(rep(-clen1*clen1, kMax)) # -x^2, x^4, -x^6, ..., -x^{14}, x^{16}
    den <- cumprod(2:iMax)[c(TRUE, FALSE)] # 2!, 4!, 6!, ..., 16!
    res = res + sum(num/den)
  }
  res
}

# `Vectorize()` toma una función y devuelve una función capaz de devolver 
# el mismo resultado pero elemento a elemento de un vector dado:
mi_cos_serie_POA_Vectorize <- Vectorize(mi_cos_serie_clen1_POA)

# Implementación propia (con la ayuda de `sapply()`) capaz de devolver el 
# coseno elemento a elemento de un vector dado:
mi_cos_serie_POA_sapply <- function(c){
  sapply(c, mi_cos_serie_clen1_POA)
}

# Implementación propia capaz de devolver el 
# coseno elemento a elemento de un vector dado:
mi_cos_serie_POA <- function(c){
  kMax <- 8
  iMax <- 16
  indx <- c != 0
  c <- c[indx]
  len <- length(c)
  num <- matrix(rep(-c*c, kMax), len)
  num <- apply(num, 1, cumprod)
  den <- cumprod(2:iMax)[c(TRUE, FALSE)]
  res <- NULL
  res[indx] <- 1 + (1/den) %*% num
  res[!indx] <- 1
  res
}
v <- seq(0, pi/4, length=7)
for(i in v){
  cat("cos(", sprintf(i, fmt='%18.16f'), ")\t", 
      sprintf(mi_cos_serie_clen1_PIEP(i), fmt='%20.16f'), "\t", 
      sprintf(mi_cos_serie_clen1_POA(i), fmt='%20.16f'), "\t", 
      sprintf(cos(i), fmt='%20.16f'), "\n", sep = "")
}
cos(0.0000000000000000)   1.0000000000000000      1.0000000000000000      1.0000000000000000
cos(0.1308996938995747)   0.9914448613738104      0.9914448613738104      0.9914448613738104
cos(0.2617993877991494)   0.9659258262890684      0.9659258262890683      0.9659258262890683
cos(0.3926990816987241)   0.9238795325112867      0.9238795325112867      0.9238795325112867
cos(0.5235987755982988)   0.8660254037844386      0.8660254037844387      0.8660254037844387
cos(0.6544984694978735)   0.7933533402912352      0.7933533402912352      0.7933533402912353
cos(0.7853981633974483)   0.7071067811865475      0.7071067811865475      0.7071067811865476
v <- seq(0, pi/4, length=7)
resul <- c(mi_cos_serie_PIEP(v), mi_cos_serie_POA_Vectorize(v), 
           mi_cos_serie_POA_sapply(v), mi_cos_serie_POA(v),  cos(v))
resul <- matrix(resul, ncol = 5) 
colnames(resul) <- c("mi_cos_serie_PIEP(v)", "mi_cos_serie_POA_Vectorize(v)", 
                     "mi_cos_serie_POA_sapply(v)", "mi_cos_serie_POA(v)", "cos(v)")
rownames(resul) <- paste0("cos(", v, ")")
resul
                       mi_cos_serie_PIEP(v) mi_cos_serie_POA_Vectorize(v)
cos(0)                            1.0000000                     1.0000000
cos(0.130899693899575)            0.9914449                     0.9914449
cos(0.261799387799149)            0.9659258                     0.9659258
cos(0.392699081698724)            0.9238795                     0.9238795
cos(0.523598775598299)            0.8660254                     0.8660254
cos(0.654498469497873)            0.7933533                     0.7933533
cos(0.785398163397448)            0.7071068                     0.7071068
                       mi_cos_serie_POA_sapply(v) mi_cos_serie_POA(v)    cos(v)
cos(0)                                  1.0000000           1.0000000 1.0000000
cos(0.130899693899575)                  0.9914449           0.9914449 0.9914449
cos(0.261799387799149)                  0.9659258           0.9659258 0.9659258
cos(0.392699081698724)                  0.9238795           0.9238795 0.9238795
cos(0.523598775598299)                  0.8660254           0.8660254 0.8660254
cos(0.654498469497873)                  0.7933533           0.7933533 0.7933533
cos(0.785398163397448)                  0.7071068           0.7071068 0.7071068
# `require()` intenta cargar la librería, si no la puede cargar devuelve FALSE
if (!require(microbenchmark)){
  install.packages("microbenchmark") # Instala librería
  library(microbenchmark) # Carga librería
}
set.seed(11081348)
c <- runif(1, 0, pi/4)
cat("c =", c)
c = 0.06901471
mbm <- microbenchmark("mi_cos_clen1_PIEP"={mi_cos_serie_clen1_PIEP(c)},
                      "mi_cos_clen1_POA"={mi_cos_serie_clen1_POA(c)},
                      "mi_cos_PIEP"={mi_cos_serie_PIEP(c)},
                      "mi_cos_serie_POA_Vectorize"={mi_cos_serie_POA_Vectorize(c)},
                      "mi_cos_serie_POA_sapply"={mi_cos_serie_POA_sapply(c)},
                      "mi_cos_serie_POA"={mi_cos_serie_POA(c)},
                      "cos"={cos(c)},
                      times=1e3)
mbm # Tabla
Unit: nanoseconds
                       expr   min      lq      mean  median      uq     max
          mi_cos_clen1_PIEP 16117 20333.0 22915.590 22498.0 24806.5   48712
           mi_cos_clen1_POA  2335  3752.5  4372.576  4305.5  4763.5   23024
                mi_cos_PIEP 18725 22989.5 25814.193 25482.5 27978.0   51085
 mi_cos_serie_POA_Vectorize 37367 44611.5 50816.782 48030.5 51029.0 2581685
    mi_cos_serie_POA_sapply 15232 18796.5 21781.538 20399.5 22104.0 1230032
           mi_cos_serie_POA 33732 39845.5 43072.776 42900.0 45546.5   90235
                        cos   151   339.5   434.361   437.0   498.0   12366
 neval
  1000
  1000
  1000
  1000
  1000
  1000
  1000
if (!require(ggplot2)){
  install.packages("ggplot2")
  library(ggplot2)
}
autoplot(mbm) # gráfico parecido al boxplot

# `require()` intenta cargar la librería, si no la puede cargar devuelve FALSE
if (!require(microbenchmark)){
  install.packages("microbenchmark") # Instala librería
  library(microbenchmark) # Carga librería
}
set.seed(11081348)
c <- runif(20, 0, pi/4)
print(c)
 [1] 0.06901471 0.10078974 0.11829167 0.60410898 0.17810267 0.08819629
 [7] 0.46757247 0.42381621 0.45641103 0.74174346 0.75628327 0.74122467
[13] 0.55322552 0.47472847 0.37166666 0.32539549 0.01587700 0.48829730
[19] 0.15890795 0.58516338
mbm <- microbenchmark("mi_cos_PIEP"={mi_cos_serie_PIEP(c)},
                      "mi_cos_serie_POA_Vectorize"={mi_cos_serie_POA_Vectorize(c)},
                      "mi_cos_serie_POA_sapply"={mi_cos_serie_POA_sapply(c)},
                      "mi_cos_serie_POA"={mi_cos_serie_POA(c)},
                      "cos"={cos(c)},
                      times=1e3)
mbm # Tabla
Unit: nanoseconds
                       expr    min       lq       mean   median       uq
                mi_cos_PIEP 348573 364191.0 395685.409 375813.0 390377.0
 mi_cos_serie_POA_Vectorize  89820 102917.5 118406.788 107722.5 113155.0
    mi_cos_serie_POA_sapply  68234  74658.5  80399.264  77799.0  81783.5
           mi_cos_serie_POA  54377  64139.5  72357.971  68433.5  72117.5
                        cos    318    660.5    846.073    819.0    947.0
     max neval
 3116020  1000
 2722180  1000
  206981  1000
 2672774  1000
   11166  1000
if (!require(ggplot2)){
  install.packages("ggplot2")
  library(ggplot2)
}
autoplot(mbm) # gráfico parecido al boxplot

8.3 Ejercicios

  • En las soluciones de PIEP, NO debe haber llamados recursivos de una o más funciones que puedan ser reemplazados por el uso de estructuras iterativas.
  • En las soluciones de POA (array-oriented), NO debe haber uso de estructuras iterativas que puedan ser reemplazadas por el uso de operaciones o funciones básicas de tipos de datos compuestos.
  • Para los subprogramas solicitados pueden usar todos los operadores y las funciones que se referencian en Elementos básicos, estructuras de control, creación de subprogramas y tipos de datos compuestos en R (intencionalmente, el operador ^ no fue referenciado), todos los demás operadores y funciones de R los pueden usar para la parte de prueba y comparación de resultados.

Haga un adecuado ANÁLISIS, DISEÑO e IMPLEMENTACIÓN EN R de:

  1. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban un número real (c) y un número entero (k), y que devuelvan la potencia con exponente entero c^k.

  2. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban un número real (c) y un vector de números reales asociados a los coeficientes de un polinomio en orden ascendiente \big(a_0 =\big.v[1], a_1 =v[2], \dots, a_{n-1} =v[n] y \big.p(x) = a_0 + a_1 x + \cdots + a_{n-1} x^{n-1}\big), y que devuelvan el polinomio evaluado en el número real recibido \big(p(c)\big).

  3. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban dos números enteros no negativos \left(k\right. y \left.r \leq k\right), y que devuelvan la cantidad de reordenamientos posibles de r elementos que no se repiten tomados de un conjunto de k elementos (número de permutaciones o variaciones sin repetición, por ejemplo ver: Combinatoria - Wikipedia). Los subprogramas solicitados deben tener en cuenta que:

    • El número de permutaciones sin elementos repetidos es P(k, r) = k P r = \frac{k!}{(k-r)!}
    • La solución debe computacionalmente mejor, es decir, debe tener un número total de operaciones menor, que simplemente hacer Factorial(k) / Factorial(k-r) para una función Factorial() que devuelva el factorial de un número entero no negativo.
  4. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciba dos números enteros no negativos \left(k\right. y \left.r \leq k\right), y que devuelvan la cantidad de subconjuntos posibles de r elementos tomados de un conjunto de k elementos (número de combinaciones sin repetición, por ejemplo ver: Combinatoria - Wikipedia). Los subprogramas solicitados deben tener en cuenta que:

    • El número de combinaciones (coeficiente binomial) es C(k, r) = k C r = \binom{k}{r} = \frac{k!}{r! (k-r)!}
    • La solución debe ser computacionalmente mejor, es decir, debe tener un número total de operaciones menor, que simplemente hacer Factorial(k) / ( Factorial(r) * Factorial(k-r) ) o Permutacion(k,r) / Factorial(r) para una función Factorial() que devuelva el factorial de un número entero no negativo y una función Permutacion(,) que devuelva el número de permutaciones.
  5. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban un número real (c) y que devuelvan una aproximación del seno de c \big(\sin(c)\big). Los subprogramas solicitados deben tener en cuenta que:

    • Si c < 0, entonces \sin(c) = -\sin(-c), lo que reduce el problema a calcular el seno de un valor mayor que cero (0).
    • Si c \geq 2 \pi, entonces \sin(c) = \sin(c - k \, 2 \pi), lo que reduce el problema a calcular el seno de un valor entre 0 y 2 \pi.
    • Si \pi \leq c < 2 \pi, entonces \sin(c) = -\sin(c - \pi), lo que reduce el problema a calcular el seno de un valor entre 0 y \pi.
    • Si \frac{\pi}{2} \leq c < \pi, entonces \sin(c) = \sin(\pi - c), lo que reduce el problema a calcular el seno de un valor entre 0 y \frac{\pi}{2}.
    • Si \frac{\pi}{4} \leq c < \frac{\pi}{2}, entonces \sin(c) = \cos\left(\frac{\pi}{2} - c\right), lo que reduce el problema a calcular el coseno de un valor entre 0 y \frac{\pi}{4}.
    • \sum\limits_{k = 0}^{n} \frac{(-1)^k}{(2k+1)!} c^{2k+1} \xrightarrow[n \to \infty]{} \sin(c), que se debe utilizar unicamente para calcular el seno de un valor entre 0 y \frac{\pi}{4}.
    • En esta ocasión, fije la cantidad de términos a usar de la serie. Es decir, primero analice y determine, a lo sumo, cuántos términos son mayores que 1 \times 10^{-15} para c entre 0 y \frac{\pi}{4}, y luego en la implementación use siempre esa misma cantidad de términos.
  6. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban un número real (c) y que devuelvan una aproximación del arco tangente de c \big(\arctan(c)\big). Puede tomar \sqrt{3} \approx 1.7320508075688773. El subprograma solicitado debe tener en cuenta que:

    • Si c < 0, entonces \arctan(c) = - \arctan(-c), lo que reduce el problema a calcular el arco tangente de un valor mayor que cero.
    • Si c > 1, entonces \arctan(c) = \frac{\pi}{2} - \arctan\left(\frac{1}{c}\right), lo que reduce el problema a calcular el arco tangente de un valor menor o igual que uno.
    • Si c > 2 - \sqrt{3}, entonces \arctan(c) = \frac{\pi}{6} + \arctan \left( \frac{\sqrt{3} \, c - 1}{\sqrt{3} + c} \right), lo que reduce el problema a calcular el arco tangente de un valor menor o igual que 2 - \sqrt{3}.
    • \sum_{k = 0}^{n} \frac{(-1)^k}{2k+1} c^{2k+1} \xrightarrow[n \to \infty]{} \arctan(c), que se debe utilizar unicamente para calcular el arco tangente de un valor entre 0 y 2 - \sqrt{3}.
    • En esta ocasión, fije la cantidad de términos a usar de la serie. Es decir, primero analice y determine, a lo sumo, cuántos términos son mayores que 1 \times 10^{-15} para c entre 0 y 2 - \sqrt{3}, y luego en la implementación use siempre esa misma cantidad de términos.
  7. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban un número real (c) y que devuelvan una aproximación de la función exponencial evaluada en c \big(\exp(c)\big). Puede tomar \mathrm{e} \approx 2.7182818284590452. El subprograma solicitado debe tener en cuenta que:

    • Si c < 0, entonces \exp(c) = \frac{1}{\exp(-c)} lo que reduce el problema a calcular la función exponencial de un valor mayor que cero.
    • Si c > 1, entonces, \exp(c) = \exp(k + d) = \exp(k) \exp(d) en donde k es un entero positivo y d es un número real entre cero y uno, lo que reduce el problema a calcular la función exponencial de un valor entero positivo y un valor entre cero y uno.
    • Si c es un entero positivo, entonces, \exp(c) = \mathrm{e}^c = \underbrace{\mathrm{e} \dots \mathrm{e}}_{c \text{ veces}} (utilice su subprograma que calcula la potencia con exponente entero de un número real)
    • \sum_{k = 0}^{n} \frac{c^{k}}{k!} \xrightarrow[n \to \infty]{} \exp(c) que se debe utilizar unicamente para calcular la función exponencial de un valor entre cero y uno.
    • En esta ocasión, fije la cantidad de términos a usar de la serie. Es decir, primero analice y determine, a lo sumo, cuántos términos son mayores que 1 \times 10^{-15} para c entre 0 y 1, y luego en la implementación use siempre esa misma cantidad de términos.
  8. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban un número real (c) y que devuelvan una aproximación de la función logaritmo natural evaluada en c \big(\ln(c)\big). Puede tomar \ln\left(2\right) \approx 0.6931471805599453. El subprograma solicitado debe tener en cuenta que:

    • Si 0 < c < 1, entonces \ln(c) = -\ln\left(\frac{1}{c}\right), lo que reduce el problema a calcular el logaritmo natural de un valor mayor que uno.
    • Si c > 1, entonces \ln(c) = \ln\left((d) \left(2^k\right)\right) = \ln(d) + k \ln\left(2\right), en donde k un entero no negativo y d es un número real entre uno y dos, lo que reduce el problema a calcular el logaritmo natural de un valor entre uno y dos.
    • 2 \sum_{k = 0}^{n} \frac{1}{2k+1} \left( \frac{c-1}{c+1} \right)^{2k+1} \xrightarrow[n \to \infty]{} \ln(c) que se debe utilizar unicamente para calcular el logaritmo natural de un valor entre uno y dos.
    • En esta ocasión, fije la cantidad de términos a usar de la serie. Es decir, primero analice y determine, a lo sumo, cuántos términos son mayores que 1 \times 10^{-15} para c entre 1 y 2, y luego en la implementación use siempre esa misma cantidad de términos.
  9. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que devuelvan un valor cercano al número \pi, usando la generación de valores seudoaleatorios / por Monte Carlo. Para el subprograma solicitado pueden usar la función runif() de R.

  10. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que devuelvan un valor cercano a la integral definida entre dos números reales dados, de una función de los reales en los reales dada (integrable y bien definida en el intervalo de integración), usando la generación de valores seudoaleatorios / por Monte Carlo (Por ejemplo, consultar Integración de Monte Carlo - Wikipedia). Para el subprograma solicitado pueden usar la función runif() de R.

  11. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que devuelvan una aproximación a la integral definida entre dos números reales dados, de una función de los reales en los reales dada (integrable y bien definida en el intervalo de integración), usando el método o regla del trapecio compuesta con todas sus consideraciones (Por ejemplo, consultar Regla del trapecio compuesta. Regla del trapecio - Wikipedia).

  12. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que devuelvan una aproximación a la integral definida entre dos números reales dados, de una función de los reales en los reales dada (integrable y bien definida en el intervalo de integración), usando el método o regla de Simpson 1/3 compuesta con todas sus consideraciones (Por ejemplo, consultar Regla de Simpson 1/3 compuesta. Regla de Simpson - Wikipedia).

  13. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que devuelvan una aproximación a la integral definida entre dos números reales dados, de una función de los reales en los reales dada (integrable y bien definida en el intervalo de integración), usando el método o regla de Simpson 3/8 compuesta con todas sus consideraciones (Por ejemplo, consultar Regla de Simpson 3/8 compuesta. Regla de Simpson - Wikipedia).

  14. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban un vector de medias y una matriz de covarianzas, y devuelvan una matriz con n filas asociadas a n valores seudoaleatorios provenientes de una vector aleatorio normal multivariado con el vector de medias y la matriz de covarianzas recibidos. Para el subprograma solicitado pueden usar las funciones rnorm() y chol() de R.

  15. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban una matriz de datos cuantitativos y que devuelvan una lista con: (1) una matriz que tenga los primeros cuatro (r = 1, 2, 3 y 4) momentos no centrales, (2) una matriz que tenga los primeros cuatro momentos centrales, y (3) una matriz que tenga los primeros cuatro momentos estándarizados, de todos y cada uno de los vectores columna de la matriz recibida. Tenga en cuenta que:

    Momentos ordinarios o no centrales (población finita de tamaño N):

    \gamma'_r = E\left[X^r\right] = \frac{1}{N} \sum_{i=1}^N X_i^r

    Note que \gamma'_1 es la media o valor esperado \mu.

    Momentos centrales:

    \gamma_r = E\left[\left(X - \gamma'_1\right)^r\right] = E\left[\left(X - \mu\right)^r\right]

    Por lo tanto,

    \begin{align*} \gamma_1 &= \gamma'_1 - \mu = 0 \\ \gamma_2 &= \gamma'_2 - \mu^2 = \sigma^2 \\ \gamma_3 &= \gamma'_3 - 3 \mu \gamma'_2 + 2 \mu^3 \\ \gamma_4 &= \gamma'_4 - 4 \mu \gamma'_3 + 6 \mu^2 \gamma'_2 - 3 \mu^4 \\ &\dots \end{align*}

    Note que \gamma_2 es la varianza \sigma^2.

    Momentos estándar o estandarizados:

    \gamma^*_r = \frac{\gamma_r}{\sigma^r}

    Note que \gamma^*_1 = 0, \gamma^*_2 = 1, \gamma^*_3 es el coeficiente de asimetría (Pearson) y \gamma^*_4 es el coeficiente de apuntamiento o curtosis (curtosis de Pearson). El exceso de curtosis (curtosis de Fisher) sería igual a \gamma^*_4 - 3.

  16. Un subprograma con una solución de PIEP y uno con una solución de POA (array-oriented) que reciban una matriz de datos cuantitativos y que devuelvan una matriz con todos y cada uno de los vectores columna estandarizados de la matriz recibida.

    Si las columnas de una matriz N \times p corresponden a las variables cuantitativas V_1, V_2, \dots, V_p, entonces una matriz con los vectores columna estandarizados sería una matriz N \times p en donde la columna i-ésima sería la variable cuantitativa Z_i = \frac{V_i - \mu_i}{\sigma_i}, donde \mu_i es la media de V_i y \sigma_i es la desviación estándar de V_i (asumamos que los datos que tenemos son poblacionales).