evitar_entrada_saida_em_funcao.html 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. <!--
  2. Introducao 'a Programacao - desde 2017 - Prof. Leo^nidas de Oliveira Branda~o
  3. Por que evitar entrada/saida de dados em funcoes?
  4. LInE (Laboratory of Informatics in Education) - http://www.usp.br/line
  5. IME - USP
  6. Material didatico
  7. Pode usar livrevemente este material para fins nao comerciais, devendo sempre fazer referencia `a autoria.
  8. Sugestões/apontamento são bem vindos: leo@ime.usp.br (favor indicar no assunto "material de introducao 'a programacao")
  9. Autor: Prof. Leo^nidas de Oliveira Branda~o
  10. http://www.ime.usp.br/~leo
  11. http://line.ime.usp.br
  12. http://www.matemtica.br
  13. -->
  14. <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
  15. <meta name='keywords' content='mac0122, material, professores, leonidas de oliveira brandao'>
  16. <link rel='stylesheet' type='text/css' href='css_img_js_conf/all.css'>
  17. <link rel='stylesheet' type='text/css' href='css_img_js_conf/line_introducao_programacao.css'>
  18. <script src="css_img_js_conf/defineLInE.js"></script> <!-- para referencias 'a documentos internos -->
  19. <div class="pagina">
  20. <p class="secao">Por que evitar entrada/saida de dados em funções</p>
  21. <p>
  22. A razão principal para se <b>evitar comandos de entrada e de saída dentro da definição de uma função</b> é conseguir
  23. maior flexibilidade para uso dessas funções, como explico a seguir.
  24. Evidentemente isso não se aplica quando a função for desenhada especificamente para providenciar a entrada (leitura) ou
  25. para a saída (impressão de dados. Por exemplo, o segundo caso ocorre na função <tt>imprime_comb</tt>
  26. Entretanto,
  27. Para explicar as razões pelas quais deve-se <b>evitar comandos de entrada e de saída dentro da definição de uma função</b>,
  28. devemos primeiro enfatizar o que é a uma função em linguagens como <i>C</i> ou <i>Python</i>:
  29. <ul>
  30. <li>é um código que recebe seus <em>dados de entrada</em> a partir de uma <i>lista de parâmetros</i> (<i class="def">parâmetros formais</i>);</li>
  31. <li>é um código que processa os dados de entrada e geralmente devolve algum valor como resposta (em seu comando <tt class="cmd">return</tt>);</li>
  32. <li>é um código que pode ser invocado a partir de outros trechos do programa, que providenciam os valores para os parâmetros
  33. (<i class="def">parâmetros efetivos</i>).</li>
  34. </ul>
  35. </p>
  36. <p>
  37. Desse modo, usando como exemplo a <i>função fatorial</i> (<i>fat(0)=1</i> e <i>fat(n)=n*fat(n-1), n&gt;0</i>), a razão para
  38. se evitar comandos de entrada e de saída dentro da definição da função pode ser resumida em:
  39. <ul>
  40. <li><i>Facilita o reúso de código</i>, ou seja, sempre que precisar de um algoritmo que compute o fatorial,
  41. basta copiar o código que já implementou (e testou);</li>
  42. <li><i>Facilita o desenvolvimento de programas maiores</i>, pois pode-se agrupar os blocos lógicos que tenham um propósito bem definido como
  43. uma função.</li>
  44. </ul>
  45. </p>
  46. <p>
  47. A fim de ficar mais clara a vantagem de <i>passar os valores via parâmetro</i>, vamos examinar um exemplo matemático,
  48. <b style="color:#0000aa">computar o número de combinações de <i>n</i>, tomados <i>k</i> a <i>k</i></b>
  49. <a href="#comb" title="ver referência sobre combinação">[1]</a>.
  50. Vamos lembrar a combinatória usualmente estudada no <i>Ensino Médio</i>.
  51. Este problema pode ser traduzido em um exemplo do tipo "loteria":
  52. de quantas maneiras distintas é possível combinar <i>n=99</i> números (dentre <i>01</i> e <i>99</i>) tomando-se
  53. <i>k=5</i> deles? A resposta geral é dada pela expressão <i>C<sub>n,k</sub>=n!/((n-k)!k!)</i>, que com os dados de interesse
  54. resultaria em <i>C<sub>100,5</sub>=100!/((100-5)!5!) = 75.287.520</i>.
  55. <br/>
  56. Portanto, se você comprar um único bilhete dessa loteria por semana, em média precisaria de mais de 75 milhões de semanas para conseguir
  57. ter um bilhete premiado.
  58. <br/>
  59. <sabermais title="para saber um pouco mais">
  60. Como seria dificílimo tentar enumerar as mais de 75 milhões de possibilidade para verificar a corretuda da fórmula
  61. acima estão corretos, vamos testar com uma combinção menor, como combinar
  62. <i>n=5</i> valores <i>3</i> a <i>3</i>, neste caso a fórmula diz que teríamos<br/>
  63. &nbsp; &nbsp; &nbsp; &nbsp; <i>C<sub>5,3</sub>=5!/((5-3)!3!) = 5*4/2 = 10</i>
  64. <br/>
  65. e, de fato, existem <i>10</i> combinações:
  66. <i>{1,2,3}, {1,2,4}, {1,2,5},
  67. {1,3,4}, {1,3,5},
  68. {1,4,5},
  69. {2,3,4}, {2,3,5},
  70. {2,4,5},
  71. {3,4,5}</i>.
  72. </sabermais>
  73. </p>
  74. <p>
  75. Nesse contexto, imaginemos o uso
  76. <i style="color:#aa5555" title="conceitualmente errônea, como tento explicar a seguir">errôneo</i> de uma leitura do valor <i>n</i>
  77. dentro da função <tt class="var">fat</tt>.
  78. Então, se precisar computar a combinação de <tt>n</tt>, tomados <tt>k</tt> a <tt>k</tt> (<i>C<sub>n,k</sub>=n!/((n-k)!k!)</i>),
  79. esse valor <b>não</b> poderá ser computado usando a expressão seguinte (com chamada à função <tt class="var">fat</tt>):
  80. <tt class="var">fat(n)/(fat(n-k)fat(k))</tt>.
  81. <br/>
  82. <b style="color:#0000aa">Por que mesmo?</b>
  83. <br/>
  84. <porque>
  85. Se não percebe o <i style="color:#aa5555" title="erro conceitual">erro de programação</i>, vale a pena fazer uma simulação.
  86. Suponha que você tenha implementado o fatorial como uma função com comando de leitura, em "Portugol" <br/>
  87. &nbsp; &nbsp;
  88. <tt><verm>inteiro</verm> fat (n) {
  89. <verm>inteiro</verm> i=2, f=1; <verd>leia</verd>(n); <azul2>repita_enquanto</azul2> (i&lt;=n) { f = f*i; i = i+1; } devolva f; }</tt>
  90. <br/>
  91. e deseje saber <i>C<sub>5,2</sub>=5!/((5-2)!2!)</i>.
  92. <br/>
  93. Então, ao entrar na função para computar <tt>fat(5)</tt> o usuário terá que digitar o valor <tt>5</tt>, para computar
  94. <tt>fat(3)</tt>, será obrigado a digitar o valor 3 e, para computar <tt>fat(2)</tt>, terá também que digitar o valor <tt>2</tt>.
  95. <br/>
  96. Mas vamos tornar o <i style="color:#aa5555">erro</i> (ou <i style="color:#aa5555">problema</i>) mais óbvio.
  97. Vamos supor que desejamos imprimir várias combinações (<i title="do Latin, exempli gratia">e.g.</i>, para computar o triângulo de Pascal).
  98. Por exemplo, examine como ficaria o calculo de <i>C<sub>10,1</sub>, C<sub>10,2</sub></i>, assim por diante até <i>C<sub>10,10</sub></i>
  99. (vide a função <tt>fat</tt> da tabela 1).
  100. Seria necessário que o "sofrido" usuário tenha que ficar digitando 10 triplas! (<i>10,9,1</i>; <i>10,8,2</i>; <i>10,7,3</i>;
  101. <i>10,6,4</i>; <i>10,5,5</i>; <i>10,4,6</i>; <i>10,3,7</i>; <i>10,2,8</i>; <i>10,1,9</i>; e <i>10,0,10</i>).
  102. Mas bastaria exigir que o usuário digitasse apenas um valor, <i>10</i>, se o programador (você) tivesse implementado o fatorial via
  103. parâmetro e sem leituras dentro dessa função. Bastaria usar um laço (vide a função <tt>main</tt> da tabela 3).
  104. <br/>
  105. Ou seja, não faz sentido obrigar o usuário a digitar dezenas, centenas, milhares, ou mais vezes, quando bastaria digitar um único valor.
  106. Se não estiver convencido da inviabilidade do uso de leitura dentro da função fatorial, copie os códigos da tabela 1 e o experimente.
  107. </porque>
  108. </p>
  109. <p>
  110. Assim, em exercícios que apresentam o conceito de função (portanto envolvendo um bloco lógico com propósito bem definido),
  111. procure, sempre que possível, <b>não</b> usar comandos de entrada ou de saída de dados <b>dentro da função</b>.
  112. Esse é um <i>bom hábito de programação</i>, no sentido de reduzir erros e facilitar que reaproveite sues códigos em outras
  113. situações.
  114. <br/>
  115. Mas vale lembrar que existem exceções: em uma função desenhada especificamente para "ler" dados, é necessá comandos para entrada e
  116. uma função específica para imprimir o <i>Triângulo de Pascal</i> precisa de comando de impressão.
  117. </p>
  118. <p>
  119. <!-- F<sub>0</sub>=1, F<sub>1</sub>=1, F<sub>k</sub> = F<sub>k-1</sub> + F<sub>k-2</sub>, k&gt;2 -->
  120. Entretanto, existem as exceções, exemplos nos quais é útil usar comando de entrada ou de saída dentro da função. Ilustraremos
  121. o caso de utilidade de um comando de saída dentro da função, isso ocorre se desejamos computar (e imprimir) os <tt>n</tt> primeiros termos da
  122. <i title="F_{0}=1, F_{1}=1, F_{k} = F_{k-1} + F_{k-2}, k&gt;1">sequência de Fibonacci</i>.
  123. Então, naturalmente precisaremos do comando de impressão/saída e como isso pode ser feito para qualquer
  124. <tt>n</tt> é adequado agrupar esse código na forma de um procedimento separado (no caso uma função <b>sem</b> valor de retorno).
  125. <br/>
  126. Porém se o objetivo fosse conhecer apenas o termo <tt>n</tt> da sequência, a função <b>não deveria ter o comando de saída</b>.
  127. </p>
  128. <p>
  129. <center>
  130. <i>Tab. 1. Códigos "errôneos" para imprimir o Triângulo de Pascal via fórmula de combinação</i>
  131. <table class="tableCd">
  132. <tr><td></td><td bgcolor="8aaada"><i>C</i> <td bgcolor="8aaada"><i>Python</i></td></tr>
  133. <tr><td><table class=""><tr class="trCd" valign="top"><td><pre style="font-size:0.8em"> 1
  134. 2
  135. 3
  136. 4
  137. 5
  138. 6
  139. 7
  140. 8
  141. 9
  142. 10
  143. 11
  144. 12
  145. 13
  146. 14
  147. 15
  148. 16
  149. 17
  150. 18
  151. 19
  152. 20
  153. 21
  154. 22
  155. 23
  156. 24
  157. 25
  158. 26
  159. 27
  160. 28
  161. 29
  162. 20
  163. </pre></td></tr></table></td>
  164. <td><table class=""><tr class="trCd" valign="top"><td><pre style="font-size:0.8em"><verm>int</verm> fat (<verm>int</verm> n) { <cyan>// define funcao com 1 parametro</cyan>
  165. <verm>int</verm> ft = 1, i=2;
  166. <cyan>// Experimente com esta linha,</cyan>
  167. <verd>scanf</verd>("%d", &n); <cyan>// depois sem ela</cyan>
  168. <azul2>while</azul2> (i &lt;= n) {
  169. i = i + 1;
  170. ft = ft * i;
  171. }
  172. return ft;
  173. }
  174. <verm>void</verm> imprime_comb (<verm>int</verm> n) {
  175. <verm>int</verm> i=0, aux;
  176. <cyan>// Com mais a leitura abaixo o codigo ficaria</cyan>
  177. <cyan>// scanf("%d", &n); // "absurdo" ao quadrado!</cyan>
  178. <azul2>while</azul2> (i &lt;= n) {
  179. aux = fat(n)/(fat(n-i)*fat(i));
  180. <verd>printf</verd>("%3d ", aux);
  181. i++;
  182. }
  183. <verd>printf</verd>("\n");
  184. }
  185. <verm>void</verm> main (void) {
  186. <verm>int</verm> i=0, n;
  187. <cyan>// Experimente com n pequeno, digamos n=3, assim ja'</cyan>
  188. <verd>scanf</verd>("%d", &n); <cyan>// percebera' o absurdo da leitura</cyan>
  189. <azul2>while</azul2> (i&lt;=n) {
  190. imprime_comb(i);
  191. i++;
  192. }
  193. }</pre></td></tr></table></td>
  194. <td><table class=""><tr class="trCd" valign="top"><td><pre style="font-size:0.8em"><cyan># Python2 para 'print' sem pular linha : print("*" , end = "");</cyan>
  195. from __future__ import print_function
  196. <verm>def</verm> fat (n) :
  197. <cyan># Experimente com esta linha,</cyan>
  198. n = int(<verd>input</verd>()); <cyan># depois sem ela</cyan>
  199. f = 1;
  200. i = 2;
  201. <azul2>while</azul2> (i&lt;=n) :
  202. f *= i;
  203. i += 1;
  204. return f;
  205. <verm>def</verm> imprime_comb (n) :
  206. <cyan># Com mais a leitura abaixo o codigo ficaria</cyan>
  207. <cyan># n = int(<verd>input</verd>()); # "absurdo" ao quadrado!</cyan>
  208. i=0;
  209. <azul2>while</azul2> (i&lt;=n) :
  210. <cyan># C(n,k) = n!/((n-k)!*k!)</cyan>
  211. val = fat(n)/(fat(n-i)*fat(i));
  212. <cyan># print("C(%d,%d)=%d" % (n,i,val));</cyan>
  213. <verd>print</verd>("%3d " % (val), end="");
  214. i += 1;
  215. <verm>def</verm> main () :
  216. n = int(<verd>input</verd>());
  217. for i in range(n+1) :
  218. imprime_comb(i);
  219. <verd>print</verd>();
  220. main();
  221. </pre></td></tr></table></td></tr>
  222. </table>
  223. </center>
  224. </p>
  225. <span style="color: #0055AA;font-size:1.1em">Exemplo 1. Dados naturais <tt>n</tt> e <tt>k</tt>, computar a combinação de <tt>n</tt> <tt>k-a-k</tt></span>
  226. <p>
  227. Suponha que precisemos fazer um programa para computar
  228. quantas são as combinações de <tt>n</tt> termos combinados <tt>k</tt>-a-<tt>k</tt>, ou seja, tendo <tt>n</tt> elementos,
  229. desejamos saber de quantos modos distintos podemos formar grupos com <tt>k</tt> dos elementos.
  230. </p>
  231. <p>
  232. Esse conceito aparece em <i>probabilidade</i> e em <i>combinatória</i>, sabemos que esta combinação corresponde ao agrupamentos de
  233. elementos nos quais a ordem não importa (tanto faz a ordem dos <tt>k</tt> elementos do tipo <tt>a</tt>) e que a fórmula que fornece
  234. o total desses subconjuntos é a seguinte:
  235. <center><a href="https://en.wikipedia.org/wiki/Binomial_theorem" title="explicacao mais detalhada na WikiPedia">C(n,k) = n! / ((n-k)! k!)</a>.</center>
  236. </p>
  237. <p>
  238. Por exemplo, combinar <tt>6</tt> valores distintos, tomados <tt>2</tt> a <tt>2</tt> resulta <tt>15=6!/((6-2)!2!)=6!/(4!2!)</tt>, que
  239. são os <tt>15</tt> subconjuntos:
  240. <tt>(6,5)</tt>, <tt>(6,4)</tt>, <tt>(6,3)</tt>, <tt>(6,2)</tt>, <tt>(6,1)</tt>,
  241. <tt>(5,4)</tt>, <tt>(5,3)</tt>, <tt>(5,2)</tt>, <tt>(5,1)</tt>,
  242. <tt>(4,3)</tt>, <tt>(4,2)</tt>, <tt>(4,1)</tt>,
  243. <tt>(3,2)</tt>, <tt>(3,1)</tt>,
  244. <tt>(2,1)</tt>.
  245. </p>
  246. <p>
  247. Assim, existem duas possibilidades de implementar esse código, uma implementando a função fatorial (<tt>fat(n)</tt>) que seria
  248. invocada três vezes pelo programa principal (com algo como <tt><verd>imprima</verd>(fat(n) / (fat(k) * fat(n-k))</tt>.
  249. Outra possibilidade é implementar também o cômputo de <tt>fat(n) / (fat(k) * fat(n-k))</tt> também como uma função.
  250. Apesar dessa segunda possibilidade não ajudar tanto na organização do código (pois a segunda função (<tt>comb(n,k)</tt>) seria muito
  251. simples, ilustraremos dessa forma por ela usar função chamando função que chama função (a principal chama <tt>comb(n,k)</tt> e essa
  252. chama <tt>fat(n)</tt>).
  253. Veja como ficaria o código em uma <i>pseudo-linguagem</i> de programação:
  254. <pre style="font-size:0.8em"><verm>inteiro</verm> fat(n) { <cyan>//# estou supondo que o valor digitado pelo usuario seja um natural maior ou igual a 0 (n>=0)</cyan>
  255. <verm>inteiro</verm> valfat = 1;
  256. <verm>inteiro</verm> cont = 2;
  257. <azul2>repita_enquanto</azul2> (cont&lt;=n) { <cyan>//# continue computando enquanto nao chegar ao valor cont==n</cyan>
  258. valfat = valfat * cont;
  259. cont = cont + 1;
  260. }
  261. devolva valfat;
  262. }
  263. <verm>inteiro</verm> comb(n, k) {
  264. devolva fat(n) / (fat(n-k)*fat(k));
  265. }
  266. <verm>vazio</verm> principal() {
  267. <verm>inteiro</verm> N, k; <cyan>//# note que os nomes de variaveis daqui NAO tem qualquer relacao com aqueles em 'fat'</cyan>
  268. <verm>inteiro</verm> a, b, c; <cyan>//# para uma segunda versao</cyan>
  269. <verd>leia</verd>(N, k); <cyan>//# leia 2 valores naturais e armazene-os respectivamente em N e em k (espera-se que digite N>=k)</cyan>
  270. <cyan>//# pode-se invocar seguidamente 'fat' 3 vezes como abaixo:</cyan>
  271. <verd>imprima</verd>(comb(N,k);
  272. <cyan>//# pode-se invocar a funcao 'fat' quanta vezes forem necessarias, aqui fazermos 3 vezes, armazenando cada resultado</cyan>
  273. a = fat(N);
  274. b = fat(k);
  275. c = fat(N-k);
  276. <verd>imprima</verd>(a/( b * c))); <cyan>//# usamos os 3 resultados de chamada de 'fat' para compor a resposta final N!/(k!*(N-k)!)</cyan>
  277. }</pre>
  278. </p>
  279. <p>
  280. A figura 1 ilustra os desvios no <i>fluxo de execução</i> do código acima.
  281. Note o destaque da instrução 2, que é uma atribuição que define o valor para a variável <i>c</i>, a ordem de construção é a
  282. usual de expressão, primeiro computa-se o <i>lado direito</i> da expressão e o resultado dela é armazenado na variável
  283. (que é o <i>lado esquerdo</i> da atribuição). Como o <i>lado direito</i> contém uma chamada de função, para computá-lo,
  284. desvia-se o <i>fluxo de execução</i> (seta que "sai" de <i>fat(k);</i>) para a execução da função <i>fat(.)</i>, inicia-se
  285. a variável local (na verdade declarada como parâmetro) <i>n</i> com o valor vindo de <i>k</i> (<i>parâmetro efetivo</i>),
  286. segue-se executando as instrução de <i>fat(.)</i> e, no exemplo, a última instrução indica que deve-se devolver para local
  287. que <i>invocou</i> <i>fat(.)</i> o valor atual na variável (local) <i>ft</i>.
  288. </p>
  289. <center>
  290. <img src="img/exemplo_exec_funcao.jpg" title="exemplo de execucao da funcao"/>
  291. <br/>
  292. <i>Fig. 1. Diagrama esquemática indicando desvio de execução função e local de retorno.</i>
  293. </center>
  294. <p>
  295. Novamente para enfatizar as desvantagens de usar leitura ou impressão dentro de funções,
  296. procure implementar o código acima, em sua linguagem favorita, e colocar nele comandos para
  297. leitura ou saída dentro da função <tt>fat(n)</tt>, como discutido abaixo.
  298. </p>
  299. <span style="color: #0055AA;font-size:1.1em">Observação 1. Vantagem de uso de função sem comandos de entrada/saída - combinação n, k-a-k</span>
  300. <p>
  301. Note que, <b>se</b> dentro da função <tt>fat</tt> exitisse um comando do tipo <tt><verd>leia</verd>(n);</tt>,
  302. a função NÃO poderia ser usada para computar o fatorial de algum valor já registrado em alguma variável, pois ao ser invocada,
  303. digamos <tt>fat(n)</tt>, seria necessário que o usuário <i style="color: #AA0000;">digitasse novamente</i> o valor para calculo
  304. do fatorial e valor para o qual desejava-se o fatorial (na variável <tt>n</tt>) seria descartado.
  305. No exemplo do código associado à figura 1, na primeira chamada para <i>N</i>, o usuário teria que digitar algum valor
  306. para calcular fatorial (e provavelmente nem saberia qual o valor guardado em <i>N</i>),
  307. na segunda chamada, para o valor para <i>k</i> ocorreria o mesmo, e por fim, o mesmo para o valor <i>N-k</i>.
  308. </p>
  309. <p>
  310. De forma análoga, se a função <i>fat</i> tivesse algum comando de saída, ao usar a função 3 vezes, o usuário
  311. receberia informações confusas: ele deseja a combinação de <i>n</i>, tomado <i>k</i>-a-<i>k</i>, mas
  312. receberia 4 infomações: na primeira chamada <i>fat(.)</i> imprimiria <i>n!</i>,
  313. segunda imprimiria <i>k!</i>, na terceira imprimiria o resultado de <i>(n-k)!</i> e, ao voltar
  314. para o código que invocou <i>fat(.)</i>, imprimiria finalmente a única coisa que o usuário desejava saber,
  315. <i>n!/(k! (n-k)!)</i>.
  316. </p>
  317. <span style="color: #0055AA;font-size:1.1em">Observação 2. Propriedade interessante de C(n,k) - Triângulo de Pascal</span>
  318. <p>
  319. Vamos aproveitar o código que computa a combinação de <i>n</i>, <i>k-a-k</i>, <i>C(n,k) = n!/(k!*(n-k)!)</i>, para computar
  320. a seguinte sequência de valores: <i>C(n,0)</i>, <i>C(n,1)</i>, <i>C(n,2)</i> e assim por diante, até <i>C(n,n)</i>.
  321. Mais ainda, vamos fazer isso para <i>n=1</i>, <i>n=2</i>, <i>n=3</i> e <i>n=4</i>.
  322. </p>
  323. <center>
  324. <i>Tab. 2. Triângulo de Pascal, como combinação e de modo direto</i>
  325. <table class="tableCd"><tr><td>
  326. <pre>Linha | Combinacoes C(n,0) ate C(n,n) | As saidas
  327. 0 | C(0,0) | 1
  328. 1 | C(1,0) C(1,1) | 1 1
  329. 2 | C(2,0) C(2,1) C(2,2) | 1 2 1
  330. 3 | C(3,0) C(3,1) C(3,2) C(3,3) | 1 3 3 1
  331. 4 | C(4,0) C(4,1) C(4,2) C(4,3) C(4,4) | 1 4 6 4 1
  332. 5 | C(5,0) C(5,1) C(5,2) C(5,3) C(5,4) C(5,5) | 1 5 10 10 5 1
  333. 6 | C(6,0) C(6,1) C(6,2) C(6,3) C(6,4) C(6,5) C(6,6) | 1 6 15 20 15 6 1</pre>
  334. </td></tr></table>
  335. </center>
  336. <p>
  337. Ou seja, na tabela acima, a linha <i>0</i>, tem uma única saída, a saber <i>C(0,0)</i>.
  338. A linha <i>1</i> tem duas saídas, <i>C(1,0)</i> e <i>C(1,1)</i>.
  339. A linha <i>2</i> tem três saídas, <i>C(2,0)</i>, <i>C(2,1)</i> e <i>C(2,2)</i>.
  340. Assim, por diante, até a linha <i>6</i> que tem sete saídas.
  341. </p>
  342. <p>
  343. O que é interessante, é que no <i>triângulo</i> (na coluna das saídas) aparece uma propriedade interessante:
  344. o elemento da linha <i>k</i>, na coluna <i>j</i> é igual à soma do elemento da
  345. linha <i>k-1</i>, na coluna <i>j-1</i>, com o elemento da
  346. linha <i>k-1</i>, na coluna <i>j</i>.
  347. Ou seja, vale a propriedade
  348. <i>C(k,j) = C(k-1,j-1) + C(k-1,j)</i> (sempre que <i>k&gt;0</i> e <i>j</i> estiver entre <i>1</i> e <i>k</i>,
  349. essa é a relação de <i title="Michael Stifel (ca. 1487 1567)">Stifel</i>
  350. [<a href="#boyer" title="examinar referencia 2 - Boyer">2</a>, <a href="#dantzig" title="examinar referencia 2 - Dantzig">3</a>],
  351. e aquele é o
  352. <b title="Atribuido a Blaise Pascal (1623 1662) mas já conhecido por Yang Hui (fl. ca. 1261 1275) e Michael Stifel (ca. 1487 1567)">
  353. Triângulo de Pascal</b>.
  354. Veja por exemplo o
  355. <a href="https://en.wikipedia.org/wiki/Pascal%27s_triangle" title="seguir para WikiPedia">Triângulo de Pascal</a>
  356. <a href="#boyer" title="examinar referência Boyer">[2]</a>
  357. na <i>WikiPedia</i>.
  358. </p>
  359. <!--
  360. <pre>1 0
  361. ---
  362. 1 1
  363. 1 0
  364. ---
  365. 2 0
  366. 2 1
  367. 2 2
  368. ---
  369. 3 0
  370. 3 1
  371. 3 2
  372. 3 3
  373. ---
  374. 4 0
  375. 4 1
  376. 4 2
  377. 4 3
  378. 4 4</pre>
  379. <p>
  380. Examinando as saídas (última coluna) notamos uma propriedade interessante:
  381. o elemento da linha <tt>n+1</tt>, coluna <tt>k+1</tt> = o elemento da linha <tt>n</tt>, coluna <tt>k</tt> + o elemento da linha <tt>n</tt>, coluna </tt>k+1</tt>.
  382. Veja por exemplo, a última linha, linha <tt>4</tt>: o segundo elemento = <tt>4</tt> = <tt>1 + 3</tt> (da linha acima).
  383. </p>
  384. -->
  385. <!-- https://pt.wikipedia.org/wiki/Produtos_not%C3%A1veis -->
  386. <!--
  387. <span style="color: #0055AA;font-size:1.1em">Exemplo 2. Coeficientes da expansão do produto notável <tt>(a+b)^n</tt></span>
  388. <p>
  389. Suponhamos que precisemos fazer um programa que computa os termos dos coeficientes da expansão de <tt>(a+b)^n</tt>.
  390. Ou seja, desejamos um programa que dado <tt>n</tt> liste quantos termos do tipo <tt>a^i x b^j</tt> existe, para cada
  391. <tt>i</tt> e cada <tt>j</tt> tais que <tt>i+j=n</tt>.
  392. o valor da combinação de <i>N</i> tomado <i>k</i> a <i>k</i>, ou seja,
  393. C(N,k) = N! / ( k! (N-k)!).
  394. Para isso percebe-se que é necessário implementar o cômputo de fatorial que será utilizado 3 vezes.
  395. Para facilitar a compreensão, podemos escrever um código com 3 variáveis auxiliares para armazenar, respectivamente,
  396. <i>N!</i>, <i>k!</i> e <i>(N-k)!</i>.
  397. </p>
  398. <pre>(a+b)^0 = 1 a^0 b^0
  399. (a+b)^1 = (a+b) (0 a^0 b^0 + 0 a^0 b^0) = 1 a^1 b^0 + 1 a^0 b^0
  400. (a+b)^2 = (a+b) (1 a^1 b^0 + 0 a^0 b^1) = 1 a^2 b^0 + 2 a^1 b^1 + 1 a^0 b^2
  401. (a+b)^3 = (a+b) (1 a^2 b^0 + 2 a^1 b^1 + 1 a^0 b^2) = 1 a^3 b^0 + 3 a^2 b^1 + 3 a^1 b^2 + 1 a^0 b^3
  402. (a+b)^4 = (a+b) (1 a^3 b^0 + 3 a^2 b^1 + 3 a^1 b^2 + 1 a^0 b^3) = 1 a^4 b^0 + 4 a^3 b^1 + 6 a^2 b^2 + 4 a^1 b^3 + 1 a^0 b^3a
  403. </pre>
  404. <pre>1
  405. 1 1
  406. 1 2 1
  407. 1 3 3 1
  408. 1 4 6 4 1
  409. </pre>
  410. -->
  411. <span style="color: #0055AA;font-size:1.1em;">Implementações para gerar o "Triângulo de Pascal" em <i>C</i> e em <i>Python</i></span>
  412. <p>
  413. Abaixo apresento uma implementação para gerar o "Triângulo de Pascal" (como apresentado acima), nas linguagens
  414. <i>C</i> e <i>Python</i>.
  415. <center>
  416. <i>Tab. 3. Outra versão de códigos para imprimir o Triângulo de Pascal via fórmula de combinação.</i>
  417. <br/>
  418. <table>
  419. <tr><td>Gerando "Triângulo de Pascal" em <i>C</i></td> <td>&nbsp;</td> <td>Gerando "Triângulo de Pascal" em <i>Python</i></td></tr>
  420. <tr>
  421. <td><pre style="font-size:0.8em">#include &lt;stdio.h&gt;
  422. <verm>int</verm> fat (<verm>int</verm> n) { <cyan>// supondo usuario digite natural n&gt;=0)</cyan>
  423. <verm>int</verm> valfat = 1;
  424. <verm>int</verm> cont = 2;
  425. <azul2>while</azul2> (cont&lt;=n) { <cyan>// continue enquanto nao chegar a cont==n</cyan>
  426. valfat = valfat * cont;
  427. cont++;
  428. }
  429. return valfat;
  430. }
  431. <verm>int</verm> comb (<verm>int</verm> n, <verm>int</verm> k) { return fat(n) / (fat(n-k)*fat(k)); }
  432. <verm>void</verm> main (void) {
  433. <verm>int</verm> N, k; <cyan>// usa inteiros N, k</cyan>
  434. <verm>int</verm> a, b, c, n;
  435. <verd>printf</verd>("Digite N - para computar C(N,0), C(N,1), ..., C(N,N): ");
  436. <verd>scanf</verd>("%d", &N);
  437. <cyan>// pode-se invocar seguidamente 'fat' 3 vezes como abaixo:</cyan>
  438. for (n=0; n&gt;N; n++) {
  439. for (k=0; k&lt;=n; k++) {
  440. a = fat(n);
  441. b = fat(k);
  442. c = fat(n-k);
  443. <cyan>// usamos resultados de 'fat' para resposta N!/(k!*(N-k)!)</cyan>
  444. <verd>printf</verd>("%3d ", a/(b * c));
  445. }
  446. <verd>printf</verd>("\n");
  447. }
  448. }
  449. </pre></td> <td>&nbsp;</td>
  450. <td><pre style="font-size:0.8em"><cyan># Python2 para 'print' sem pular linha : print("*" , end = "");</cyan>
  451. from __future__ import print_function
  452. <verm>def</verm> fat (n) : <cyan># supondo usuario digite natural n&gt;=0)</cyan>
  453. valfat = 1;
  454. cont = 2;
  455. <azul2>while</azul2> (cont&lt;=n) : <cyan># continue enquanto nao chegar a cont==n</cyan>
  456. valfat = valfat * cont;
  457. cont = cont + 1;
  458. return valfat;
  459. <verm>def</verm> comb(n, k) :
  460. return fat(n) / (fat(n-k)*fat(k));
  461. <verm>def</verm> main () :
  462. <cyan># usa inteiros N, k</cyan>
  463. <verd>print</verd>("Digite N - para computar C(N,0), C(N,1), ..., C(N,N): ");
  464. N = int(<verd>input</verd>());
  465. <cyan># pode-se invocar seguidamente 'fat' 3 vezes como abaixo:</cyan>
  466. for n in range(N) :
  467. for k in range(n+1) :
  468. a = fat(n);
  469. b = fat(k);
  470. c = fat(n-k);
  471. <cyan># usamos resultados de 'fat' para resposta N!/(k!*(N-k)!)</cyan>
  472. <verd>print</verd>("%3d " % (a/(b * c)), end="");
  473. <verd>print</verd>();
  474. main();
  475. </pre></td>
  476. </tr></table>
  477. </center>
  478. </p>
  479. <span style="color: #0055AA;font-size:1.1em">Referências bibliográficas sobre "Triângulo de Pascal"</span>
  480. <ol type="1">
  481. <li> <a name="comb">[1]</a>
  482. <a href="https://en.wikipedia.org/wiki/Binomial_coefficient" title="examinar combinação na WikiPedia"
  483. target="_blank">https://en.wikipedia.org/wiki/Binomial_coefficient</a>.</li>
  484. <li> <a name="boyer">[2] Uta C. Merzbach e Carl B. Boyer</a>,
  485. "A History of Mathematics", third edition, John Wiley & Sons, Inc., 2011 (primeira edicao de 1968)
  486. </li>
  487. <li> <a name="dantzig">[3] Tobias Dantzig</a>, "NUMBER: The Language of Science", Pi Press, New Yourk, 2005
  488. </li>
  489. </ol>
  490. <!--
  491. Boyer, Carl B. (Carl Benjamin), 1906 1976.
  492. pg 184. "The Jade Mirror opens with a diagram of the arithmetic triangle,
  493. inappropriately known in the West as “Pascal’s triangle.” (See the fol-
  494. lowing illustration.) In Zhu’s arrangement, we have the coefficients of"
  495. -->
  496. <!--
  497. republicacao da 4a edicao de 1954
  498. (primeira edicao de 1930)
  499. pg. 71. "It is significant that we owe the first explicit formulation of
  500. the principle of recurrence to the genius of Blaise Pascal, a contem-
  501. porary and friend of Fermat. Pascal stated the principle in a tract
  502. called The Arithmetic Triangle which appeared in 1654. Yet it was"
  503. pg 279. "FIG 2. THE ARITHMETIC TRIANGLE OF PASCAL"
  504. -->
  505. <p class="autoria">
  506. <a href="https://www.ime.usp.br/~leo" target="_blank" title="seguir para a pagina do prof. Leônidas">Leônidas de Oliveira Brandão</a><br/>
  507. <a href="http://www.ime.usp.br/~leo" target="_blank" title="seguir para a página do LInE">http://line.ime.usp.br</a>
  508. </p>
  509. <p class="rodape">
  510. <b>Alterações</b>:<br/>
  511. 2020/08/09: revisão do formato e ampla revisão do texto;<br/>
  512. 2019/06/06: vários pequenos acertos ao longo do texto;<br/>
  513. 2019/04/07: versao 2 (acrescentado novos paragrafos, melhorando explicacoes e frases);<br/>
  514. 2017/04/06: primeira versao.
  515. </p>
  516. </div>