a = 1 
ce qui montre que la variable existe dans les environnements d'exécution des fonctions, mais pas dans l'environnement d'exécution du programme principal.
On peut tester si une variable "a" est globale avec la commande
isglobal(a)
Gestion des erreurs.
L'exécution d'une fonction, et en particulier un calcul, peut générer une erreur, ce qui va interrompre le déroulement du programme. On peut éviter ceci de plusieurs manières :
Blinder un programme, cela consiste essentiellement à vérifier que le contenu des variables est conforme à leur utilisation. C'est en particulier important lorsqu'il y a une entrée de données : lecture d'un fichier ou bien saisie au clavier. Par exemple, lorsque l'on demande à l'utilisateur d'entrer un nombre entier, on vérifie qu'il s'agit bien d'un entier, et si ce n'est pas le cas, on le signale et on redemande une nouvelle saisie.
On peut donc vérifier
Vérifier l'existence de la variable.
La commande
exists(nom_de_variable)
où codice_170 est une chaîne de caractères (par exemple codice_171), renvoie codice_172 si la variable existe, codice_173 sinon. Si l'on précise le paramètre codice_174, la commande vérifie alors si la variable existe "en local". Par exemple : 
exists("X", "l")
placé au sein d'une fonction permet de vérifier si la variable codice_175 existe au sein de cette fonction ; s'il s'agit d'une variable passée en paramètre, cela permet de vérifier que l'appel de la fonction contient bien cette variable (faute de quoi la fonction risquerait d'utiliser la valeur d'une variable globale de même nom).
On peut aussi utiliser la fonction
isdef("X")
isdef("X", "l")
où codice_175 est la variable ; cette fonction renvoie un booléen.
Dans une fonction, on peut récupérer le nombre d'arguments d'entrée avec la commande
nb_arg_entree = argn(2)
puis à tester la valeur de codice_177. On pourra par exemple voir la définition de la fonction codice_178 en tapant codice_179 dans la ligne de commande.
Une autre manière de faire consiste à initialiser la variable avec un contenu vide — codice_180 — ou bien particulier — codice_181 —, puis à tester la valeur de la variable avant de l'utiliser (voir plus loin).
Vérifier le format de la variable.
Scilab propose des fonctions de test codice_182 (« est-ce… ? »), c'est-à-dire des fonctions renvoyant des valeurs booléennes codice_183 (vrai) ou codice_184 (faux) :
Vérifier le contenu de la variable.
Rappelons les opérations de comparaison de valeurs : codice_204, codice_205, codice_206, codice_207, codice_208. La commande codice_209 est vraie si les "n" valeurs sont toutes égales.
Scilabe propose également les commandes :
Générer un message d'erreur.
Lorsque l'on détecte un problème, on peut générer soi-même une erreur, avec la commande codice_213 (déjà présentée), ou bien un message d'avertissement, avec codice_214.
On peut personnaliser le message en indiquant la valeur de la variable illégale. Pour cela, il faut soit composer une chaîne de caractères contenant la variable, par exemple
texte_erreur = "fonction f : valeur de l"argument "+string(X)+" illégale.";
error(texte_erreur)
ou bien utiliser les commandes de type « langage C », mais il faut alors être sûr du format de la variable :
texte_erreur = "fonction f : valeur de l'argument %d illégale.";
error(msprintf(texte, X))
Notons qu'un certain nombre de termes standard peuvent être traduits automatiquement selon la langue définie sur le système (paramètres de régionalisation, "localisation") ; la commande codice_215 permet de traduire automatiquement les termes, et d'adapter la typographie (par exemple, mettre une espace devant les deux-points et points-virgules en français).
Dérouter une erreur.
Pour « dérouter » une erreur, c'est-à-dire éviter que le programme ne s'interrompe, on utilise la fonctions codice_216. La fonction codice_217 permet ensuite de tester si une erreur est survenue. On peut ne s'intéresser qu'à un type d'erreur : codice_218 et codice_219 ("n" > 0) pour l'erreur "n" (voir la "table des erreurs").
On peut indiquer à codice_220 une action faire en cas d'erreur :
errcatch(n, "action")
où "action" vaut :
Enfin, on peut indiquer ce que doit faire Scilab en cas d'erreur de calcul, avec la commande codice_228 :
Encapsuler le code problématique.
Certaines partie de code sont plus susceptibles que d'autre de produire des erreurs. C'est par exemple le cas d'une entrée-sortie hasardeuse — saisie au clavier, lecture d'un fichier volumineux —, ou bien de l'utilisation d'une opération instable — valeur pouvant provoquer un dépassement ou un soupassement… Pour gérer cette situation, on peut utiliser une structure codice_232 :
try
 <instructions "normales">
catch
 <instructions exécutées en cas d'erreur>
end
[message_erreur, numero_erreur] = lasterror(%t) // enregistrement de l'erreur
<suite du script>
Si le code problématique est court, on peut également l'encapsuler dans une comande codice_239 avec l'option codice_240.
numero_erreur = execstr("<instructions normales>", "errcatch", "message d.erreur")
S'il n'y a pas d'erreur, le numéro d'erreur est 0.
Bibliothèque de fonctions.
Il est possible de créer une bibliothèque de fonctions "(library)". Cela permet à plusieurs programmes de partager les mêmes fonctions. L'avantage est double :
L'inconvénient est qu'une modification a un impact sur tous les programmes, ce qui peut obliger à une gestion des différentes versions d'une fonction. Cet inconvénient est aussi un avantage : une erreur dans une fonction va avoir un impact sur tous les programmes l'utilisant, donc va être détectée plus rapidement.
La bibliothèque peut aussi contenir des variables.
On peut simplement définir un fichier codice_4 et l'appeler avec codice_242 ou codice_9 comme indiqué précédemment. Mais Scilab fournit également une gestion spécifique des bibliothèques.
Le fait de recourir à une bibliothèque plutôt qu'à un fichier codice_4 permet entre autres de gérer des fonctions ayant le même nom, par exemple des fonctions réalisant la même chose mais avec un algorithme différent — on peut raisonnablement se demander l'intérêt de la chose, et souligner les problèmes que cela pose (est-on sûr de savoir exactement quelle fonction l'on utilise ?), mais c'est une possibilité. Par exemple, si l'on a une fonction codice_245 définie dans deux bibliothèques codice_246 et codice_247, on peut alors charger les deux bibliothèques et utiliser codice_248 ou codice_249 ; si l'on utilise codice_245 tout court, c'est alors "a priori" la dernière bibliothèque chargée qui est utilisée.
Structure d'une bibliothèque.
Pour Scilab, une bibliothèque est :
Création d'une bibliothèque.
Le programme suivant :
// Création de la bibliothèque persolib
clear();
// Paramètres de la bibliothèque
cheminbiblio = ".../persolib/";
// Fonctions
function [y] = gauss(mu, sigma, x)
 // fonction gaussienne
 // mu : espérance
 // sigma : écart type
 y = 1/(sigma * sqrt(2*%pi))*exp(-1/(2*sigma^2)*(x - mu).^2)
endfunction
function [y] = lorentz(x0, Gamma, x)
 // fonction lorentzienne
 // x0 : position du sommet
 // mu : gamma : largeur à mi-hauteur (FWHM)
 HWHM = Gamma/2; // facilite l'expression
 y = ((HWHM)/%pi)*((x - x0).^2 + HWHM^2).^(-1)
endfunction
// Constantes
unsurpi = 1/%pi;
// Création de la bibliothèque
chdir(cheminbiblio)
// compilation et enregistrement des fonctions
save("gauss.bin", gauss)
save("lorentz.bin", lorentz)
save("unsurpi.bin", unsurpi)
// creation de l'index
mputl(["gauss" ; "lorentz" ; "unsurpi"], "names")
Utilisation d'une bibliothèque.
Le programme suivant :
// Utilisation de la bibliothèque persolib
clear();
// Paramètres de la bibliothèque
cheminbiblio = ".../persolib/";
// Déclaration et chargement de la bibliothèque
mabibliotheque = lib(cheminbiblio);
// Utilisation des fonctions
X = -3:0.1:3;
Yg = gauss(1,1,X);
Yl = lorentz(1,1,X);
plot(X,Yg)
plot(X,Yl)
disp(unsurpi)
Commandes sur les bibliothèques.
Si l'on tape simplement le nom de la variable dans laquelle on a déclarée la bibliothèque (ici codice_265), Scilab retourne :
La fonction codice_268 a le même effet, mais permet de mettre les valeurs retournées dans des variables, par exemple avec
[fcts, chem] = libraryinfo(mabibliotheque)
la variable codice_269 est une matrice de chaînes de caractères contenant les noms des fonctions, et la variable codice_270 est une chaîne de caractères contenant le chemin d'accès.
La fonction codice_271 teste si la bibliothèque est déclarée.
La fonction codice_272 efface les fonctions et variables définies par la bibliothèque.
La fonction codice_273 indique dans quelle bibliothèque se trouve une fonction (mais pas une variable). Par exemple, codice_274 retourne codice_265.
La fonction codice_276 indique la liste des bibliothèques chargées.
Lancement d'un programme.
Un programme (fichier codice_1) peut être lancé depuis Scinotes, en cliquant sur le menu Execute puis en choisissant Load into Scilab. On peut aussi utiliser la combinaison de touches codice_278.
On peut aussi l'exécuter à partir de l'interpréteur de commandes, avec codice_279. Le paramètre « -1 » permet de ne pas afficher les lignes exécutées.
Optimisation d'un programme.
Si un programme est destiné à traiter des données volumineuses, il devient important de s'intéresser à la durée d'exécution. Plusieurs outils permettent de comparer les durées d'exécution et ainsi de faire des choix entre plusieurs solutions possibles pour effectuer une tâche (réaliser une fonction, au sens large de fonctionnalité).
Tout d'abord, Scilab peut lire l'horloge du système. La commande codice_280 retourne un vecteur ligne de 6 éléments indiquant :
Mais cela ne permet d'avoir une précision que de la seconde. On peut avoir les millisecondes avec :
instant = getdate();
instant(9) + instant(10)/1000
en effet, la commande codice_281 renvoie un vecteur dont la neuvième composante est la seconde (nombre entier entre 0 et 59) et la dixième composante est la milliseconde (nombre entier entre 0 et 999).
Scilab dispose également d'un chronomètre :
L'exécution d'une fonction externe peut être caractérisé par son « profil ». Le profil est une matrice ayant le même nombre de lignes que la fonction (la 1 ligne est celle contenant la commande codice_145). Pour chaque ligne, le profil contient 3 colonnes :
La commande codice_285 « prépare » la fonction : cette commande est nécessaire pour extraire ensuite le profil. La commande codice_286 indique le « profile de la fonction ». 
La commande codice_287 met en correspondance ces données et les instructions de la fonctions. La commande codice_288 synthétise le profil sous la forme d'un histogramme.
Conseils
Un programme rapide est un programme qui effectue peu d'opérations. Le premier point est donc d'utiliser un algorithme « économe ». Par exemple, pour le calcul de la valeur d'un polynôme, on utilisera la méthode de Horner ; dans le même ordre d'idées, pour calculer les carrés des éléments d'une matrice réelle, il vaut mieux utiliser codice_289 que codice_290. L'algorithme le plus économe peut dépendre de la structure des données, c'est le cas notamment des algorithmes de tri — voir par exemple le tri par tas et le tri rapide.
Certaines opérations sont plus gourmandes que d'autres ; pour de gros volumes de données, il peut être intéressant de ne pas utiliser l'écriture « naïve » de ce que l'on veut calculer. Par exemple, la division utilise plus d'opérations que la multiplication, ainsi, si l'on remplace
par
on remplace deux divisions par une division et cinq multiplications. Ceci est favorable pour de gros volumes de données, comme le montre l'exemple suivant
// Génération des données
n = 9e5;
a = rand(n, 1);
b = rand(n, 1) + 1; // +1 garantit que l'on n'a pas de zéro
c = rand(n, 1);
d = rand(n, 1) + 1;
// Calcul naïf
tic();
e = a./b;
f = c./d;
t1 = toc();
// Calcul optimisé
tic();
dn = 1 ./(b.*d);
E = a.*d.*dn;
F = c.*b.*dn;
t2 = toc();
// Comparaison
disp(t1, t2);
Par contre, les erreurs d'arrondis ne sont pas les mêmes, les résultats peuvent donc être légèrement différents, et il faut vérifier que cela ne cause pas d'erreur de dépassement.
Lorsque Scilab effectue un calcul, il commence par vérifier le type de données et les dimensions de la matrice sur laquelle il travaille — rappelons qu'un nombre est une matrice 1×1 —, afin de savoir comment il va mener le calcul (arbre de décision). Par exemple, pour effectuer une addition codice_291, Scilab effectue une dizaine d'opérations préalables :
Si l'on a des calculs répétitifs à faire, il vaut donc mieux mettre les données dans une matrice et effectuer le calcul sur la matrice : ainsi, les opérations de contrôle et de décision ne seront faites qu'une seule fois.
De manière générale, un calcul est plus long qu'une opération de lecture/écriture en mémoire. Ainsi, si un calcul est répété, on a intérêt à stocker son résultat dans une variable, en particulier s'il s'agit d'un calcul long (par exemple sur une matrice). Si par exemple on utilise plusieurs fois sin(π/3), on a intérêt à créer la variable
sinPiSurTrois = sin(%pi/3)
et à utiliser cette variable, plutôt que de calculer à chaque fois la valeur.
Dans un tableau (matrice), si l'on s'attend à ce que des valeurs volumineuses (par exemple des nombre à virgule flottante à double précision) soient déplacées plusieurs fois, on peut créer une matrice de correspondance entre indices (donc ne contenant que des entiers), et faire les transferts uniquement à la fin ; ainsi, les opérations de lecture/écriture fréquentes se font sur des données peu volumineuses.
On voit que l'optimisation consiste fréquemment à trouver un équilibre entre volume de données et durée des opérations. Si l'on génère trop de données intermédiaires (dépassant la capacité de la mémoire vive), cela oblige le système d'exploitation à avoir recours à de la mémoire virtuelle "(swap)" et donc à faire des opérations de lecture et écriture sur disque dur (ou mémoire flash) qui ralentissent l'exécution.
Déverminage.
Pour déverminer (« débugger ») un programme, on peut :
Recommandations.
Les « bonnes pratiques de programmation » ont pour but de faciliter la conception et la maintenance des programmes. Cela inclue la possibilité de reprendre des programmes plusieurs années après, de les adapter aux nouvelles versions des logiciels, de réutiliser des bouts de code dans d'autres programme, que d'autres personnes réutilisent le code, l'adapte, … bref créer du code directement réutilisable sans modification "(boilerplate code)". Rappelons que 80 % du coût d'un bout de programme réside dans la maintenance et qu'au bout d'un certain temps, cette maintenance n'est en général plus faite par l'auteur original du code.
Scilab est un langage de calcul ; ces calculs s'appliquent à divers domaines : mécanique, optique, thermique, électronique, traitement du signal, biologie, géophysique, économie, … En général, les utilisateurs sont des spécialistes du domaine d'application (physiciens, biologistes, économistes, …) mais ne sont "pas" des informaticiens. Cette section a donc pour but de leur apporter quelques outils simples facilitant la programmation.
Exemple
Pour illustrer les concepts, nous allons prendre un exemple : vous êtes chargé par une entreprise de mécanique, faisant de l'usinage, d'évaluer les défauts lors de la réalisation d'une forme circulaire. Le client de l'entreprise demande à ce que l'arête d'une pièce forme un cercle, et vous êtes chargé de valider le fait que les imperfections sont dans les tolérances admises. Vous avez pour cela un nuage de points ("x", "y", "z") relevé sur la pièce réalisée.
Démarche projet.
Un programme est un projet. On doit donc lui appliquer les outils classiques d'un projet. Cela ne signifie pas nécessairement qu'il faille produire une documentation — notons que les commentaires d'un programme (voir ci après) "sont" une documentation, et que certains outils permettent de les extraire —, mais simplement qu'il faut se poser des questions et y répondre avant de commencer.
Définir les objectifs.
Un programme a un but, un objectif : il doit répondre aux attentes d'un utilisateur, qui est souvent le programmeur lui-même. Cette identité utilisateur = programmeur évite les incompréhensions liée à la transmission d'informations, mais peut mener à un manque de rigueur et donc à des difficultés.
La première étape consiste donc à recenser (par écrit ou dans sa tête) les besoins et l'objectif à atteindre. Pour un projet de calcul, c'est essentiellement :
Cette étape doit inclure des données de test permettant de valider le programme : on a des données pour lesquelles on connaît le résultat, ce qui permettra de vérifier que le programme fonctionne bien.
Dans des cas limites — par exemple gros volumes de données, ou bien si le programme doit communiquer avec d'autres dispositifs (comme des capteurs) —, il est nécessaire de prendre en compte l'environnement du programme :
Exemple
Pour notre exemple, nous avons donc :
Cette petite étude formelle met une chose en évidence : la demande est incomplète, il faut connaître la nature des tolérances.
Après dialogue avec le chargé d'affaire de l'entreprise et/ou le client, la forme circulaire sert à positionner une pièce mâle de forme cylindrique. Ce qui importe pour le client est que :
Le cahier des charges est validé par les parties (programmeur, chargé d'affaire, client).
Pour les tests, nous prévoyons de créer des données factices correspondant à un cercle parfait auquel on ajoute des défauts maîtrisés. Nous prévoyons un exemple devant passer le test en ayant des défauts justes inférieurs à la limite (mettons à 1 %), trois exemples ayant des défauts justes supérieurs à la limite (1 % également), chacun pour un type de défaut (orientation du plan, position du centre, écart à la circularité) et un exemple ayant les trois défauts.
Chercher des solutions.
La deuxième étape consiste à rechercher les solutions. Cela peut être une recherche bibliographique : trouver un algorithme adapté, ou un programme déjà existant et faisant globalement la même chose. Cela peut aussi être le développement de solutions originales. À l'issue de cette étape, il faut choisir la solution appliquée.
Une méthode consiste à partir du besoin exprimé sous la forme de fonctions, une fonction étant un verbe à la forme active avec un sujet et un complément. Cette fonction peut être découpée en sous-fonctions, et l'on continue ce découpage jusqu'à arriver à des fonctions élémentaires faciles à coder (que l'on sait réaliser d'une ou plusieurs manières). Voir "".
Le choix de cette solution est critique car il conditionne tout le reste. Il ne peut être pertinent que si les objectifs sont clairs. Notons que l'on peut dans un premier temps retenir une solution peu performante mais facile à programmer, ce qui permet d'avoir rapidement un résultat et avec moins de risques d'erreur ; puis, par la suite, développer une autre solution plus performante, la première solution servant de référence. La programmation modulaire (fractionnement en fonctions) facilite cette démarche : il suffit d'écrire une nouvelle fonction (sous-programme) ayant le même nom que l'ancienne, et de renommer l'ancienne fonction pour se laisser la possibilité de revenir en arrière.
Exemple
Les fonctions que l'on peut dégager sont :
On s'aperçoit que la fonction f1 peut être réalisée de trois manières très différentes (f1a, f1b et f1c) et que la fonction f4 dépend de qui va être chargé de mettre en œuvre le programme, il faut donc éclaircir ces points avec les personnes responsables des mesures.
Concernant la fonction f2.1 « le programme représente le cercle sous une forme exploitable numériquement » : dans l'espace, une courbe simple peut être définie par une équation ƒ("x", "y", "z") = 0. Il faut donc chercher dans la bibliographie (ou dans ses souvenirs) quel type de fonction décrit un cercle. Deux solutions sont possibles :
Concernant la première solution, il apparaît que le cercle est l'intersection d'une sphère et d'un plan, qui dans l'idéal passe par le centre de la sphère, on peut donc définir assez facilement le cercle par un système d'équations : si l'on appelle ("x"0, "y"0, "z"0) les cordonnées du centre et R le rayon, alors
Pour la deuxième solution, il faut déterminer un plan
puis un repère formula_5 dans ce plan, et donc l'équation du cercle
Concernant la fonction f2.2.1 « le programme détermine les écarts par rapport à la géométrie idéale », il apparaît que le problème présente deux « échelles » :
On voit donc qu'il faut déterminer dans un premier temps le cercle « parfait » le plus proche possible des points mesurés, et :
Il faut donc passer par une étape de régression pour déterminer le cercle global. Dans le cas d'une description par l'intersection d'une sphère et d'un plan, la régression consiste à déterminer huit facteurs ("x"0, "y"0, "z"0, R, "a", "b", "c", "d"), mais on a une équation liant trois facteurs, ce qui ramène à sept l nombre de facteurs indépendants. Dans le cas de la seconde description, on n'a que sept facteurs à déterminer ("x"0, "y"0, R, "a", "b", "c", "d"), mais on rajoute une étape de projection des points sur le plan.
Nous nous orientons vers la seconde description,en deux étapes, qui permet de séparer la résolution en deux étapes élémentaires.
La recherche bibliographique sur la régression circulaire nous indique qu'il y a deux types d'algorithmes :
Il y a peu de risque d'avoir des points aberrants(sauf erreur de mesure), mais les méthodes linéaires sont plus rapides et plus stables : les méthodes non-linéaires sont itératives, donc gourmandes en ressources et peuvent éventuellement diverger. Comme nous ne cherchons pas à déterminer un loi statistique, le fait que l'on ne minimise pas l'écart quadratique (donc l'écart type empirique) n'a pas d'importance. Nous retenons donc une méthode linéaire, celle de Kåsa et Coope.
Déterminer la structure du programme.
La troisième étape consiste à déterminer la structure du programme, son architecture. L'organisation des modules (fonctions) est obtenue à partir de l'analyse fonctionnelle. Il faut également choisir la structure des données (vecteur, matrice, liste, …) et déterminer des test permettant de savoir si chaque module fonctionne.
Les modules doivent être "hiérarchisés", ainsi :
Typiquement, l'interface avec l'utilisateur peut être importante, en particulier si le programme doit être utilisé par quelqu'un « n'y connaissant rien », mais doit être développée à la fin, lorsque le programme fonctionne.
Rappelons-le, ces trois étapes ne sont pas nécessairement formalisées. Elles ne se font pas non plus nécessairement d'un bloc avant de commencer à programmer : les besoins exprimés peuvent changer en cours de projet, on peut découvrir de nouvelles solutions, … C'est donc un processus dynamique.
Exemple
Ici, nous avons une structure assez simple, linéaire :
Les modules 2 à 8 sont incontournables. Par contre, les modules 1 et 9, correspondant aux interaction avec l'utilisateur, peuvent être réduit au minimum dans une première phase.
Écrire le programme, le tester et le maintenir.
La quatrième étape consiste à faire du codage unitaire : on code chaque fonction, chaque module. On vérifie que chaque fonction remplit bien son rôle, avec des données de test unitaire.
La cinquième étape consiste à intégrer les fonctions, à les mettre dans un même programme. On vérifie que l'on transmet bien les bonnes données aux bonnes fonctions.
La sixième et dernière étape consiste à vérifier que le programme fini fonctionne bien, grâce au données de test établies à la première étape, et qu'il "remplit bien les besoins" de l'utilisateur (qu'il suit le cahier des charges).
Là encore, ces trois étapes se font souvent de manière dynamique voire simultanée : au sein du programme, on écrit une nouvelle fonction, on la teste (test unitaire et test d'intégration), puis on passe à la fonction suivante. Mais on n'oubliera pas la hiérarchisation : les premières fonctions développées ne sont pas les premières à être utilisées chronologiquement dans le programme, mais les fonctions les plus importantes (le moteur avant l'interface).
Dernière étape ? En fait non, il reste l'étape la plus longue et la plus difficile : la maintenance, la correction des erreurs qui se révèlent lors des utilisations (déverminage). Cela commence par le nettoyage du code : on retire les morceaux de code obsolètes (« bouts d'essai »).
Bilan.
La démarche globale est donc :
Pour des projets importants et devant être formalisés, on pourra par exemple s'intéresser au .
Structure générale du script.
On recommande de mettre la plupart du code dans des fonctions ; le « programme principal », c'est-à-dire ce qui n'est pas dans les fonctions, devrait essentiellement se réduire à la définition des données de base et à l'appel des différentes fonctions. Un script a typiquement la forme suivante
Bloc de commentaires :
 nom du script
 versions du script, dates, auteurs
 version de Scilab utilisée, modules Atoms utilisés
 Objectif du script : fonctions qu'il rempli, son but, son rôle
 entrées et sorties : saisies clavier, affichages, fichiers, formats
Commandes préliminaires
 préparation de l'environnement
 p. ex. clc(), imports (input()) …
Constantes
 définition de variables constantes
Fonctions
 définition des fonctions
Programme principal
 appel des fonctions
Par ailleurs, les fonctions ne devraient pas être trop longues, typiquement une page d'écran maximum (environ 80 lignes) ; au-delà, il convient de scinder la fonction en plusieurs sous-fonctions. Elles ne devraient pas utiliser plus de 5 ou 10 variables locales ; au-delà, il faut repenser la fonction, par exemple la scinder.
Le code doit être
Voir "".
Du code explicite ….
Il faut utiliser les noms de fonctions et de variable voulant dire quelque chose. Les noms ne doivent contenir que des caractères alphanumériques (en particulier "pas" de tiret de soulignement "«  »"), et si possible même que des lettres non accentuées (les chiffres sont déconseillés) ; ils doivent commencer par une lettre en minuscule.
On peut utiliser des noms « bidons » (comme codice_305, codice_306) pour des variables utilisées sur de petites portions de programme. On utilise aussi fréquemment des noms « standard » : codice_307 (abscisse, inconnue d'une équation, variable d'une fonction), codice_33 (nombre entier évolutif : indice, compteur), codice_309 (nombre entier constant : quantité), …
Si l'on travaille en équipe, il est recommandé d'utiliser une nomenclature systématique (voir "Convention de nommage"). D'un point de vue de la forme, on peut par exemple recommander de former les noms de variable à partir de mots ; chaque changement de mot est indiqué par une capitale, les autres lettres étant en minuscules (codice_310). Concernant la composition du nom, on peut si nécessaire spécifier le type de variable (« matrice de réels », « vecteur ligne de chaînes de caractères », …) en début "ou" en fin de nom (mais toujours au même endroit), selon une convention commune (voir "Notation hongroise").
… Aéré ….
Il faut se limiter à une seule commande par ligne, voire plusieurs lignes pour une commande si la syntaxe est longue (utilisation de trois points codice_311), la coupure se faisant après une virgule ou avant un opérateur. La longueur d'une ligne ne devrait pas dépasser 80 caractères (l'éditeur SciNotes matérialise d'ailleurs cette limite). Mais l'on peut à l'inverse envisager de mettre deux commandes courtes et s'articulant sur une même ligne.
Par ailleurs, on laisse un ligne vide au sein d'une fonction pour séparer les grands blocs, et on laisse deux lignes vides entre les fonctions.
… En alinéa (« indenté ») ….
Des blancs en début de ligne marquent l'imbrication des commandes, en particulier à l'intérieur des délimiteurs de fonctions (codice_312), de boucles (codice_313, codice_314) et des exécutions conditionelles (codice_315). Par défaut, l'éditeur de Scilab (SciNotes) crée des alinéas de quatre espaces.
… Abondamment commenté ….
Chaque fonction doit comprendre une introduction (commentaires) expliquant ce qu'elle fait, la nature des variables qui lui sont passées et la nature des variable en sortie — ce qu'elles signifient et le type qu'elles doivent avoir (précondition à l'exécution de la fonction, voir "Programmation par contrat). Les grandes étapes de la fonctions doivent être indiquées par des commentaires.
De manière générale, les commentaires doivent donner un aperçu du code, les informations nécessaire à l'utilisation du code ainsi que celle relatives à la lecture et à la compréhension du code, et les raisons du choix d'une solution si son choix n'est pas trivial. Par contre, on évite de commenter ce qui est évident dans le code, ainsi que ce qui risque de devenir obsolète lorsque le code évolue.
Une ligne de commentaire commence par codice_316 (deux barres de fraction). Depuis la version 6.0.0, il est possible d'avoir des blocs de commentaire, c'est-à-dire un commentaire écrit sur plusieurs lignes sans avoir à commencer chaque ligne par la double barre de fraction : un bloc de commentaire commence par codice_317 (barre de fraction-astérisque) et se termine par codice_318 (astérisque-barre de fraction).
// Voici une ligne de commentaire
/* Voici un bloc de commentaire
c'est-à-dire un commentaire
écrit sur plusieurs lignes */
… Fractionné ….
Comme signalé plus haut, le code doit être découpé en fonction de moins de 80 lignes. Le programmeur doit tant que faire se peut utiliser des variables locales. À l'exception de quelques variables très générales, essentiellement des constantes, toutes les variables utilisées par une fonction doivent être définies dans la fonction, ou bien transmises comme paramètre.
Outre la facilité de maintenance, le fait de mettre du code dans des fonctions accélère l'exécution d'un script. En effet, les fonctions sont compilée en code intermédiaire "(bytecode)" ; cette opération — automatique — de compilation consiste d'une part à vérifier que la syntaxe est correcte, et d'autre part réorganise les commandes en notation polonaise inverse, mieux adaptée à l'exécution (qui passe par une pile).
Si certaines fonctions sont très générales, elle méritent de figurer dans un fichier codice_4 à part, appelé par la commande codice_242, voire dans une bibliothèque (voir ci-dessus).
… Et général.
De manière plus spécifique, pour Scilab, on peut recommander de faire des fonctions les plus générales possibles. Par exemple, une fonction numérique devrait être capable de traiter un nombre, mais aussi une matrice ; on peut ainsi définir un ensemble de définition de type codice_321 et appliquer directement codice_322. Si l'on a une fonction de deux variables X et Y, on peut générer deux matrices « grille » et ainsi avoir une carte de résultats f(X, Y), avec la fonction codice_323 (grille à "n" dimensions) :
X = vx1:pasx:vx2;
Y = vy1:pasy:vy2;
[X_matrice, Y_matrice] = ndgrid(X, Y);
f(X_matrice, Y_matrice)
On a ainsi
 X_matrice = [X(1) X(1) … X(1)
 X(2) X(2) … X(2)
 X(m) X(m) … X(m)]
 Y_matrice = [Y(1) Y(2) … Y(n)
 Y(1) Y(2) … Y(n)
 … … … Y(n)
 Y(1) Y(2) … Y(n)]
 f(X_matrice, Y_matrice) = [f(X(1),Y(1)) f(X(1),Y(2)) … f(X(1),Y(n))
 f(X(2),Y(1)) f(X(2),Y(2)) … f(X(2),Y(n))
 f(X(m),Y(1)) f(X(m),Y(2)) … f(X(m),Y(n))]
À titre d'exercice, on peut chercher comment soi-même cette fonction.
S'il n'est pas possible de créer une fonction gérant les matrices (ou si l'on n'y arrive pas), on peut toujours utiliser « l'évaluation de groupe » codice_324 à la place de codice_322.
La manière la plus simple de créer une fonction pouvant agir sur une matrice consiste à faire défiler les indices, par exemple :
function [y]=carre(x)
 // calcule le carré des composantes d'une matrice
 // entrées : x : matrice de nombres
 // sorties : y : matrice de nombres
 [imax, jmax] = size(x);
 for i = 1:imax
 for j = 1:jmax
 y(i,j) = x(i,j)^2;
 end
 end
endfunction
ainsi, si l'on transmet un vecteur, codice_326 ou codice_327 vaudra 1, et si l'on transmet un nombre unique (scalaire), les deux vaudront 1. Mais l'utilisation de boucle ralentit considérablement l'exécution du programme. On peut souvent utiliser le fait que Scilab est fait pour travailler avec des matrices, par exemple utiliser les versions « pointées » des opérateurs :
function [y]=carre(x)
 // calcule le carré des composantes d'une matrice
 // entrées : x : matrice de nombres
 // sorties : y : matrice de nombres
 y = x.^2;
endfunction
Rappelons de manière utile que l'inverse peut s'obtenir par codice_328 ou par codice_329 (bien respecter l'espace entre le 1 et le point), la racine carrée par codice_330 ou codice_331 ; les racines n-ièmes par codice_332 ou codice_333. D'autre part, la plupart des fonctions primitives s'appliquent aux matrices (par exemple codice_334, codice_331, …). Par ailleurs, nous avons vu précédemment qu'un calcul effectué sur une matrice est plus rapide qu'un calcul effectué successivement sur chacun de ses éléments (en raison des opérations préliminaires au calcul). Pour une question de rapidité, il vaut donc mieux favoriser les calculs globaux sur des matrices que des calculs en faisant défiler les indices.
On peut utiliser de manière « intelligente » les raccourcis d'indice (codice_336, codice_113), ainsi que la possibilité d'extraire certains indice en utilisant une matrice booléenne. Dans l'exemple suivant, nous définissons une fonction ayant une formule différente à gauche et à droite d'une valeur "x"0 ; il s'agit d'un pic dissymétrique, formé de deux demies gaussienne de même moyenne et même hauteur, mais de largeurs différentes.
function [y] = gauss_dissym(A, x)
 // génère un pic gaussien dissymétrique
 // entrées : A(1) : position du pic
 // A(2) : hauteur de la courbe
 // A(3) : largeur de la courbe à gauche
 // A(4) : largeur de la courbe à droite
 // x : vecteur de nombres
 // sorties : y : vecteur de nombres
 indice = (x < A(1)); // vecteur de %t à gauche, %f à droite
 y = zeros(x); // initialisation
 y(indice) = A(2)*exp(-(x(indice) - A(1)).^2/A(3)); // profil gauche
 y(~indice) = A(2)*exp(-(x(~indice) - A(1)).^2/A(4)); // profil droit
endfunction
On peut ainsi l'utiliser avec un nombre unique
A = [3, 2, 1.5, 2.5];
y = gauss_dissym(A, 2.5)
ou bien avec un vecteur
A = [3, 2, 1.5, 2.5];
X = 0:0.1:6;
plot(X, gauss_dissym(A, X))
De manière plus générale, considérons une fonction de deux variables, définie de manière différente à gauche et à droite pour x ; donc concrètement deux fonctions fg("x", "y") et fd("x", "y"). Nous voulons l'évaluer sur deux vecteurs à partir desquels on crée deux matrices grille (voir plus haut). On peut utiliser la solution suivante :
function [z] = f(A, x, y)
indice = (x < A); // vecteur de %t à gauche, %f à droite
z = zeros(x, y); // initialisation
z = fg(x, y)*bool2s(indice)
z = z + fd(x, y)*bool2s(~indice)
Enfin, on peut transmettre une fonction en paramètre à une autre fonction. Dans l'exemple ci-dessous, nous appliquons la fonction codice_338 à deux fonctions différentes (il existe une fonction codice_339 qui remplit parfaitement ce rôle ; le code suivant n'est donné qu'à titre d'illustration).
//============================================================================
// nom : carre_inverse_derivee.sce
// auteur : Christophe Dang Ngoc Chan
// date de création : 2012-10-20
// dates de modification : 
// 2013-07-08 : ajout de xtitle dans les tracés
// guillemets ' -> "
// 2018-05-28 : ajout de scf(0), suppr. de clear
// version de Scilab : 5.3.1
// module Atoms requis : aucun
// Objectif : Tracer les fonction carré et inverse, ainsi que leurs dérivées
// Entrées : aucune (paramètres en dur)
// Sorties : fenêtre graphique avec 4 tracés
// Initialisation
scf(0);
clf;
// **********
// Constantes
deltax = 1e-6; // précision pour la dérivation
// **********
// Fonctions
function [y]=carre(x)
 // calcule le carré des composantes d'une matrice
 // entrées : x : matrice de nombres
 // sorties : y : matrice de nombres
 y = x.^2;
endfunction
function [y]=inverse(x)
 // calcule l'inverse des composantes d'une matrice
 // entrées : x : matrice de nombres
 // sorties : y : matrice de nombres
 y = x.^(-1);
endfunction
function [yprime] = derivation (f, x, epsilon)
 // calcule la dérivée aprochée de la fonction f
 // entrées : f : fonction
 // x : ensemble de définition (matrice de nombres)
 // epsilon : nombre positif, normalement petit,
 // mais pas trop pour éviter les erreurs de soupassement
 // sorties : yprime : matrice de nombres
 yprime = 1/(2*epsilon)*(f(x+epsilon) - f(x-epsilon));
endfunction
// **********
// Programme principal
// Génération des données
X = [1:0.1:10];
Y1 = carre(X);
Yprime1 = derivation(carre, X, deltax);
Y2 = inverse(X);
Yprime2 = derivation(inverse, X, deltax);
// Tracé
subplot(2,2,1)
plot(X, Y1, "b")
xtitle("$f(x) = x^2$", "x", "y")
subplot(2,2,3)
plot(X, Yprime1, "b")
xtitle("$f"(x)$", "x", "y")
subplot(2,2,2)
plot(X, Y2, "r")
xtitle("$y = g(x) = 1/x$", "x", "y")
subplot(2,2,4)
plot(X, Yprime2, "r")
xtitle("$y = g"(x)$", "x", "y")
Relecture de code.
Une manière simple de s'assurer de la rigueur dans l'application des règles consiste à relire le code, voire à le faire relire par un tiers (voir ""). La relecture de code consiste à s'assurer que les règles énoncées — découpage en fonctions de moins de 80 lignes et ayant moins de 10 variables locales, non recours à des variables globales, respect identations, commentation du code, … — sont bien vérifiées "et c'est tout" (mais c'est déjà beaucoup) !
En particulier, il serait illusoire, et contre-productif car décourageant, d'espérer comprendre "rapidement" un code qu'un auteur a mis plusieurs jours voire semaines à écrire. Par contre, on peut relever les endroits où l'auteur a été peu rigoureux — typiquement, des endroits où il y a eu beaucoup d'essais-erreurs, des modifications vites faites (correction de petites erreurs, petits ajouts).
Distribuer un exécutable.
Un auteur peut vouloir distribuer un exécutable, par exemple pour avoir une utilisation transparente de Scilab, ou encore pour masquer un script afin que l'on ne puisse pas le lire, pour garder confidentiel un algorithme. On peut pour cela utiliser la fonction codice_340 au sein d'un programme C/C++. Cela fait appel à l'API codice_341.
Au sein d'un programme C/C++, le code Scilab est alors mis dans une chaîne de caractères, puis envoyé au moteur Scilab par la commande codice_340. Le programme C/C++ peut ensuite être compilé.
On peut également utiliser SWIG "()" pour interfacer C/C++ avec Scilab.
Le module Atoms codice_343 fournit une commande codice_344 permettant d'encapsuler un script Scilab dans un exécutable Microsoft Windows. Cependant, l'exécution fait appel à Scilab, il ne s'agit pas d'un programme indépendant.
Le module Atoms codice_345 permet de convertir le script Scialb en C. Ce code peut ensuite être compilé.
La société Equalis distribue l'extension (payante) WildCruncher pour son logiciel (payant) Pro Plus, qui permet de générer du code C à partir du script Scilab puis de le compiler pour obtenir un exécutable .
Exemples.
Voici quelques exemples de programmes complets mettant en œuvre des algorithmes simples.
Crible d'Ératosthène.
Le programme suivant détermine la liste des nombres premiers inférieurs à une valeur donnée, appelée ici codice_346, en utilisant l'algorithme du crible d'Ératosthène.
//============================================================================
// nom : crible_eratosthene.sce
// auteur : Christophe Dang Ngoc Chan
// date de création : 2012-10-16
// dates de modification : 
// 2013-07-08 : floor -> uint32 (pour diminuer la taille nécessaire)
// guillemets ' -> "
// 2014-05-14 : uint8 (pour diminuer la taille nécessaire)
// 2018-01-02 : indices() booléen
// imax évalué à la volée et non pas par la racine carrée
// (plus respectueux de l'algorithme initial)
// élimination d'une boucle
// 2018-02-04 : correction : 1 n'est pas premier
// version de Scilab : 6.0.0
// module Atoms requis : aucun
// Objectif : détermine la liste des nombres premiers inférieurs à un nombre
// entier donné par le crible d'Ératosthène
// Entrées : nombre entier (scalaire)
// Sorties : vecteur de nombres entiers
// ***** fonctions et procédures *****
function [liste] = eratosthene(limite)
 // renvoit la liste (vecteur) des nombres premiers inférieurs à la limite
 indices = (ones(limite, 1)==1);
 // indices(i) = %t si i est premier, %f sinon
 indices(1)=%f; // 1 n'est pas premier
 imax = uint32(limite);
 i = uint32(2);
 while i <= imax
 if indices(i) then
 jmax = uint32(limite/i);
 j=uint32(2:jmax);
 indices(i*j)=%f; // élimination des multiples de i
 test = (i*jmax == imax);
 while test // recul de imax si le dernier nombre n'est pas premier
 imax = imax - 1;
 test = ~indices(imax);
 end
 end
 i = i + 1;
 end
 // constitution de la liste
 liste0 = uint32(1:limite);
 liste = liste0(indices);
endfunction
// ***** programme principal *****
// accueil
disp("Crible d"Ératosthène")
// entrer le plus grand nombre que l'on veut tester
maximum=input("nombre entier maximum : ");
// exécuter l'algorithme
lst = eratosthene(maximum);
// afficher le résultat
disp("Liste des nombres premiers entre 1 et "+string(maximum)+" : ");
disp(lst);
Algorithme d'Euclide.
Le programme suivant permet de déterminer le PGCD et le PPCM de deux nombres entiers, en utilisant l'algorithme d'Euclide.
//============================================================================
// nom : pgcd_ppcm_euclide.sce
// auteur : Christophe Dang Ngoc Chan
// date de création : 2012-10-16
// dates de modification : 
// 2013-07-08 : guillemets ' -> "
// version de Scilab : 5.3.1
// module Atoms requis : aucun
// Objectif : détermine le PGCD et le PPCM par l'algorithme d'Euclide
// Entrées : deux nombre entier (scalaires)
// Sorties : deux nombres entiers (scalaires)
// ***** Fonctions et procédures *****
function [resultat] = euclide(a, b)
 // détermine le PGCD de a et de b (deux entiers)
 r = modulo(a,b); // initialisation du reste
 while r <> 0
 a = b;
 b = r;
 r = modulo(a,b); // calcul du reste
 end
 resultat = b;
endfunction
// ***** Programme principal *****
// accueil
disp("Calcul du PGCD et du PPCM de deux nombres par l"algorithme d"Euclide")
// valeurs
n1 = input("Premier nombre : ");
n2 = input("Second nombre : ");
// exécution de l'algorithme
pgcd = euclide(n1, n2);
ppcm = n1*n2/pgcd;
// affichage du résultat
print(%io(2),pgcd)
print(%io(2),ppcm)
Courbe de Koch.
Le programme suivant trace la courbe du flocon de Koch de manière récursive.
//============================================================================
// nom : von_koch.sce
// auteur : Christophe Dang Ngoc Chan
// date de création : 2012-10-23
// dates de modification : 
// 2013-07-08 : guillemets ' -> "
// 2013-07-2 : vectorisation du calcul
// 2016-06-21 : ajout de commentaires
// 2018-05028 : ajour de scf, suppr. de clear
// version de Scilab : 5.3.1
// module Atoms requis : aucun
// Objectif : trace la courbe du "flocon de neige" de von Koch
// Entrées : aucun (paramètres codés en dur)
// Sorties : fenêtre graphique avec une courbe ; fichier SVG
scf(0);
clf;
// * constantes *
n = 6; // nombre d'étapes ;
// limité à 9 (262 145 points), sinon il faut changer la taille de la pile (stacksize)
// 6 etapes (4 097 points) sont suffisantes pour un bon rendu
sin_soixante = sqrt(3)/2; // sin(60°)
l = 1; // longueur du segment initial (unité arbitraire)
// * initialisation *
// *************
// * fonctions *
function []=vonkoch(A, B, i)
 u = (B - A)/3 ; // tiers du vecteur AB
 v = [0.5*u(1) - sin_soixante*u(2) ; sin_soixante*u(1) + 0.5*u(2)] ;
 // vecteur tourné de +60°
 C = A + u ;
 D = C + v ;
 E = B - u ;
 if i == 1 then
 // tracé des segments si l'on est au dernier niveau
 x = [A(1) ; C(1) ; D(1) ; E(1) ; B(1)] ;
 y = [A(2) ; C(2) ; D(2) ; E(2) ; B(2)] ;
 xpoly(x, y, "lines")
 else
 // sinon, appel récursif
 j = i - 1 ;
 vonkoch(A, C, j);
 vonkoch(C, D, j);
 vonkoch(D, E, j);
 vonkoch(E, B, j);
 end
endfunction
// * programme principal *
debut = [0;0] ;
fin = [l;0];
vonkoch(debut, fin, n) // tracé du flocon
isoview(0, l, 0, l*sin_soixante/3) // dimensions de l'image
// enregistrement du fichier
nom = "von_koch_"+string(n)+"_etapes.svg" ;
xs2svg(0, nom)
Lancer un programme sans ouvrir directement Scilab.
Il est possible de lancer un programme Scilab sans ouvrir l'interface graphique Scilab. Cela se comporte comme s'il s'agissait d'un exécutable.
Pour cela, il faut exécuter la commande suivante dans la ligne de commande du système d'exploitation "(shell)" :
scilab -nw -f monprogramme.sce
Si le système d'exploitation ne trouve pas lui-même Scilab, il faut lui indiquer l'emplacement. Par exemple 
sous Unix
/bin/scilab -nw -f monprogramme.sce
ou bien sous Microsoft Windows :
"C:\Program Files\scilab-5.3.3\bin\Scilex.exe" -nw -f monprogramme.sce
Si l'on veut rediriger la sortie de Scilab vers la sortie standard (fenêtre système), on peut « tuber » Scilab, par exemple sous Unix
/bin/scilab -nwni < monprogramme.sce
echo "disp('Hello world')" |scilab -nwni
On peut mettre ces commandes de système d'exploitation dans un script.
On peut enfin appeler le moteur Scilab à partir d'un programme écrit dans un autre langage, voir les rubriques d'aide :
Notes.
"Graphiques et sons" < ↑ > "Créer une interface graphique GUI"