O objetivo do trabalho é implementar, na linguagem C, uma biblioteca
que permita representar valores inteiros signed de 128 bits,
e ofereça algumas operações aritméticas básicas sobre esses valores (soma,
subtração, multiplicação, negação) e operações de deslocamento de bits.
Para representar um valor inteiro de 128 bits, a biblioteca deverá usar
a seguinte definição:
#define NUM_BITS 128
typedef unsigned char BigInt[NUM_BITS/8];
Ou seja, um valor do tipo BigInt deve ser representado por um
array de bytes, interpretado como um único inteiro
de 128 bits, em complemento a 2 e seguindo a ordenação little-endian.
Por exemplo, o array
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
representa o valor inteiro 1.
O array a seguir
{0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
representa o inteiro 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE, que corresponde ao
valor -2 em complemento a 2.
/* Atribuição (com extensão) */ void big_val (BigInt res, long val); /* Operações Aritméticas */ /* res = -a */ void big_comp2(BigInt res, BigInt a); /* res = a + b */ void big_sum(BigInt res, BigInt a, BigInt b); /* res = a - b */ void big_sub(BigInt res, BigInt a, BigInt b); /* res = a * b */ void big_mul(BigInt res, BigInt a, BigInt b); /* Operações de Deslocamento */ /* res = a << n */ void big_shl(BigInt res, BigInt a, int n); /* res = a >> n (lógico)*/ void big_shr(BigInt res, BigInt a, int n); /* res = a >> n (aritmético)*/ void big_sar(BigInt res, BigInt a, int n);
big_val
atribui a
res
o valor fornecido por l
(um signed long), corretamente estendido para 128 bits.
big_comp2
atribui a
res
o valor "negado" (complemento a 2) de
a
.
big_sum
, big_sub
e big_mul
realizam, respectivamente,
as operações de soma, subtração e multiplicação
de dois inteiros de 128 bits (a
e b
), armazenando o resultado em res
.
big_shl
realiza um deslocamento
para a esquerda (shift left) de um inteiro de 128 bits (a
),
armazenando em res
o resultado da operação.
Sua implementação pode assumir que o valor de n
é um inteiro no intervalo [0,127].
big_shr
realiza um deslocamento
lógico
para a direita (shift right) de um inteiro de 128 bits (a
),
armazenando em res
o
resultado da operação.
Sua implementação pode assumir que o valor de n
é um inteiro no intervalo [0,127].
bigint.c
,
contendo a implementação das funções descritas acima
e funções auxiliares, se for o caso.
Esse arquivo não deve conter uma função main
!
O arquivo bigint.c
deverá incluir o arquivo de cabeçalho
bigint.h
,
fornecido aqui.
Você não deve alterar este arquivo. Caso necessite de definições
auxiliares, faça-as dentro de seu arquivo fonte bigint.c
.
Para testar seu programa, use técnica de TDD (Test Driven Design), na qual testes são escritos antes do código. O propósito é garantir ao desenvolvedor (você) ter um bom entendimento dos requisitos do trabalho antes de implementar o programa. Com isto a automação de testes é praticada desde o início do desenvolvimento, permitindo a elaboração e execução contínua de testes de regressão. Desta forma fortalecemos a criação de um código que nasce simples, testável e próximo aos requisitos do trabalho. Os passos gerais para seguir tal técnica:
Para este trabalho, crie um outro arquivo, testebigint.c
,
contendo uma função main
.
Este arquivo também deverá incluir o arquivo de cabeçalho bigint.h
,
além de outras possíveis funções para realização dos vários testes que julgar
necessário.
Crie seu programa executável testebigint
) com a linha:
gcc -Wall -o testebigint bigint.c testebigint.c
Importante! Se, por acaso, você não implementar alguma função, crie uma função dummy para que o programa de teste acima além do usado para a correção do trabalho possa ser gerado sem problemas.
Essa função deverá ter o nome da função não implementada e o corpo
{ return; }Esta técnica é denominada de mocking que consiste em criar funções apenas para teste quando as reais ainda não se encontram implementadas. Isto é também prático para o trabalho incremental em equipe, pois permite tornar indepentende o trabalho de cada membro.
Lembre-se que deve haver uma preocupação constante em subtituir as funções
dummy ou Mocks pelos códigos corretos quando estes estiverem
testados e disponibilizados.
Por exemplo, você pode implementar primeiro a operação de atribuição, e para testá-la usar alguma função auxiliar que realize um dump do array usado para armazenar o inteiro de 128 bits. Em seguida, vá implementando o teste e correspondente função, um a um, passando para o próximo quando estiver funcionando.
Devem ser entregues via Moodle / EAD três arquivos:
Coloque no início do arquivo fonte, como comentário, os nomes dos integrantes do grupo, da seguinte forma:
/* Nome_do_Aluno1 Matricula Turma */ /* Nome_do_Aluno2 Matricula Turma */Lembre-se que este arquivo não deve conter a função
main
!
main
e demais possíveis funções auxiliares
que você usou para testar seu trabalho.
Coloque no início do arquivo fonte, como comentário, os nomes dos integrantes do grupo, da seguinte forma:
/* Nome_do_Aluno1 Matricula Turma */ /* Nome_do_Aluno2 Matricula Turma */
um arquivo texto, chamado relatorio.txt, relatando o que está funcionando e, eventualmente, o que não está funcionando. Explique sua estratégia geral de teste, como organizou seu roteiro e consequentemente seu arquivo de teste.
Você não deve explicar a sua implementação neste relatório. Seu programa deve ser suficientemente claro e bem comentado.
Coloque também no relatório o nome dos integrantes do grupo.
Para grupos de alunos da mesma turma, apenas uma entrega é necessária (usando o login de um dos integrantes do grupo).
Se o grupo for composto por alunos de turmas diferentes, os dois alunos deverão realizar a entrega, e avisar aos professores,