2
votes

Journal de tracé (n sur k)

Je n'ai jamais utilisé Matlab auparavant et je ne sais vraiment pas comment corriger le code. J'ai besoin de tracer le journal (1000 sur k) avec k allant de 1 à 1000.

Warning: Function behaves unexpectedly on array inputs. To improve performance, properly
vectorize your function to return an output with the same size and shape as the input
arguments. 
In matlab.graphics.function.FunctionLine>getFunction
In matlab.graphics.function.FunctionLine/updateFunction
In matlab.graphics.function.FunctionLine/set.Function_I
In matlab.graphics.function.FunctionLine/set.Function
In matlab.graphics.function.FunctionLine
In fplot>singleFplot (line 241)
In fplot>@(f)singleFplot(cax,{f},limits,extraOpts,args) (line 196)
In fplot>vectorizeFplot (line 196)
In fplot (line 166)
In P1 (line 5)

Erreur:

y = @(x) log(nchoosek(1000,x));

fplot(y,[1 1000]);


5 commentaires

nchoosek a besoin d'une entrée scalaire. Vous devez utiliser une boucle pour calculer son résultat pour chaque k séparément. Mais là encore, je pense que votre exercice est destiné à ne pas utiliser nchoosek , car les valeurs intermédiaires sont énormes et ne rentreront probablement pas dans les nombres à virgule flottante double précision (ou du moins donneront des résultats erronés) . Quelle est l'équation pour log (n sur k)?


cela vous aidera tutorialspoint.com/matlab/matlab_plotting.htm


Copie possible de ajustement et tracé d'une parabole, matlab


Pas du tout un doublon. Cette question utilise fplot (qui prend une fonction anonyme comme entrée), tandis que l'autre utilise plot (qui prend des vecteurs numériques). En outre, cette question présente des problèmes potentiels de précision numérique, en raison des grands nombres impliqués dans l'approche du PO


@LuisMendo Étant donné que ses données sont toutes discrètes, il serait probablement plus logique pour lui d'utiliser plot que fplot pour cette application.


4 Réponses :


3
votes

Il y a plusieurs problèmes avec le code:

  • nchoosek ne vectorise pas sur la deuxième entrée, c'est-à-dire qu'il n'accepte pas de tableau comme entrée. fplot fonctionne plus rapidement pour les fonctions vectorisées. Sinon, il peut être utilisé, mais il émet un avertissement.
  • Le résultat de nchoosek est proche du débordement pour des valeurs aussi importantes de la première entrée. Par exemple, nchoosek (1000,500) donne 2,702882409454366e + 299 et émet un avertissement.
  • nchoosek attend des entrées entières. fplot utilise en général des valeurs non entières dans les limites spécifiées, et donc nchoosek génère une erreur.

Vous pouvez résoudre ces trois problèmes en exploitant la relation entre la factorielle et la fonction gamma et le fait que Matlab a gammaln , qui calcule directement le logarithme de la fonction gamma:

n = 1000;
y = @(x) gammaln(n+1)-gammaln(x+1)-gammaln(n-x+1);
fplot(y,[1 1000]);

Notez que vous obtenez un tracé avec des valeurs y pour tous x dans la plage spécifiée, mais en réalité le coefficient binomial n'est défini que pour les entiers non négatifs.

 entrez la description de l'image ici

p >


1 commentaires

Excellente et intelligente exploitation de la fonction factorielle et gamma (+1). De plus, je n'étais pas au courant de la fonction gammaln . Merci!



1
votes

Cette solution utilise arrayfun pour gérer le fait que nchoosek (n, k) code > nécessite que k soit un scalaire. Cette approche ne nécessite aucune boîte à outils .

En outre, cela utilise plot a > au lieu de fplot depuis cette réponse intelligente explique déjà comment faire avec fplot .

% MATLAB R2017a
n = 1000;
fh=@(k) log(nchoosek(n,k));  
K = 1:1000;
V = arrayfun(fh,K);    % calls fh on each element of K and return all results in vector V

plot(K,V)

Notez que pour certaines valeurs de k supérieures ou égales à 500, vous recevrez l'avertissement

Attention: le résultat peut ne pas être exact. Le coefficient est supérieur à 9,007199e + 15 et n'est précis qu'à 15 chiffres

car nchoosek (1000,500) = 2.7029e + 299 . Comme indiqué par @Luis Mendo , cela est dû à realmax = 1.7977e + 308 code > qui est la plus grande virgule flottante réelle prise en charge. Voir ici pour plus d'informations.

 Tracé de nchoosek avec n = 1000


0 commentaires

2
votes

OK, puisque vous avez de toute façon reçu des spoilers pour votre exercice de devoirs, je posterai une réponse que je pense être plus facile à comprendre.

Le formule multiplicative pour le coefficient binomial dit que

n sur k = produit i = 1 à k ((n + 1-i) / i)

(désolé, pas moyen d'écrire des formules appropriées sur SO, voir le lien Wikipedia si ce n'était pas clair).

Pour calculer le logarithme d'un produit, nous pouvons calculer la somme des logarithmes:

log (produit (x i )) = somme (log (x i ))

Ainsi, nous pouvons calculer les valeurs de (n + 1-i) / i pour tout i , prendre le logarithme, puis résumer les premières valeurs de k pour obtenir le résultat pour un k donné .

Ce code accomplit qu'en utilisant cumsum , le cumul somme. Sa sortie à l'élément de tableau k est la somme de tous les éléments de tableau d'entrée de 1 à k.

n = 1000;
i = 1:1000;
f = (n+1-i)./i;
f = cumsum(log(f));
plot(i,f)

Notez également ./ , la division par élément. / effectue une division matricielle dans MATLAB, et ce n'est pas ce dont vous avez besoin ici.


4 commentaires

C'est intelligent. Je n'avais pas envisagé l'approche somme des logs mais rend parfait depuis maintenant que vous l'énoncez. Approche très nette et propre. (+1)


Autre support de site SE utilisant MathJax pour rendre LaTex. Cela semble également être une fonctionnalité très utile sur SO.


@John: Cette suggestion a été discutée et rejetée plusieurs fois sur Meta. Ils ne veulent pas le faire, malheureusement.


@CrisLuengo Ouais, je suis juste allé dans un terrier de lapin pour enquêter sur ça. On dirait que cela revient souvent et nous vivons juste avec une composition moche et une communication inefficace pour des raisons ...



2
votes

Le type de fonction syms reproduit exactement ce que vous voulez

syms x

y = log(nchoosek(1000,x));
fplot(y,[1 1000]);

entrez la description de l'image ici


0 commentaires