Newsgroup: it.comp.lang.c
Titolo: Lunghezza sequenze alternate

Estraggo in sequenza una serie di double che possono andare (in teoria) 
da -INF a +INF (in pratica, difficilmente vedrò numeri al di fuori di +/-6).
I numeri sono memorizzati in un vettore.
 
Devo determinare quanti numeri consecutivi a partire dall'ultimo si 
alternano in alto e in basso (mi interessano solo gli ultimi 14 numeri 
usciti).
 
Esempio:
-3.1, -1.4, 6.2, 4.5, 3.9, 5.2, -1.7
 
il numero più a destra è l'ultimo uscito, arrivando a quello più a 
sinistra che è il primo uscito.
Il risultato deve essere 4 (perché 6,2 continua la salita iniziata da 
4,5, mentre doveva essere inferiore a 4,5).
 
Il programmino che ho scritto io utilizza un intero ausiliario che può 
valere 1 o -1 e potrebbe anche andar bene, ma mi chiedevo se a qualcuno 
viene in mente un'implementazione più veloce della mia (l'unica cosa che 
conta è la velocità).
 
 
Sempre per la stessa sequenza, dovrei anche considerare gli ultimi 5 
numeri usciti e verificare se ce ne sono 4 o 5 che superano un certo 
valore x (ad esempio x= 2 o x= 1).
Questo l'ho risolto banalmente memorizzando i numeri nel vettore di cui 
parlavo, ma è piuttosto inefficiente, in quanto tutte le volte scandisco 
gli ultimi 5 numeri e conto quanti sono superiori a x.
 
Vi viene in mente un altro sistema? Sarei contento se riuscissi a fare a 
meno del vettore.
 
Grazie
Cristiano

 gli ultimi 5 numeri e conto quanti sono superiori a x.
 
Non ho capito perche' dici che "tutte le volte scandisco gli ultimi 5 
numeri" se poco prima hai detto "dovrei anche considerare gli ultimi 5 
numeri usciti" => cioe' devi aspettare di averne 5 di numeri e poi fai 
il controllo, non "tutte le volte scandisco..."
 
Ciao

 Cristiano
 
ciao
riki

 soglia aggiungi 1 al numero ottenuto al punto 2 (che è N o N-1).
 
L'idea è buona, ma ci sono piccole differenze rispetto al metodo 
"sicuro" (quello banale che scandisce sempre gli ultimi 5 numeri).
Devo capire dov'è che sbaglio.
 
Cristiano

 il controllo, non "tutte le volte scandisco..."
 
Voglio dire che ogni volta che estraggo un numero scandisco gli ultimi 5 
numeri estratti (ovviamente, devo aspettare che siano usciti almeno 5 
numeri).
 
Cristiano

 Speravo che l'esempio chiarisse la faccenda.
 
Ok, ora capisco, dalla tua spiegazione ti riferisci a:
http://en.wikipedia.org/wiki/Nelson_rules
 (rule 4)
 
Ho fatto una implementazione (funzione nelson_rule4) che si basa 
soprattuto sulla chiarezza, creando una struttura value_s che descrive 
sia il double, che la direzione rispetto al successivo.
 
Analizzo la direzione a partire dal primo elemento, non dall'ultimo, ma 
se preferisci dall'ultimo lo puoi modificare facilmente.
 
Riguardo alla velocita', a meno che non devi farlo eseguire da un PIC, 
credo non ci siano problemi.
 
La funzione nelson_rule4 puo' inoltre analizzare un array 
arbitrariamente lungo.
 
Guarda se ti va bene, ciao.
 
===================================================================
#include <stdio.h>
 
typedef struct value_s {
     double v; /* valore */
     int dir;  /* direzione rispetto al successivo */
} value_t;
 
/**
  * Dato un array di punti, ritorna il numero di punti in direzione 
alternata
  *
  * values: array di value_t che rappresentano i numeri da analizzare
  * len: lunghezza dell'array
  * ritorna il numero di punti in direzione alternata
  */
int nelson_rule4(value_t *values, int len)
{
     int i;
 
     // almeno 3 valori da analizzare
     if (len < 3)
         return 0;
 
     // primi due valori uguali?
     if (values[0].v == values[1].v)
         return 0;
 
     // calcolo la direzione per ciascun punto
     for (i = 0; i < len - 1; i++)
         values[i].dir = values[i].v == values[i + 1].v ? 0 :
                         values[i].v < values[i + 1].v ? 1 : -1;
 
     // eventuale debug
     //for (i = 0; i < len - 1; i++)
     //    printf("values[%d].dir = %d\n", i, values[i].dir);
 
     // cerco dopo quanto la direzione e' 0 oppure non cambia
     for (i = 0; i < len - 1; i++)
         if (values[i].dir == 0 || values[i].dir == values[i + 1].dir)
             break;
 
     return i;
}
 
int main()
{
     value_t values[14] = {
         { 1 }, { 2 }, { 1 }, { 3 }, { 1 }, { 4 },
         { 1 }, { 5 }, { 1 }, { 6 }, { 1 }, { 7 },
         { 1 }, { 8 }
     };
 
     printf("nelson_rule4: %d\n", nelson_rule4(values, 14));
 
     return 0;
}
===================================================================

 Guarda se ti va bene, ciao.
 
Nella fretta non ho corretto la documentazione della funzione. Te la 
riscrivo qui corretta. Ciao.
 
 
/**
   * Dato un array di value_t, ritorna il numero di value_t in direzione
alternata
   *
   * values: array di value_t che rappresentano i valori da analizzare
   * len: lunghezza dell'array di value_t
   * ritorna il numero di value_t in direzione alternata
   */
 


 > [...]
 
per cui non l'ho potuto provare.
 
Ad ogni modo, vedo 2 cicli for di lunghezza len-1, di cui il primo viene 
eseguito per tutta la lunghezza (il secondo non lo vedo), mentre il 
codice che ho implementato io ha un solo ciclo for che viene interrotto 
appena possibile:
 
int i, s= 1; if(x < xb[UCHAR(xc-1)]) s= -1;
for(i= 1; i < 14; i++) {
	double xi= xb[UCHAR(xc-i)];
	if((x - xi) * s < 0) break;
	x= xi; s = -s;
}
if(i == 14) goto oof;
 
xb[] è il buffer circolare in cui memorizzo i double che escono;
xc è il puntatore all'ultimo double uscito.
 
Leggo che ti basi soprattutto sulla chiarezza, ma io avrei bisogno della 
velocità massima, perché devo eseguire questi controlli milioni di volte 
in ogni simulazione.
L'ideale, come dicevo, sarebbe addirittura togliere di mezzo il vettore 
e i cicli for.
L'idea di Riccardo per la regola 4/5 sarebbe ottima e sto tentando 
d'implementarla anche per questa regola, ma non sono ancora riuscito a 
capire perché non funziona nemmeno per la regola 4/5.
 
Cristiano

 punto, poi sembra accavallarsi con l'altro tuo messaggio di correzione:
 
Ho usato google groups; tutto ok, adesso provo il tuo codice.
 
Cristiano

 soglia aggiungi 1 al numero ottenuto al punto 2 (che è N o N-1).
 
Finalmente sono riuscito ad implementare il tuo metodo; ho dovuto 
"sparpagliarlo" per aggiungere un ulteriore controllo per verificare che 
siano usciti almeno N numeri.
Il guadagno di velocità non è male (circa il 15%). Se riesco ad 
implementarlo per il controllo sull'alternanza dei 14 valori, 
l'incremento di velocità dovrebbe essere notevole.
 
Ciao e grazie
Cristiano