Topic: OverflowError Numerical result out of range [Risolto]  (Letto 944 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline ndrini

  • python unicellularis
  • *
  • Post: 49
  • Punti reputazione: 0
    • Mostra profilo
Ciao
sto eseguendo un calcolo di acustica, che implica valori grandi somma di 10**10.

Con misuraz che è un lista di 36000 valori pari a 100, al momento dell'elevazione a potenza e somma:
[codice]integrale  = sum(  [ 10. ** (i/10.) for i in  misuraz ] )[/codice]

mi dà un errore:
[codice]OverflowError: (34, 'Numerical result out of range')
[/codice]


Ho provato con

[codice]
from decimal import *
getcontext().prec = 100
integrale  = Decimal( sum(  [ Decimal(10. ** (i/10.)) for i in  misuraz ] ))
[/codice]

ma è estremamente lento (di fatto non ha finito i calcoli...)

Chi mi può indicare una forma di risolvere la cosa?

Andrea
« Ultima modifica: Luglio 25, 2016, 11:37 da ndrini »

Offline GlennHK

  • python sapiens sapiens
  • ******
  • Post: 1.654
  • Punti reputazione: 1
    • Mostra profilo
    • La Tana di GlennHK
Re: OverflowError Numerical result out of range
« Risposta #1 il: Luglio 21, 2016, 11:19 »
Usa i decibel, no?

Offline ndrini

  • python unicellularis
  • *
  • Post: 49
  • Punti reputazione: 0
    • Mostra profilo
Re: OverflowError Numerical result out of range
« Risposta #2 il: Luglio 21, 2016, 12:00 »
Usa i decibel, no?

ah ah ah
non mi pare una cattiva idea :-P

é che questa è la formula che ho trovato per passare da una serie puntuale di misure in dB (infatti i 36000 valori sono quanto è stato rilevato in un'ora, ogni .1 s ) al livello equivalente.

http://web.taed.unifi.it/fisica_tecnica/Secchi/documenti/acustica.pdf

E' solo che, per fare questo passaggio, bisogna ritrasformare i simpatici decibel nei terribili livelli di pressione sonora in Pa...

Leq = 10 log10 [1/T ( 0T p²(t) /p0² dt) ]     [dB]


:(

Andrea

Offline ndrini

  • python unicellularis
  • *
  • Post: 49
  • Punti reputazione: 0
    • Mostra profilo
Re: OverflowError Numerical result out of range
« Risposta #3 il: Luglio 22, 2016, 19:24 »
Che strano,
pare il problema si verifichi solo se sono all'interno di unittest!


Infatti, dopo aver fatto conoscenza con il formato Decimal,
per fare un po' di prove riscrivo lo script in file a parte,
fuori da unittest e ...
funziona senza problemi!!!

[codice]import numpy as np

def livello_equivalente(misuraz, intervalli = .1 ):
    intervallo_tempo = len(misuraz)                            # / intervalli      #
    integrale  = sum(  [ 10. ** (i/10.) for i in  misuraz ] )  # / intervalli
    return 10 * np.log10( integrale/ intervallo_tempo )
dati = [50. for i in range(0,20*60*10-10)]
[dati.append(100. + 0.1) for i in range(0,10)]
print livello_equivalente(dati)
[/codice]

Sapete di qualche particolarità in unittest che fanno scattare il problema?

Andrea
« Ultima modifica: Luglio 22, 2016, 19:31 da ndrini »

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.870
  • Punti reputazione: 9
    • Mostra profilo
Re: OverflowError Numerical result out of range
« Risposta #4 il: Luglio 22, 2016, 20:17 »
E' veramente difficile capire qualcosa di quello che scrivi.

Parti dicendo

> misuraz che è un lista di 36000 valori pari a 100

Ma se io ti prendo in parola e provo a fare il conto, in realtà non ho assolutamente un OverflowError (e ci mancherebbe, si vede a occhio nudo):

[codice]
>>> misuraz = [100] * 36000
>>> sum(  [ 10. ** (i/10.) for i in  misuraz ] )
360000000000000.0
[/codice]

Quindi, o il conto che fai realmente non è quello che hai postato, oppure "misuraz" non è 36mila volte 100. Oppure hai installato python sulla pulsantiera del citofono. Boh?

Poi ci dici che usando Decimal...

> ma è estremamente lento (di fatto non ha finito i calcoli...)

Ovviamente è più lento, ma ci mette solo un secondo (massimo due, toh):
[codice]
>>> from decimal import *
>>> getcontext().prec = 100
>>> misuraz = [Decimal(100.)] * 36000
>>> sum(  [ Decimal(10.) ** (i/Decimal(10.)) for i in  misuraz ] )
Decimal('360000000000000')
[/codice]


Poi cambi discorso e parli di unittest, ma il codice che posti NON ha assolutamente nulla a che vedere con unittest... la parola "unittest" proprio non compare nel codice che posti... e però chiedi a noi "perché dentro unittest non funziona, e fuori invece sì"... Eh? e che ne sappiamo? Facci vedere il codice, non so.

Comunque, la cosa buffa è che nel codice che posti, in sostanza fai lo stesso calcolo di prima, ma con altri dati di partenza... e anche questa volta il calcolo riesce senza problemi!
[codice]
>>> dati = [50. for i in range(0,20*60*10-10)]
>>> _ = [dati.append(100. + 0.1) for i in range(0,10)]  # vedi nota sotto
>>> sum(  [ 10. ** (i/10.) for i in  dati ] )
103528299228.07536
>>>
 [/codice]
(nota: quel [dati.append(100. + 0.1) for i in range(0,10)] è un modo veramente assurdo di estendere una lista. Restituisce una lista di dieci None, ed estende la lista di partenza come side effect... brrr. Per evitarmi la sparata dei dieci None sulla shell, ovviamente l'ho assegnato a una variabile. Il resto del codice è uguale al tuo).


Morale: ri-controlla il codice che hai postato, perché mi sa tanto che l'errore è provocato da qualcos'altro che non ci dici / non ci fai vedere.

Comunque, in linea di principio: sì, è assolutamente possibile sforare la capacità dei float python, ed è anche piuttosto facile:
[codice]
>>> 10.**1000
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Result too large')
>>> 10**1000  # ma nota che invece questo funziona
[/codice]
Naturalmente, Decimal risolve il problema:
[codice]
>>> Decimal(10.)**1000
Decimal('1.000000(ehm... un sacco di zeri)000000E+1000')
>>>
[/codice]
E, sempre in linea di principio, quando il calcolo in python ci mette troppo tempo, di solito basta passare a numpy.
« Ultima modifica: Luglio 22, 2016, 20:19 da RicPol »

Offline ndrini

  • python unicellularis
  • *
  • Post: 49
  • Punti reputazione: 0
    • Mostra profilo
Re: OverflowError Numerical result out of range
« Risposta #5 il: Luglio 23, 2016, 19:20 »
Grazie RicPol della dettagliata risposta.
(e scusa per il brivido alla schiena sulla lista, ora vedo come estenderla come da tuo consiglio).

Preparerò un codice sintetico con unittest :-P

Andrea

Offline ndrini

  • python unicellularis
  • *
  • Post: 49
  • Punti reputazione: 0
    • Mostra profilo
Re: OverflowError Numerical result out of range
« Risposta #6 il: Luglio 25, 2016, 11:36 »
Ok, scagionato unittest!
(lo avevo usato per fare la somma con dei numeri veramente grandi, da qui il  OverflowError Numerical ).


Grazie per il consiglio su come scrivere i post.

Tornando a come estendere una lista.
Effettivamente bastava fare come scritto per dati_2:
[codice]dati_1 = [50. for i in range(0,20*60*10-10)]  
[dati_1.append(100. + 0.1) for i in range(0,10)]

dati_2 = [50] * (20*60*10-10) + [100.1]*10

print len(dati_1), len(dati_2)
[/codice]  

Il metodo di RicPol usava la variabile "_", che rappresenta l'ultima elaborazione fatta da Python, credo.

Comunque grazie.
Metto risolto.

Offline GlennHK

  • python sapiens sapiens
  • ******
  • Post: 1.654
  • Punti reputazione: 1
    • Mostra profilo
    • La Tana di GlennHK
Re: OverflowError Numerical result out of range [Risolto]
« Risposta #7 il: Luglio 25, 2016, 12:29 »
Mmm, no.

Ric ha detto "Per evitarmi la sparata dei dieci None sulla shell, ovviamente l'ho assegnato a una variabile.". Avrebbe potuto scrivere anche "pippo" al posto di "_", non ha usato il significato di _.

Il problema è che tu stai usando un costrutto sintattico per la *creazione* di liste solo per un side effect.
Il modo corretto di effettuare quell'operazione è un semplice for:

[codice]
for i in range(0,10):
    dati_1.append(100. + 0.1)
[/codice]

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.870
  • Punti reputazione: 9
    • Mostra profilo
Re: OverflowError Numerical result out of range [Risolto]
« Risposta #8 il: Luglio 25, 2016, 13:13 »
E inoltre:

> Ok, scagionato unittest!
> (lo avevo usato per fare la somma con dei numeri veramente grandi, da qui il  OverflowError Numerical ).

Uhm, no... neanche questo.
Si scrivono i test per imparare qualcosa di nuovo sul codice che hai scritto (nello specifico, per imparare come si comporta il tuo codice in diverse condizioni). Se il tuo test solleva una eccezione, ci sono due possibilità:
1) hai imparato che il tuo codice non regge di fronte a un determinato scenario che potrebbe presentarsi: allora devi modificare il tuo codice in modo che passi il test.
2) hai scritto male il test, e lo scenario che rappresenta in effetti non può mai verificarsi: questo è moooolto più raro nella pratica (di fatto, proprio il test che hai scritto rappresenta già un caso in cui, appunto, si è verificato quello scenario). Ma quando riconosci che il test "non sta né in cielo né in terra", allora dovresti modificare il test.

Quindi non basta "scagionare unittest", e non era questo lo scopo. Se dopo aver "scagionato unittest" non hai modificato né il tuo codice né il tuo test, allora continua a esserci un problema serio da qualche parte.