2009-11-20 23 views
39

He llegado a ser propietario de un montón de código de MATLAB y he notado un montón de "números mágicos" dispersos sobre el código. Normalmente, me gusta hacer esas constantes en lenguajes como C, Ruby, PHP, etc. Al buscar en Google este problema, encontré que la forma "oficial" de tener constantes es definir funciones que devuelven el valor constante. Parece kludgey, especialmente porque MATLAB puede ser complicado cuando permite más de una función por archivo.Constantes en MATLAB

¿Es esta realmente la mejor opción?

Estoy tentado de usar/hacer algo como el preprocesador C para hacer esto por mí. (Encontré que algo llamado mpp fue hecho por alguien más en una situación similar, pero parece abandonado. El código no compila, y no estoy seguro si satisfaría mis necesidades)

Respuesta

19

Normalmente solo defino una variable con UPPER_CASE y la coloco cerca de la parte superior del archivo. Pero debes tomar la responsabilidad de no cambiar su valor.

De lo contrario, puede use MATLAB classes para definir las constantes con nombre.

+6

Normalmente utilizo una clase MATLAB para mantener todos mis parámetros configurables. Esto también le brinda la posibilidad de crear múltiples configuraciones e intercambiarlas fácilmente. Incluso puede crear una serie de configuraciones e iterar a través de la matriz, ejecutando su código de prueba en cada configuración sucesivamente. – bta

2

Puede que algunos de estas respuestas How do I create enumerated types in MATLAB? útil. Pero, en resumen, no hay una forma de "una sola línea" de especificar variables cuyo valor no debería cambiar después de la configuración inicial en MATLAB.

2

De cualquier manera que lo hagas, seguirá siendo un poco complicado. En proyectos anteriores, mi enfoque era definir todas las constantes como variables globales en un archivo de script, invocar el script al comienzo de la ejecución del programa para inicializar las variables, e incluir "MYCONST global"; declaraciones al comienzo de cualquier función que necesite usar MYCONST. Si este enfoque es superior a la forma "oficial" de definir una función para devolver un valor constante es una cuestión de opinión que uno podría discutir de cualquier manera. De ninguna manera es ideal.

34

Matlab tiene constantes ahora. El estilo más nuevo (R2008a +) "classdef" de Matlab OOP le permite definir propiedades de clase constante. Esta es probablemente la mejor opción si no requiere compatibilidad con versiones anteriores de Matlabs antiguo. (O, por el contrario, es una buena razón para abandonar la compatibilidad con versiones anteriores.)

Defínalos en una clase.

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

A continuación, consúltelos desde cualquier otro código mediante la calificación de punto.

>> disp(MyConstants.SECONDS_PER_HOUR) 
     3600 

Consulte la documentación de Matlab para "Programación orientada a objetos" en la "Guía del usuario" para obtener todos los detalles.

Hay un par de inconvenientes menores. Si el código accidentalmente intenta escribir en una constante, en lugar de obtener un error, creará una estructura local que enmascara la clase de constantes.

>> 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    

Pero el daño es local. Y si desea ser minucioso, puede protegerse contra esto llamando al constructor MyConstants() al comienzo de una función, lo que obliga a Matlab a analizarlo como un nombre de clase en ese ámbito. (En mi humilde opinión esto es una exageración, pero está ahí si lo desea.)

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

El otro Gotcha es que las propiedades y métodos classdef, especialmente la estática como este, son lentos. En mi máquina, leer esta constante es aproximadamente 100 veces más lento que llamar a una función simple (22 usec contra 0.2 usec, vea this question).Si está utilizando una constante dentro de un bucle, cópielo a una variable local antes de ingresar al bucle. Si por alguna razón debe usar el acceso directo de las constantes, vaya con una función simple que devuelva el valor.

Por el bien de su cordura, aléjese de las cosas del preprocesador. Hacer que funcione dentro del Matlab IDE y el depurador (que son muy útiles) requeriría hacks profundos y terribles.

+4

Me gustaría * usar * las cosas OOP introducidas en las versiones más nuevas de Matlab, pero hace las cosas ** deprimentemente lentas ** en nuestras pruebas. (Ejecutar una función * simple * 100,000 veces pasó de tomar 0.0837 segundos a 2.3689 segundos al cambiar de funciones anidadas a OOP). La mayoría de las cosas que escribimos deben estar bastante optimizadas, por lo que la sobrecarga es bastante disuasoria. –

+0

(Puedo publicar el código si lo desea) –

+0

Te escucho. (Ver los otros Q vinculados en el rendimiento OOP.) Lo uso con moderación, por la misma razón. Puede mezclar y combinar: ponga constantes en un classdef para organización, y mantenga el resto del código en funciones o estilo antiguo (más rápido) OOP. Gastos generales es por llamada; la introducción de OOP no hace que el código no OOP existente sea más lento. Tire de la constante en una variable local antes de ingresar bucles apretados y puede estar bien. Salvo eso, las funciones que devuelven valores constantes son la forma idiomática previa a 2008a de hacer constantes, y lo que yo sugeriría. –

7

MATLAB no tiene un equivalente exacto const. Recomiendo NO utilizar global para las constantes, por un lado, debe asegurarse de que estén declaradas donde quiera que las use. Crearía una función que devuelva los valores que desea. Puede consultar this blog post para obtener algunas ideas.

0

¡No llame a una constante usando myClass.myconst sin crear primero una instancia! A menos que la velocidad no sea un problema. Tenía la impresión de que la primera llamada a una propiedad constante crearía una instancia y luego todas las llamadas futuras harían referencia a esa instancia, (Properties with Constant Values), pero ya no creo que ese sea el caso. He creado una función de prueba muy básico de la forma:

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

Con clases definidas como:

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 

Para diferentes casos de objetos, objetos de manejo, objetos anidados etc. (así como las operaciones de asignación). Tenga en cuenta que estos fueron todos escalares; No investigué matrices, celdas o caracteres. Para N = 1.000.000 mis resultados (por el tiempo transcurrido total) fueron:

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) 

También creé una clase Java y se pasó una prueba similar:

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

La sobrecarga de llamar al objeto Java es alta, pero dentro del objeto, las operaciones simples de acceso y asignación ocurren tan rápido como los objetos regulares de Matlab. Si desea que arranque el comportamiento de referencia, Java puede ser el camino a seguir. No investigué llamadas a objetos dentro de funciones anidadas, pero he visto algunas cosas raras. Además, el generador de perfiles es basura cuando se trata de muchas de estas cosas, por lo que pasé a guardar manualmente los tiempos.

Como referencia, la clase Java utilizadas:

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; 
     } 
    } 
    } 

En una nota relacionada, aquí hay un enlace a una tabla de constantes NIST: ascii table y una función de Matlab que devuelve una estructura con esos valores enumerados: Matlab FileExchange

+0

Noté que Andrew recientemente hizo una actualización sobre la velocidad de Matlab. Probablemente más útil que el mío: http://stackoverflow.com/questions/1693429/is-matlab-oop-slow-or-am-i-doing-something-wrong/1745686#1745686 –

1

Mi manera de hacer frente a las constantes que quiero pasar a otras funciones es utilizar una estructura:

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

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

no es tan limpio como los archivos de encabezado C, pero hace el trabajo y evita MATLAB globales. Si desea las constantes definidas en un archivo separado (por ejemplo, getConstants).m), que también sería fácil:

params = getConstants(); 
0

utilizo un guión con constantes simples en las capitales y incluyo teh escritura de guiones en otras = tr que les BEED.

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

No me importa que no sean constantes. Si escribo "IZQUIERDA = 3", entonces seré simple y estúpido y de todos modos no hay cura contra la estupidez, así que no me molesto. Pero realmente odio el hecho de que este método desordene mi espacio de trabajo con variables que nunca tendría que inspeccionar. Y tampoco me gusta usar sothing como "turn (MyConstants.LEFT)" porque esto hace que las afirmaciones más largas, como un trillón de caracteres, hagan que mi código no sea legible.

Lo que necesitaría no es una variable sino la posibilidad de tener constantes reales de precompilador. Es decir: cadenas que se reemplazan por valores justo antes de ejecutar el código. Así es como debería ser. Una constante no debería ser una variable. Solo está destinado a hacer que su código sea más legible y mantenible. MathWorks: POR FAVOR, POR FAVOR, POR FAVOR. No puede ser tan difícil implementar esto. . .