Errore nel calcolo delle percentuali - 2

Avvisi e discussioni su bug, soluzioni e migliorie del software

Moderatori: roby, Moderators

roby
Site Admin
Site Admin
Messaggi: 1260
Iscritto il: ven apr 25, 2008 12:00 am
Contatta:

Messaggio da roby »

Riassumo la logica della funzione così è più facile isolare l'argomento di dibattito:
- parametri in ingresso sono un array dei valori e il totale rispetto al quale calcolare la percentuale.
- carico l'array temp2 con i "resti" necessari ad ogni valore per ottenere lo 0,01 in piu'
- contemporaneamente carico l'array temp3 con le stesse percentuali calcolate
- e calcolo la somma delle percentuali calcolate con due decimali.
- Verifico che tale somma non sia superiore a 100, se lo è apro un ciclo e decremento di 0,01 il temp3 corrispondente al temp2 più alto, quindi azzero questo temp2 in modo da escluderlo dai successivi decrementi (se i valori fossero tutti a zero la somma delle percentuali non potrebbe essere diversa da 100).
- per ovviare al problema della precisione eseguo un controllo testuale della somma delle percentuali (che a questo punto non può essere superiore a 100) e se è 100 la funzione termina ritornando l'array delle percentuali
- altrimenti controllo che la somma non sia inferiore a 100 e se lo è entro nel ciclo di incremento corrispondente concettualmente a quello di decremento.
- a questo punto la somma delle percentuali è sicuramente 100 quindi la funzione restituisce l'array delle percentuali.
Roberto
margottid
Newbie
Newbie
Messaggi: 193
Iscritto il: mar mag 12, 2009 12:00 am

Messaggio da margottid »

roby ha scritto: [...]
apro un ciclo e decremento di 0,01 il temp3 corrispondente al temp2 più alto, quindi azzero questo temp2 in modo da escluderlo dai successivi decrementi (se i valori fossero tutti a zero la somma delle percentuali non potrebbe essere diversa da 100).
[...]
- altrimenti controllo che la somma non sia inferiore a 100 e se lo è entro nel ciclo di incremento corrispondente concettualmente a quello di decremento.
[...]
Quindi, ragionando in maniera opposta a come funziona il ciclo di decremento, quello di incremento dovrebbe aumentare di 0,01 il temp3 corrispondente al temp2 più basso, e poi viene messo a 1 quel temp2 in modo da escluderlo dai successivi incrementi.

Però ci possono essere casi in cui il temp2 più basso è uguale a zero, proprio perché per alcuni valori non ci sono stati arrotondamenti (magari perché il numero di voti/schede è uguale a zero, o - caso meno frequente - è un sottomultiplo del totale dei voti e pertanto la percentuale è già arrotondata alla seconda cifra decimale), e sarebbe giusto lasciare invariate queste percentuali, modificando solo quelle hanno effettivamente subito un arrotondamento.

La mia proposta consisteva nell'escludere, dal ciclo di incrementi, quei temp3 che non sono stati arrotondati, impostando a 1 il corrispondente temp2 - il tutto ancora prima che inizi il ciclo di incrementi vero e proprio.

Sto ragionando in maniera corretta?

Daniele
roby
Site Admin
Site Admin
Messaggi: 1260
Iscritto il: ven apr 25, 2008 12:00 am
Contatta:

Messaggio da roby »

Si il ragionamento concettualmente è giusto, direi di inserire un controllo che consenta la chiamata alla funzione solo se almeno uno dei valori è maggiore di zero, per quanto riguarda il caso in cui il temp2 più basso è uguale a zero direi che la funzione risponde correttamente perché in questo caso i temp2 sono tutti uguali a zero (non potendo essere negativi) quindi non ci sono arrotondamenti da fare, la somma delle percentuali è già 100.00 e la funzione termina.
Roberto
margottid
Newbie
Newbie
Messaggi: 193
Iscritto il: mar mag 12, 2009 12:00 am

Messaggio da margottid »

Mi spiego meglio riportandoti i dati del mio caso specifico.

Questi sono i valori su cui vengono calcolate le percentuali:
- Voti Validi: 17126
- Schede Nulle: 297
- Schede Bianche: 127
- Voti Contestati: 0
- Voti Nulli: 0

Questi sono i valori degli array temp3 e temp2 PRIMA del ciclo di incremento:
97.58 - 0.159544159544
1.69 - 0.0769230769231
0.72 - 0.763532763533
0.00 - 0
0.00 - 0

Questi sono i valori degli array temp3 e temp2 DOPO il ciclo di incremento:
97.58 - 0.159544159544
1.69 - 0.0769230769231
0.72 - 0.763532763533
0.01 - 1
0.00 - 0

Un eventuale controllo che consenta la chiamata alla funzione solo se almeno uno dei valori è maggiore di zero avrebbe - in questo caso - successo, e la funzione verrebbe eseguita.
Purtroppo però, tra questi valori, c'è anche qualche temp2 uguale a zero, ed è proprio uno di questi ad essere vittima dell'incremento di un punto percentuale!

Daniele
roby
Site Admin
Site Admin
Messaggi: 1260
Iscritto il: ven apr 25, 2008 12:00 am
Contatta:

Messaggio da roby »

Quando uno non vuole capire non c'e' niente di meglio che un esempio pratico!
Però ora mi è chiaro il problema, ci penso un po' e ti dico.
Roberto
margottid
Newbie
Newbie
Messaggi: 193
Iscritto il: mar mag 12, 2009 12:00 am

Messaggio da margottid »

:lol: :lol: :lol: :lol: :lol: :lol: :lol:

Senza fretta, perché sarò in ferie per una settimana, e potrò fare eventuali verifiche solo al ritorno.

Grazie mille e Buona Pasqua!

Daniele
roby
Site Admin
Site Admin
Messaggi: 1260
Iscritto il: ven apr 25, 2008 12:00 am
Contatta:

Messaggio da roby »

Buona Pasqua anche a te,
Ti mando intanto la soluzione che ho pensato di adottare cioè inserire la linea:
foreach ($temp2 as $key => $val) if($val==0) $temp2[$key]=1;

prima del secondo ciclo, così da escludere i valori a zero da quelli che possono essere incrementati.
Roberto
roby
Site Admin
Site Admin
Messaggi: 1260
Iscritto il: ven apr 25, 2008 12:00 am
Contatta:

Messaggio da roby »

Ho pensato che hai ragione tu e gli elementi che non devono avere incrementi o decrementi non vanno inseriti nell'array di controllo, così ho rivisto la funzione apportando anche una correzione (nella funzione ceil la moltiplicazione va fatta per 10000 e non per 1000).
Ho anche risistemato 02_risultati e 01_votanti per formattarne l'output grafico.
Il pacchetto con i tre file si scarica da qui:

Modifico il messaggio per ulteriori modifiche, scaricare e applicare in ordine:
http://trac.eleonline.it/eleonline/chan ... zip&new=73
http://trac.eleonline.it/eleonline/chan ... zip&new=74
http://trac.eleonline.it/eleonline/chan ... zip&new=75
http://trac.eleonline.it/eleonline/chan ... zip&new=76
Buona rientro a tutti.
Roberto
roby
Site Admin
Site Admin
Messaggi: 1260
Iscritto il: ven apr 25, 2008 12:00 am
Contatta:

Messaggio da roby »

E' anche possibile scaricare tutti i file modificati dalla versione 73 alla 76 in un unico pacchetto da questo indirizzo:
https://trac.eleonline.it/eleonline/cha ... d_path=%2F
Cartelle compresse di windows non riesce a gestire il pacchetto zip che viene prodotto, ma altri prodotti, ad esempio winrar, non hanno problemi.
Roberto
margottid
Newbie
Newbie
Messaggi: 193
Iscritto il: mar mag 12, 2009 12:00 am

Messaggio da margottid »

Ho caricato la versione aggiornata, ma continua a darmi il problema (vedi: http://elezioni.comune.lugo.ra.it/clien ... id_lista=0).

Ho visto che hai aggiunto, nell'IF, il controllo "or $temp2tot==0", ma non basta, perché nel mio caso $temp2tot vale 99.99, e pertanto il ciclo di incremento viene eseguito: questo comporta l'incremento di una percentuale che non aveva avuto alcun arrodontamento...

Bisognerebbe trovare il modo di escludere, all'interno del ciclo di incremento, la modifica di quei valori che non sono stati arrotondati.

Come primo tentativo avevo provato a modificare queste righe:

Codice: Seleziona tutto

foreach ($temp2 as $key => $val) {
  if ($val == min($temp2)) {$temp3[$key]+=0.01;$temp2tot+=0.01;$temp2[$key]=1;break;}
}
così:

Codice: Seleziona tutto

foreach ($temp2 as $key => $val) {
  if ($val!=0) {
    if ($val == min($temp2)) {$temp3[$key]+=0.01;$temp2tot+=0.01;$temp2[$key]=1;break;}
  }
}
ma lo script va in loop infinito, poiché min($temp2) vale ancora zero.

Bisogna modificare l'array $temp2, affinché il suo valore minimo rispecchi l'effettivo arrotondamento più basso, anziché il "non-arrotondamento".
La prima soluzione che avevi prospettato (cioè, inserire la linea "foreach ($temp2 as $key => $val) if($val==0) $temp2[$key]=1;" prima del secondo ciclo) è una strada percorribile: in questo modo si escludono i "non-arrotondamenti".

Daniele
roby
Site Admin
Site Admin
Messaggi: 1260
Iscritto il: ven apr 25, 2008 12:00 am
Contatta:

Messaggio da roby »

in effetti la funzione non mi convince ancora, ma tornerei ad una delle tue prime proposte: non inserire i valori "tondi" tra quelli da prendere in considerazione per gli incrementi o decrementi. Considerato che:
1) l'array temp2 viene utilizzato solo per fare il controllo e
2) se i valori sono tutti tondi non sono necessari ritocchi
credo che per risolvere si potrebbe (come dicevi tu) non valorizzare, per i valori tondi e cioé a zero, temp2 in questo modo:

Codice: Seleziona tutto

$temp4=(ceil($voti*10000/$sevaltot)-($voti*10000/$sevaltot)); 
if ($temp4) $temp2[$key]=$temp4;
$valperc=number_format($voti*100/$sevaltot,2); 
in modo che temp3 sia comunque valorizzato e temp2 non lo sia.
Che ne pensi?
Roberto
margottid
Newbie
Newbie
Messaggi: 193
Iscritto il: mar mag 12, 2009 12:00 am

Messaggio da margottid »

Direi che funziona, sia concettualmente che sul campo (ho fatto una prova sull'installazione di test, e stavolta gli zeri sono rimasti tali).

Aspetto l'inserimento nel trunk...!

Grazie mille,
Daniele
roby
Site Admin
Site Admin
Messaggi: 1260
Iscritto il: ven apr 25, 2008 12:00 am
Contatta:

Messaggio da roby »

Inserita nel trunk. Nel frattempo avevo anche inviato la funzione per la cancellazione delle consultazioni che, visto che si parla di cancellazione definitiva dei dati, consiglio di provare solo dopo adeguato dump del DB. Si trova nel menu "Autorizza comuni", quindi "edit" sulla consultazione, spunta per abilitare la cancellazione, scelta della voce cancellazione nel combo dello stato e infine pulsante "Cancella consultazione". La cancellazione riguarda i dati del singolo comune mentre manca ancora la cancellazione totale della consultazione che penso di inserire nel menu "Consultazione" del superuser.
Valutazioni e consigli sono sempre graditi.
Roberto
Rispondi