2009-11-20 11 views
39

Sono entrato in possesso di un gruppo di codice MATLAB e ho notato una serie di "numeri magici" sparsi sul codice. Tipicamente, mi piace fare quelle costanti in linguaggi come C, Ruby, PHP, ecc. Quando si cerca su Google questo problema, ho scoperto che il modo "ufficiale" di avere costanti è definire funzioni che restituiscono il valore costante. Sembra quasi azzardato, soprattutto perché MATLAB può essere pignolo quando consente più di una funzione per file.Costanti in MATLAB

Questa è davvero l'opzione migliore?

Sono tentato di usare/fare qualcosa come il Preprocessore C per fare questo per me. (Ho scoperto che qualcosa chiamato mpp è stato creato da qualcun altro in una situazione simile, ma sembra abbandonato. Il codice non viene compilato e non sono sicuro se soddisferà le mie esigenze.)

risposta

19

In genere, definisco una variabile con UPPER_CASE e posiziono vicino all'inizio del file. Ma devi assumerti la responsabilità di non cambiarne il valore.

Altrimenti è possibile use MATLAB classes definire costanti denominate.

+6

In genere utilizzo una classe MATLAB per contenere tutti i miei parametri configurabili. Questo ti dà anche la possibilità di creare più configurazioni e scambiarle facilmente e facilmente. È anche possibile creare una serie di configurazioni e iterare attraverso l'array, eseguendo a turno il codice di test su ciascuna configurazione. – bta

2

Si potrebbe di queste risposte How do I create enumerated types in MATLAB? utili. Ma in breve, non esiste un modo "a una riga" per specificare variabili il cui valore non dovrebbe cambiare dopo l'impostazione iniziale in MATLAB.

2

In qualunque modo tu lo faccia, sarà ancora un po 'un gioco da ragazzi. Nei progetti passati, il mio approccio a questo era di definire tutte le costanti come variabili globali in un file di script, richiamare lo script all'inizio dell'esecuzione del programma per inizializzare le variabili e includere "global MYCONST;" dichiarazioni all'inizio di qualsiasi funzione che necessitava di utilizzare MYCONST. Se questo approccio sia o meno superiore al modo "ufficiale" di definire una funzione per restituire un valore costante è una questione di opinione che si potrebbe obiettare in entrambi i modi. In nessun caso è l'ideale

34

Matlab ha costanti ora. Lo stile "classdef" più recente (R2008a +) di Matlab OOP consente di definire proprietà di classe costanti. Questa è probabilmente l'opzione migliore se non si richiede la compatibilità con i vecchi Matlabs. (Oppure, al contrario, è un buon motivo per abbandonare la compatibilità retroattiva.)

Definirli in una classe.

classdef MyConstants 
    properties (Constant = true) 
     SECONDS_PER_HOUR = 60*60; 
     DISTANCE_TO_MOON_KM = 384403; 
    end 
end 

Poi riferimento da qualsiasi altro codice utilizzando dot-qualificazione.

>> disp(MyConstants.SECONDS_PER_HOUR) 
     3600 

Vedere la documentazione Matlab per "Programmazione orientata agli oggetti" in "Guida dell'utente" per tutti i dettagli.

Ci sono un paio di trucchi secondari. Se il codice tenta accidentalmente di scrivere su una costante, invece di ottenere un errore, creerà una struttura locale che maschera la classe delle costanti.

>> MyConstants.SECONDS_PER_HOUR 
ans = 
     3600 
>> MyConstants.SECONDS_PER_HOUR = 42 
MyConstants = 
    SECONDS_PER_HOUR: 42 
>> whos 
    Name    Size   Bytes Class  Attributes 

    MyConstants  1x1    132 struct    
    ans    1x1     8 double    

Ma il danno è locale. E se vuoi essere completo, puoi proteggerlo chiamando il costruttore MyConstants() all'inizio di una funzione, che costringe Matlab ad analizzarlo come nome di classe in quell'ambito. (IMHO questo è eccessivo, ma è lì se lo vuoi.)

function broken_constant_use 
MyConstants(); % "import" to protect assignment 
MyConstants.SECONDS_PER_HOUR = 42 % this bug is a syntax error now 

L'altro punto è che le proprietà ei metodi classdef, specialmente statica come questo, sono lenti. Sulla mia macchina, la lettura di questa costante è di circa 100 volte più lenta di una semplice funzione (22 usec vs 0.2 usec, vedi this question).Se stai usando una costante all'interno di un ciclo, copialo su una variabile locale prima di entrare nel ciclo. Se per qualche motivo devi utilizzare l'accesso diretto alle costanti, vai con una funzione semplice che restituisce il valore.

Per motivi di sanità mentale, stai lontano dal materiale del preprocessore. Ottenere che funzioni all'interno dell'IDE e del debugger Matlab (che sono molto utili) richiederebbero hack profondi e terribili.

+4

Mi piacerebbe * usare * la roba OOP introdotta nelle nuove versioni di Matlab, ma rende le cose ** debolmente lente ** nei nostri test. (L'esecuzione di una funzione * simple * 100.000 volte è passata da 0,0837 secondi a 2,3689 secondi quando si passa da funzioni annidate a roba OOP.) La maggior parte delle cose che scriviamo deve essere abbastanza ottimizzata, in modo che l'overhead sia piuttosto scoraggiante. –

+0

(Posso postare il codice se lo desideri.) –

+0

Ti ho sentito. (Vedi le altre prestazioni Q collegate su OOP.) Lo uso con parsimonia, per lo stesso motivo. Puoi mescolare e abbinare: mettere le costanti in un classdef per l'organizzazione e mantenere il resto del codice in funzioni o OOP vecchio stile (più veloce). L'overhead è per chiamata; l'introduzione di OOP non rende più lento il codice non OOP esistente. Tirare la costante in una variabile locale prima di entrare nei loop stretti e potrebbe andare tutto bene. Escludendo, le funzioni che restituiscono valori costanti sono il modo idiomatico pre-2008a di fare costanti e cosa suggerirei. –

7

MATLAB non ha un equivalente const preciso. Raccomando NON usare global per le costanti - per prima cosa, devi assicurarti che siano dichiarate ovunque tu voglia usarle. Vorrei creare una funzione che restituisce il valore (s) che si desidera. Potresti dare un'occhiata a this blog post per alcune idee.

0

Non chiamare una costante utilizzando myClass.myconst senza creare prima un'istanza! A meno che la velocità non sia un problema. Avevo l'impressione che la prima chiamata a una proprietà costante avrebbe creato un'istanza e che tutte le chiamate future avrebbero fatto riferimento a tale istanza, (Properties with Constant Values), ma non credo più che sia così. Ho creato una funzione di prova di base di forma:

tic; 
for n = 1:N 
    a = myObj.field; 
end 
t = toc; 

Con le classi definite come:

classdef TestObj 
    properties 
     field = 10; 
    end 
end 

o:

classdef TestHandleObj < handle 
    properties 
     field = 10; 
    end 
end 

o:

classdef TestConstant 
    properties (Constant) 
     field = 10; 
    end 
end 

Per diverso casi di oggetti, oggetti maniglie, oggetti nidificati ecc. (così come le operazioni di assegnazione). Si noti che questi erano tutti scalari; Non ho studiato matrici, celle o caratteri. Per N = 1.000.000 miei risultati (per il tempo trascorso totale) sono stati:

Access(s) Assign(s) Type of object/call 
    0.0034 0.0042 'myObj.field' 
    0.0033 0.0042 'myStruct.field' 
    0.0034 0.0033 'myVar'     //Plain old workspace evaluation 
    0.0033 0.0042 'myNestedObj.obj.field' 
    0.1581 0.3066 'myHandleObj.field' 
    0.1694 0.3124 'myNestedHandleObj.handleObj.field' 
29.2161   - 'TestConstant.const'  //Call directly to class(supposed to be faster) 
    0.0034   - 'myTestConstant.const' //Create an instance of TestConstant 
    0.0051 0.0078 'TestObj > methods'  //This calls get and set methods that loop internally 
    0.1574 0.3053 'TestHandleObj > methods' //get and set methods (internal loop) 

Ho anche creato una classe Java e corse un test simile:

12.18  17.53  'jObj.field > in matlab for loop' 
    0.0043 0.0039 'jObj.get and jObj.set loop N times internally' 

L'overhead nel chiamare l'oggetto Java è alto, ma all'interno dell'oggetto, le semplici operazioni di accesso e assegnazione avvengono velocemente come gli oggetti MATLAB regolari. Se si desidera il comportamento di riferimento per l'avvio, Java potrebbe essere la strada da percorrere. Non ho studiato le chiamate agli oggetti all'interno di funzioni annidate, ma ho visto alcune cose strane. Inoltre, il profiler è spazzatura quando si tratta di molte cose, ed è per questo che sono passato a salvare manualmente i tempi.

Per riferimento, la classe Java utilizzata:

public class JtestObj { 
    public double field = 10; 

    public double getMe() { 
     double N = 1000000; 
     double val = 0; 
     for (int i = 1; i < N; i++) { 
      val = this.field; 
     } 

     return val; 
    } 

    public void setMe(double val) { 
     double N = 1000000; 
     for (int i = 1; i < N; i++){ 
      this.field = val; 
     } 
    } 
    } 

In una nota correlata, ecco un link a una tabella di costanti NIST: ascii table e una funzione MATLAB che restituisce una struct con quei valori elencati: Matlab FileExchange

+0

Ho notato che Andrew ha recentemente effettuato un aggiornamento sulla velocità di Matlab. Probabilmente più utile del mio: http://stackoverflow.com/questions/1693429/is-matlab-oop-slow-or-am-i-doing-something-wrong/1745686#1745686 –

1

Il mio modo di trattare con le costanti che voglio passare ad altre funzioni è quello di utilizzare una struttura:

% Define constants 
params.PI = 3.1416; 
params.SQRT2 = 1.414; 

% Call a function which needs one or more of the constants 
myFunction(params); 

non è pulito come i file header C, ma fa il lavoro ed evita i globals MATLAB. Se si desidera che le costanti siano tutte definite in un file separato (ad es. GetConstants.m), che sarebbe anche facile:

params = getConstants(); 
0

Io uso uno script con semplici costanti nelle capitali e includo Teh copione in altri script tr = che li Beed.

LEFT = 1; 
DOWN = 2; 
RIGHT = 3; etc. 

Non mi interessa che non siano costanti. Se scrivo "SINISTRA = 3", allora io sono semplicemente stupido e comunque non c'è cura contro la stupidità, quindi non mi preoccupo. Ma odio davvero il fatto che questo metodo ingombra il mio spazio di lavoro con variabili che non avrei mai dovuto ispezionare. Inoltre, non mi piace usare il sizing come "turn (MyConstants.LEFT)" perché questo rende dichiarazioni più lunghe come una zillion di caratteri, rendendo il mio codice non leggibile.

Quello che mi serve non è una variabile ma una possibilità di avere costanti pre-compilatore. Cioè: stringhe che vengono sostituite da valori appena prima dell'esecuzione del codice. Questo è come dovrebbe essere. Una costante non dovrebbe essere una variabile. Serve solo a rendere il tuo codice più leggibile e mantenibile. MathWorks: PER FAVORE, PER FAVORE, PER FAVORE. Non può essere così difficile implementarlo. . .