Newsgroup: it.comp.java
Titolo: problema con un array

Ho scritto due versioni di un metodo che deve controllare se un grande  
array di interi contiene almeno un valore minore di 1.
A.
==========
   public boolean ancora_negativi()
   {
     boolean negativi = false;
     int totale = quanti.length;
     while ((totale > 0) || (negativi == false)) if (quanti[--totale] < 0)  
negativi = true;
     return negativi;
   }
==========
B.
==========
   public boolean ancora_negativi()
   {
     boolean negativi = false;
     for (int conta = 0; conta < quanti.length; conta ++) if (quanti[conta]  
< 0) negativi = true;
     return negativi;
   }
==========
Secondo il mio modesto parere il metodo A dovrebbe essere più efficiente  
del metodo B, però, pur funzionando, ogni volta che viene invocato produce  
il seguente errore nell'Output di NetBeans:
==========
Exception in thread "AWT-EventQueue-0"  
java.lang.ArrayIndexOutOfBoundsException: -1
==========
Il metodo B, invece, non dà alcun problema. Qualcuno sa dirmi dov'è  
l'arcano?
Grazie a tutti per l'attenzione.
-- 
Michele Giordano


Direi perche' nella condizione del while devi
connettere le due espressioni con un AND anziche' con un OR:
public boolean ancora_negativi()
{
      boolean negativi = false;
      int totale = quanti.length;
      while (totale > 0 && !negativi)
        if (quanti[--totale] < 0)  negativi = true;
      return negativi;
}
Quanto all'efficienza, nulla ti vieta di scrivere il metodo B
in modo equivalente al metodo A:
public boolean ancora_negativi()
{
      boolean negativi = false;
      for (int conta = 0; conta < quanti.length && !negativi; conta++)
       if (quanti[conta]  < 0) negativi = true;
      return negativi;
}
Ciao!
Roberto

 }
[..]
quanto all'efficienza credo si possa migliorare..
for (int conta = 0; conta < quanti.length; conta++)
 if (quanti[conta] < 0) return true;
return false;
gia' migliore..
-- 
 

 }
Questo mi sembra meno banale.
Mi stai dicendo che posso condizionare la durata del ciclo FOR come se  
fosse un WHILE?
Come devo interpretare il costrutto?
per CONTA uguale a zero e fino alla lunghezza dell'array ma a condizione  
che NEGATIVI sia falso, ecc. ecc.?
Grazie tante, comunque.
-- 
Michele Giordano

In data Thu, 29 Dec 2005 23:05:56 +0100, iuz <us...@host.network> ha  
scritto:

Non avrei mai osato uscire così da un ciclo FOR...
Grazie.
-- 
Michele Giordano

 fosse un WHILE?
In un linguaggio con la semantica del C (riguardo for e while) ogni
ciclo for può essere convertito in un ciclo while e viceversa in modo
sostanzialmente banale.
Per brutto che la metti
for(;cond;) <==> while(cond)
Java in questo ha la semantica del C.
-- 
non vincono, non vinceranno, non hanno domani
la forza è nel puntello impugnato da oneste fortissime mani

 
per favore non mettere 'Java' e 'C' nella stessa frase..
-- 
 

 per favore non mettere 'Java' e 'C' nella stessa frase..
In questo caso quello che conta è proprio avere la stessa semantica del
C. Poi probabilmente a livello di pura simpatia di linguaggio, io e te
non concorderemmo. ;)


 
per favore alimenta la discussione..
vorrei tanto capire che cosa ha di cosi' conveniente il java da essere
preferito da cosi' tante persone..
anzi apro un'altro thread..
-- 
 

 anzi apro un'altro thread..
Se vuoi te lo dico anche qui... faccio presto. Il "sono costretto" è un
buon motivo. Fosse per me mi barcamenavo fra C/C++ a livello basso e
medio basso [ a seconda del task ] e Python/ObjectiveC a livello alto.
Java va "appena più giù di Python" (anche se non altrettanto su) e copre
"molto meno di ObjectiveC". Tuttavia il supporto "industriale" a Java è
ordini di grandezza superiore a quello di ObjC e comunque nettamente
superiore a Python.
Grosso modo finisce qui. E la libreria non è affatto male, anzi. 


 gia' migliore..
Bè, magari è più leggibile ma hai aumentato la complessità ciclomatica...
E questo non è ancora meglio?
for (int i : quanti)
    if (i < 0)
	return true;
return false;
-- 
Pietro
(\_/)  <- This is Bunny.
(°_°)     Copy Bunny into your signature to help
(> <)     him on his way to world domination.

 return false;
Sinceramente, non so, anche se ammiro la concisione e prendo atto delle  
novità di Java 5.0.
Mi ripugna, in linea di principio, l'idea di uscire in questo modo da un  
ciclo FOR.
Per me il FOR è il FOR e il WHILE è il WHILE e resto affezionato all'idea  
che esistano cicli chiusi e cicli aperti. Se la differenza cade forse il  
linguaggio diventa più espressivo, il programmatore può esercitare meglio  
il proprio "stile" di programmazione, ma la chiarezza di organizzazione  
del codice ne risente... un po' come in certe applicazioni dove puoi fare  
la stessa cosa da quattordici menù e sette bottoni differenti, non so se  
alla fine è meglio.
Michele Giordano

> for($0;$1;$2){$3} <==> $0; while($1){$3$2}
Dove trovo questo formalismo?
Grazie.
Michele Giordano

 Dove trovo questo formalismo?
Cosa intendi con "questo formalismo"?
Nel senso che vuoi la dimostrazione in semantica naturale e/o a suon di
triple di Hoare?
Non č forse meglio convincerti "intuitivamente" che vale... tra l'altro
ricordo ancora gli schemini a Programmazione 1, anche con un flowchart
dovresti convincertene.
-- 
non vincono, non vinceranno, non hanno domani
la forza č nel puntello impugnato da oneste fortissime mani

 Michele Giordano
e' piu' efficiente ed IMHO leggibile..
-- 
 

 dovresti convincertene.
Non sto chiedendo di essere convinto.
Sicccome sto studiando "coreJava" di Horstmann e Cornell i quali - pur  
portando avanti un serrato confronto Java-C nel corso della trattazione -  
non fanno cenno a questo tuo discorso, mi stupivo di questo e ti chiedevo  
dove si può trovare.
Michele Giordano


Io non parlavo di efficienza, parlavo di univocità delle strutture di  
controllo.
Michele Giordano

 dove si può trovare.
Ma non capisco cosa? Il fatto che il ciclo for del Java si comporta
(sostanzialmente [0]) nello stesso modo di quello del C? Diciamo come
quello del C++ e siamo a posto.
Beh, questo è ovvio. È una cosa talmente banale che non va neppure
"scritta". Chiunque conosca entrambi i linguaggi lo sa e basta. E se uno
non conosce C o C++ non gli interessa minimamente :) [ esempio, a me
della semantica del for del Cobol non interessa nulla, anche perchè, se
ricordo bene, il cobol non ha un'istruzione for -- ma correggetemi se
sbaglio -- ].
Se parli dell'equivalenza fra for e while.. beh. Possiamo andare un
pochino nella teoria dei linguaggi, computazione e simili, ma andremmo
un filo fuori tema.
Quindi puoi scrivermi la proposizione che vorresti che io ti provassi
vera?
----
[0] vero se parliamo di C99, in realtà se parliamo di C89 ci sarebbero
un paio di eccezioni, ovvero:
for (int i=0; i < MAX; ++i) ; 
è codice Java valido, codice C++ valido, codice C99 valido ma non codice
C89 valido [ dovrebbe essere
int i;
for (i=0; i < MAX; ++i) ;
in quanto le variabili vanno dichiarate ad inizio di ogni blocco, ma
questo è in realtà un giochino.
-- 
non vincono, non vinceranno, non hanno domani
la forza è nel puntello impugnato da oneste fortissime mani

 controllo.
Ma non in tutti i linguaggi questo è vero. Diciamo che generalmente
questo è vero solo se hai un ciclo for "castrato".
Non succede nulla se voli fuori da un ciclo for con un return. La gente
se lo aspetta. Non è meno leggibile e non è sbagliato.
Tieni presente che con assegnamento, un'istruzione condizionale e
recursione riesci ad esprimere tutto quello che è turing compatibile 
Ma addirittura ci riesci con questi assiomi:
Ix = x per ogni x
Kxy = x
Sxyz = xz(yz)
[ anzi, bastano K ed S, I può essere espresso con quei due ].
[ ma qui siamo OT abbestia ]


 un filo fuori tema.
La questione è proprio questa. Il discorso è partito da un banale problema  
che avevo con un array (risolto grazie al NG) e poi mi sono incuriosito su  
un dettaglio di espressività del linguaggio che piano piano ci ha portato  
un po' lontano da Java.
Grazie comunque.
Michele Giordano

 
beh io credo che si volesse solo dimostrare che un ciclo while puo' divenire
senza problemi un ciclo for senza differenze nemmeno minime e viceversa (in
java cosi' come in C)..
anche se in effetti in java la corrispondenza esatta credo dovrebbe essere..
{ $0 while ($1) { $3 $2 } } <==> for( $0 ; $1 ; $2 ) { $3 }
in C si dimostra facilmente, la corrispondenza e' ovvia..
[s1.c]
int main(void) 
{
  int i, c;
  for (i = 0; i < 10; i++) { c = 0; }
}
[/s1.c]
[s2.c]
int main(void) 
{
  int i, c;
  i = 0;
  while (i < 10) { c = 0; i++; }
}
[/s2.c]
[s1.s]
        .file   "s1.c"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        addl    $15, %eax
        addl    $15, %eax
        shrl    $4, %eax
        sall    $4, %eax
        subl    %eax, %esp
        movl    $0, -4(%ebp)
.L2:
        cmpl    $9, -4(%ebp)
        jle     .L5
        jmp     .L3
.L5:
        movl    $0, -8(%ebp)
        leal    -4(%ebp), %eax
        incl    (%eax)
        jmp     .L2
.L3:
        leave
        ret
        .size   main, .-main
        .section        .note.GNU-stack,"",@progbits
        .ident  "GCC: (GNU) 3.3.4 (pre 3.3.5 20040809)"
[/s1.s]
[s2.s]
        .file   "s2.c"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        addl    $15, %eax
        addl    $15, %eax
        shrl    $4, %eax
        sall    $4, %eax
        subl    %eax, %esp
        movl    $0, -4(%ebp)
.L2:
        cmpl    $9, -4(%ebp)
        jle     .L4
        jmp     .L3
.L4:
        movl    $0, -8(%ebp)
        leal    -4(%ebp), %eax
        incl    (%eax)
        jmp     .L2
.L3:
        leave
        ret
        .size   main, .-main
        .section        .note.GNU-stack,"",@progbits
        .ident  "GCC: (GNU) 3.3.4 (pre 3.3.5 20040809)"
[/s2.s]
-- 
 

 in C si dimostra facilmente, la corrispondenza e' ovvia..
Tutto questo per voi sarà ovvio, ma io lo trovo molto interessante.
Quello che io trovo interessante - e mi scuso se scivolo un po' fuori tema  
- è notare che il disassemblato che riporti contiene, come è ovvio, i  
salti incondizionati di remota memoria che dalla programmazione  
strutturata in poi sono diventati una specie di tabù, anche se Java, per  
esempio, ha una parola riservata GOTO (peraltro non implementata).
So bene che alla fine qualsiasi linguaggio finisce nell'Assembly che  
tritura tutto in una pappa uniforme e primordiale, ma io non mi domandavo  
- e scusate ancora se sono fuori tema - se è "possibile" o "utile" o  
"comodo" convertire un WHILE in un FOR e viceversa, ma se è - non ridete  
per piacere - "etico".
Grazie.
Michele Giordano


Ti correggo. Non si chiama for ma ti pare che un linguaggio di
programmazione può fare a meno di un ciclo ricorsivo?
Ad ogni modo,
while(condizioneDiPermanenza) <==> PERFORM UNTIL NOT
CONDIZIONEDIPERMANENZA
do{...} while (condizioneDiPermanenza) <==> PERFORM UNTIL NOT
CONDIZIONEDIPERMANENZA WITH TEST AFTER
for (i=a; condizioneDiPermanenza; i=i+step) <==> PERFORM VARYING I FROM
A BY STEP UNTIL NOT CONDIZIONEDIPERMANENZA

 programmazione può fare a meno di un ciclo ricorsivo?
Se è per quello la risposta è "si". Purchè supporti ricorsione. A un
linguaggio per essere turing-completo basta quello (con chiaramente un
istruzione condizionale, etc.).
Ah, anche il salto incondizionato dal punto di vista della computabilità
va bene lo stesso. Per esempio un processore non ha un'istruzione "for"
(ne nulla che ne abbia la semantica), eppure tutti i linguaggi con i
vari cicli vengono in qualche modo tradotti in codice macchina.
Ad ogni modo il fatto che non si chiami "for" è sufficiente per dire che
Cobol non ha un ciclo for. Esattamente come non è una bestemmia dire che
C non ha un ciclo foreach, che invece ha il Perl e mi pare il PHP. :)
Diciamo che mi parrebbe strano parlare della semantica di un costrutto
sintattico non valido (e sempre se ricordo bene, ma tu pari confermare
nella sintassi Cobol il for non esiste).


 in C si dimostra facilmente, la corrispondenza e' ovvia..
Questo lo feci anche io, a suo tempo. Ma purtroppo *non* č una
dimostrazione.
Se lavori in questo campo devi lavorare con strumenti formali, non puoi
semplicemente prendere *un* sorgente e fare vedere che viene  generato
lo stesso codice.
Questo va estremamente bene a livello intuitivo e ha il vantaggio
didattico non trascurabile che convince anche i sassi. Perň uno potrebbe
chiedere di piů. 
Inoltre con un determinato compilatore quanto scrivi potrebbe non
valere. Per esempio per sc2 potrebbe venire generato un codice macchina
equivalente (dopo avere analizzato quello che fanno) ma leggermente
diverso.
Per esempio stesso identico programma (concettuale) in Java ha bytecode
diverso (disassemblato), almeno sulla mia macchina [ man javap ], anche
se la dimostrazione formale che i due programmi fanno la stessa cosa č
tendenzialmente banale (magari un po' lunghetta e noiosetta... la logica
di hoare č cosě, in semantica naturale si farebbe prima, certo).
-- 
non vincono, non vinceranno, non hanno domani
la forza č nel puntello impugnato da oneste fortissime mani

 un po' lontano da Java.
Il modo migliore per convincertene intuitivamente č leggere il post di
iuz (vabbč, č C, ma dovrebbe andarti bene uguale) oppure farti un
banalissimo flowchart. Se non fosse che ad andare di ascii ci metto piů
che a dirlo, te lo farei anche qui.
Se vuoi roba *molto* piů formale... dipende dal tuo background,
sostanzialmente.
-- 
non vincono, non vinceranno, non hanno domani
la forza č nel puntello impugnato da oneste fortissime mani

La parola chiave "for" nel cobol non esiste.
L'istruzione equivalente al for invece sì.

 writes:
EF> Per esempio stesso identico programma (concettuale) in Java ha
EF> bytecode diverso (disassemblato),
Ahem, 
public class K {
  /**
   * Describe <code>main</code> method here.
   *
   * @param args a <code>String[]</code> value
   */
  public static final void main(final String[] args) {
    int a;
    a = 0;
    while (a<10) {
      System.out.println(a);
      a++;
 
    }
    for (a = 0; a< 10; a++) {
      System.out.println(a);
 
    }
  }
}
Compiled from K.java
public class K extends java.lang.Object {
    public K();
    public static final void main(java.lang.String[]);
}
Method K()
   0 aload_0
   1 invokespecial #1 <Method java.lang.Object()>
   4 return
Method void main(java.lang.String[])
   0 iconst_0
   1 istore_1
   2 goto 15
   5 getstatic #2 <Field java.io.PrintStream out>
   8 iload_1
   9 invokevirtual #3 <Method void println(int)>
  12 iinc 1 1
  15 iload_1
  16 bipush 10
  18 if_icmplt 5
  21 iconst_0
  22 istore_1
  23 goto 36
  26 getstatic #2 <Field java.io.PrintStream out>
  29 iload_1
  30 invokevirtual #3 <Method void println(int)>
  33 iinc 1 1
  36 iload_1
  37 bipush 10
  39 if_icmplt 26
  42 return
I due cicli sono effettivamente uguali, sul mio vecchio paperoga...
(BTW, non è una dimostrazione formale, of course...)
-- 
 /\            ___
/___/\__|_|\_|__|___Gian Uberto Lauri_____________________
  //--\ | | \|  |   Integralista GNUslamico  
\/		    e allevatore di bug da competizione

 (BTW, non č una dimostrazione formale, of course...)
Questo anche sul mio viene lo stesso. Il giochetto che invece avevo
preparato io (lo stesso, senza System.out.printlm) ma "in due classi
diverse" dava risultati diversi. Bah... non escludo nemmeno di avere
fatto casino, capita di questi tempi. :)
