elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Únete al Grupo Steam elhacker.NET


  Mostrar Mensajes
Páginas: 1 2 3 4 5 [6] 7 8 9 10 11
51  Programación / Programación C/C++ / Re: ENIGMA SOBRE C . Terminación de programas en: 4 Marzo 2019, 12:57 pm
Exacto MAFUS! Lo has clavado!

Yo lo veo una proposición más filosófica que práctica.
Ya de por sí la premisa, sobre el segundo fuentes, es falsa porque ese bucle no terminan nunca, al tener en la condición un 1 y por tanto siempre será cierta. Pero en ese mismo fuente se podría considerar que 1 es falso ya que ese valor detiene el bucle y, además, hace saltar al assert. ...
En ese supuesto, imposible por otra parte, sí que se llegaría a la solución propuesta.

Bueno, creo que ya lo tengo, chicos. Me han ayudado un poco por ahí... Y cuando lo entiendes, es una pura broma.... :D :D :D :D

La cuestión tiene que ver no tanto con C, como con dos aspectos de la algoritmia:
  • la terminación de un programa
  • la corrección parcial, que nos dice que si acaba, (notese la cursiva) entonces el programa computa lo que se espera de él.  

Las dos cuestiones son ciertas. Empiezo por la más extraña, la segunda, la del bucle infinito.
  • Según el estandar ANSI-C, asssert solo falla cuando la evaluación del parámetro da 0 (false). En nuestro caso, assert(1), cuando 1==0, lo que es un absurdo  :o :o
  • Según el estandar ANSI-C, el bucle acaba cuando la parte del discriminante da 0 (false) . En nuestro for( ; 1; ), caso, cuando 1==0 , (en terminos prácticos, nunca)   :D :D
  • O sea, que cuando el bucle acabe, (no dice que acabe, dice que cuando acabe, esto es importante!) se cumplirá   1==0, lo que es la condición para que assert(1) falle.  :D :D :D :D

 :D :D :D :D Esta bien el enigma... A nadie engaña por decir que esperando lo suficiente, el assert(1) fallará... Eso sí, tiene que esperar lo suficiente, por los siglos de los siglos...

Formalmente, pura lógica...
Código:

(Short proof)
     1=0 |= 1=0  q.e.d  

(Full proof)

Let Post Q:1=0 .

Then we have to proof that

  { I } for( ; 1 ; ) { Q } (Partial correctness, no matter I)

  1. { I } skip {I}  SKIP
  2. I and 1=1 -> I (Logic, stronger antecedent )
  3. { I and 1=1 } skip { I } STREN(1,2)
  4. I and 1=0 -> 1=0 (Logic, false (or stronger) antecedent)
  5. { I } for( ; 1 ; ) { 1=0 }  WHILE(3,4)

  q.e.d

Remark: ANSI-C states
     * assert(1) call does fail when 1=0 ("never")
     * loop for( ;1;) does end when 1=0 ("never" ;-D)
     * empty loop's body is skip.

El primer problema, que todos veíamos que acababa, también es parecido...pero ahora si nos interesa demostrar que efectivamente acaba, y nos da igual lo que pase al acabar.

En los libros de algoritmia se dice que para que un bucle acabe (terminación) tenemos que idear una quota definida positiva en el punto antes de evaluar la condición de salida  (un invariante). Como no hay variables, escogemos como quota C(n)=0... Esta quota tiene que disminuir cada vuelta, es decir 0 < 0, lo que es un absurdo.
Como va a disminuir cada vuelta, si nunca entra? Bueno, seg'un el estandar ANSI entra cuando la evualuación de la guarda es  distinta de 0, nuestro caso for( ; 0 ; ) , cuando 0!=0 (o sea nunca).

El resultado es que cuando 0!=0 entonces ocurrirá que 0 < 0. No dice que 0!=0, sino que cuando 0!=0, absurdo, entonces 0<0 (otro absurdo). Genial!  Pura lógica.

Código:

(Short proof)

   0!=0 |= 0 < 0   q.e.d.

(Full proof)

Let C()=0 >= 0 positively defined, i.e.

      I -> 0 >= 0  (no matter I)
      
Then we have to proof

     { I and 0!=0 and 0=0 } skip { 0 < 0} (Quota indeed decreases)

    1. { 0 < 0 } skip { 0 < 0 } (SKIP)
    2. I and 0!=0 and 0=0 -> 0 < 0  (Logic, false antecedent)
    3. { I and 0!=0 and 0=0 } skip { 0 < 0 } (STRENG(2,1))

    q.e.d

Remark :   * ANSI-C states the loop is entered
           when 0!=0, i.e. "never" ;-D
  * empty loop's body is "skip"





52  Programación / Programación C/C++ / Re: ENIGMA SOBRE C . Terminación de programas en: 4 Marzo 2019, 10:10 am
Hola NEBIRE
...

El primer tema a considerar: Los bucles infinitos versa que si el incremento es 0 y el valor inicial es igual al valor final, no es un bucle infitio, en otro caso si:
       bucle infinito = ((inc = 0) and (inicio <> final))
...y si el cuerpo está vacío (como es el caso), o no existe dentro una sentencia de escape del bucle (si existe, deberá examinarse también). Lógicamente en tiempo de compilación...
       Por eso no se cumple en el primer caso y sí en el segundo.
...
Esta propuesta no vale. Estás describiendo un caso muy partícular de bucles "for", los que se parecen /ajustan al patrón de Pascal
Código:
for < variable-name > := < initial_value > to [down to] < final_value > do 
   S;

Pero en el caso de C que se da, que variables hay?, cual es el valor inicial y/o final?
En C, el bucle for es tan versátil/expresivo como el while.

EScrito de otro modo, en el primer caso hay que explicar por qué el bucle C, acaba:

Código
  1. while (0) ;

Aqui no hay duda de que no hay valores iniciales, ni finales.... Solo constantes.



53  Programación / Programación C/C++ / Re: ENIGMA SOBRE C . Terminación de programas en: 1 Marzo 2019, 09:37 am
Chicos, gracias por vuestras repuestas.
  Loretz, muy buena tu exhibición, pero el ejercicio que propones no cumple lo que dice, porque YA es otro fichero fuente del que se propone...

Creo que hay que hacerlo sobre el mismo contenido del original y lo que me choca más... se supone que no vale argûir "Alguien ha jugado con el assert, pues yo también...", porque el sistema ha de ser compatible ANSI-C/ISO-C, o sea, el assert tiene que hacer lo que se espera de él...

Os digo mis progresos:
  • Es un absurdo esperar a que acabe un programa que no acaba. Todo el mundo está de acuerdo en que el bucle es infinito.
  • Es un absurdo esperar que assert falle cuando el parámetro sea 1, ya que sólo falla cuando vale 0, según el ANSI-C/ISO-C

No hay manera de relacionar estos absurdos entre sí? Me huelo que "por aquí va la tostada", rollo lógica....

En cuanto tenga algo os lo paso...


El primer caso a mí me parece lo mismo; para el segundo lo único que se me ocurre es que alguien ha estado jugando con <assert>, así que si yo también...

Código
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. #define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
  5.  
  6. #define assert(expression) (void)((!(expression)) || (mostrar(#expression, __FILENAME__, (unsigned)(__LINE__), __func__), 0))
  7.  
  8. #define for(a) while(0)
  9. ...
  10.  
54  Programación / Programación C/C++ / ENIGMA SOBRE C . Terminación de programas en: 28 Febrero 2019, 13:57 pm
Hola!

En una facultad de Madrid me he encontrado pinchado en el panel este original reto...
Está en inglés, pero creo que se entiende...
  • El primer problema pide demostrar que el programa dado acaba
  • El segundo dice que cuando acabe, el sistema sacará la llamada correspondiente al assert.  :o :o


Alguna propuesta ? :o :o :o
55  Programación / Programación C/C++ / Re: Programa que calcula el número más próximo al primero en: 29 Enero 2019, 10:07 am
No me habia dado cuenta de la fecha como salto al principio dije "a ver tiene una hermana y si lo ayudamos?"  ;-)

Bueno, vale, pues ayudémoslo! Total, quedará registrado en Internet para la posteridad para el que quiera consultarlo...

Lo que no entiendo es por qué no le dejan usar arrays ni bucles...En fin...

Código
  1. #include <stdio.h> // scanf, printf
  2. #include <stdlib.h> // abs
  3.  
  4. /*
  5.    Note: Arrays and loops forbidden! 8-O
  6.  
  7.    P : True
  8.    fun min5(a0,a1,a2,a3,a4) dev <p,d>:(int,int)
  9.    Q : p=min i : 1 <= i < 5 : |ai-a0|=d and
  10.        d=min i : 1<=i<N : |ai-a0|
  11.  
  12.    (Not sure about legitimate use of ai at object language)
  13.  
  14. */
  15.  
  16.  
  17. void min5(const int a0,const int a1,const int a2,const int a3,const int a4,
  18.          int *p, int *d)
  19. {
  20.  *p=1; *d=abs(a0-a1);
  21.  if (*d>abs(a0-a2))
  22.    { *p=2; *d=abs(a0-a2);}
  23.  if (*d>abs(a0-a3))
  24.    { *p=3; *d=abs(a0-a3);}
  25.  if (*d>abs(a0-a3))
  26.    { *p=3; *d=abs(a0-a3);}
  27.  if (*d>abs(a0-a4))
  28.    { *p=4; *d=abs(a0-a4);}
  29.  return;
  30. }
  31.  
  32. int main(int argc, char *args[])
  33. {
  34.  int a0,a1,a2,a3,a4;
  35.  int p,d;
  36.  for( ;scanf("%d%d%d%d%d",&a0,&a1,&a2,&a3,&a4)==5 ; )
  37.    {
  38.      min5(a0,a1,a2,a3,a4,&p,&d);
  39.      printf("%d %d\n",p,d);
  40.    }
  41.  return 0;
  42. }
  43.  
  44.  
  45.  

EDIT Según me han hecho notar, efectivamente hay un errata: las líneas 25-26 aparecen duplicadas por error

Algunas pruebas de ejecución...

  • La línea impar es la entrada de cinco variables(a0,a1,a2,a3,a4).
  • La línea par saca el ordinal de la variable que esta más cerca (4 -> a4) y la distancia |a4-a0|. En caso de varías a la misma distancia, escoge la de ordinal más baja

Código:
1001 1002 2 3 4
1 1
1001 2 1002 3 4
2 1
1001 2 3 1002 4
3 1
1001 2 3 4 1002
4 1
1001 1001 1001 1001 1001
1 0
56  Programación / Programación C/C++ / Re: Como intercambiar valores de un iterator en C++ en: 22 Enero 2019, 16:02 pm
Justo, mil gracias!!

Dejo el código para intercambiar iteradores y ordenar con iteradores una lista alfabeticamente por si le sirve a alguien.

Código:
void Agenda::ordenaListas(){
    Contacto auxiliar;
    for(list<Contacto>::iterator it1 = listapal.begin(); it1 != --listapal.end(); it1++)
        for(list<Contacto>::iterator it2 = (++it1)--; it2 != listapal.end(); it2++)
            if(it1->comparar(it2->getNombre()))
{
                auxiliar = *it1;
                *it1 = *it2;
                *it2 = auxiliar;
            }
}
...
Más simple  (y más C++). Usa el operador ">" de strings, los operadores next(),begin() de iterator, y swap!!
Código
  1. #include <string>
  2. #include <utility> //swap
  3. #include <list> //list
  4.  
  5. using namespace std;
  6. ...
  7. // BubleSort
  8. // P : listapal=A[0..N) N>=0
  9. // Q : \forall i : 0 <= i < N-1: V[i] < V[i+1] and permut(listapal,A,N)
  10. void  Agenda::ordenaListas()
  11. {
  12.  list<Contacto>::iterator it1, it2;
  13.  for( it1 = listapal.begin(); it1 != prev(listapal.end()); it1++)
  14.    for(it2 = next(it1); it2 != listapal.end(); it2++)
  15.      if (it1->getNombre() > it2->getNombre()) swap(*it1,*it2);
  16. }
  17.  
No puedo mandar resultados porque no tengo el resto de los componentes, (Contacto, Agenda)...
 Fijaos que es una traducción del clasico en pseudocodigo.
En algún sitio he leído que hay que tener cuidado con usar el operador "<" en iteradores!. Tiene que estar definido por el programador del iterador!
Código
  1. for (i=0; i<n-1; i++)
  2.   for (j=i+1; j<n; j++)
  3.    if(V[i]>V[j])
  4.       V[i],V[j]=V[j],V[i]; // Esto no existe en C
  5.  



57  Programación / Programación C/C++ / Re: Recursion en bst en: 21 Enero 2019, 10:47 am
Tiene razón, me siento estupida, pero de todas formas no quiero pasar dos parametros solo el arbol  nada mas y si no se puede pues ni modo.  :-(

Ya... Te entiendo. Para lograrlo, tienes que hacer distinguible la raiz del resto de nodos de algún modo. Y esto se hace de dos maneras:
  • O planteas tu structura con un campo "padre", que apunte al nodo padre, en el caso de la raiz null (Recomendable)
  • Usas un viejo truco de C, el cualificador "static", que como efecto lateral irá grabado siempre el nivel de descenso

De otro modo no se puede... Es como si, en tu solución iterativa, dijeras que no puedes porque antes del buble while solo está permitido empezar con pilas vacías. O en otra brillante metáfora, dicha por un político en otro contexto

Citar
como un hombre con los pies en un cubo tratando de levantase tirando de la asa

Espero que esto te valga  :D . Ahh! Y no me parece que seas "estúpida" por preguntar eso. La mayoría de los chicos y chicas de tu edad, a los 14 años,  se dedican a jugar a video juegos, sin profundizar en las cuestiones fundamentales de la computación.

Te propongo esta con el "truco" de static

Código
  1.  
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4.  
  5. /*    Binary search tree
  6.  
  7.                         10
  8.       /  \
  9.      5   14
  10.     /  / \
  11.    3   13  15
  12.  
  13.    Adding non-leaf and non-root nodes, i.e. 19
  14.  
  15.    Warning: This solution may be not portable to other languages than C
  16. */
  17.  
  18. typedef struct nodo {
  19.  struct nodo *izq;
  20.  struct nodo *der;
  21.  int dato;
  22. }  *pnodo;
  23.  
  24. int sumar(const pnodo a)
  25. {
  26.  static int level = 0 ; // <== An eye to static qualifier (side effect!)
  27.  int suma=0;
  28.  
  29.  if(a!=NULL){
  30.    level++;  // <=== An eye.
  31.    suma=sumar(a->izq)+sumar(a->der);
  32.    level--; // <== An eye.
  33.    if ((a->izq!=NULL || a->der!=NULL) && level)  //  <=== An eye
  34. suma+=a->dato;
  35.  }
  36.  return suma;
  37. }
  38.  
  39.  
  40.  
  41. int main(int argc, char *args[])
  42. {
  43.  pnodo a=NULL;
  44.  
  45. /* Raw building of tree. More abstraction might be needed here */
  46.  if ((a = (struct nodo* )malloc(sizeof(struct nodo)))==NULL)
  47.    {
  48.      perror("malloc");
  49.      exit(1);
  50.    }
  51.  a->dato = 10;
  52.  if ((a->izq = (struct nodo* )malloc(sizeof(struct nodo)))==NULL)
  53.    {
  54.      perror("malloc");
  55.      exit(1);
  56.    }
  57.  a->izq->dato = 5;
  58.  if ((a->izq->izq = (struct nodo* )malloc(sizeof(struct nodo)))==NULL)
  59.    {
  60.      perror("malloc");
  61.      exit(1);
  62.    }
  63.  a->izq->izq->dato = 3;  
  64.  if ((a->der = (pnodo )malloc(sizeof(struct nodo)))==NULL)
  65.    {
  66.      perror("malloc");
  67.      exit(1);
  68.    }
  69.  a->der->dato = 14;
  70.  if ((a->der->der = (pnodo )malloc(sizeof(struct nodo)))==NULL)
  71.    {
  72.      perror("malloc");
  73.      exit(1);
  74.    }
  75.  a->der->der->dato = 15;
  76.  if ((a->der->izq = (pnodo )malloc(sizeof(struct nodo)))==NULL)
  77.    {
  78.      perror("malloc");
  79.      exit(1);
  80.    }
  81.  a->der->izq->dato = 13;
  82.  
  83.  printf("Adding internal nodes %d\n",sumar(a));
  84.  
  85. }
  86.  
  87.  

Esta es la salida del programa
Código:
Adding internal nodes 19

58  Programación / Programación C/C++ / Re: Recursion en bst en: 17 Enero 2019, 14:35 pm
Puedes marcar la raiz en el cálculo pasándola por parámetro.

Código
  1. int sumar(const pnodo a, const pnodo root)
  2. {
  3.  int suma=0;
  4.  if(a!=NULL){
  5.    suma=sumar(a->izq,root)+sumar(a->der,root);
  6.    if ((a->izq!=NULL || a->der!=NULL) && a!=root) // neither leaf nor root
  7.      suma+=a->dato;
  8.  }
  9.  return suma;
  10. }
  11.  
  12. // Initial call
  13. pnode a ;
  14. // populate tree a with subtrees
  15. sumar(a,a);
  16.  
59  Programación / Programación C/C++ / Re: Duda - Como eliminar numeros repetidos de un arreglo en C? en: 16 Enero 2019, 15:06 pm
NEBIRE, me alegro de participar contigo.

 Yo también soy partidario de escribir en pseudo-código, máxime cuando este da facilidades que los lenguajes "reales" no ofrecen, como asignación simultánea.... (En este sentido, me encanta más Python) Pero el valor inicial de una variable es algo esencial a tener explícitamente en cuenta.

Tu algoritmo se puede escribir más simple, y eso hace que el programador (no la máquina) lo entienda mejor.

Código:
P : sorted(V=A[0..N)
Q : \forall  i : 0 <= i < N : (\exists j : 0 <=j < M : A[i]=V[j])

I : Q[N/n] and 0 <= k <= n <= N and N>n>0 -> V[n]!=V[n-1]
C(n) = N-n >= 0

proc bajarRepes(i/o V=A[0..N) of integer, o k integer )
n,k = 0,0
while n<N do
   V[k],k = V[n],k+1
   n=n+1
   while n<N and V[n]==V[n-1]
      n = n+1
   end
endwhile

Que efecitvamente, esta en O(n), ya que la instrucción crítica (n<N) se ejecuta un máximo de N veces. (Siendo pedantes, también está en O(n^2) , en O(n^56)  :xD)
Erratas tenemos todos... Pero también los ingleses dicen que "el diablo está en los detalles"...
60  Programación / Programación C/C++ / Re: Duda - Como eliminar numeros repetidos de un arreglo en C? en: 15 Enero 2019, 11:40 am
El problema es bonito, pero no trivial. Con ánimo constructivo ;-)
  • La solución de Ana es correcta pero ineficiente, se dice que está en O(n^3) (3 bucles)
  • La solucion de NEBIRE tiene ideas aprovechables, porque se requiere ordenar el vector, pero el paso 2 es díficil de seguir con 7 variables, algunas sin inicializar, y _creo_ que está en O(n^2), por los dos bucles. Además creo que se pide eliminar los elementos del vector de entrada, no una opia

La que propongo, ya implementada en C++, requiere ordenar el vector, cosa que se puede hacer con las rutinas de STL, en complejidad O(nlog(n)), y la que hace el proceso de "soltar" los repetidos está en O(n). En total O(nlog(n)) que es mejor que O(n^2).
 Fijaos que es muy simple, aunque no tan sencillo de demostrar que sea correcta.

Fijaos en los dibujos que ilustran el invariante y podr'eis ententer como progresa el algoritmo.

Código
  1. /*
  2.    P : V=A[0..N)   N>= 0
  3.    fun dropRedundant(V=A[0..N) of int) return M:int
  4.    Q : \forall i : 0 <=  i < N : \exists j :0 <= j < M : A[i]=V[j]
  5.        and
  6.        M = #i : 0 <= i < N : frec(A,0,N,A[i])= 1
  7.  
  8.    I : Q[N/n] and  0 <= M <= n <= N and
  9.        StrictSorted(V,0,M) and Sorted(V,n,N)
  10.  
  11.    where
  12.  
  13.    frec(A,i,j,v) ::= # p : i<= p < j : A[p]=v
  14.  
  15.  
  16.    I and B |- Q  (trivial, since n=N)
  17.  
  18.  
  19. Snapshot invariant: (Hard)
  20. -------------------
  21.  
  22. 0     1     2    m=3    4     5     6    n=7    8           N
  23. +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  24. |  1  |  2  |  3  |  3  |   3 |  3  |  3  |  4  |     |     |
  25. +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  26.  
  27.  
  28. */
  29.  
  30. #include <iostream>
  31. #include <algorithm> // sort
  32.  
  33. using namespace std;
  34. // O(n)
  35. int dropRedundant(int V[], const int N)
  36. {
  37.  int m,n;
  38.  sort(V,V+N); // O(nlog(n)
  39.  // V sorted.
  40.  for(n=m=0;n<N;n++) // O(n)
  41.    if (m==0 || V[n]>V[m-1]) V[m++]=V[n];
  42.  return m;
  43. }
  44.  
  45. #define MAX 10000
  46.  
  47. int main(int argc, char *args[])
  48. {
  49.  int N,M;
  50.  int V[MAX];
  51.  for ( ; cin >> N; )
  52.    {
  53.      for(int n=0 ; n < N ;  n++ ) cin >> V[n];
  54.      M=dropRedundant(V,N);
  55.      cout << M << endl;
  56.      for(int m=0;m<M;m++) cout << V[m] << " ";
  57.      cout << endl;
  58.    }
  59. }
  60.  


Algunos ejemplos de entreada. La primera linea  marca el numero de elementos, la segunda el vector a considerar.

Código:
6
1 1 2 2 3 3
6
2 2 1 3 4 5
6
2 2 2 2 3 1
En la salida, se da la dimensión del nuevo vector y los elementos originales sin repetir
Código:
3
1 2 3
5
1 2 3 4 5
3
1 2 3
Que os sirva!
Páginas: 1 2 3 4 5 [6] 7 8 9 10 11
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines