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.)
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.
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.
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.
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.
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.
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();
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
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. . .