Ficha OCaml 2. Do familiar para o novo.


 

Ficha OCaml 2. Do familiar para o novo.Nível básicoEx. Digit Sum.Ex. Triângulo de Floyd.Nível MédioEx. Procura de número.Ex. Troca de variável, com poupança.Ex. Função de Rolling Hash para string.

 

Nível básico


 

Ex. Digit Sum.

 

Considere o seguinte programa C que calcula a soma dos dígitos de uma dado número.

Proponha duas versões OCaml da função getSum:

 

  1. Uma versão iterativa, fiel a versão C, get_sum_iter : int -> int.

    Assim, get_sum_iter 3415 = 13

  2. Uma versão recursiva get_sum_rec : int -> int.

    Assim, get_sum_rec 3415 = 13


 

Ex. Triângulo de Floyd.

O triângulo de Floyd é uma matriz triangular de números naturais. O seu nome se refere ao Robert Floyd.

É definido pelo preenchimento das linhas do triângulo com números consecutivos, começando com 1 no canto superior esquerdo. Assim o triângulo de Floyd com 5 linhas é:

Um programa C que calcula este triângulo com um dado número de linhas é:

 

Escreva a função OCaml print_triangle : int -> unit que realize esta mesma tarefa. Assim:

 


 

 

Nível Médio


 

 

Ex. Procura de número.

Charles Babbage propôs um desafio de aritmética simples mas que pensava poder ser resolvido mais comodamente com máquinas se estas existissem, em particular se ele tivesse os meios de as construir.

 

Qual é o menor inteiro positivo cujo quadrado termina nos dígitos 269.696?

(Babbage, carta para Lord Bowden, 1837)

 

Ele achou que a resposta poderia ser 99.736, cujo quadrado é 9.947.269.696; mas ele não tinha certeza.

Obviamente ele resolveu o problema com papel e caneta, mas é tao mais prático, de facto usar um programa de computador.

 

 

Esta é uma solução em C (retirada do excelente site rosetta code, apesar deste exemplo aqui...).

Infelizmente este código tem alguns problemas escondidos.

  1. Liste estas situações e proponha um programa C isento destes problemas.
  2. Traduza o programa C corrigido para OCaml na forma de uma função babbage : unit -> int que de um argumento unit (o argumento vazio) calcula o inteiro pretendido pelo Charles Babbage .
  3. Não haverá melhor algoritmo? Se responder positivamente, proponha uma nova e otimizada versão OCaml. Esperamos a função seguinte: babbage_opt : unit -> int.
  4. Mas então, qual é este menor valor?

 


 

 

Ex. Troca de variável, com poupança.

Há uma forma simples de trocar o valor de duas variáveis numéricas, digamos x e y sem usar uma variável auxiliar.

 

 

Este pequeno programa C implementa esta ideia simples. Mas, sem devidos cuidados, é uma prenda envenenada.

  1. Proponha uma versão OCaml na forma da função swap : int -> int -> unit cujo esqueleto se mostra aqui e que lhe pedimos por completar:

     

  2. Liste os potenciais problemas que este programa tem (tanto na versão C como na versão OCaml).

  3. Proponha uma versão OCaml sem a parte envenenada, ou seja a função nice_swap : int -> int -> unit. Caso seja necessário poderá lançar a exceção Failure "nice_swap"

     

Uma alternativa ao método proposto é usar o operador bitwise XOR para trocar para números. O operador XOR bit a bit avalia cada bit do resultado como 1 se os bits correspondentes dos dois operandos forem diferentes, caso contrário, avalia 0.

Sejam x e y dois valores inteiros, seja a = x XOR y. Agora a XOR y será avaliado como x e a XOR x será avaliado como y.

Uma solução em C pode ser:

 

  1. Qual é o operador bitwise XOR em OCaml?
  2. Proponha uma versão OCaml na forma da função bitwise_swap : int -> int -> unit.
  3. Poderá esta solução também padecer do problema da solução original anterior?

 

 

Ex. Função de Rolling Hash para string.

Uma função de hash de uma string tem por objeto a conversão de uma string para um número inteiro que será intitulado como hash dessa string. Idealmente esta associação é única. Mas na prática duas strings podem ter o mesmo hash (fenômeno designado de colisão).

Uma boa função de hash é aquela em que a probabilidade em ter o mesmo hash para duas strings diferentes é residual ou é aquela para a qual é muito difícil saber que outra string tem uma colisão com uma dada string. Este tema será abordado com mais detalhe mais adiante nesta matéria e no curso.

Um caso particular de função de hash são as funções designadas de rolling hash. São funções auxiliares importantes em alguns algoritmos de processamento de texto. Por exemplo o algoritmo de procura de string em textos grandes conhecido por algoritmo Rabin-Karp para a procura em string usa uma função de rolling hash como função auxiliar.

 

Uma das funções Rollin Hash mais simples calcula uma hash para uma string da seguinte forma:

os valores e devem ser escolhidos cuidadosamente e onde os são os valores numéricos associados a cada letra considerada. Para o fim deste exercício, trabalharemos com strings constituídas exclusivamente por letras minúsculas, assim escolhemos e e o valor de 'a' é , o valor de 'b' é , etc.

Por exemplo

 

 

  1. Numa primeira versão, não tomaremos conta do tamanho dos inteiros manipulados, ou seja, vamos trabalhar com valores de tipo int na esperança que estes sejam suficientes. Proponha uma versão OCaml desta função rollingHash : string -> int (o tamanho de uma string pode ser calculado da própria string em OCaml, não é preciso fornecê-lo explicitamente).

    Assim rolling_hash "hello" = 14222002.

  2. Pretendemos agora garantir este mesmo cálculo mas com base numa função recursiva

    Assuma as definições seguintes:

Complete a definição da função rolling_hash_rec.

  1. Proponha agora uma redefinição da função rolling_hash (qualquer uma das duas acima referida) que recorra à aritmética de precisão arbitrária (módulo zarith). A função esperada é: rollingHash_wide : string -> Z.t