Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 17
  1. #1

    Ottimizzazione parseDouble

    Salve ragazzi,
    Scrivo dopo tanti anni qui più che altro come sfogo che come altro...
    Ho passato parte del pomeriggio e della notte a cercare di capire perchè il mio software che analizza un file di 700kb contenente circa 100.000 numeri all'interno ci mettesse 2 secondi e rotti quando alla fine sono arrivato alla conclusione che la funzione Double.parseDouble() del Java quando viene richiamata moltissime volte (come nel mio caso) è mooooooooooooooooooooooooooooooooooolto lenta!

    Vi posto il codice che io ho utilizzato ed utilizzo ancora adesso (probabilmente utilizzerò per il resto della vita! ) e che mi ha consentito di ridurre i tempi a 400ms.

    codice:
        //dato un numero stringa e la posizione in cui si trova la virgola ottiene la parte intera
        private static double getInteger(String text, int pointIndex)
        {
            double result=0;
            int cnt=0;
    
            int startIndex=0;
            int endIndex=text.length();
            if(pointIndex!=-1)
                endIndex=pointIndex-1;
            
            for(int i=endIndex;i>=startIndex;i--)
            {
                char c=text.charAt(i);
                if(c<'0' || c>'9')
                    throw new IllegalStateException("CHARACTER "+c+" AT POSITION "+i+" ISN'T DIGIT!");
                
                double once=(c-'0')*(Math.pow(10, cnt));
                result+=once;
                ++cnt;
            }
    
            return result;
        }
    
        //dato un numero stringa e la posizione in cui si trova la virgola ottiene la parte decimale
        private static double getDecimal(String text, int pointIndex)
        {
            double result=0;
            int cnt=1;
    
            int startIndex=pointIndex+1;
            int endIndex=text.length();
            if(pointIndex==-1)
                startIndex=endIndex+1;
    
            for(int i=startIndex;i<endIndex;i++)
            {
                char c=text.charAt(i);
                if(c<'0' || c>'9')
                    throw new IllegalStateException("CHARACTER "+c+" AT POSITION "+i+" ISN'T DIGIT!");
    
                double once=(c-'0')*(1/Math.pow(10,cnt));
                result+=once;
                ++cnt;
            }
    
            result=MathUtil.round(result, cnt-1);
            return result;
        }
        
        //alla rinfusa!!!
        public static Double parseDouble(String value)
        {
            Double result=null;
            try
            {
                int fromIndex=0;
                int sign=value.charAt(0);
                double multiply=1.0;
                switch (sign)
                {
                    case '+':
                        multiply=1.0;
                        fromIndex=1;
                        break;
                    case '-':
                        multiply=-1.0;
                        fromIndex=1;
                        break;
                }
    
                value=value.substring(fromIndex);
                int pointIndex=value.indexOf('.');
                if(pointIndex==-1)
                    pointIndex=value.indexOf(',');
    
                double integer=getInteger(value, pointIndex);
                double decimal=getDecimal(value, pointIndex);
                result=(integer+decimal)*multiply;
            }
            catch(Exception ex)
            {
                result=null;
            }
    
            return result;
        }
    Se ci sono dei bug ditemi con che numero state provando che vedo subito di rimediare!
    Ciao, ale500.
    Let's your dream came true!

  2. #2
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Così, per chiedere... che roba è "MathUtil"?


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  3. #3
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: Ottimizzazione parseDouble

    Originariamente inviato da ale500
    il mio software che analizza un file di 700kb contenente circa 100.000 numeri all'interno ci mettesse 2 secondi e rotti quando alla fine sono arrivato alla conclusione che la funzione Double.parseDouble() del Java quando viene richiamata moltissime volte (come nel mio caso) è mooooooooooooooooooooooooooooooooooolto lenta!
    La cosa è molto relativa .... e dipende anche da svariati altri fattori (hardware macchina) e da come leggi il file e da cosa fai, di altro, con quei valori.

    Sul mio portatile di lavoro (dual core T5500 1.66GHz) il parseDouble di una stringa es. "12345.6789" impiega intorno ai 0,7 microsecondi. Leggere un file di testo di 100000 righe contenenti valori come appena detto e parsarli, impiega circa 80 millisecondi (0,08 secondi).

    La mia impressione è che non sia il parseDouble il tuo problema ...... ma altro!
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  4. #4
    MathUtil è semplicemente una mia classe, se serve la posto..
    Per quanto riguarda invece la velocità sono ben certo di quello che dico..

    La funzione è composta da:
    1) Parte di lettura del file (come unico blocco)
    2) Parse della stringa cercando i "\n"
    3) Conversione da String a Double

    Bene, detto questo se tolgo il punto 3 ci impiega 2 secondi (con il vecchio metodo)
    Se metto che la funzione mi restituisce sempre null ci mette con se il punto non ci fosse.
    Detto questo ovvio che l'errore stà nella conversione Java moooooooooolto lenta (anche ampiamente documentato su internet).

    Inoltre ho già ridotto all'osso tutto quello che ci stava prima ma i risultati non sono cambiati, finchè non ho riscritto la funzione di conversione. Leggere un file con circa 100.000 numeri ci mette 80 ms circa il resto è Java e la sua Double.parseDouble()

    Ciao, alessio.
    Let's your dream came true!

  5. #5
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da ale500
    1) Parte di lettura del file (come unico blocco)
    2) Parse della stringa cercando i "\n"
    Il tuo problema è sicuramente in queste 2 parti .... lo ripeto, non è il parseDouble il problema!!!

    Posta il codice dove leggi il file e cerchi i newline. Se è come penso, hai letto tutto il file per metterlo in un String o StringBuffer. Ed è qui la questione.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  6. #6
    Ti rispondo volentieri perchè non si finisce mai di apprendere..
    Ti confesso che sono mooooooooooooooooooooooooolto convinto di quello che ho detto però per la frase detta prima posto volentieri il codice...

    LETTURA FILE
    codice:
        private String fastStreamCopy(File file)
        {
            String result=null;
            FileChannel fileChannel = null;
            try
            {
                fileChannel = new FileInputStream(file).getChannel();
                MappedByteBuffer byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
    
                int size = byteBuffer.capacity();
                if (size > 0)
                {
                    // Retrieve all bytes in the buffer
                    byteBuffer.clear();
                    byte[] bytes = new byte[size];
                    byteBuffer.get(bytes, 0, bytes.length);
                    result = new String(bytes);
                }
    
                fileChannel.close();
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }
            finally
            {
                if (fileChannel != null)
                {
                    try
                    {
                        fileChannel.close();
                    }
                    catch (IOException ignore)
                    {
                        // ignore
                    }
                }
            }
            return result;
        }
    SPLIT RIGA PER RIGA
    codice:
                    do
                    {
                        int endIndex=result.indexOf('\n', fromIndex);
                        if(fromIndex>=size)
                        {
                            exit=true;
                            break;
                        }
    
                        String text = result.substring(fromIndex, (endIndex==-1 ? size : endIndex));
                        if(text.charAt(text.length()-1)=='\r')
                            text=text.substring(0, text.length()-1);
    
                        Object item = this.fileFilter.filter(row, text);
                        if (item != null)
                        {
                            //aggiungo l'elemento
                            this.listRows.add(item);
                        }
    
                        if(endIndex==-1)
                            exit=true;
                        else
                        {
                            ++row;
                            fromIndex=endIndex+1;
                        }
                    }
                    while(!exit);
    Quella che ho evidenziato in grassetto è la parte che poi richiama la parseDouble.
    Se commento quella riga il tempo di esecuzione è zero! Se la lascio e viene richiamata la parseDouble il tempo è di oltre 1 secondo per circa 100.000 stringhe che rappresentano numeri (questo con la parseDouble) standard..

    Ciao, ale500.
    Let's your dream came true!

  7. #7
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da ale500
    Quella che ho evidenziato in grassetto è la parte che poi richiama la parseDouble.
    Bene, posta anche questa che vediamo .....
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  8. #8
    Originariamente inviato da andbin
    Bene, posta anche questa che vediamo .....


    codice:
    Double value=Double.parseDouble(text);
    Scusa ma hai capito quello che ho scritto??
    Adesso non ti stò a postare tutto il progetto, perdona ma ci metto una mesata circa, ma li ci stà un'interfaccia che viene implementata e che il metodo all'interno fa il parseDouble...
    Let's your dream came true!

  9. #9
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Senti, tagliamo la testa al toro, come si dice??? Ecco il codice che ho provato io, concettualmente simile al tuo:

    codice:
    import java.io.*;
    import java.util.*;
    
    public class Prova {
        public static void main(String[] args) {
            try {
                BufferedReader br = new BufferedReader(new FileReader("nums.txt"));
    
                try {
                    long t1 = System.currentTimeMillis();
    
                    ArrayList<Double> list = new ArrayList<Double>();
                    String line;
    
                    while ((line = br.readLine()) != null) {
                        Double d = Double.parseDouble(line);
    
                        list.add(d);
                    }
    
                    long t2 = System.currentTimeMillis();
    
                    System.out.println(list.size());
                    System.out.println(t2 - t1);
                } finally {
                    br.close();
                }
            } catch (Exception e) {
                System.err.println(e);
            }
        }
    }
    Ho naturalmente fatto un file nums.txt con dentro 100000 righe contenenti il numero 12345.6789 (in ogni riga).

    Output sulla mia macchina:
    100000
    141

    Sono 141 millisecondi in tutto per leggere 100000 righe, parsarle, inserire i Double nella lista.
    Non so .... cosa devo dirti??? Prova a leggere il tuo file con il mio codice ... posta il risultato.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  10. #10
    Maddai!
    Questa sera provo e ti faccio sapere..
    Quello che posso dirti è che il tuo codice è mooooooooooooooooooooooooooooolto simile a quello che prima ci stava...

    Aspetta aspetta però
    Come hai costruito il file dei 100.000 numeri??

    Sono con la virgola?? Quante cifre??
    Posta anche il file cosi faccio le tue stesse prove prima..
    Ciao, alessio.
    Let's your dream came true!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.