Pues sí, algo así como . Pero no realmente , OMI.
Lo que hacen la mayoría de los lenguajes de programación es una torpeza, matemáticamente hablando. Un bucle for imperativo incrementa una variable . Eso no debería ser posible: las matemáticas no saben tiempo . Si defines algo una vez, entonces se mantendrá conceptualmente siempre es decir, si se empieza con $i = 0$ no es posible tener después $i=3$ .
Lo que realmente sucede, matemáticamente, es que se escribe un abstracción una expresión para todos $i$ . A continuación, se aplica a esa expresión la operación de orden superior "suma sobre todas esas $i$ en algún rango". La variable $i$ nunca tiene un valor particular, es sólo un marcador de posición para "considerar el valor aquí".
Existe un marco matemático adecuado que puede expresar de forma agradable cálculos como una suma. Se llama cálculo lambda . En esto, tal abstracción sobre alguna variable se llama expresión lambda , escrito como * $$ \lambda i \mapsto \frac1{2^i} $$ Más comúnmente, este tipo de abstracción se llamaría función y escrito $$ f : \mathbb{N}\to\mathbb{Q}, \quad f(i) = \frac{1}{2^i} $$ o, en los lenguajes de programación, algo como
double f(int i) {
return 1.0 / 2**i;
}
Ahora bien, lo que hace un operador de suma es que toma dicha función lambda y arroja un número igual a la función evaluada con todos los argumentos posibles en un rango y sumados. Por ejemplo, $$ S = \sum_{i=0}^{5}\frac1{2^i} $$ es, en cierto modo, una notación abreviada de algo $$ S = \Sigma(0,5,f). $$ Tenga en cuenta que no he escrito $f(i)$ pero sólo $f$ Esto es no el resultado de aplicar $f$ a cualquier $i$ pero el objeto de la función $f$ en sí mismo. No es un número, sino una función.
No es necesario dar primero $f$ un nombre y luego usarlo en la suma, también puedo simplemente poner la expresión lambda: $$ S = \Sigma(0,5,\lambda i\mapsto 1/2^{i}). $$ Entiendo las sumas como una forma especial de escribir esta expresión.
Ahora bien, ¿cómo se puede implementar el operador de suma en un ordenador? Bueno: en un lenguaje imperativo, un bucle for sería sin duda una forma razonable de hacerlo. Como † ,
double sumFromTo(int i0, int iend, function<double(int)> f) {
int i;
double result;
for(i=0; i<=iend; ++i) {
result += f(i);
}
return result;
}
Pero como dije, matemáticamente no tiene sentido cambiar el valor de una variable. Sin embargo, es posible definir el equivalente de un bucle de este tipo directamente en el cálculo lambda: mediante recursividad . Esto requiere algunas definiciones un poco extrañas para utilizarlo en el entorno matemático/lógico original, pero también puede escribirse en lenguajes de programación:
double sumFromTo_rec(int i, int iend, function<double(int)> f) {
if (i<=iend)
return f(i) + sumFromTo_rec(i+1, iend, f);
else
return 0;
}
Ahora, en la llamada recursiva, i
tendrá el valor de i+1
de la llamada exterior. Así que, ¿estoy haciendo una mutación matemática poco sólida aquí de nuevo? No, en realidad ¡! El i
El argumento de la función es sólo una abstracción. En la llamada a la función interna, es simplemente una diferente que casualmente también se llama i
(pero eso es un detalle de implementación irrelevante).
Puede que le parezca una tontería. Si el ordenador puede simplemente reutilizar la misma variable i
incrementándola, ¿por qué deberíamos molestarnos en definir una nueva? En cierto modo tendrías razón. sumFromTo_rec
sería de hecho ineficiente en un lenguaje como C, porque el ordenador tendría que asignar un nuevo entero real en la pila en cada llamada a la función.
Sin embargo, desde un punto de vista práctico, la mutación de variables también abre numerosas posibilidades de errores de programación. Lenguaje de programación funcional por lo tanto, evitar (o prohibir por completo ) esto. Estos lenguajes han llegado con varias optimizaciones como llamadas de cola para evitar la sobrecarga de asignar nuevas variables en cada llamada recursiva (así que, básicamente, escribes una semántica matemática limpia pero bajo el capó la misma memoria se reutiliza en realidad, como lo haría en un lenguaje imperativo).
Si eres un programador interesado en las matemáticas (o un matemático interesado en la computación) te recomiendo que consultes Haskell . Es un lenguaje de programación funcional moderno con una semántica muy limpia, pero con un gran rendimiento y una buena compatibilidad con las "aplicaciones del mundo real". La suma recursiva anterior se vería en Haskell tan simple como
sumFromTo i iEnd f
| i<=iEnd = f i + sumFromTo (i+1) iEnd f
| otherwise = 0
Esto es bastante similar a cómo la rigurosa definición recursiva de $\sum$ en notación matemática sería: $$ \sum_{i=i_0}^{i_{\text{end}}} f(i) = \begin{cases} f(i_0) + \sum_{i=i_0+1}^{i_{\text{end}}}f(i) & \text{if $i_0 < i_{\text{end}}$} \\ 0 & \text{otherwise} \end{cases} $$ Observe que $f(i)$ como tal nunca se evalúa realmente: siempre es $f(i_0)$ (sin embargo, esa variable tiene un valor diferente en cada nivel de recursión). Esto se refleja mejor en un lenguaje de programación que en la notación matemática: los primeros realmente hacen un punto de no aplicando $f$ a cualquier cosa cuando se habla de la función en sí misma, y no del resultado de aplicar esa función a un argumento concreto.
* La notación estándar clásica en el cálculo lambda es en realidad $\lambda i.\ 1/{2^i}$ pero creo que la flecha aclara más lo que ocurre que el punto. La mayoría de los lenguajes de programación utilizan un símbolo de flecha si ofrecen funciones lambda, por ejemplo, en Haskell se escribiría
sumFromTo 0 6 (\i -> 1/2^i)
† A diferencia de las matemáticas, en la programación se prefiere generalmente (excepto en Fortran y Matlab, que no considero muy bien diseñados) expresar el rango <em>con el límite superior excluido </em>. Esta resulta ser la convención más útil en la práctica; véase <a href="https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html" rel="noreferrer">lo que el famoso Dijkstra escribió al respecto </a>.
1 votos
Sí, esto es lo que significa.
1 votos
Esencialmente, sí. Más información en wikipedia . Existen otras formas de utilizarlo además de comenzar con $i=start$ y recorriendo todos los valores enteros de $start$ a $end$ . Por ejemplo, el conocido lema del apretón de manos en la teoría de grafos $\sum\limits_{v\in V}\deg(v)=2|E|$ que dice que la suma de los grados de los vértices de cualquier grafo debe ser igual al doble del número de aristas. En este caso, utilizamos un conjunto de índices, $V$ y se hace un ciclo sobre todos los elementos, $v$ en ese conjunto.
0 votos
Básicamente, pero es un poco más flexible, porque se puede resumir contablemente muchos términos, lo que significa que se pueden añadir incluso infinitos términos (lo que se conoce como una Serie). Aunque puede converger o no a un valor significativo (esta cuestión ha sido muy estudiada a lo largo de los años).
0 votos
Debo añadir que la multiplicación tiene un símbolo análogo, una letra griega mayúscula pi: $\Pi$
3 votos
@JustinBenfield $\prod$
\prod
0 votos
En C++ como for{i=a,i<=n,i++} donde a es el valor inicial
1 votos
@JMoravitz: Algunos lenguajes de programación también permiten esta forma. Por ejemplo, en C++ puedes decir "for (auto v: V") si V es un contenedor.
4 votos
@Archis: dos errores:
{
debe ser(
y,
debe ser;
. ¡Muy descuidado!0 votos
La gran diferencia es que a no computa nada en realidad. Muchos de los usos que se ven, especialmente al principio de las matemáticas, son fácilmente computables, y nadie dedica mucho tiempo a una serie si no espera al menos poder calcular algo sobre ella. Pero no hay ningún requisito de que los términos de la suma sean computables en ningún sentido, y mucho menos que sepas cómo calcularlos, o que puedas encontrar su suma,
0 votos
Hmmm bien @ Tony k
0 votos
¿Alguien ha mencionado la definición alternativa $\sum_{n \in \mathbb{N}}$ o $\sum_{x \in A}$ ¿anotación?
1 votos
Es un poco más sutil que "sumarlos". En un bucle For, es un proceso que tiene lugar en el tiempo. Sumamos las cosas, de una en una. En una suma, ocurre todo de una vez. La expresión de la suma es la suma, no se convierte en ella.