Les constantes de MATLAB

j'ai acquis un tas de code MATLAB et j'ai remarqué un tas de "nombres magiques" dispersés autour du code. Typiquement, j'aime faire ces constantes dans des langues comme C, Ruby, PHP, etc. En Googlant ce problème, j'ai trouvé que la façon "officielle" d'avoir des constantes est de définir des fonctions qui renvoient la valeur constante. Semble kludgey, d'autant plus que MATLAB peut être délicat en permettant plus d'une fonction par fichier.

est-ce vraiment la meilleure option?

je suis tenté d'utiliser / faire quelque chose comme le préprocesseur C pour faire ceci pour moi. (J'ai trouvé que quelque chose appelé mpp a été fait par quelqu'un d'autre dans une situation semblable, mais il semble abandonné. Le code ne se compile pas, et je ne suis pas sûr qu'il réponde à mes besoins.)

39
demandé sur chappjc 2009-11-21 02:24:16

8 réponses

d'habitude je définis juste une variable avec UPPER_CASE et place près du haut du fichier. Mais vous devez prendre la responsabilité de ne pas changer sa valeur.

sinon vous pouvez utiliser les classes MATLAB pour définir les constantes nommées.

19
répondu Amro 2012-10-04 13:33:21

Matlab a des constantes maintenant. Le nouveau style (r2008a+) "classdef" de Matlab OOP vous permet de définir des propriétés de classe constante. C'est probablement la meilleure option si vous n'avez pas besoin de rétrocompatibilité avec les vieux Matlabs. (Ou, à l'inverse, est une bonne raison d'abandonner la rétrocompatibilité.)

Les définit dans une classe.

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

puis les référencer à partir de tout autre code en utilisant le point-qualification.

>> disp(MyConstants.SECONDS_PER_HOUR)
        3600

voir la Documentation Matlab pour la " programmation orientée objet "sous" Guide de L'utilisateur " pour tous les détails.

il y a quelques petites gotchas. Si le code essaie accidentellement d'écrire à une constante, au lieu d'obtenir une erreur, il créera une structure locale qui masquera la classe des 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              

mais les dégâts sont locaux. Et si vous voulez être minutieux, vous pouvez vous protéger contre cela en appelant le constructeur MyConstants () au début d'une fonction, ce qui oblige Matlab à l'analyser comme un nom de classe dans cette portée. (IMHO ceci est exagéré, mais il est là si vous le voulez.)

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

l'autre gotcha est que les propriétés et les méthodes de classedef, en particulier la statique comme celle-ci, sont lentes. Sur ma machine, lire cette constante est environ 100 fois plus lent que d'appeler une fonction simple (22 usec contre 0.2 usec, voir cette question ). Si vous utilisez une constante à l'intérieur d'une boucle, le copier sur une variable locale avant entrer dans la boucle. Si pour une raison quelconque vous devez utiliser l'accès direct des constantes, allez avec une fonction simple qui renvoie la valeur.

pour votre santé mentale, restez loin des trucs de préprocesseur. Pour que cela fonctionne à l'intérieur de L'interface et du débogueur (qui sont très utiles), il faudrait des piratages profonds et terribles.

35
répondu Andrew Janke 2017-05-23 12:01:31

MATLAB n'a pas d'équivalent exact de const. Je recommande de ne PAS utiliser mondiale pour les constantes - pour une chose, vous devez vous assurer qu'ils sont déclarés partout où vous voulez les utiliser. Je voudrais créer une fonction qui retourne la valeur(s) que vous souhaitez. Vous pouvez consulter ce billet de blog pour quelques idées.

7
répondu Loren 2010-10-21 18:28:02

Vous pourriez certaines de ces réponses Comment puis-je créer des types énumérés dans MATLAB? utile. Mais en bref, il n'y a pas de façon "une seule ligne" de spécifier des variables dont la valeur ne devrait pas changer après le réglage initial dans MATLAB.

3
répondu mtrw 2017-05-23 12:01:31

de quelque façon que vous le fassiez, ce sera encore un peu un kludge. Dans les projets antérieurs, mon approche était de définir toutes les constantes comme des variables globales dans un fichier script, d'invoquer le script au début de l'exécution du programme pour initialiser les variables, et d'inclure des déclarations "global MYCONST;" au début de toute fonction qui devait utiliser MYCONST. Que cette approche soit supérieure ou non à la façon "officielle" de définir une fonction pour retourner une valeur constante est une question de l'opinion que l'on pourrait dire de toute façon. Aucune de ces manières est idéal.

2
répondu 2009-11-20 23:56:17

ma façon de traiter les constantes que je veux passer à d'autres fonctions est d'utiliser une structure:

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

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

il n'est pas aussi propre que les fichiers d'en-tête C, mais il fait le travail et évite les globals MATLAB. Si vous voulez les constantes toutes définies dans un fichier séparé (par exemple, getConstants.m), qui serait aussi facile:

params = getConstants();
1
répondu David Steinhauer 2014-11-26 20:07:50

N'appelez pas une constante en utilisant myClass.myconst sans créer d'abord une instance! Sauf si la vitesse n'est pas un problème. J'avais l'impression que le premier appel à une propriété constante créerait une instance et que tous les appels futurs feraient référence à cette instance, ( propriétés avec valeurs constantes ), mais je ne crois plus que ce soit le cas. J'ai créé une fonction de test très basique de la forme:

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

avec des classes définies comme:

classdef TestObj
    properties
        field = 10;
    end
end

ou:

classdef TestHandleObj < handle
    properties
        field = 10;
    end
end

ou:

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

pour différents cas d'objets, handle-objects, objets imbriqués, etc. (ainsi que les opérations de cession). Notez qu'il s'agissait de scalaires; Je n'ai pas enquêté sur les tableaux, les cellules ou les chars. Pour N = 1 000 000 mes résultats (pour le temps total écoulé) étaient:

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)

j'ai aussi créé une classe Java et j'ai fait un test similaire:

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

l'appel de L'objet Java est haut, mais à l'intérieur de l'objet, des opérations simples d'accès et d'assignation se produisent aussi vite que des objets matlab réguliers. Si vous voulez que le comportement de référence démarre, Java peut être la solution. Je n'ai pas enquêté sur les appels d'objets dans les fonctions imbriquées, mais j'ai vu des choses bizarres. En outre, le profileur est un déchet quand il s'agit de beaucoup de ces choses, ce qui est pourquoi je suis passé à sauver manuellement les temps.

pour référence, la classe Java utilisée:

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

Sur une note connexe, voici un lien vers un tableau de NIST constantes: table ascii et une fonction matlab qui renvoie une structure avec celles qui figurent sur les valeurs: Matlab FileExchange

0
répondu Nathan Donnellan 2012-02-24 18:02:31

j'utilise un script avec des constantes simples dans les majuscules et inclure le script teh dans d'Autres scripts tr=qui les biffe.

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

cela ne me dérange pas qu'ils ne soient pas constants. Si j'écris "gauche=3" alors je serai tout simplement stupide et il n'y a pas de remède contre la stupidité de toute façon, donc je ne me donne pas la peine. Mais je déteste le fait que cette méthode encombre mon espace de travail avec des variables que je n'aurais jamais à inspecter. Et je n'aime pas non plus utiliser sothing comme "tour(MyConstants.Gauche) " parce que cela fait des déclarations plus longues comme un zillion de chars large, ce qui rend mon code illisible.

ce dont j'aurais besoin n'est pas une variable mais une possibilité d'avoir de vraies constantes de pré-compilateur. Qui est. les chaînes sont remplacés par des valeurs juste avant d'exécuter le code. C'est comme ça que ça devrait être. Un constante doit pas être une variable. Il est seulement destiné à rendre votre code plus lisible et maintenable. MathWorks: S'il vous plaît, S'il vous plaît, S'il vous plaît. Il ne peut pas être difficile à mettre en œuvre. . .

0
répondu jasper van casteren 2018-02-08 13:04:13