Lo que Todo Programador de C Debe Saber Sobre el Comportamiento Indefinido #2/3

By Jose Melgarejo | Created: December 06, 2023 | Last updated: December 17, 2024 | Read Time: 10 minutes

Por Chris Lattner

Artículo Original: blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html

May 14, 2011

#optimization , #Clang

En la Parte 1 de nuestra serie, discutimos qué es el comportamiento indefinido, y cómo permite a los compiladores de C y C++ producir aplicaciones de mayor rendimiento que los lenguajes "seguros". Este post habla de lo "inseguro" que es realmente C, explicando algunos de los efectos más sorprendentes que puede causar el comportamiento indefinido. En la Parte #3, hablamos de lo que los compiladores amigables pueden hacer para mitigar algunas de las sorpresas, incluso si no están obligados a hacerlo.

Me gusta llamar a esto "Por qué el comportamiento indefinido es a menudo una cosa aterradora y terrible para los programadores C" :-)

La interacción de las optimizaciones del compilador conduce a resultados sorprendentes

Un optimizador de compilador moderno contiene muchas optimizaciones que se ejecutan en órdenes específicos, a veces iterados, y cambian a medida que el compilador evoluciona con el tiempo (por ejemplo, cuando salen nuevas versiones). Además, los distintos compiladores suelen tener optimizadores sustancialmente diferentes. Dado que las optimizaciones se ejecutan en distintas fases, pueden producirse efectos emergentes debido a que optimizaciones anteriores modifican el código.

Veamos un ejemplo tonto (simplificado a partir de un fallo explotable que se encontró en el Kernel de Linux) para hacer esto más concreto:

void contains_null_check(int *P) {
  int dead = *P;
  if (P == 0)
    return;
  *P = 4;
}

En este ejemplo, el código comprueba "claramente" el puntero nulo. Si el compilador ejecuta la "Eliminación de Código Muerto" antes de la "Eliminación de Comprobación Nula Redundante", veremos que el código evoluciona en estos dos pasos:

void contains_null_check_after_DCE(int *P) {
  //int dead = *P;     // deleted by the optimizer.
  if (P == 0)
    return;
  *P = 4;
}

y luego:

void contains_null_check_after_DCE_and_RNCE(int *P) {
  if (P == 0)   // Null check not redundant, and is kept.
    return;
  *P = 4;
}

Sin embargo, si el optimizador tiene una estructura diferente, podría ejecutar RNCE antes que DCE. Esto nos daría estos dos pasos:

void contains_null_check_after_RNCE(int *P) {
  int dead = *P;
  if (false)  // P was dereferenced by this point, so it can't be null 
    return;
  *P = 4;
}

y luego se ejecuta la eliminación de código muerto:

void contains_null_check_after_RNCE_and_DCE(int *P) {
  //int dead = *P;
  //if (false)
  //  return;
  *P = 4;
}

Para muchos programadores (¡razonables!), eliminar la comprobación de nulos de esta función sería muy sorprendente (y probablemente presentarían un error contra el compilador :). Sin embargo, tanto "contains_null_check_after_DCE_and_RNCE" como "contains_null_check_after_RNCE_and_DCE" son formas optimizadas perfectamente válidas de "contains_null_check" según el estándar, y ambas optimizaciones son importantes para el rendimiento de varias aplicaciones.

Aunque este ejemplo es intencionadamente simple y artificioso, este tipo de cosas ocurren todo el tiempo con el inlining: inlining una función a menudo expone una serie de oportunidades de optimización secundarias. Esto significa que si el optimizador decide inlinear una función, pueden entrar en acción una serie de optimizaciones locales que cambian el comportamiento del código. Esto es perfectamente válido según la norma e importante para el rendimiento en la práctica.

El comportamiento indefinido y la seguridad no combinan bien

La familia C de lenguajes de programación se utiliza para escribir una amplia gama de código crítico para la seguridad, como núcleos, demonios setuid, navegadores web y mucho más. Este código está expuesto a entradas hostiles y los errores pueden dar lugar a todo tipo de problemas de seguridad explotables. Una de las ventajas más citadas de C es que es relativamente fácil entender lo que está pasando cuando lees el código.

Sin embargo, el comportamiento indefinido elimina esta propiedad. Después de todo, la mayoría de los programadores pensarían que "contains_null_check" haría una comprobación de nulos por encima. Mientras que este caso no es demasiado aterrador (el código probablemente se bloqueará en la tienda si se le pasa una comprobación nula, lo que es relativamente fácil de depurar) hay una amplia gama de fragmentos en C de aspecto muy razonable que son completamente inválidos. Este problema ha afectado a muchos proyectos (incluyendo el Kernel de Linux, OpenSSL, glibc, etc) e incluso llevó al CERT a emitir una nota de vulnerabilidad contra GCC (aunque mi creencia personal es que todos los compiladores de C optimizados ampliamente utilizados son vulnerables a esto, no sólo GCC).

Veamos un ejemplo. Consideremos este código C cuidadosamente escrito:

void process_something(int size) {
  // Catch integer overflow.
  if (size > size+1)
    abort();
  ...
  // Error checking from this code elided.
  char *string = malloc(size+1);
  read(fd, string, size);
  string[size] = 0;
  do_something(string);
  free(string);
}

Este código está comprobando que malloc es lo suficientemente grande como para contener los datos leídos del fichero (porque hay que añadir un byte terminador nul), saltando si se produce un error de desbordamiento de enteros. Sin embargo, este es exactamente el ejemplo que dimos antes en el que se permite al compilador optimizar (válidamente) la comprobación. Esto significa que es perfectamente posible que el compilador convierta esto en:

void process_something(int *data, int size) {
  char *string = malloc(size+1);
  read(fd, string, size);
  string[size] = 0;
  do_something(string);
  free(string);
}

Cuando se construye en una plataforma de 64 bits, es bastante probable que se trate de un fallo explotable cuando "size" es INT_MAX (quizás el tamaño de un archivo en disco). Consideremos lo terrible que es esto: un auditor de código leyendo el código pensaría muy razonablemente que se está produciendo una comprobación de desbordamiento adecuada. Alguien probando el código no encontraría ningún problema a menos que probara específicamente esa ruta de error. El código seguro parece funcionar, hasta que alguien se adelanta y explota la vulnerabilidad. En definitiva, se trata de un tipo de error sorprendente y bastante aterrador. Afortunadamente, la solución es sencilla en este caso: basta con utilizar "size == INT_MAX" o similar.

Resulta que el desbordamiento de enteros es un problema de seguridad por muchas razones. Incluso si está usando aritmética de enteros completamente definida (ya sea usando -fwrapv o usando enteros sin signo), hay una clase completamente diferente de error de desbordamiento de enteros posible. Afortunadamente, esta clase es visible en el código y los auditores de seguridad conocedores suelen ser conscientes del problema.

Depurar código optimizado puede no tener sentido

Algunas personas (por ejemplo, programadores embebidos de bajo nivel a los que les gusta mirar el código máquina generado) hacen todo su desarrollo con las optimizaciones activadas. Debido a que el código frecuentemente tiene errores cuando está siendo desarrollado, estas personas terminan viendo un número desproporcionado de optimizaciones sorprendentes que pueden conducir a comportamientos difíciles de depurar en tiempo de ejecución. Por ejemplo, omitir accidentalmente el "i = 0" en el ejemplo "zero_array" del primer artículo permite al compilador descartar completamente el bucle (compilando zero_array en "return;") porque es un uso de una variable no inicializada.

Otro caso interesante que mordió a alguien recientemente ocurrió cuando tenía un puntero de función (global). Un ejemplo simplificado es el siguiente

static void (*FP)() = 0;
static void impl() {
  printf("hello\n");
}
void set() {
  FP = impl;
}
void call() {
  FP();
}

que clang optimiza:

void set() {}
void call() {
  printf("hello\n");
}

Se le permite hacer esto porque llamar a un puntero nulo es indefinido, lo que le permite asumir que set() debe ser llamado antes de call(). En este caso, el desarrollador olvidó llamar a "set", no se bloqueó con una desviación de puntero nulo, y su código se rompió cuando alguien más hizo una compilación de depuración.

El resultado es que es un problema solucionable: si sospechas que algo raro está pasando, intenta compilar en -O0, donde es mucho menos probable que el compilador esté haciendo optimizaciones.

El código "funcional" que utiliza un comportamiento indefinido puede "romperse" a medida que el compilador evoluciona o cambia.

Hemos visto muchos casos en los que aplicaciones que "parecen funcionar" de repente se rompen cuando se utiliza un LLVM más nuevo para compilarlas, o cuando la aplicación se ha movido de GCC a LLVM. Mientras que LLVM tiene ocasionalmente un error o dos :-), esto es más a menudo debido a errores latentes en la aplicación que ahora están siendo expuestos por el compilador. Esto puede ocurrir de diferentes maneras, dos ejemplos son:

1. una variable no inicializada que fue inicializada a cero por suerte "antes", y ahora comparte algún otro registro que no es cero. Esto es comúnmente expuesto por cambios en la asignación de registros.

2. un desbordamiento de array en la pila que empieza a clobber una variable que realmente importa, en lugar de algo que estaba muerto. Esto se expone cuando el compilador reorganiza la forma en que empaqueta las cosas en la pila, o se vuelve más agresivo a la hora de compartir el espacio de la pila para valores con tiempos de vida que no se solapan.

Lo importante y aterrador es darse cuenta de que casi *cualquier* optimización basada en un comportamiento indefinido puede empezar a activarse en código con errores en cualquier momento en el futuro. Inlining, loop unrolling, memory promotion y otras optimizaciones seguirán mejorando, y una parte significativa de su razón de existir es exponer optimizaciones secundarias como las anteriores.

Para mí, esto es profundamente insatisfactorio, en parte porque inevitablemente se acaba culpando al compilador, pero también porque significa que enormes cuerpos de código C son minas terrestres a punto de explotar. Esto es aún peor porque...

No hay forma fiable de determinar si una gran base de código contiene comportamientos indefinidos.

Hacer de la mina terrestre un lugar mucho peor es el hecho de que no hay una buena manera de determinar si una aplicación a gran escala está libre de comportamiento indefinido, y por lo tanto no es susceptible de romperse en el futuro. Hay muchas herramientas útiles que pueden ayudar a encontrar algunos de los errores, pero nada que dé plena confianza de que su código no se romperá en el futuro. Veamos algunas de estas opciones, junto con sus puntos fuertes y débiles:

1. La herramienta memcheck de Valgrind es una forma fantástica de encontrar todo tipo de variables no inicializadas y otros errores de memoria. Valgrind está limitado porque es bastante lento, sólo puede encontrar errores que todavía existen en el código máquina generado (por lo que no puede encontrar cosas que el optimizador elimina), y no sabe que el lenguaje fuente es C (por lo que no puede encontrar errores de desplazamiento fuera de rango o desbordamiento de enteros con signo).

2. Clang tiene un modo experimental -fcatch-undefined-behavior mode que inserta comprobaciones en tiempo de ejecución para encontrar violaciones como cantidades de shift fuera de rango, algunos errores simples de array fuera de rango, etc. Esto es limitado porque ralentiza el tiempo de ejecución de la aplicación y no puede ayudarte con desferencias aleatorias de punteros (como Valgrind), pero puede encontrar otros errores importantes. Clang también soporta completamente la opción -ftrapv (no confundir con -fwrapv) que hace que los bugs de desbordamiento de enteros con signo se atrapen en tiempo de ejecución (GCC también tiene esta opción, pero es completamente poco fiable/deficiente en mi experiencia). Aquí hay una demostración rápida de -fcatch-undefined-behavior:

$ cat t.c
int foo(int i) {
  int x[2];
  x[i] = 12;
  return x[i];
}

int main() {
  return foo(2);
}
$ clang t.c 
$ ./a.out 
$ clang t.c -fcatch-undefined-behavior 
$ ./a.out 
Illegal instruction

3. Los mensajes de advertencia del compilador son buenos para encontrar algunas clases de estos errores, como variables no inicializadas y errores simples de desbordamiento de enteros. Tiene dos limitaciones principales: 1) no tiene información dinámica sobre tu código mientras se ejecuta, y 2) debe ejecutarse muy rápido porque cualquier análisis que haga ralentiza el tiempo de compilación.

4. El Analizador Estático de Clang realiza un análisis mucho más profundo para tratar de encontrar errores (incluyendo el uso de comportamientos indefinidos, como las referencias a punteros nulos). Puedes pensar en él como un generador de mensajes de advertencia del compilador mejorado, porque no está limitado por las restricciones de tiempo de compilación de las advertencias normales. Las principales desventajas del analizador estático es que 1) no tiene información dinámica sobre tu programa mientras se ejecuta, y 2) no está integrado en los flujos de trabajo normales de muchos desarrolladores (aunque su integración en Xcode 3.2 y posteriores es fantástica).

5. El subproyecto "Klee" de LLVM utiliza el análisis simbólico para "probar todos los caminos posibles" a través de un fragmento de código para encontrar errores en el código y produce un caso de prueba. Es un pequeño gran proyecto que está limitado principalmente por no ser práctico para ejecutarse en aplicaciones a gran escala.

6. Aunque nunca la he probado, la herramienta C-Semantics de Chucky Ellison y Grigore Rosu es una herramienta muy interesante que aparentemente puede encontrar algunos tipos de errores (como violaciones del punto de secuencia). Todavía es un prototipo de investigación, pero puede ser útil para encontrar fallos en programas (pequeños y autocontenidos). Recomiendo leer el post de John Regehr al respecto para obtener más información.

El resultado final de esto es que tenemos un montón de herramientas en la caja de herramientas para encontrar algunos errores, pero no hay una buena manera de demostrar que una aplicación está libre de comportamiento indefinido. Dado que hay muchos errores en aplicaciones del mundo real y que C se utiliza para una amplia gama de aplicaciones críticas, esto da bastante miedo. En nuestro último artículo, examino varias opciones que tienen los compiladores de C para tratar el comportamiento indefinido, con un enfoque específico en Clang.

What Every C Programmer Should Know About Undefined Behavior #1/3

What Every C Programmer Should Know About Undefined Behavior #3/3


Author profile
Jose Melgarejo

Jose Melgarejo is a seasoned writer with extensive experience in detailed analysis and narrative construction. He specializes in producing well-researched, clear, and informative content for various publications, effectively communicating complex topics to a broad audience.


Related Articles
logo
El debate sobre el calentamiento global El debate sobre el calentamiento global CSR

Articulo Original: https://web.mst.edu/~cottrell/Issues/The%20global%20warming%20debate.htm
Por: Mitchell S. Cottrell

Como con cualquier teoría científica, se propone una hipótesis, se adquieren datos científicos y luego la hipótesis se demuestra o se refuta. En teoría, así es como funciona la ciencia. ¿Qué sucede cuando la política se encuentra con la ciencia? En el entorno actual, la necesidad de financiación continua para la investigación tiende a orientar los hallazgos hacia aquellos que permiten obtener aún más financiación. En el debate sobre el calentamiento global, la situación se complica por varios hechos.

La Tierra no es estática. Los modelos creados para comprender cómo responde la Tierra deben ser, necesariamente, complejos.

En la comunidad científica actual, la especialización es la regla. Cada científico es un experto en su propio campo, pero no en el de los demás que lo rodean, y tienden a creer que el suyo es el más importante.

Las presiones e influencias políticas no solo son significativas, sino que es difícil determinar quién está alimentando la agenda de quién.

Estos hechos han generado mucha especulación y teorías conspirativas. A pesar de esto, la película "Una verdad incómoda" ha sido aclamada como una obra innovadora para presentar al público los riesgos del calentamiento global, así como un llamado a la acción. La película ha circulado ampliamente y ha sido vista por millones de personas. El problema es que la película se presenta a sí misma como una obra basada en hechos científicos, cuando en realidad es poco más que una declaración política que exagera la ciencia. De hecho, muchos de los científicos que fueron citados en la película han declarado públicamente, algunos de ellos de manera bastante vocal, que el ex vicepresidente Al Gore tergiversó sus opiniones y declaraciones. Como ejemplo, un punto particular de la película afirma que un aumento de 20 pies en los niveles del mar es un efecto a corto plazo realista que podemos esperar. Afirma que toda la capa de hielo de Groenlandia y la Antártida podría derretirse rápidamente, causando inundaciones en todas las costas del mundo. El científico que proporcionó este peor escenario había declarado claramente que era una perspectiva muy improbable, con aumentos en el nivel del mar de dos o tres pulgadas en el próximo siglo como escenario más probable. Esta subida de dos o tres pulgadas también es la opinión mantenida por la mayoría de los climatólogos convencionales. Entonces, ¿a quién crees? Veamos la ciencia involucrada.


En un estudio financiado por el Programa de Procesos Criosféricos de la NASA y el Programa de Glaciología Antártica de la Fundación Nacional de Ciencias, de 1992 a 2003, Curt Davis, profesor de ingeniería eléctrica e informática de la MU, y su equipo de investigadores observaron 7.1 millones de kilómetros de la capa de hielo, utilizando satélites para medir los cambios en la elevación. Descubrieron que el interior de la capa de hielo estaba ganando masa en aproximadamente 45 mil millones de toneladas por año, lo que fue suficiente para reducir el aumento del nivel del mar en 0,12 milímetros por año.

Además, según los datos de la NOAA presentados en el sitio web de Bill Chapman del Grupo de Investigación Polar de la Universidad de Illinois (Urbana-Champaign), el nivel global de hielo marino ha alcanzado aproximadamente el mismo nivel que en 2003. El cambio actual en la cobertura global de hielo marino es de un millón de kilómetros cuadrados positivo, es decir, una ganancia de 1.8 millones de kilómetros cuadrados en el Hemisferio Sur compensada por una pérdida de 800,000 kilómetros cuadrados en el Hemisferio Norte.

¿Se está derritiendo el hielo polar y glacial? Ciertamente que sí. Pero también debemos recordar que todavía estamos (desde el punto de vista ecológico) saliendo de la última mini-edad de hielo, que terminó en 1880 (oficialmente). También debemos recordar que nuestro período interglacial actual ya tiene 10,000 años de antigüedad. Ningún período interglacial durante el último medio millón de años ha persistido por más de 12,000 años. La mayoría ha tenido una duración de solo 10,000 años o menos. Estadísticamente, por lo tanto, estamos a punto de deslizarnos hacia el próximo período glacial.

Así que volvamos a la política. Se ha hecho mucho ruido sobre el informe histórico del IPCC (Grupo Intergubernamental de Expertos sobre el Cambio Climático), que afirma claramente que el hombre y su quema de combustibles fósiles son los culpables del aumento de los niveles de CO2 y que esos niveles son responsables del cambio global de temperatura. Eso es obviamente una simplificación de lo que dice el informe, pero si realmente lo reduces, esa es la esencia. El IPCC está compuesto por cientos de científicos que combinaron sus conocimientos para producir esta obra histórica, aclamada como un hito de la colaboración científica y el consenso.

John R. Christy, miembro del IPCC, co-receptor del premio Nobel de la paz en 2007, y uno de los muchos científicos que forman parte de este consenso, hace esta declaración:

Estoy seguro de que la mayoría (pero no todos) de mis colegas del IPCC se estremecen cuando digo esto, pero no veo ni la catástrofe en desarrollo ni la prueba irrefutable que demuestre que la actividad humana sea la culpable de la mayor parte del calentamiento que vemos. Más bien, veo una dependencia de los modelos climáticos (útiles pero nunca una "prueba") y la coincidencia de que los cambios en el dióxido de carbono y las temperaturas globales tienen una similitud temporal imprecisa. Algunos de nosotros seguimos siendo tan humildes ante la tarea de medir y comprender el sistema climático extraordinariamente complejo que somos escépticos de nuestra capacidad para saber qué está haciendo y por qué. Sin embargo, a medida que construimos conjuntos de datos climáticos desde cero y observamos el interior del sistema climático, no encontramos que la teoría alarmista coincida con las observaciones. (Los datos satelitales de la Administración Nacional Oceánica y Atmosférica que analizamos en la Universidad de Alabama en Huntsville muestran un calentamiento modesto: alrededor de 2.5 grados Fahrenheit por siglo, si las tendencias actuales de calentamiento de 0.25 grados por década continúan).

Dada esta declaración de uno de los científicos que escribió el informe que se utiliza hoy en día como la biblia del calentamiento global, uno tendría que preguntarse, ¿exactamente qué tipo de consenso hubo para este informe innovador? La respuesta es que cuando se les preguntó, de los 345 científicos estadounidenses que estaban en el comité, solo el 14% estuvo de acuerdo en que el clima ideal era más frío que el clima actual. (http://prnewswire.com/cgi-bin/stories.pl?ACCT=104&STORY=/www/story/11-08-2007/0004701174&EDATE=). Si un total del 14% representa un consenso sobre este punto más importante del debate, entonces, ¿qué tipo de consenso tuvo el resto de los puntos del informe?

Dejando de lado el consenso, veamos el tema principal que el informe reclama. "El CO2 generado por el hombre, principalmente a través de la quema de combustibles fósiles, es responsable de un aumento de la temperatura global sin precedentes en la historia conocida". De nuevo, esto es una generalización, pero resumir cientos de páginas aburridas a algo legible requiere un poco de simplificación. Ahora echemos un vistazo a la afirmación.

La generación de CO2 por la quema de combustibles fósiles está causando un aumento de la temperatura global. Para que esto sea cierto, tendría que haber un aumento promedio de la temperatura global. El siguiente gráfico muestra el cambio de temperatura para el año 2007 frente a la temperatura promedio de 1880 a 1980. Tenga en cuenta que los colores rojos son temperaturas más altas y los azules son más frías.

Observando este gráfico, queda claro que el aumento general de la temperatura no es global. De hecho, hay zonas significativamente más frías. La teoría sostiene que la agitación del aire y las corrientes de las tormentas generalmente mezclan suficiente aire como para que un cambio de temperatura global equivalga a una tendencia general al alza en todo el planeta, con algunas anomalías de temperatura más alta que aparecen localmente de manera intermitente. El gráfico, generado a partir de datos proporcionados por NASA GISS (http://data.giss.nasa.gov/gistemp/maps/), muestra claramente que hay áreas significativas de temperaturas más altas y muchas de temperaturas más bajas. Tenga en cuenta también que las áreas de temperaturas más altas NO coinciden con las áreas que se dice que son las principales productoras de CO2. Mirando el mapa de EE. UU., puede ver claramente que grandes secciones del país tienen temperaturas más bajas. ¿No sería la conclusión natural que, si los grandes productores de CO2 tuvieran más CO2 sobre ellos, y si el CO2 fuera la causa real, entonces la temperatura en estas áreas no sería más alta? Lo que vemos es que las temperaturas más altas NO coinciden de ninguna manera con localidades que producen grandes volúmenes de CO2. Ahora bien, los expertos argumentarían que al CO2 le lleva más tiempo llegar a la atmósfera superior. Una vez allí, se propaga por todo el globo. Si esto es cierto, ¿por qué solo hay pequeños puntos de aumento de temperatura?

El gráfico anterior, generado a partir de la Administración de Información Energética, muestra que las áreas que corresponden a las zonas de mayor aumento de temperatura son en realidad los productores más bajos de CO2.

La teoría también sostiene que el CO2 en la atmósfera refleja la radiación infrarroja hacia el suelo, calentando la Tierra. ¿De dónde proviene esta radiación? En pocas palabras, proviene del sol. Ahora bien, si el CO2 refleja la radiación infrarroja del sol, ¿cómo puede pasar en primer lugar? ¿No crees que nos enfriaríamos, en lugar de calentarnos, con toda esa radiación infrarroja reflejada hacia el espacio debido a los altos niveles de CO2? Ah, sí, eso es correcto. Solo refleja la radiación DESPUÉS de que pasa por primera vez. Intenta este argumento en un trabajo de ciencias de la tierra de secundaria y seguramente encontrarás que está adornado con una calificación reprobatoria. ¿Por qué entonces este argumento tendría validez en cualquier otro lugar?
Otro problema grave con el argumento de que el CO2 causa temperaturas más altas son las temperaturas oceánicas. Un estudio reciente de las temperaturas oceánicas frente a las temperaturas del aire muestra que las temperaturas oceánicas son más altas que la temperatura del aire correspondiente. Hmmmm, pensemos en eso por un segundo. ¿El aire más frío calienta el agua del océano? Algo no cuadra. Bueno, el hecho es que no cuadra. El agua del océano no se calienta por el aire. Sin embargo, se calienta por la radiación infrarroja. Ah, sí, ahí está esa radiación infrarroja de nuevo. Solo que esta vez, es exactamente correcta. El agua absorbe grandes cantidades de radiación infrarroja. Cualquiera que haya pasado tiempo en un clima árido sabe que los cambios de temperatura son enormes, en comparación con un clima más húmedo, como una selva tropical, donde los cambios diarios son de solo unas pocas decenas de grados como máximo. En un desierto, puedes ver una temperatura baja en la noche de casi congelación y una alta por encima de los cien grados Fahrenheit. ¿Por qué es esto? Cualquier buen meteorólogo o profesor de ciencias de secundaria puede responder eso sin siquiera abrir un libro. Una tierra árida no tiene agua para absorber la radiación infrarroja del sol y luego emitir el calor almacenado durante las áreas oscuras. Este almacenamiento de energía funciona en el agua de la tierra, el aire y las plantas. Así que volvamos a nuestro océano. ¿De qué está hecho un océano? ¡Agua! Eso es correcto. Los océanos se calientan por el sol. Ahora, lo siguiente se vuelve un poco técnico, pero intentaré simplificarlo. Los océanos contienen altas cantidades de CO2. La mayor parte de esto está en el agua en lo que se conoce como solución. La cantidad de CO2 que el agua puede contener está directamente relacionada con la temperatura del agua. Cuanto más caliente esté el agua, menos CO2 puede contener debido a algo conocido como presión parcial. Ahora bien, si el agua se está calentando, ¿crees que está liberando más CO2? Por supuesto que sí. Y la evidencia muestra que los océanos están liberando su CO2 a ritmos tremendos. El siguiente gráfico muestra un ejemplo de lo que se conoce como el ciclo del carbono.

Tenga en cuenta que la quema de combustibles fósiles libera 5.3 mil millones de toneladas de carbono por año. Los océanos liberan y reabsorben entre 100 y 115 mil millones de toneladas por año. Mirando esto como un problema de concentración, los niveles de CO2 en la atmósfera aumentaron en 5 partes por millón entre 2001 y 2003. Según el Dr. Jarl Ahlbeck de la Universidad Abo Akademi, Finlandia, un aumento de temperatura de un grado en el océano puede aumentar los niveles atmosféricos de CO2 entre 10 y 20 partes por millón. (http://www.john-daly.com/oceanco2/oceanco2.htm)

Ahora bien, puede que solo sea un simple ingeniero, pero si los océanos se están calentando y los océanos cálidos crean varias veces más CO2 que el aumento observado entre 2001 y 2002, ¿no tendría sentido que esto sea un factor significativo en el aumento global de CO2? De hecho, un aumento de la temperatura promedio del océano de solo un cuarto de grado explicaría TODO el aumento de CO2 que observamos el año pasado. Este mismo punto ha sido señalado por el Dr. Ahlbeck. Los estudios de núcleos de hielo que cubren el clima de los últimos 60,000 años muestran que primero llega el calentamiento, luego el CO2. Esto se ha conocido y establecido en una serie de estudios científicos desde 1989. (http://www.co2science.org/scripts/CO2ScienceB2C/articles/V6/N26/EDIT.jsp)

Entonces, si el calentamiento viene antes del CO2 (de acuerdo con la ciencia real, no la política), ¿cuál es el factor determinante? Veamos. El infrarrojo calienta el agua del océano y el agua del océano emite CO2. Y sabemos que el agua en la mayoría de los climas absorbe infrarrojos moderándolos. Entonces, ¿es posible que el vapor de agua sea un factor? ¿Hay más vapor de agua en las zonas más cálidas de la atmósfera? Según la NOAA, las temperaturas más altas y el mayor contenido de vapor de agua están claramente relacionados, el uno alimenta al otro. La pregunta es, qué viene primero y qué alteró el ciclo de retroalimentación que mantiene las cosas bajo control.

En pocas palabras, sin el efecto invernadero, no habría vida en la Tierra. Es lo que nos impide convertirnos en poco más que un trozo de roca flotando en el espacio como la Luna. El siguiente diagrama muestra una versión muy simplificada de cómo funciona el efecto invernadero (tomado de Junkscience.com).

Puede ver que hay muchos factores que reflejan los infrarrojos tanto lejos de la Tierra como hacia ella. El equilibrio de estas energías es lo que permite que nuestro planeta se mantenga a sus cómodas temperaturas de vida. Cuando este equilibrio cambia, la Tierra cambia. Algunos de estos cambios son a largo plazo y otros a corto plazo. Como ejemplo, la década de 1880 fue el final de lo que se conoce como la pequeña edad de hielo, un período de la historia de nuestro planeta que comenzó en el siglo XVII, donde la temperatura promedio global bajó alrededor de medio grado. Este período siguió a un período de temperatura relativamente más alta conocido como el período cálido medieval, un aumento que alcanzó su punto máximo alrededor de dos décimas de grado en el año 1100. ¿Qué causó estos períodos más cálidos y más fríos? ¿Qué alteró el equilibrio y permitió que el equilibrio global cambiara? Científicamente, ya hemos eliminado el CO2 como causa, los datos de núcleos de hielo muestran claramente que los niveles de CO2 aumentaron después del calentamiento.
La respuesta es que simplemente no lo sabemos. Los modelos climáticos que se utilizan para determinar lo que está haciendo el clima global son simplemente inadecuados. Ninguno de los dieciséis modelos que existen actualmente predice correctamente nuestra situación actual sin "ajustes". Este ajuste es una recalibración manual a una temperatura arbitraria de 14 grados Celsius. ¿Por qué se hace esto? Porque si no lo haces, ninguno de los modelos predice con precisión dónde estamos hoy. Ahora bien, si vas a una tienda de comestibles, querrás que la caja registradora sume exactamente lo que gastas. ¿Cuántos de ustedes irían a una tienda que cobrara la mayor parte de su pedido y luego calculara cuánto debería ser su total y le cobrara por eso? Sé que yo no lo haría, pero eso es exactamente lo que quiere que hagas el IPCC. Tienen modelos que toman datos históricos y suman esos datos. En teoría, si el modelo es correcto, debería ser capaz de predecir un corto período en el futuro. Desafortunadamente, los modelos no funcionan, por lo que para reforzar su argumento de que el CO2 es el problema, ajustan el modelo para obtener el resultado que quieren. La realidad es que la temperatura media absoluta del aire superficial de la Tierra no se conoce y no hay una especificación de exactamente lo que estamos tratando de medir o cómo hacerlo. Nadie sabe cuál sería la temperatura óptima de la Tierra o cómo podría ajustarse de manera consciente y predecible, incluso si se pudiera acordar un óptimo.

¿Existe el calentamiento global? Ciertamente que sí. Si no fuera así, seríamos una bola de hielo flotando en el espacio. El verdadero problema es cuánto cambio climático global es bueno y cuánto es natural. ¿Somos realmente tan vanidosos como para pensar que realmente podemos afectar nuestra atmósfera en tal grado en un período de tiempo tan corto? La realidad nos muestra que una sola erupción volcánica masiva puede causar un cambio climático masivo. El año sin verano, 1816, fue causado por la erupción del Monte Tambora en abril del año anterior. El invierno volcánico causó un enfriamiento grave y aberraciones de temperatura en todo el mundo durante el próximo año. Pero incluso esto fue de corta duración. El sistema de corrección activo de la Tierra se ajustó y las cosas volvieron a la normalidad. Otro ejemplo son todas las pruebas científicas que erróneamente culparon a nuestra producción de clorofluorocarbonos por crear el agujero de ozono sobre el polo sur. Toda esa buena evidencia científica fue proporcionada por los científicos de Dupont, que casualmente estaban en posesión de las patentes de los productos basados en Freón que supuestamente causaban ese agujero. Las mismas patentes que estaban a punto de expirar y fueron rápidamente reemplazadas por patentes de los nuevos Freones. Pero ¿qué pasa con el agujero? En un artículo titulado "Forty Years' Research on Atmospheric Ozone at Oxford: A History" (Applied Optics, marzo de 1968), Dobson describió un programa de monitoreo de ozono que comenzó en Halley Bay en 1956. En este programa de monitoreo, describió lecturas en 1956, veinte años antes del uso de CFC, indicando que había una caída estacional en los niveles de ozono justo donde se "descubrió" el agujero en los años 90. ¿Fue este un descubrimiento motivado científicamente por los científicos de Dupont? Aparentemente no. Parece haber sido poco más que un descubrimiento motivado financieramente que usted está pagando actualmente todos los días. ¿Es el CO2 una causa válida de "calentamiento global"? Una vez más, aparentemente no, pero si la máquina política se sale con la suya, usted pagará por este descubrimiento con costos paralizantes para intentar controlar las emisiones que no tienen ninguna prueba científica de ser más que un indicador de un fenómeno natural. ¿Esto significa que no deberíamos preocuparnos? Claramente hay espacio para la preocupación, sin embargo, es preocupación por entender lo que está sucediendo, no por actos precipitados que podrían no tener otro efecto que destruir las economías enteras de los países.


logo
La guía de referencia de Hoffman La guía de referencia de Hoffman CSR

Articulo original : https://www.freesoft.org/software/hoffman/13Sep2018/reference.pdf
Por : Brent Baccala


Septiembre 13, 2018

Hoffman es un programa para resolver finales de ajedrez usando análisis retrógrado, que es muy diferente de los programas convencionales de ajedrez por computadora. El análisis retrógrado solo es útil en el final, funciona muy lentamente y produce enormes cantidades de datos. Su gran ventaja radica en su capacidad para resolver completamente el final. En un sentido muy real, un motor retrógrado no tiene un "horizonte de movimiento" como un motor de ajedrez convencional. Lo ve todo. Para aquellos que no estén al tanto de la cultura estadounidense, el programa lleva el nombre de Trevor Hoffman, un lanzador de béisbol All Star que se especializa en "cerrar" juegos. Fue escrito específicamente para el juego The World vs. Arno Nickel.

Hoffman usa XML extensivamente tanto para configurar su operación como para etiquetar las bases de datos resultantes. De hecho, una base de datos Hoffman completa (típicamente en un archivo .htb) es solo un archivo comprimido con gzip que contiene un prefijo XML seguido de datos binarios de la base de datos (en un formato especificado por el XML). Básicamente, para operar Hoffman, se escribe un archivo XML que especifica el análisis que se quiere hacer, y luego se lo alimenta al programa. Como salida, produce una versión modificada del XML de entrada que incluye datos binarios de la base de datos añadidos al final.

1 Procesamiento Paralelo con Hoffman
Un análisis de Hoffman puede ser bastante intensivo en computación. El programa se puede compilar para usar hilos POSIX (si están disponibles), con el número de hilos especificado en tiempo de ejecución usando la opción -t. El programa también está diseñado para usar múltiples computadoras en paralelo, todas trabajando simultáneamente en un análisis. Esto se logra dividiendo el análisis en piezas más pequeñas, cada una con su propio archivo de configuración XML.

2 Tablas de propagación

Un análisis de Hoffman también puede ser bastante intensivo en espacio. Dado que su patrón de utilización de memoria es básicamente aleatorio, Hoffman comenzará a intercambiar dramáticamente y sufrirá una caída desastrosa en el rendimiento una vez que el tamaño de su conjunto de trabajo exceda la memoria disponible de la máquina. Para aliviar esto, el programa se puede operar en un modo en el que llena una serie de tablas de propagación, escribiendo cada una en disco cuando está llena, y luego las lee secuencialmente durante la siguiente pasada. Aunque menos eficiente que cuando el conjunto de trabajo puede contenerse en la memoria, las tablas de propagación permiten al programa construir bases de datos de tamaño esencialmente ilimitado sin intercambio y con una utilización razonable de la CPU. Este modo se activa en tiempo de ejecución especificando el tamaño de las tablas de propagación (en MB) con el interruptor -P. Los archivos temporales se escribirán en el directorio actual.

Por ejemplo, el comando hoffman -g -t 2 -P 1024 kqqkqq.xml activará una ejecución de generación de Hoffman con dos hilos, utilizando un gigabyte (1024 megabytes) de memoria.
3 Sintaxis XML

El elemento XML raíz en una base de datos Hoffman es siempre <tablebase>. Su único atributo (offset) es añadido por el programa, no debe ser suministrado por el usuario, e indica un desplazamiento de bytes hexadecimal en el archivo donde comienzan los datos binarios de la base de datos.

Dentro de un <tablebase> pueden ocurrir los siguientes elementos en el orden listado (los elementos y atributos obsoletos no están documentados):

3.1 <prune-enable color="white|black" type="concede|discard"/>
Especifica qué tipos de elementos de poda se permitirán en esta base de datos y en sus futuras bases. Ambos atributos son requeridos. concede significa que se pueden conceder victorias al color nombrado; discard significa que los movimientos del color nombrado pueden ser descartados. Se puede especificar como máximo un prune-enable para cada color. Sin embargo, no se requiere ningún elemento prune-enable, pero no se permiten elementos prune sin uno y las futuras bases no pueden tener elementos prune-enable adicionales más allá de los especificados para la base de datos actual.
3.2 <variant name="normal|suicide"/>
El elemento opcional <variant> especifica qué versión de las reglas de ajedrez se aplica a esta base de datos.

Predeterminado: normal
3.3 <index type="naive|naive2|simple|compact|no-en-passant|combinadic|combinadic2|combinadic3|combinadic4|pawngen" symmetry="1|2|4|8"/>
El elemento <index> especifica el algoritmo que se utilizará para calcular los números de índice en la base de datos; es decir, el algoritmo que convertirá las posiciones del tablero en desplazamientos de la base de datos y viceversa. Normalmente no es especificado por el usuario (pero puede serlo).

naive utiliza 26n+1 índices para almacenar posiciones para n piezas. Asigna un solo bit para la bandera de turno de juego, luego asigna 6 bits a cada pieza, que se usa para codificar un número de 0 a 63, indicando la posición de la pieza en el tablero.

naive2 Difiere de naive en su manejo de múltiples piezas idénticas, que almacena como una base y un desplazamiento, ahorrando así un solo bit. Actualmente, solo se manejan pares de piezas idénticas; se producirá un error fatal si hay más de dos piezas idénticas.

simple Como naive, pero solo asigna números a los cuadrados que son legales para una pieza en particular. Más lento de calcular que naive, pero más compacto para las bases de datos con muchas restricciones de movimiento en las piezas.

compact Una combinación de la codificación delta utilizada para piezas idénticas en naive2, la codificación de piezas restringidas utilizada en simple, más una codificación emparejada de los reyes para que nunca puedan ser adyacentes.

no-en-passant Una mejora de compact que utiliza el esquema de codificación emparejado para peones restringidos al mismo archivo. Como nunca pueden pasarse entre sí, podemos codificarlos como si fueran un par idéntico, y luego asignar sus colores en el mismo orden en que fueron especificados originalmente. En passant complica esto significativamente y no puede ser manejado con este esquema.

combinadic
Una mejora de naive2 que puede codificar más de dos piezas idénticas y superpuestas utilizando un esquema de codificación combinatoria (ver la página de wikipedia "Sistema de números combinatorios").

combinadic2 Como combinadic, pero las piezas posteriores completamente contenidas en el rango semilegal de las piezas anteriores se codifican utilizando menos posiciones. El orden de las piezas es significativo. No se realiza ningún intento de reducir la codificación de los peones.

combinadic3 Como combinadic2, pero las codificaciones de peones también se reducen, reduciendo su valor de codificación (con en-passant incluido), mientras que se usa su posición en el tablero para reducir otras piezas.

combinadic4 Como combinadic3, pero las bases de datos simétricas de color, aquellas invariantes al intercambiar colores, se optimizan eliminando la bandera de turno de juego, reduciendo el tamaño de la base de datos a la mitad. (por ejemplo, kqkq es simétrico de color, pero kqkr no lo es)

pawngen Como combinadic4, pero los peones se manejan por separado construyendo una tabla de todas las posibles posiciones de peones que pueden resultar de una configuración inicial de peones dada.


El atributo opcional symmetry se puede usar para codificar múltiples posiciones usando una sola entrada, pero su utilidad depende del análisis exacto que se esté realizando. Una base de datos sin peones y sin restricciones de movimiento se puede codificar con simetría de 8 vías, ya que el tablero se puede rotar alrededor de un eje horizontal, vertical o diagonal sin afectar el comportamiento de las piezas. Una base de datos con peones puede utilizar una simetría de 2 vías como máximo, ya que solo un reflejo sobre un eje vertical preserva el comportamiento de las piezas. Una base de datos con restricciones en las posiciones de las piezas (por ejemplo, peones congelados) no puede usar ninguna simetría en absoluto. No todas las simetrías son compatibles con todos los tipos de índice; por ejemplo, la simetría de 8 vías no se puede utilizar con los tipos de índice naive o naive2.

Predeterminado: combinadic4 con simetría seleccionada automáticamente, a menos que haya un elemento pawngen presente en el XML, lo que activa pawngen.
3.4 Formato de base de datos
Los siguientes tres elementos especifican el formato de las entradas de la base de datos. Como máximo se puede especificar uno de ellos.

<dtm bits=integer/> especifica una métrica de distancia al mate. Se utiliza cero para los empates, -1 para las posiciones en las que el lado en movimiento está en jaque mate, y 1 para las posiciones en las que el lado en movimiento puede capturar al rey contrario, por lo que un campo dtm de ocho bits puede registrar distancias al mate de hasta 126. Si no se especifica un tamaño de campo, se selecciona automáticamente.

<dtc bits=integer/> especifica una métrica de distancia a la conversión, que es el número de movimientos necesarios antes de alcanzar una base de datos diferente. Se utiliza cero para los empates, -1 para las posiciones en las que el lado en movimiento está en jaque mate, y 1 para las posiciones en las que el lado en movimiento puede capturar al rey contrario, por lo que un campo dtm de ocho bits puede registrar distancias de hasta 126. Si no se especifica un tamaño de campo, se selecciona automáticamente.
<basic/> especifica una bitbase donde se utilizan dos bits para cada posición, y no se almacena información de distancia, solo una indicación del resultado final (ganar, perder o empatar). Tal formato es más compacto y requiere menos tiempo para generar, pero requiere más esfuerzo de usar, ya que se debe tener cuidado de evitar bucles al seguir líneas ganadoras.

<flag type="white-wins|white-draws"/> especifica una bitbase donde solo se usa un bit para cada posición. white-draws incluye tanto las posiciones ganadoras como las de empate para las blancas, por lo que esencialmente se da la situacion: NOT Black-wins.

Predeterminado: DTM con tamaño de campo seleccionado automáticamente.

3.5 <piece color="white|black" type="king|queen|rook|bishop|knight|pawn"location="string"/>

Los elementos piece se utilizan para especificar las piezas de ajedrez presentes en la base de datos. El color y el tipo son requeridos y deben ser obvios. El orden de los elementos de piece es significativo ya que afecta directamente al algoritmo de indexación, pero no hay ningún efecto visible para el usuario en el orden.

El atributo opcional location restringe las posiciones del tablero disponibles para esta pieza. Debe ser una lista de cuadrados, en notación algebraica, en los que se permite que esté la pieza. Un solo cuadrado resulta en una pieza completamente congelada. Además, los peones pueden usar una sintaxis adicional que consiste en un solo cuadrado inicial seguido de un signo más, lo que indica que el peón puede moverse hacia adelante lo más lejos posible. Esto se puede usar, por ejemplo, para ubicar un peón negro en "a7+" y un peón blanco en "a2+", indicando que ambos pueden moverse hacia adelante, pero no pueden "pasarse" el uno al otro.

3.6 <pawngen white-pawn-locations="string" black-pawn-locations="string"

white-pawns-required="number" black-pawns-required="number"

white-queens-required="number" black-queens-required="number"

white-captures-allowed="number" black-captures-allowed="number"/>


Las configuraciones de peones se pueden especificar utilizando un elemento pawngen en lugar del elemento piece. Se especifica un conjunto de ubicaciones iniciales de peones para cada color utilizando los atributos *-pawn-locations, y se calculan todos los posibles movimientos de peones desde esa configuración inicial. Dado que el número y los tipos de piezas son fijos para cada ejecución del programa, los atributos *-pawns-required deben especificarse para indicar cuántos peones de cada color están permitidos. Opcionalmente, los atributos *-queens-required pueden especificarse para forzar la consideración de posiciones donde cierto número de peones se han convertido en reinas, y los atributos *-captures-allowed incluyen la consideración de posiciones donde cierto número de piezas que no son peones han sido capturadas (las capturas de peones ya se consideran).

El script Perl auxiliar pawngen puede aceptar archivos de control sin atributos *-pawns-required, y genera nuevos archivos de control interconectados con los atributos requeridos añadidos.
3.7 <futurebase filename="string" colors="invert"/>
Se puede especificar una o más futuras bases con este elemento. Se debe especificar un comando filename para localizar una futura base, que debe ser otra base de datos, ya sea en formato Hoffman, Nalimov o Syzygy. La ruta a una base de datos Nalimov se ignora; debe estar en el directorio especificado en la línea de comandos usando la opción -N.


La futura base debe estar relacionada con la base de datos actual de una de las siguientes maneras:

Tiene exactamente la misma configuración de piezas que la base de datos actual, y corresponde al movimiento de una de las piezas restringidas, es decir, la base de datos actual tiene un peón blanco congelado en e4 y la futura base tiene un peón blanco congelado en e5.

Tiene exactamente la misma configuración de piezas que la base de datos actual excepto que falta una sola pieza, es decir, ocurrió una captura.

Tiene exactamente la misma configuración de piezas que la base de datos actual excepto que un solo peón ha sido reemplazado por un caballo, alfil, torre o reina, es decir, un peón promovido.

Tiene exactamente la misma configuración de piezas que la base de datos actual excepto que un solo peón ha sido reemplazado por un caballo, alfil, torre o reina, y se ha eliminado una sola pieza no peón del color opuesto, es decir, un peón capturado y promovido en el mismo movimiento.
El atributo opcional colors="invert" puede especificarse para indicar que los colores de las piezas de la futura base deben invertirse a medida que se procesa. Esto evita la necesidad de calcular, por ejemplo, una base de datos con una reina blanca y una torre negra, así como una base de datos con una reina negra y una torre blanca. La primera puede ser utilizada (con esta opción) como una futura base para calcular una base de datos con dos torres blancas y una reina negra.

Nota: Cualquier elemento prune-enable de la futura base debe ser un subconjunto de los elementos prune-enable de la base de datos actual.
3.8 <prune color="white|black" move="string" type="concede|discard"/>
Los movimientos futuros no manejados especificando futuras bases deben ser podados usando uno o más de estos elementos, o se producirá un error. La accion move se especifica usando sintaxis de expresión regular para hacer coincidir un movimiento en un subconjunto de notación algebraica estándar. Todas las siguientes cadenas son ejemplos de cadenas de movimientos legales en un elemento prune: Pe5, P=Q, RxQ, PxR=Q. Las siguientes expresiones regulares coincidirían con Kd4: Kd?, K?4, K[a-d]4, K*. El atributo type especifica qué se debe hacer con los movimientos coincidentes: tratarlos como victorias para el lado en movimiento en este caso; (concede), o ignorarlos completamente con(discard). Si múltiples elementos prune coinciden con un movimiento particular, es una advertencia avisara si son del mismo type, o un error fatal saltara si sus types difieren.

Se puede especificar un solo elemento prune con move="stalemate" y type="concede". En este caso, el atributo color indica a qué lado se deben conceder los empates como victorias.
Nota: los elementos prune no afectan los movimientos dentro de una base de datos. Especificar un elemento prune que solo coincida con movimientos dentro de una base de datos no hará nada.

Nota: Si se especifica un elemento prune para un futuro movimiento manejado por una futura base, entonces la futura base tiene prioridad. Sin embargo, este caso se maneja rastreando cada futuro movimiento en cada posición, por lo que es posible especificar futuras bases que manejen un subconjunto de los posibles movimientos futuros, y luego usar elementos prune para manejar el resto por defecto.

Nota: los elementos prune solo están permitidos si coinciden con un elemento prune-enable. Si no se especificaron elementos prune-enable, entonces no se permitirán elementos prune.

Nota: Las versiones anteriores de Hoffman permitían un atributo pawngen-condition que ya no es compatible.
3.9 Controles de generación

Estos elementos son todos opcionales, pero siempre que output no sea especificada, se debe especificar un nombre de archivo de salida output en la línea de comandos usando el interruptor -o.
3.9.1 <output filename="string"/>
Como máximo debe utilizarse un único elemento de output para especificar dónde debe escribirse la base de datos terminada.
3.10 <tablebase-statistics> ... </tablebase-statistics>
Este elemento es añadido por el programa y no debe ser especificado en la entrada. Contiene estadísticas relacionadas con la base de datos terminada.


Elementos

Interpretacion

indices

Número total de entradas en la base de datos no comprimida

PNTM-mated-positions

Número total de posiciones en las que el jugador que no se mueve está en jaque mate; es decir, posiciones ilegales en las que un rey puede ser capturado inmediatamente

legal-positions

Número total de posiciones legales; es decir, número total de entradas, menos entradas ilegales donde dos piezas ocupan el mismo espacio, menos posiciones de jaque mate PNTM

stalemate-positions

Posiciones de tablas (no empate por repetición)

white-wins-positions

Posiciones desde las que las Blancas pueden forzar una victoria

black-wins-positions

Posiciones desde las que las Negras pueden forzar una victoria

forward-moves

Número total de movimientos hacia adelante desde posiciones en esta base de datos (incluyendo movimientos futuros)

futuremoves

Número total de movimientos hacia adelante desde posiciones en esta base de datos hacia futuras bases o podados

max-dtm

Mayor distancia al mate de todas las posiciones en esta base de datos

min-dtm

Menor distancia al mate de todas las posiciones en esta base de datos, es decir, un número negativo que indica la pérdida forzada más larga

3.11 <generation-statistics> ... </generation-statistics>

Este elemento es añadido por el programa y no debe ser especificado en la entrada. Contiene estadísticas relacionadas con la ejecución del programa que generó la base de datos.


Elementos

Interpretacion

host

Nombre de host del sistema que generó la base de datos


program

Nombre y versión del programa que generó la base de datos

args

Línea de comandos utilizada para la ejecución de generación

start-time

Tiempo en que se inició inicialmente la ejecución del programa

completion-time

Tiempo en que finalizó la ejecución del programa

user-time

Tiempo de CPU utilizado por la ejecución en el espacio de usuario

system-time

Tiempo de CPU utilizado por la ejecución en las llamadas al sistema

real-time

Tiempo de reloj de pared utilizado por la ejecución

page-faults

Número de veces que el programa tuvo que esperar a que se intercambiara una página de memoria desde el disco

page-reclaims

Número de veces que el programa recuperó una página de la lista libre; esto típicamente serán páginas de instrucciones del programa

proptable-writes

Si las tablas de propagación están en uso, el número de tablas de propagación escritas en disco

proptable-write-time

Si las tablas de propagación están en uso, el tiempo real total requerido para todas las escrituras de tablas de propagación

pass

Estadísticas por pasada, incluyendo tiempo real y tiempo de usuario


4 Algunos mensajes de error confusos


4.1 Las futuras bases no pueden ser menos simétricas que la base de datos en construcción


Las bases de datos simétricas colapsan múltiples posiciones en una, por lo que las futuras bases deben tener la misma simetría (al menos), o la futura base podría manejar de manera diferente dos posiciones que la base de datos más simétrica trata como una.


4.2 Los peones doblados deben (actualmente) aparecer en orden de tablero en la lista de piezas


Actualmente, los peones doblados que usan ubicaciones "más" (por ejemplo, location="a2+") en el mismo archivo deben tener los elementos de piece listados en el XML en el orden en que los peones aparecen en el tablero, contando en notación algebraica de la fila 1 a la fila 8. Quiero decir, de la fila 2 a la fila 7.


4.3 Restricciones de piezas no permitidas con índices simétricos (todavía)


No se puede especificar un atributo de caracter index symetry sin también especificar atributos piece location, incluso si las restricciones en las ubicaciones de las piezas pudieran ser compatibles con la simetría solicitada.


4.4 Restricciones de piezas superpuestas no idénticas no permitidas con este tipo de índice


Para los tipos de índice naive, naive2 y simple, no se pueden especificar dos piezas idénticas con diferentes restricciones del tipo location a menos que esas restricciones sean completamente distintas. Por ejemplo, no puedes tener una torre blanca libre y otra torre blanca restringida al archivo a. Si lo piensas bien, esta situación permitiría que las torres "cambiaran de lugar": ambas podrían moverse al archivo a y luego cualquiera de las dos podría moverse. Los tipos de índice más simples no pueden manejar esta situación. Sin embargo, podrías tener una torre blanca restringida al archivo a y otra restringida al archivo d (o usar un tipo de índice más sofisticado, como compact).


4.5 La futura base no coincide con los prune-enables!


Recuerde que los elementos prune-enable de la futura base deben ser un subconjunto de los prune-enables de la base de datos actual.


4.6 No hay futura base o poda para ...

Movimientos futuros no manejados ...


Si uno o más movimientos futuros no se manejan especificando una futura base o una declaración de poda, se producirá un error fatal inmediatamente o después de la pasada de inicialización. Para ayudar en el diagnóstico, el mensaje de error incluye el FEN de la posición infractora.


4.7 pawngen no admite elementos de salida en los controles de generación


El script pawngen genera automáticamente todos sus nombres de archivo. Elimine el elemento de salida. Después de la generación, todos los archivos htb resultantes se pueden cargar juntos en el modo de sonda de Hoffman.

logo
Una Meditación de Acción de Gracias Una Meditación de Acción de Gracias CSR

Artículo Original: https://pages.ucsd.edu/~dkjordan/diversions/ThanksgivingMeditation.html

Por:David K. Jordan
Meditación de Acción de Gracias
El Día de Acción de Gracias, simbolizado en América del Norte por un festín alegre en compañía de amigos y familiares, es un momento para reflexionar sobre el hecho de que, a pesar de las frustraciones de la vida, uno se encuentra sin embargo, en muchos sentidos, en una buena posición.

Para una persona que contempla la amplia gama de variaciones humanas y considera cómo las sociedades de nuestro mundo evolucionaron hasta lo que son hoy, hay varias características del orden mundial moderno, tanto en las regiones ricas como en las pobres, por las cuales me parece que dar gracias puede ser especialmente apropiado.

A riesgo de ser un poco sentimental, sugiero algunas de ellas aquí por si te gustaría pensar en ellas durante las fiestas.

Política y Derecho

  1. Creemos que el gobierno debe servir a los gobernados. (Los estados del pasado a menudo argumentaban lo contrario.)
  2. Apoyamos las cortes y los parlamentos, y condenamos a los tiranos. (La mayoría de los estados desde la Edad del Bronce fueron dirigidos por tiranos y nunca oyeron hablar de parlamentos. Hoy en día, incluso los peores tiranos afirman ser elegidos por los gobernados.)
  3. Experimentamos indignación ante la corrupción, la explotación y el racismo. (La mayoría de las sociedades han asumido que estos son inevitables. Mucha gente todavía lo cree.)
  4. Rara vez glorificamos la guerra por el simple hecho de la guerra. (Los estados modernos buscan evitar la guerra o emprenderla con justificaciones públicas de su necesidad.)
  5. Condenamos el uso de la tortura para extraer confesiones.
  6. Condenamos el castigo desorbitado de los crímenes. (Casi todas las sociedades a lo largo de la historia han tratado mal a los sospechosos y a los criminales, o los han ejecutado sumariamente.)
  7. No otorgamos estatus legal al delito de brujería. (Ha sido una sociedad rara la que no ha castigado o ejecutado a brujos.)
  8. No practicamos el sacrificio humano ritual.

Relaciones Sociales y Derechos Humanos

1. Apoyamos la libertad personal como una idea general, y distinguimos algunas libertades específicas como las libertades de:

  • Informar noticias
  • Estudiar y obtener educación
  • Reunirse
  • Poseer propiedad
  • Elegir a su propio cónyuge
  • Crear, exhibir y realizar obras de arte
  • Perseguir objetivos políticos o económicos
  • Tanto para mantener como para compartir opiniones, incluidas las opiniones disidentes

(La libertad política era una idea rara hasta los tiempos modernos. La tolerancia religiosa era casi desconocida, ni mucho menos fomentada. En pocas sociedades se elegía a la propia pareja. En muchas sociedades, la educación, incluso la simple alfabetización, se desalentó activamente, especialmente para las mujeres. Informar noticias sigue estando restringido en gran parte del mundo incluso hoy en día.)

2. Ya no toleramos la esclavitud, a pesar de su persistencia. (La mayoría de las sociedades desde el Neolítico la han exhibido.)

3.Apoyamos la monogamia y condenamos los harenes y el concubinato. (Esto no ha sido así en la mayoría de las sociedades.)

4.Respaldamos la protección estatal de los individuos frente a los ataques de otros. (Los ladrones, piratas, matones, pandillas y señores de la guerra pueden ser un riesgo inevitable en todas las sociedades, pero todos los estados modernos intentan brindar al menos cierta protección contra ellos.)
Salud

  1. Nuestro enfoque de la enfermedad suele ser a través de la ciencia y solo en raras ocasiones a través de la magia. (La mayoría de las sociedades desde el comienzo de la humanidad han intentado curar enfermedades principalmente a través de la magia.)
  2. Buscamos aliviar la escasez y la hambruna en todas partes del mundo, por distantes que estén.(En siglos pasados, las hambrunas extranjeras eran objeto de curiosidad más que de preocupación.)
  3. Buscamos asegurar la salud y el bienestar físico de todos.(Pocas sociedades han tenido los medios o la voluntad para hacerlo.)
  4. Nos hemos dado cuenta del papel del ser humano en la ecología de nuestro planeta, y existe una preocupación generalizada por cambiar ese papel de destructivo a protector. (Hasta hace muy pocos años, el deterioro ecológico se ignoraba ampliamente en las políticas públicas, e incluso hoy en día los "negacionistas del clima" siguen siendo influyentes en algunos países.)

Conocimiento

  1. Valoramos la alfabetización y buscamos extenderla a todos. (A lo largo de la historia, casi todos los humanos han sido analfabetos; los alfabetizados a menudo han tratado de confinar la alfabetización a clases limitadas de personas.)
  2. Apoyamos la curiosidad por otras sociedades y sus culturas, y condenamos a quienes tratan a otras sociedades con desprecio instintivo.
  3. Aprobamos la curiosidad sobre cómo funciona el mundo en lugar de reprimirla. (La mayoría de las sociedades han preferido una línea del partido a una mente abierta. Algunas personas todavía lo hacen.)
  4. Apoyamos a los museos, universidades y centros de investigación para mejorar y aplicar nuestro conocimiento sobre el mundo y para transmitir ese conocimiento de manera amplia en la sociedad.
  5. Tenemos café espresso, teléfonos inteligentes, envoltura plástica, mayonesa, Wikipedia y plomería interior.
  6. Dedicamos un día festivo a reflexionar sobre todas las razones por las que deberíamos estar agradecidos.
    Meditación de Acción de Gracias

Una versión anterior de esta página se creó por primera vez en 1997 y se revisó ligeramente a lo largo de los años siguientes. La redacté para estudiantes de una clase grande de Civilización Mundial que se dirigían a casa para las vacaciones de Acción de Gracias, y quería situar el mundo moderno en el contexto de todo lo que había sucedido anteriormente. Al observar el mundo moderno de esta manera, la página sugiere que incluso las personas que viven bajo regímenes opresivos en la actualidad tienen motivos para ser optimistas, ya que la historia, en última instancia, está de su lado.

logo
20 Preguntas 20 Preguntas CSR

Artículo Original: https://theworld.com/~swmcd/steven/stories/questions.html

Por: Steven W. McDougall

¿Cuántos nombres hay en tu mundo?

En el juego de las 20 preguntas, una persona piensa en algo y la otra persona debe adivinarlo haciendo no más de 20 preguntas de sí o no.

El hecho de que este juego sea interesante —en oposición a trivial o imposible— sugiere que los humanos tienen nombres para 2^20, o un millón, de cosas en su mundo. Si los humanos solo tuvieran nombres para mil cosas, entonces diez preguntas serían suficientes para especificar cualquiera de ellas; si los humanos tuvieran nombres para mil millones de cosas, entonces serían necesarias 30 preguntas.


¿Cómo divides tu mundo?

Al observar cómo las personas juegan 20 preguntas, podemos descubrir no solo el tamaño de su mundo, sino también cómo lo estructuran.

Por tradición, un juego de 20 preguntas comienza con la pregunta ternaria fija

  • ¿Es animal, vegetal o mineral?

Las tradiciones como esta comienzan porque los jugadores experimentados encuentran que siempre comienzan el juego con la misma pregunta o dos, reflejando las dos o tres categorías conceptuales más amplias en su modelo del mundo. El hecho de que la gente comience el juego preguntando "¿animal, vegetal o mineral?" sugiere que organizan su mundo así


Divisiones del siglo XXI


El juego de las 20 preguntas se remonta a siglos atrás, y la pregunta "¿animal, vegetal o mineral?" tiene más de 100 años. Como tal, refleja la visión del mundo que solía tener la gente.

Cuando juego a las 20 preguntas, no encuentro la clasificación "animal, vegetal o mineral" tan útil. En cambio, comienzo preguntando:


  • ¿Está hecho por el hombre?
  • ¿Está vivo?


Lo que sugiere que organizo mi mundo como


Esto probablemente refleja el ascenso de la tecnología en nuestras vidas durante los últimos 100 años.


Notas

siglos

concebiblemente, al origen del lenguaje hablado