Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.

Temas - argentinator

Páginas: [1] 2 3 4 ... 8
1
Foro general / Los números telefónicos no son números
« en: 09 Febrero, 2021, 10:18 pm »
Afirmo eso, tal cual dice el título:

Los números telefónicos no son números.

Tampoco son números los números de las tarjetas de crédito.

A ver quien se anima a contradecirme.

3
Queridos usuarios del foro.

A lo mejor hayan tenido problemas de conexión, avisados con un mensaje titulado: "Connection Problems".
Me ha ocurrido largo rato durante el día de hoy.

En estos casos, puede resultar desagradable que, tras escribir un largo mensaje, aparezca ese mensaje de error al querer publicar, y el texto completo se pierda antes de que sea recibido correctamente por el foro.

Para prevenir ese inconveniente, lo que sugiero hacer es lo siguiente:

* Tras escribir todo el texto, pintarlo todo para hacer un "copiar y pegar".
* Presionar la combinación de teclas "Control C", a fin de "copiar" todo el texto (quedando guardado en memoria).
* Si el mensaje no se pudo publicar por algún error del servidor, volver a intentar, bastando ahora presionar las teclas "Control V" para que aparezca el mensaje completo original, y así no tener que tipearlo todo desde cero.


4
En este hilo voy a poner unas dudas y unos comentarios de la parte de Lógica de Primer Orden del libro de Lógica Matemática de Ivorra (que pueden bajar de su página web).

Espero contar con la participación de Carlos. ;)

Lo pondré repartido en varios hilos, porque es un poco largo,
aunque quería dejar plasmadas todas las cuestiones de un solo golpe,
para que se sepa al menos hasta dónde quiero llegar.


5
Quiero compartir una reflexión y ver si alguien complementa o corrige.
Hay pruebas de Teoremas en teoría de grupos que salen por inducción en el orden g del grupo G.
Pero esto implica que para cada natural g estamos haciendo referencia a la clase propia C(g) que contiene todos los grupos G de orden g.
La inducción en ZFC se establece para subconjuntos del conjunto N.
Tales subconjuntos se pueden definir mediante fórmulas, las cuales sólo admiten conjuntos como terminos, y no admiten clases propias.
Luego ese tipo de inducción no puedo expresarla en ZFC.

A simple vista parece que la prueba se sale de ZFC.
Pero creo haber emparchado la situación observando que,
en realidad, estamos hablando sólo de grupos finitos,
y que un grupo de orden n es aubgrupo del grupo de permutaciones Sn.

Si definimos \(A=S_1\times S_2 \times \cdots \), el producto directo infinito de los Sn,
eso da un conjunto que no es clase propia,
y todo grupo involucrado en la prueba de un teorema sobre grupos finitos es isomorfo a un subgrupo de \(A\).
Allí la inducción sobre el orden g de un grupo G se refiere al cardinal g de un subgrupo de \(A\).
Eso más algunos retoques con isomorfismos debiera arreglar la cuestión.

Un ejemplo de tal prueba por inducción es la de que un grupo finito G tiene un p-subgrjpo de Sylow para p primo.

6
Lógica / Causalidad y lógica
« en: 13 Junio, 2015, 07:36 pm »
Me ha tocado estos días tener que reflexionar acerca de la naturaleza del tiempo.
Quisiera entender algunas cuestiones básicas del fluir del tiempo sin necesidad de teorías físicas,
apelando solamente a la razón, y más aún, al razonamiento aún no formalizado,
porque quiero entender qué papel juega el tiempo al hablar de "algoritmos" o "procedimientos" en metamatemática.
O sea, el tiempo a nivel de computación, de programas.
Si yo utilizara la Relatividad de Einstein, estaría entrando en un círculo vicioso, porque esa es una teoría basada en el formalismo matemático, que a su vez se construyó primero con elementos más intuitivos y básicos.

No obstante, puedo aludir sin problemas a hechos experimentales y verificados de la Teoría de la Relatividad,
porque la evidencia es algo tangible, concreto, y de paso es anecdótico apenas, que puede estar enmarcada o no en una teoría.
Por ejemplo, se puede comprobar experimentalmente lo siguiente:

Existen pares de fenómenos E y F y ternas de testigos u, v, w, tales que:

* En su marco de referencia, u percibe que E ocurrió antes que F, en su línea de tiempo propia.
* En su marco de referencia, v percibe que E y F ocurrieron simultáneamente, en su línea de tiempo propia.
* En su marco de referencia, w percibe que F ocurrió antes que E, en su línea de tiempo propia.

Por otra parte, se puede demotrar con las fórmulas de la teoría de la relatividad que si el evento E causa el evento F,
entonces E siempre precede a F en todos los marcos de referencia. Los mismos testigos u, v, w, verían cada uno en su marco de referencia que E sucede antes que F.

---------

Lo que yo me pregunto es si esta "demostración" puede hacerse sin usar las fórmulas de la Teoría de la Relatividad,
usando solamente el razonamiento puro.

Yo enunciaría algo más general como esto (que espero no sea tramposo):

(1) Si para que suceda el evento F es lógicamente necesario que ya haya sucedido el evento E, entonces en todos los marcos de referencia el evento E se percibe antes que el evento F.

Me parece que esto es mera consecuencia de las palabras que estoy usando para enunciar la propiedad,
aunque no sé si me estoy engañando en alguna parte.

O sea, mi "demostración" sería que: las reglas del razonamiento lógico son las mismas para todos los posibles testigos
de los eventos E y F, y que si estoy diciendo que, cualquiera sea el evento F, es lógicamente necesario que haya ocurrido el E,
quiere decir que, en cada marco de referencia, el correspondiente testigo tiene que percibir que E ha sucedido ya, para que tenga sentido o sea posible la ocurrencia de F.

-----------

Una vez que se ha establecido este orden causal entre eventos,
entonces es posible hablar de eventos ordenados en secuencia a lo largo del tiempo,
con independencia del marco de referencia, y así establecer una línea de tiempo que avance del pasado al futuro en forma absoluta.
Esta "línea" de tiempo no necesariamente es para mí un "continuo", ni nada concreto,
sino una "cosa" que tiene la propiedad de que ciertos eventos pueden ponerse en orden allí
O sea que, sólo estoy seguro de que puede extraer una sucesión discretizaada de instantes \( t_n^R \) de allí,
tal que para números enteros es \( m<n \) si y sólo si \( t_m^R<t_n^R \) en cualquier marco de referencia \( R \).

---------

Si esta "demostración" es demasiado chapuza, a lo mejor podría contentarme con la existencia de tales eventos mediante
algún otro argumento, aunque quiero evitar apelar a la Física mientras sea posible.

¿Alguna opinión?


7
Estoy tratando de entender el concepto de RAZONAMIENTO.
Para eso parece que no puedo eludir la cuestión del tiempo.
Un razonamiento es un procedimiento, por eso requiere tiempo.
Pero quiero ser más preciso en esto, y evitar definir el término PROCEDIMIENTO.
Si tengo premisas A y B y una conclusión C, y consideremos un razonamiento, que por brevedad voy a referir como R, el cual infiere que de A y B se deduce C.
Parece lo.más natural del mundo que uno enuncie primero antes de cierto instante t  las premisas A y B, y que en un instante posterior t' enuncie C a fin de llevar a cabo el razonamiento R.

Me pregunto entonces: ¿es esto necesariamente así, es esta una propiedad de todo razonamiento?
¿Qué significa que R lleva de las premisas A y B a la conclusión C? ¿Es un razonamiento una TAREA que debe hacerse en determinado orden a lo largo ddl tiempo?

Sería más claro preguntar si un razonamiento es un algoritmo, pero como se trata de algo INFORMAL no me convence preguntarlo así.


9


Ya me he acostumbrado a considerar que hay una entidad intuitiva, "la" colección de (meta) números naturales, que denotaré N.

Este N es considerado el modelo estándar de las varias teorías formales de números naturales que andan por ahí (axiomas de Peano, Presburger, etc.).

No obstante, cualquier otra colección intuitiva N' de objetos, que permite dar una clara correspondencia entre los objetos 1, 2, 3, ... de N y los objetos 1', 2', 3', etc. de N', tiene que dar "otro" modelo estándar de dichas teorías.
Estos objetos de N' también se pueden sumar, multiplicar, y poner en un orden total,
con tal de contagiar las operaciones y relaciones respectivas ya dadas en N.

Estoy tratando de hablar con cuidado para no salirme del país "meta", y no caer en formalización alguna.

Ahora, la pregunta que tengo es la siguiente:

¿Es necesario que un modelo alternativo/isomorfo de N sea intuitivo?

Si logro generar de algún modo una colección infinita con un lenguaje de programación que luzca como N, ¿se consideraría también un modelo estándar de N?

---------------------------

Más concretamente:

En C es posible definir objetos "semánticamente" hablando, de tamaño arbitrario.
Por ejemplo, un programa que genera una lista enlazada de datos del mismo tipo.

Un tipo de datos T en C involucra dos cosas: un conjunto de ciertos valores (entidades abstractas, mentales, matemáticas), y un modo de representarlos en una máquina real.
Una declaración como esta:

typedef char T;
T carac;

lo que hace es definir un tipo de datos T como sinónimo de char (de hecho, es char).
El tipo T en este caso admite los valores 0 a 255.
Estos "valores" son entidades matemáticas abstractas.
Para cada valor posible, el tipo T determina un modo concreto de representarlo en una computadora, digamos como una secuencia finita de bits 0 y 1.
Finalmente está el objeto con nombre carac, declarado de tipo T.

Hay 3 tipos de entidades aquí:

1. La colección de valores matemáticos abstractos de 0 a 255.
2. La colección (abstracta, mental, intuitiva) de pares ordenados (v, r), donde v es uno de los valores dados en (1.), y r es la secuencia finita de bits conque se representa en una computadora el valor v.
3. El objeto real caract, que es un bloque concreto de memoria RAM, por ejemplo, con sus bits puestos a 0 ó 1, representando físicamente el valor v mediante la secuencia de bits indicada por r.

Podríamos todavía dividir el punto 2 en dos partes:
2.(a). La "promesa" del lenguaje C, desde un punto de vista meramente sintáctico, de que a cada valor de 0 a 255 le corresponderá una representación concreta.
2.(b). La regla propiamente dicha que transforma un valor v en una representación r, que sería usada ulteriormente en una máquina real.


El lenguaje C define (aquí estoy mintiendo un poco para simplificar, pero no es relevante), mediante la declaración typedef, una asociación entre los valores v de 0 a 255, y los modos de representación en bits r.
Esto da lugar a una colección de 255 pares ordenados (v, r), y por lo tanto no hay gran diferencia entre los puntos (1.) y (2.).
Los "estados" posibles que puede tomar el objeto caract en la memoria RAM son, por lo tanto, también los correspondientes de 0 a 255. Son 256 estados posibles.

Hasta aquí todo viene fácil de entender, porque es una asociación trivial.
Lo que quiere dejar de relieve es lo siguiente:

En 1. tenemos entidades estrictamente matemáticas (e intuitivas).
En 2.(a). tenemos de nuevo entidades intuitivas, pero que a su vez están declaradas como parte de C, como lenguaje, en el "costado" sintáctico del mismo.
En 2.(b). tenemos una regla definida por el compilador, que asocia a un valor v un formato concreto r. Esto es "semántico", pero todavía está en abstracto, como una "regla".

En 3. estamos  en el "costado" semántico del programa, ya con la versión corriendo, o sea en forma ejecutable, en que todas las declaraciones escritas en C se han convertido en acciones concretas en una máquina. En particular, una porción de memoria RAM de cierta máquina ha adoptado unos estados eléctricos determinados que indican los bits 0 y 1.

En todos los casos, las colecciones involucradas son finitas, pues el tipo char sólo admite una colección finita de valores.

En C todo tipo de datos aritmético admite sólo una cantidad finita de valores,
y por lo tanto no pueden representarse todos los números naturales.


Pero también es posible definir tipos de datos T tal que su colección de posibles valores sea infinita. Éste es el caso, por ejemplo, de las listas enlazadas.
Una estructura como la siguiente:

typedef struct T { char d; struct T *link; } T;
T number;

Eso define un tipo de datos, T, con dos campos: uno de tipo char, y otro un puntero a un objeto de nuevo de tipo T.
O sea, es una estructura recursiva.

El campo d, que es de tipo char, ya sabemos que sólo admite un número finito de valores, digamos de 0 a 255.
En cambio, el campo link es de tipo struct T*, y es un apuntador a un objeto de tipo T.

El objeto number, declarado de tipo T, tiene esta estructura:

number: [d, link---> [d, link---> [d, link---> ... [d, link--->#] ... ]]]

He indicado con un signo # el final de la lista.

Este "final" de lista puede irse corriendo hacia la derecha tanto como uno quiera.
El lenguaje C permite ir agregando nuevos objetos de tipo T, de uno en uno, que serán apuntados por "link".

--------------

Ahora bien.
La idea es que cada campo "d" de tipo char sea un caracter indicando un dígito (en la base que queramos, por ejemplo decimal o binaria): '0', '1', ¿etc.?

Y cada "link" apunta hacia el siguiente "dígito".

Esta estructura está permitida por el lenguaje C, o sea que yo podría hablar,
acorde al punto (2.), de todos las listas enlazadas posibles que puedo asignar
a un objeto de tipo T, de manera que quede representado un número con cualquier cantidad de dígitos.

Algo más o menos parecido y más sencillo de entender sería,
simplemente, generar una cadena de caracteres formada por
tantos dígitos como queramos.
Hay inconvenientes técnicos, que me impiden especificar una cadena de caracteres de longitud arbitraria desde el lenguaje mismo. (La longitud máxima, aunque muy grande, sigue siendo finita...).

Por eso prefiero usar el planteo de las listas enlazadas.

Ahora bien, las computadoras reales no tienen suficiente memoria para representar los dígitos de un número demasiado grande.

Sin embargo el lenguaje C por sí mismo no impide nada desde el punto de vista sintáctico (o sea que las entidades indicadas en el punto (2.) serían infinitas), y de hecho, amontonando muchas tarjetas de memoria RAM sería posible representar cualquier secuencia finita de dígitos, por grande que sea.

Así que, suponiendo siempre un Universo de infinitos átomos (que no hay),
sería posible representar los dígitos de cualquier número natural estándar en una computadora concreta.

Algo todavía más sencillo sería el mero acto de imprimir dígitos en un rollo de papel de una impresora.

Entonces mi pregunta es si acaso la colección de todos los posibles objetos así generados pueden considerarse todavía un "modelo estándar de N".

Y con estándar me refiero, de paso, a que no hay elementos no estándar.
De hecho, para "generar" estos números, no hay más remedio que comenzar desde un objeto con un solo dígito, e ir agregando de uno en uno, a lo largo de la línea temporal, los dígitos que van haciendo falta.

Ya que sobre los dígitos puedo definir las operaciones de suma y multiplicación en forma mecánica e iterativa (de un dígito pasando al siguiente), me da toda la sensación de ser un sustituto del N "estándar".


10
Si bien es una pregunta que tiene que ver con computadoras,
va en la sección de Metamatemática,
porque la motiva exclusivamente una duda de fundamentos de la lógica.
(Nada tiene que ver con la discusión sobre inteligencia artificial en otro hilo).

Primero que nada, pongo un ejemplo que me parece claro a mí mismo.
Supongamos una demostración de un razonamiento cómo éste:

(x = y) & (y = z) ----> (x = z)

La demostración de algo como eso se puede hacer en base a los axiomas de la lógica,
siguiendo reglas mecánicas que transforman un texto en otro.
Por ello, es algo que, si se realiza en forma mecánica con una computadora, y se imprimen los pasos de la demostración,
el resultado se consideraría una demostración igual de válida que si la hubiera escrito un humano,
porque la demostración es, apenas, la escritura de unos pasos de lógica formal o matemática formal.

Sin embargo, como hemos hablado varias veces en el foro, en metamatemática intervienen algunos ingredientes mágicos:

(1) Una capacidad inherente de razonamiento, que no es formal.
(2) Números naturales intuitivos.
(3) Interpretación de variables en un modelo "de carne y hueso".
(4) Modelos concretos en alguna parte (¿en la imaginación?).
(5) Nociones de Verdadero y Falso al afirmar hechos sobre entes de un modelo, o relaciones y funciones sobre entes que son parte de un modelo.

Estos "ingredientes" no son formales.

Pero si yo quiero que un programa informático muestre resultados que evidencien ese tipo de cosas, no tengo más remedio que representar todo de manera escrita, o sea, imprimiendo caracteres.
Esto es una especie de "formalización".

La duda que tengo es cuál sería la manera más correcta en que yo tendría que hacer un programa, de modo que cuando escriba respuestas en la pantalla, sean juzgadas como "metamatemáticas", y que no se confundan con las demostraciones mecánicas formales.
Por ejemplo, me parece más o menos fácil (aunque no trivial) hacer que un programa "razone" sobre frases sencillas en español.
Pero conceptualmente, no sé si a esto se le puede llamar estrictamente "razonamiento" en el mismo sentido que el ingrediente (1).
Y lo mismo con los demás ingredientes.

Otro ejemplo.
Podría considerar modelos finitos, con relaciones y funciones entre sus elementos, perfectamente descriptibles por tablas finitas de datos.
Esto no requiere intuición alguna, porque es todo finito.
¿Se considera igualmente un modelo?
Si el programa dice: "la relación R entre los elementos A y B del modelo M es Verdadera", ¿está bien dicho? ¿Se considera bien hecho?
Si tengo una tabla de datos, finita, con una relación definida por una tabla, y a partir de esa tabla hago un cálculo e imprimo en pantalla que la relación entre dos elementos A y B es "verdadera", ¿es "verdaderamente" verdadera, o sea, es correcto interpretar que es verdadera en el mismo sentido que se considera en un texto de metamatemática?

Espero que se entienda la pregunta.
Es algo conceptual.

Por otro lado, estaría haciendo metamatemática a partir de un lenguaje formal (el lenguaje de programación de turno). Así que los conceptos me dan vueltas en círculos.
Pues si bien creo entender esto de que es posible realizar razonamientos formales en ZFC sobre cuestiones metamatemáticas, eso no es suficiente para justificar lo que ocurre en el universo metamatemático, pues justamente ZFC no se ha probado que sea consistente.

(No obstante, los lenguajes de programación son distintas, porque se puede suponer de ellos que están sujetos a restricciones de finitud, desde varios "flancos"...)

11
No me convenzo de lo que significa "intuición matemática", sobretodo "hasta dónde se supone que llega".

En esta búsqueda encontré un libro dedicado exclusivamente al tema:

RICHARD L. TIESZEN, Mathematical Intuition

He comenzado a leerlo, y es sobretodo filosófico, como es natural.
Parece ser una referencia adecuada para estudiar el tema.

Me gustaría saber vuestra opinión personal sobre el libro, si es que les resulta:
Atinado, desatinado, una porquería, da en el clavo, vale la pena leerlo, no vale la pena malgastar tiempo leyéndolo,
es científico, anticientífico, pseudocientífico, demasiado delirante, tiene la cuota necesaria de delirio, etc.

De todos modos lo voy a leer a fin de cuentas.

12
Encontré en Wikipedia una lista de una gran cantidad de lógicas:

http://en.wikipedia.org/wiki/Intermediate_logic

La pregunta va dirigida a Carlos, quien me ha dicho que hay una sola lógica "intuitiva", diǵámoslo así,
la cual se formaliza con la lógica de 1er orden, y que permite demostrar toda sentencia "verdadera".

Entonces, ¿qué relación tienen todas esas lógicas intermedias, incluyendo la versión formalizada del "intuicionismo", con la lógica clásica?
¿Acaso formalizan sólo "porciones" de la lógica clásica?
¿Son teorías consideradas "incompletas"?


13
Acerca de las diferencias entre infinito potencial e infinito real parece que hay mucha investigación en estos días.
He partido de leer un artículo de un tal Nelson, de Princeton, https://web.math.princeton.edu/~nelson/papers/e.pdf,
que por las dudas dejo colgado como archivo adjunto.

En ese artículo Nelson define los números naturales que llama "counting" (o "para contar" o "que cuentan"), dando a entender que se trata de la versión intuicionista de los números naturales. Ellos se van construyendo de 1 en 1, quién sabe hasta dónde.

Afirma que en realidad existen dos sistemas de números naturales, y no uno solo: uno en que los naturales van apareciendo de uno en uno (sistema A, por Aristóteles), y otro en donde todos los naturales existen a la vez, de un solo golpe (infinito real, sistema P, por Platón).

Una cosa es dudar del sistema P, otra cosa es dudar del sistema A, pero otra distinta es estar de acuerdo con los dos sistemas.

Leí el artículo muy rápidamente, así que no lo he masticado bien.
Pero deja en claro que el punto de vista del infinito potencial no sólo tiene muchos adeptos hoy en día, sino que es área activa de investigación.
Además, afirma que hace más fácil resultados clásicos.

Yo cada vez entiendo menos cuál es, entonces, "el" sistema de números naturales que se supone tienen en mente quienes estudian Fundamentos.
¿Alguna idea?

14
Enlaces sugeridos / ¡Acceso al foro aún cuando está colgado!
« en: 27 Enero, 2014, 11:47 pm »
La web www.archive.org guarda copias de las páginas webs de años anteriores.
Aproximadamente una vez por mes hace una copia de lo que se ha publicado en el foro.
No sé si esta copia se hace automáticamente o alguien la sugiere. En todo caso, yo no fui.

Se puede acceder a copias antiguas del foro a través de este enlace:

http://web.archive.org/web/*/www.rinconmatematico.com/foros

Ahí hay que elegir el año que nos interese en la barra superior,
y debajo en el almanaque elegir la fecha que nos interese.

A mí me sirvió para recuperar unos posts que había perdido parcialmente.

No se actualiza todos los días, así que no hay garantía de poder ver los posts más recientes.
Pero puede servir en caso de que la web esté colgada y queramos ver algún post de más de un mes de antigüedad.

Saludos

15
Tutoriales y fórmulas con LaTeX / Información general sobre LaTeX
« en: 14 Noviembre, 2013, 05:07 am »
Para obtener toda la información existente y actualizada sobre LaTeX, hay que ir a la web del catálogo de TeX online:

CTAN

16
Zona de resolución / Curso de C - Ejercicio 49.1
« en: 06 Octubre, 2013, 07:12 pm »
Problema 49.1. del curso de C

(Esto proviene de: Sección 49 del curso de C)
 
En todo programa, primero hay una etapa de diseño y planificación.

Hay que estudiar bien el problema antes de lanzarse a programar como locos.

Veamos el enunciado:
   
\( \bullet \)  49.1. Pedir al usuario que ingrese una base \( b \). Luego, pedir al usuario que ingrese números reales (en decimal), y convertirlos a base \( b \) a medida que el usuario los va ingresando. Continuar hasta que el usuario ingrese 0 o un valor fuera del rango que hemos convenido adoptar para el tipo double.

Aunque no lo parezca, el enunciado contiene algunas imprecisiones. Por ejemplo:
   
¿La base \( b \) es un número entero positivo?

Lo típico al hablar de cambios de bases es que: sí. Las bases son enteros positivos.
Pero hay teorías matemáticas que discuten bases con otras características.
Si éste fuera el caso, tendríamos que estudiar primero el tema de las bases "en general".

Por otro lado, siempre conviene intentar resolver primero la versión más simple de un programa, y luego atacar versiones más complicadas o sofisticadas.

\( \bullet \) Así que en una 1er versión del programa vamos a considerar sólo bases enteras positivas.

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Ahora, sin embargo, se nos presentan otros problemas.
Dado un número, digamos \( x \), en base \( b \), necesitamos representarlo con tantos dígitos como indica la base, es decir, \( b \). Esto es, un alfabeto de \( b \) símbolos.
Lo usual es que el alfabeto de dígitos contenga los primeros elementos del conjunto de dígitos decimales: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
Esto sólo es posible cuando la base es diez o menor que diez.
Si la base es 16, se usan las letras A, B, C, D, E, F, como dígitos adicionales.
Podemos entonces usar esos mismos símbolos cuando la base sea mayor que diez y menor o igual que 16.

¿Y si la base es mayor que 16? ¿Se pueden usar las restantes letras del alfabeto?
En principio sí, pero notemos que hay algunos obstáculos.
Por ejemplo, la letra O se confundiría fácilmente con un dígito "cero".
Como la letra O ocupa la posición 15 en el alfabeto (siguiendo la secuencia de caracteres ASCII, o sea, rindiéndonos antes el imperialismo yanki), sólo podríamos llegar sin obstáculos hasta la N, que ocupa la posición 14.
No podríamos usar las letras de la P en adelante, porque el orden de los dígitos no sería ahora claro (de la N saltaríamos a la P, y eso sería confuso, pues la P representaría un valor menor que el que intuitvamente le adjudicaríamos).
Agregando los diez dígitos decimales, tendríamos como máximo unos 24 dígitos disponibles, lo cual nos permitiría representar bases que vayan hasta la 24.

Pero veo otro obstáculo. Es la letra I, que ocupa la posición 9 en el alfabeto. Es muy probable que llegue a confundirse con un dígito 1.
Pensando en eso, de nuevo descartaríamos las letras que siguen a la I, porque habría un salto antiintuitivo en la secuencia, al pasar de la H a la J en la lista de "dígitos".
Así que sólo tendríamos 8 letras disponibles para dígitos: de la A a la H (8 letras), pudiendo representar así bases hasta la 18.

Para bases mayores que 18 habría que decidir otro tipo de diseño.
Hay varias alternativas, pero cualquiera que elijamos, resulta extraño que elijamos un diseño basado en letras del alfabeto para las bases 17 y 18, y que ya para la base 19 adoptemos un diseño totalmente distinto.

Lo que podemos hacer aquí es dar opciones al usuario, para que elija la manera que él prefiera para representar dígitos.

No me convence ese enfoque, porque en la parte teórica no hemos visto herramientas del todo adecuadas para hacer que el programa venga tan "interactivo".

Así que para las bases 11 a 16 usaré el enfoque de utilizar letras del alfabeto para los dígitos adicionales, tomando lo que necesitemos de la secuencia: A, B, C, D, E, F.
Y para las bases mayores que 16 usaré sólo números escritos en decimal, pero de tal modo que los "dígitos" queden claramente separados entre sí.
Por ejemplo, un número en base 34 utilizaría los números 0 al 33 como "digitos", y esto obligaría a que pongamos un separador (por ejemplo, un apóstrofo):
   
11'7'9'0'33'14'11'11'2'25

El uso del apóstrofo soluciona el problema, y permite ahora salir del paso con cualquier base, porque ya tenemos un método que funciona en general.

Pero ocurre también que poner un apóstrofo por cada dígito hace muy accidentada la lectura del número.
Me parece preferible buscar un método en que no se usen esos apóstrofos.
Hacerlo así, sin más, da resultados ambiguos. El ejemplo anterior quedaría así:

1179033141111225

¿Qué significa ese número en base 34? ¿Comienza con un dígito 11, o con dos dígitos 1?

Se me ocurre aquí una solución bastante sencilla: usar dos dígitos decimales por cada dígito en base 34. Rellenar con 0's o con espacios en blanco cuando el dígito en base 34 tenga un valor menor que 10.
Así, el ejemplo anterior quedaría:
   
11070900331411110225

Con la convención de que cada par de dígitos decimales representa un dígito en base 34, ahora no hay ambigüedad en la lectura.
Esa seguidilla de cifras debe leerse como la secuencia de dígitos en base 34 siguiente:

11  7  9  0  33  14  11  11  2  25

Si usáramos "espacios" en vez de 0's, sería aún más fácil de leer:

11 7 9 033141111 225

Ahí se entiende que el "trozo" 033141111, que sigue a un "espacio", tiene que leerse como el dígito 0, seguido de los dígitos 33, 14, 11 y 11, ya que la ausencia de "espacios" indica que han de leerse dígitos "de a pares".

Según el contexto, esto puede resultar confuso, porque no sabemos si se trata de un solo número, o varios números separados por espacios en blanco.

Así que en vez de un espacio en blanco pondré allí algún caracter visible, como por ejemplo, un subrayado: _
El ejemplo anterior queda ahora así:

11_7_9_033141111_225

Ahora el subrayado _ sirve de marca para decir: "aquí no se lee un par de dígitos, sino uno solo".

Con la misma idea, podríamos representar dígitos en base 299, pero ahora necesitaríamos 3 dígitos decimales por cada dígito en base 299.
Por ejemplo:

115'8'27'277'66'4'11'0'114

sería un número con dígitos en base 299, separadads por apóstrofos.

Esto de los apóstrofos lo estamos usando, a fin de cuenta, como parte de la discusión del diseño, para entendernos, pero no como parte de los resultados que arrojará nuestro programa. ¿Loco no?

Nuestro programa intentará mostrar ese número con 3 caracteres, ya sea dígitos decimales o el subrayado: _.

115__8_27277_66__4_11__0114

Notemos que los dígitos entre 0 y 9 necesitan un doble subrayado: __,
mientras que los dígitos entre 10 y 99 necesitan un solo subrayado: _.
Los demás (entre 100 y 298), se leen tomando de 3 en 3 cifras decimales.
Por ejemplo, el "trozo" _27277 se lee como la secuencia de 2 dígitos en base 299: 27, 277.

A fin de cuentas, el subrayado _ está jugando el mismo papel que un 0.
Estaría de más, en ese caso.
Pero me parece a mí que un subaryado _ es más fácil de interpretar, al leerlo en pantalla, que un 0.
Contrastemos el efecto visual del mismo número en base 299 anterior, poniendo 0's en donde había subrayados:

115__8_27277_66__4_11__0114

115008027277066004011000114


En general, si la base está entre \( 10^k < b \leq  10^{k+1} \), vamos a usar la convención de utilizar por cada dígito en base \( b \), exactamente \( k \) dígitos en base diez, y reemplazando los 0's con subrayados para mayor legibilidad.

Importante: se exceptúa el caso en que el dígito en base \( b \) es él mismo el 0. Allí sí usaremos el dígito 0 para representarlo.

Este último detalle seguramente nos traerá algún pequeño escollo cuando diseñemos el programa. Por eso lo he remarcado.
Todas las "excepciones" traen dolores de cabeza que luego hay que atender.

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Cuando la base es \( b=1 \), el programa debe indicar un mensaje de error, ya que no es posible escribir números en base 1.
Lo mismo si la base es 0 o un número negativo.

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Cuando se debe realizar una conversión de una base a otra, suele ser muy complicado lidiar con la parte detrás del punto fraccionario.
Consideremos el siguiente ejemplo:

Es fácil pasar el número 104 (en base diez) a base 7, porque hacemos:
   
\( 104 / 7 \)  --->  14 con resto 6
\( 14 / 7 \)   --->   2 con resto 0
\( 2 / 7 \)    --->   0 con resto 2

Luego, 104 en base 7 es 206 (tomamos los restos de atrás hacia adelante).
Este enfoque nos obligaría a ir guardando los restos, para mostrarlos al final a todos, en orden inverso.
Pero no es necesario hacerlo así.
Podemos operar "al revés":
   
\( 104 / 7^2 \) ---> 2 con resto 6
\( 6   / 7^1 \) ---> 0 con resto 6
\( 6   / 7^0 \) ---> 6 con resto 0

Ahora tomamos los "cocientes" sucesivos, en vez de los "restos", y eso nos va "regurgitando" los dígitos en base 7, que nos da:
   
2 0 6

¿Cómo lidiar con los números que tienen una parte fraccionaria?

Pasar el número 0.104 (en base diez) a base 7.

Aquí se procede de modo algo distinto: se va multiplicando por 7 a fin de obtener los sucesivos dígitos, hasta "terminar", si es que esto es posible, o hasta hallar una repetición periódica.
   
\( 0.104 \cdot 7  \)   ---> 0.728. Se toma la parte entera 0 como dígito en base, y el resto sigue operando:
\( 0.728 \cdot 7  \)   ---> 5.096 ---> Se toma 5 como dígito, y "resto" 0.096
\( 0.096 \cdot 7  \)   ---> 0.672 ---> Se toma 0 como dígito, y "resto" 0.672
\( 0.672 \cdot 7  \)   ---> 4.704 ---> Se toma 4 como dígito, y "resto" 0.704

Esto está destinado a continuar sin fin.

Pero necesitamos que nuestro programa termine en algún lugar.
Deberíamos poder reconocer que hay una repetición a partir de algún momento, indicar que allí hay un período (de dígitos en base 7), y terminar allí el programa.

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Más aún, tengamos en cuenta que el resultado obtenido no será del todo preciso, ya que en realidad los cálculos anteriores realizan una previa conversión interna del número decimal 0.104 a base 2.
Los cálculos los hace la computadora internamente en base 2, y allí podemos tener pérdidas de precisión.

Como trabajaremos con datos de tipo double, sabemos que al menos 10 dígitos decimales serán confiables o significativos.
Así que podríamos proseguir nuestros cálculos hasta agotar esos 10 decimales significativos.

O bien, podríamos advertir al usuario que más allá de esos 10 decimales los resultados pueden contener errores, e igual le mostramos lo que nos dé.

En ese caso, tenemos que reconocer en qué momento los dígitos en base 7 comienzan a repetirse, si es que lo hacen.
Esto no resulta sencillo.
Dado que tenemos "apenas" 10 decimales significativos, al multiplicarlos en secuencia por 7 (o por otra base cualquiera) podemos obtener, como mucho, una lista de \( 10^{10} \) "restos" distintos (números entre 0 y 1).
O sea que el proceso terminar en alguna parte. No obstante, esos son demasiados dígitos a mostrar en pantalla.

Dado que la precisión (en base decimal) del tipo double está indicada por la macro DBL_DIG, no conviene presentar más dígitos en base \( b \) que esos cuando \( b \) es mayor que 10.
Eso dará una buena idea del número. Si queremos, podemos exhibir un par de dígitos más en base \( b \), como para "espiar" un poco más allá, a ver qué hace la computadora con esto.

Cuando la base \( b \) es menor que 10, debiéramos presentar más dígitos que la cantidad DBL_DIG. ¿Cuántos?
Bueno, algo así como multiplicar por un factor de \( [\log_{b} 10] + 1 \) (los corchetes indican "parte entera").
Esto para base 2 nos da un factor de 4.

No veo del todo sencilla la parte de "reconocer la parte periódica" del número convertido a base \( b \).
Esto requeriría algún tipo de manipulación de fracciones.
Se puede hacer, pero lo dejaré para una 2da versión del programa.

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

En general, se ve que tenemos procedimientos que nos permiten ir generando las cifras en base \( b \) de un número, sin necesidad de memorizar los dígitos que vamos obteniendo en alguna parte.

Esto permite resolver el problema con las herramientas teóricas que hemos visto hasta ahora, que son muy pocas.
También muestra que es posible resolver este problema sin el uso de memoria adicional.

(En realidad, estaríamos usando la pantalla del monitor como "memoria", jeje).

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Primero conviene escribir el esqueleto del programa, y luego ir rellenando los huecos, que suelen ser de complejidad creciente, y requieren análisis detallado.

En virtud de la previa discusión de diseño, podemos vislumbrar algunas pautas generales del esqueleto.

Como siempre, incluiremos las librerías <stdio.h> para intercambiar datos con el usuario vía consola estándar, y <stdlib.h> para cambiar la página de códigos a 28591 a fin de visualizar correctamente los acentos en castellano, mediante:

   system("CHCP 28591");


También incluiremos la librería <stdbool.h>, acorde a los comentarios de la Sección 48 del curso.
Como no usaremos números complejos, no hará falta incluir esta vez <complex.h>.

Dado que nombramos la macro DBL_DIG de la librería <float.h>, podríamos necesitar incluir esta librería.
De hecho, no lo haré, y esto lo decido aquí caprichosamente.
Hemos dicho en la Sección 48 que sólo asumiremos 10 dígitos decimales significativos.

Así que preferiré usar una constante llamado Significant_Digits, puesta igual a 10, y usaré ésta en vez de DBL_DIG.

Esto nos evitará algunos inconvenientes imprevistos. Por ejemplo, podría darse el caso de que tengamos la suerte de tener una súpercomputadora en la que haya 40000 dígitos significativos para el tipo double. Eso causaría estragos en nuestro inocente programa, que intentaría mostrar siempre esa cantidad de dígitos.

En una futura versión del programa, se podría pedir al usuario que elija la cantidad de dígitos significativos que desea, informándole previamente de la cantidad máxima disponible.

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Esqueleto

bc.00.01.c


// BC 00.01

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

int main(void) {
    system("CHCP 28591");
   
    int Significant_Digits;
    Significant_Digits = 10;
   
    printf("BaseConv (Base Converter) v. 0.01\n\n");
    printf("Este programa convierte números x de base decimal a base b.\n\n");
    printf("Se le pedirá al usuario que elija una base b para trabajar.\n");
    printf("Luego, se le pedirá al usuario que escriba números x en base decimal, para ser convertidos a base b.\n");
    printf("Para terminar, ingrese el número x = 0\n\n");
   
    int b;  /* Base a la que convertiremos los números decimales */
   
    do {
        printf("Elija la base b = ");       
        scanf("%d", &b);
       
        if (b <= 1)
           printf("Error: la base debe ser b >= 2.\nIntente de nuevo.\n\n");
           
    } while(b <= 1);
    /* Desde aquí ya estamos seguros que b >= 2 */
   
    double x;  /* Esta variable contendrá el número que deseamos expresar en base b */
   
    do {
        printf("Escriba un número decimal x = ");
        scanf("%lg", &x);
       
        // Convertir x a base b, e ir mostrando los dígitos de la conversión
       
    } while(x != 0.0);
   
    printf("Con la elección x = 0 este programa termina.\n");
    printf("Fin del programa.\n");

    system("PAUSE");   
    return 0;
}



Arriba de todo: una línea de comentario con el nombre y versión del programa. Esto es información para el programador (por ahora, nosotros mismos solamente).

Tras la inclusión de las librerías estándar, entramos directo en la función main(), que es en donde se desarrollará nuestro programa.

La primer sentencia cambia la página de códigos en la línea de comandos de Windows, de modo que se visualicen correctamente los acentos y eñes del castellano.
Quienes usen Linux u otro sistema, pueden quitar esa línea, o cambiarla por alguna otra cosa conveniente para su sistema particular.

Al final del programa tenemos otra llamada al sistema, sólo para hacer una pausa en la ejecución del programa, y evitar que nos desaparezca la ventana de línea de comandos antes de ver los últimos mensajes del programa.
Esta línea también puede omitirse o sustituirse por algún otro procedimiento.

Importante: Observen que sólo he hecho uso de la función system() al principio y al final del programa, para que quede claro que sólo en esos puntos de ejecución estoy haciendo uso de llamadas al sistema. Más aún, quitando esas dos líneas, se puede omitir la inclusión de la librería <stdlib.h>.

Al principio se declara un objeto que quedará constante a lo largo del programa: la variable entera Significant_Digits, que ponemos igual a 10, de una vez y para siempre. Esto respeta nuestra convención hecha en la Sección 48 de la teoría, en que los dígitos significativos de valores double serán, para nosotros, de 10.
Decisiones de diseño para casos más generales, vendrán más adelante en el curso.

A continuación viene una seguidilla de instrucciones printf() que muestran mensajes al usuario:
   
- Nombre y versión del programa.
         Las versiones con números menores que 1.00 se usan para programas aún no completados.

- Propósito general del programa.

- Explicación del funcionamiento del programa, junto con algunas indicaciones al usuario, y resultados esperados.

- Alguna indicación o explicación de cuándo y cómo se termina el programa.

Después de esas preliminares, se declara un objeto b de tipo int, en el que guardaremos la información de la base de numeración a la que haremos las conversiones.

Luego se pide al usuario que elija una base b.
Se le informa con un mensaje mediante printf() qué es el dato que debe ingresar.
Se usa scanf() para "capturar" el dato ingresado por el usuario.

Normalmente el usuario tiene que presionar la tecla ENTER para terminar el ingreso de datos en forma correcta.

Observemos que hemos usado una estructura do while() para el ingreso de este dato.
¿Por qué?
Muy sencillo: para perseguir estilo pesadilla al usuario mientras este ingrese una base que no nos gusta.
Le obligamos a que ingrese un número \( b \geq 2 \), que si no, se repite el pedido de ingresar otra vez un número.

Podemos estar seguros de que al usuario rebelde le ganaremos por cansancio. Tal así funciona Terminator: con un do while():   

do {

    buscar_a_Sarah_Connor_y_atentar_contra_su_vida();

} while(Sarah_Connor_sigue_viva());


Eso sí: Terminator no falla jamás gracias a que alguien se tomó el trabajo de escribir correctamente los punto y coma al final de cada instrucción.

Cuando el usuario ingresa un valor de base no deseado, le informamos con un mensaje de error.
Esto requiere que previamente verifiquemos si el valor ha sido erróneo, lo cual nos obliga a utilizar una estructura if().

Una consecuencia desagradable de esto es que acabamos por "preguntar" dos veces lo mismo: ¿es cierto que \( b\leq 1 \)? Lo preguntamos en el if() y luego en la línea while();.
Por ahora, esto lo dejamos así, porque es más claro a la vista.
Hay modos antiestéticos de quitar esa comparación adicional...

Una vez que el usuario ha cesado en su rebeldía, y ha elegido una base \( b\geq 2 \), observemos que podemos confiar en ello y no tenemos necesidad de verificarlo nuevamente.
Así que, desde el punto de vista lógico, es siempre cierto a partir de allí que \( b\geq 2 \), y esto lo pusimos como un comentario.

Es lo que damos en llamar: un invariante lógico del programa.
Es una condición que sabemos que a partir de ese momento se cumple, hasta que aparezca otro comentario que nos informe de lo contrario.

Trabajaremos siempre asiduamente con comentarios del tipo "invariante lógico".

Seguidamente declaramos un objeto x de tipo double.
Esta variable irá cambiando de valor muchas veces, pues es en donde guardaremos los números que el usuario nos vaya dando para trabajar.

Lo que sigue es un while(), tal que en cada iteración se le pide al usuario que ingrese un número decimal (que puede tener parte fraccionaria).
A continuación se lo ha de convertir a base \( b \), pero como esto es complicado, lo postergamos, y ponemos ahí sólo una línea de comentario con la promesa de que lo vamos a resolver luego.

El ciclo se repite hasta que el usuario elige un valor de x igual a 0.0 (ó 0).

Finalmente el programa se despide con algunos mensajes.

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

Continuará... :)

17
Problemas y Desafíos / !
« en: 29 Septiembre, 2013, 06:36 pm »
!

18
Álgebra / !
« en: 29 Septiembre, 2013, 06:34 pm »
!

19
Matemáticas Generales / !
« en: 29 Septiembre, 2013, 06:33 pm »
!

20
Matemática Discreta y Algoritmos / ?
« en: 29 Septiembre, 2013, 06:32 pm »
?

Páginas: [1] 2 3 4 ... 8