Commons Math é uma biblioteca desenvolvida em JAVA composta de um pequeno conjunto de utilitários com objetivo de resolver alguns problemas de programação, como os citados abaixo:
• Variâncias e estatísticas de resumo para uma lista de números;
• Ajuste de uma reta a um conjunto de pontos por meio de regressão linear;
• Encontrar uma curva suave que passe através de uma coleção de pontos (interpola- ção);
• Colocação de um modelo paramétrico para um conjunto de medidas usando méto- dos de mínimos quadrados;
• Resolução de equações envolvendo funções reais • Resolução de sistemas de equações lineares; • Solução de equações diferenciais ordinárias; • Minimização de funções multi-dimensional;
• Geração de números aleatórios com mais restrições (por exemplo, a distribuição gama), do que é possível usar no JDK;
• Realização de testes de significância estatística;
• Diversas funções matemáticas tais como fatoriais, coeficientes binomial e "funções especiais".
3.8.1
Organização
Commons Math é dividido em catorze sub-pacotes, com base na funcionalidade for- necida. Estes sub-pacotes são:
1. org.apache.commons.math.stat - estatísticas, testes estatísticos.
2. org.apache.commons.math.analysis - integração, interpolação, polinômios. 3. org.apache.commons.math.random - números aleatórios, cordas e de geração de dados.
4. org.apache.commons.math.special - funções especiais (Gama, Beta).
5. org.apache.commons.math.linear - matrizes, resolução de sistemas lineares.
6. org.apache.commons.math.util - matemática comum/ funções estendendo java.lang.Math. 7. org.apache.commons.math.complex - números complexos.
8. org.apache.commons.math.distribution - distribuições de probabilidade. 9. org.apache.commons.math.fraction - números racionais.
10. org.apache.commons.math.transform - métodos de transformação (Fast Fou- rier).
11. org.apache.commons.math.geometry - geometria (espaços euclidianos e Parti- cionamento Espacial Binária).
12. org.apache.commons.math.optimization - maximização ou minimização da função.
13. org.apache.commons.math.ode - equações diferenciais ordinárias integração. 14. org.apache.commons.math.genetics - algoritmos genéticos.
3.8.2
Números Complexos
O pacote org.apache.commons.math.complex é responsável pela criação do tipo nú- mero complexo e pela implementação das suas funções.
Este pacote é composto pelas seguintes classes: Complex
Esta classe é responsável pela representação do número complexo, ou seja, um nú- mero com uma parte real e uma parte imaginária.
As implementações de operações aritméticas lidam com NaN e valores infinitos de acordo com as regras para o tipo Double, ou seja, equals (java.lang.Object) é uma relação de equivalência para todas as instâncias que têm um NaN, na parte real ou imaginária, por exemplo, são considerados iguais:
• 1 + NaNi • NaN + i • NaN + NaNi Construtores:
1. Complex(double real): Cria um número complexo dado sua parte real.
2. Complex(double real, double imaginaria): Cria um número complexo dado sua parte real e imaginária.
Métodos:
A Tabela 3.4 apresenta todos os métodos implementados na classe Complex: Tabela 3.4: Métodos da classe Complex
Método Função
abs() Retorna o valor absoluto de um número com- plexo
acos() Calcula o arco-cosseno de um número com- plexo
add(Complex c) Retorna o complexo cujo valor é (this + c) add(double d) Retorna o complexo cujo valor é (this + d) asin() Calcula o arco-seno de um número complexo atan() Calcula o arco-tangente de um número com-
plexo
cosh() Calcula o cosseno hiperbólico de um número complexo
createComplex(double r, double i) Cria um número complexo dado sua parte real e imaginária
divide(Complex divisor) Retorna um número complexo cujo valor é (this / divisor)
Divide(double divisor) Retorna um número complexo cujo valor é (this / divisor)
equals(java.lang.Object outro) Testa se dois Complexos são iguais
exp() Calcula a função exponencial de um número complexo
getArgument() Calcula o argumento de um número complexo getField() Obtem o campo ao qual a instância pertence.
getImaginary() Retorna aparte imaginária de um número com- plexo
getReal() Retorna a parte real de um número complexo hasCode() Obter um hashCode para o número complexo isInfinity() Verifica se ambas as partes de um número com-
plexo tem um valor infinito
isNaN() Verifica se uma ou ambas as partes de um nú- mero complexo é NaN.
log() Calcula o logaritmo natural de um número com- plexo
multiplay(Complex f) Retorna um número complexo cujo valor é (this * f)
multiplay(double f) Retorna um número complexo cujo valor é (this * f)
multiplay(int f) Retorna um número complexo cujo valor é (this * f)
negate() Retorna um número complexo cujo valor é (- this)
nthRoot(int n) Calcula as n raízes de um número complexo pow(Complex x) Retorna um número complexo elevado à x pow(double x) Retorna um número complexo elevado à x reciprocal() Retorna o inverso multiplicativo
sin() Calcula o seno de um número complexo
sinh() Calcula o seno hiperbólico de um número com- plexo
sqrt() Calcula a raiz quadrada de um número com- plexo
sqrt1z() Calcula a raiz quadrada de (this -1)
substract(Complex s) Retorna um número complexo cujo valor é (this -s)
substract(double s) Retorna um número complexo cujo valor é (this -s)
tanh() Calcula a tangente hiperbólica de um número complexo
toString() Complex valueOf(double realPart) Cria um nú- mero complexo dado a parte real
valueOf(double r, double i) Cria um número complexo dado ambas as par- tes
ComplexField
Esta classe é responsável pela representação dos números complexos. É composta pelos seguintes métodos:
getInstance(): Obtém uma instância única retornando um ComplexField; getOne():Obtém a identidade multiplicativa e retorna um Complex; getRuntimeClass(): Retorna a classe runtime do FieldElement e getZero():Obtém a identidade aditiva e retorna um Complex; ComplexFormat
Esta classe é responsável pelo formato de um número complexo, Re(c) + Im(c)i. i pode ser substituído por j (ou qualquer outra coisa), e o formato de número de peças reais e imaginárias podem ser configurados.
Construtores:
1. ComplexFormat (): Cria uma instância com a parte imaginária padrão, i, e o for- mato de número padrão para ambas as partes reais e imaginárias.
2. ComplexFormat (formato java.text.NumberFormat): Cria uma instância com um formato de número personalizado para as partes reais e imaginárias.
3. ComplexFormat (java.text.NumberFormat realFormat, java.text.NumberFormat ima- ginaryFormat): Cria uma instância com um formato de número personalizado para a parte real e um formato de número personalizado para a parte imaginária.
4. ComplexFormat (imaginaryCharacter java.lang.String): Cria uma instância com um carácter personalizado imaginário, e no formato de número padrão para ambas as par- tes reais e imaginárias.
5. ComplexFormat (imaginaryCharacter java.lang.String, formato java.text.NumberFormat): Cria uma instância com um carácter personalizado imaginário, e um formato de número personalizado para as partes reais e imaginárias.
6. ComplexFormat (imaginaryCharacter java.lang.String, java.text.NumberFormat re- alFormat, java.text.NumberFormat imaginaryFormat): Cria uma instância com um carác- ter personalizado imaginário, um formato de número personalizado para a parte real, e um formato de número personalizado para a parte imaginária.
Métodos:
A Tabela 3.5 apresenta todos os métodos implementados na classe ComplexFormat: Tabela 3.5: Métodos da classe ComplexFormat
Método Função
format(Complex c) Este método chama for- mat(Object,StringBuffer,FieldPosition).
format(Complex complexo, StringBuffer sb, FieldPosi- tion pos)
Formata um objeto complexo para produzir uma string.
format(Double c) Esse método chama for-
mat(Object,StringBuffer,FieldPosition). format(Object obj, String-
Buffer sb, FieldPosition pos)
Formata um objeto para produzir uma string
getAvailableLocales() Obtêm um conjunto de localidades para as quais for- matos complexos estão disponíveis.
getImaginaryCharacter() Acessa o ImaginaryCharacter getImaginaryFormat() Formata o imaginaryFormat
getInstance() Retorna o formato padrão complexo para o local atual.
getInstance(Locale locale) Retorna o formato padrão complexo para a determi- nada localidade.
getInstance(String ima- ginaryCharacter, Locale locale)
Retorna o formato padrão complexo para a determi- nada localidade.
getRealFormat() Acessa o realFormat
parse(String source) Analisa uma string para produzir um objeto com- plexo.
parse(String source, ParsePo- sition pos)
Analisa uma string para produzir um objeto com- plexo.
3.9
Linguagens XSC
Há cinco décadas que estão sendo desenvolvidas pesquisas com o intuito de possibi- litar que máquinas suportem uma aritmética mais poderosa que a do ponto flutuante. A partir daí surgiram as linguagens XSC (eXtended Scientific Computing) que são lingua- gens para computação científica com algoritmos precisos carregando seu próprio controle de precisão.
No final da década de setenta, mais precisamente entre 1976 e 1979, duas universi- dades alemãs a Universidade Karlshure e Kaiserlautern se uniram para desenvolver uma extensão do PASCAL, que ficou conhecida como PASCAL-SC. Nos anos seguintes, jun- tamente com a IBM, foi lançada uma versão do FORTRAN 77 implementada em compu- tadores IBM/370 chamada ACRITH-SC.
A primeira geração das linguagens científicas foram as linguagens SC. As primeiras linguagens desenvolvidas foram FORTRAN-SC e PASCAL-SC, sendo esta última bas- tante citada na literatura sobre computação intervalar. Diversos pacotes foram criados para estas linguagens tanto para tarefas numéricas usuais quanto para resolução de sis-
temas lineares. Uma grande desvantagem desta linguagem é que só estavam disponíveis para uma variedade limitada de computadores [Kearfott 1996].
O desenvolvimento de novas linguagens de programação, como C++ e JAVA, torna- ram mais fácil a portabilidade das linguagens, ou seja, C++ e JAVA são capazes de se adaptar a hardwares e softwares. Deste fato surgiram as linguagens XSC, uma segunda geração de linguagens com maior exatidão com suporte a operações intervalares.
De acordo com [Dutra 2000], estas novas linguagens para computação científica têm como características principais:
• Sobrecarga de operadores,
• Agrupamento das funções em módulos específicos, • Vetores dinâmicos,
• Arredondamento direcionado,
• Tipos numéricos primitivos simples, como real, complexo e intervalo; • Operadores aritméticos de maior exatidão para os tipos numéricos e • Funções elementares de maior exatidão para os tipos numéricos.
Nas próximas subseções serão apresentadas duas destas linguagens: PASCAL-XSC e C-XSC.
3.9.1
PASCAL-XSC
A linguagem de programação PASCAL-XSC6 é uma ferramenta desenvolvida para solucionar problemas numéricos. Esta nova versão, diferente da PASCAL-SC, tem a vantagem de ser portável para outros hardwares e possui tipos de dados específicos para intervalos, números complexos e matrizes.
PASCAL-XSC foi desenvolvida na linguagem e programação C e seus compiladores são utilizados por uma variedade de computadores tais como computadores pessoais, es- tações de trabalho, mainframes e supercomputadores.
Os principais conceitos de Pascal-XSC são [Klatte et al. 1999]: • Padrão ISO do PASCAL;
• Conceito de operador universal;
• Funções e operadores com tipo de resultado arbitrário; • Sobrecarga de procedimentos;
• Rotinas de leitura e escrita; • Conceito de módulo;
• Arrays dinâmicos, acesso e subarrays; • Conceito de string;
• Arredondamento controlado; • Produto escalar ótimo;
• Tipo de padrão dotprecision e tipos aritméticos adicionais; • Aritmética de alta-exatidão para todos os tipos;
• Funções de alta-exatidão e avaliação exata de expressões; • Funções e operadores.
Esta linguagem pode implementar aplicações em módulos, cuja função é simplificar um programa (código) grande em pequenos blocos de códigos, para resolver problemas numéricos comuns, tais como:
• Sistemas de equações lineares e não-lineares; • Inversão de matrizes;
• Autovalores e Autovetores;
• Avaliação de expressões aritméticas;
• Avaliação de polinômios e busca de zeros de polinômios; • Quadratura numérica;
• Equações diferenciais; • Equações integrais; • Diferenciação automática; • Otimização.
Descrição dos tipos básicos
PASCAL-XSC é baseado na linguagem de programação PASCAL. Aqui serão apre- sentados os tipos básicos de PASCAL e as alterações que foram necessárias durante o desenvolvimento de PASCAL-XSC. Os tipos básicos em Pascal são os tipos integer, boolean, char, tipos de enumeração e subtipos. A seguir eles são definidos: [Klatte et al. 1999]
Integer: Uma constante literal do tipo integer é uma sequência de dígitos (decimais) com ou sem um sinal de + ou -. Em PASCAL-XSC, um valor do tipo inteiro pode também ser escrito como uma constante hexadecimal inicializada com o caractere $ e seguido por uma sequência de dígitos hexadecimais composto pelos dígitos 0, 1, ..., 9 e as letras A, B, ..., F e a, b, ..., f.
Real: Uma constante literal do tipo real tem a seguinte representação: ± mantissa E expoente.
A mantissa é uma sequência de dígitos com o sem ponto decimal e o expoente é um valor inteiro. A notação ’± mantissa’, onde o expoente é omitido, também é permitida.
Em Pascal-XSC, para realizar a conversão de constantes literais real dentro do for- mato de dados internos de maneira controlada, é necessária uma notação adicional para estas constantes. Enquanto a notação de real em PASCAL implica na conversão com arredondamento para o numero de ponto-flutuante mais próximo, ela possibilita a espe- cificação de constantes reais que são convertidas com arredondamento para o número de ponto-flutuante menor mais próximo ou para o maior mais próximo com notações ’(< ± mantissa E expoente)’ e ’(> ± mantissa E expoente)’ respectivamente. O E e o expoente podem ser omitidos mas os parênteses são obrigatórios.
Boolean: Este tipo é composto pelas constantes lógicas true e false, onde false < true. Char: Estas constantes são fechadas entre aspas simples. A ordem de relação é a seguinte:
’0’ < ’1’ < ... < ’9’ e ’a’ < ’b’ < ... < ’z’.
Tipos e enumeração: Este tipo consiste de constantes listadas na definição de tipos. A relação de ordem é definida pela ordem da enumeração. Um tipo de enumeração é definido pelo programador em uma definição de tipos. As constantes literais que são os elementos de uma enumeração não podem colidir com nenhum valor de outra enumera- ção.
Subtipos: Subtipos podem ser definidos pela especificação limite inferior e do limite superior (constante ... constante). O conjunto dos valores de um subtipo consiste em to- dos os valores que estão entre esses limites.
Dotprecision: PASCAL-XSC introduz esse novo tipo que é baseado no tipo real e permite a representação de produtos de dois números reais arbitrários e a adição de um número arbitrário de tais produtos em um formato de ponto-flutuante fixo de tamanho adequado. Se o formato real interno é fixado pela mantissa de tamanho l e os expoen- tes máximo (emax) e mínimo (emin) então uma variável dotprecission ocupa espaço de armazenamento da forma
Figura 3.2: Tamanho de uma variável do tipo dotprecision
O tamanho total é: L = g + 2emax + 2|emin| + 2l dígitos, onde g denota o número de dígitos guardados na acumulação de carga durante a adição.
Valores do tipo dotprecision tipicamente ocorrem durante a multiplicação de vetores e matrizes.
Os Tipos Intervalo e Complexo
PASCAL-XSC provê uma aritmética adicional para os tipos complex, interval e cin- terval. Eles não possuem constantes nem operadores como sua linguagem, portanto, tam- bém não há expressões. O uso de operadores e funções padrões requer o uso dos módulos aritméticos correspondentes (C_ARI, I_ARI e CI_ARI, respectivamente).
O tipo complex: O número complexo z= x + iy, com x sendo a parte real e y a parte imaginária podem ser declaradas em PASCAL como:
type complex = record re, im: real end;
Em PASCAL-XSC, este tipo é um tipo pré-definido. A declaração da variável var z:complex;
especifica uma variável complexa z. As partes real e imaginária de z podem ser aces- sadas por z.re e z.im, respectivamente.
a= [a, a] :={x ∈ R|a ≤ x ≤ a}
com a sendo o limite inferior e a o limite superior, PASCAL-XSC provê um tipo intervalpré-definido, declarado da seguinte forma:
type interval = record inf, sup: real end; A declaração de variável
var a: interval;
especifica uma variável a do tipo intervalo. Os limites superior e inferior podem ser acessados por a.inf e a.sup, respectivamente.
O tipo cinterval: Intervalos complexos são retângulos com lados paralelos aos eixos no plano complexo. O tipo pré-definido cinterval é definido por:
type cinterval: record re, im: interval end; As partes de um complexo intervalar c, declarado como
var c: cinterval;
podem ser acessados por c.re (um intervalo para a parte real) e c.im (um intervalo para a parte imaginária). Os seus limites podem ser acessados por c.re.inf, c.re.sup, c.im.inf e c.im.sup.
3.9.2
C-XSC
Segundo [Hofschuster & Krämer 2010], a linguagem C-XSC7é uma ferramenta bas-
tante poderosa e fácil de ser manuseada. Esta linguagem tem como principal objetivo auxiliar no desenvolvimento de algoritmos numéricos que necessitam de alta precisão. As características, ou tipos, mais importantes em C-XSC são os tipos real, complexo, in- tervalo e complexo intervalar.
A escolha da linguagem de programação C++ ao invés de C se dá pelo fato que esta segunda não ser apropriada para programar algoritmos numéricos, já que não fornece as estruturas de dados numéricas básicas como vetores e matrizes e não faz a checagem da indexação em arrays [Wiethoff 1996]. Já a linguagem C++, que é uma extensão da C
orientada à objetos, fornece várias facilidades que suprem as deficiências da C, já que agora a linguagem apresenta o conceito de classes e sobrecarga de operadores.
As características básicas da C-XSC são:
• Tipos de dados real (real), complexos (complex), intervalo (interval) e complexo intervalar (cinterval);
• Fornece uma notação específica para manipular subarrays de vetores e matrizes tornando-os tipos dinâmicos;
• Dotprecision, ou seja, tipos com precisão após a vírgula; • Maior precisão em operadores aritméticos pré-definidos; • Funções padrões de alta ocorrência;
• O controle de arredondamento durante operações de entrada e saída de dados se dá pelo conceito de sobrecarga dos operadores << e >> da C++. Sendo assim, é possível especificar o número de casas decimais do valor impresso.
• Fornece uma aritmética dinâmica de múltipla precisão, como o real longo (l_real) e o intervalo longo (l_interval), bem como também são implementados vetores dinâmicos correspondentes a matrizes, incluído operações vetoriais.
• Fornece uma biblioteca para resolução de problemas, que nada mais é do que uma coleção de rotinas de problemas padrões para análises numéricas, com isto, garante resultados de alta precisão.
Descrição dos tipos básicos
C-XSC provê os tipos de dados numéricos simples como real, interval, complex e cinterval. Cada um com suas próprias aritméticas, operadores relacionais e funções arit- méticas padrão. Todos os operadores aritméticos pré-definidos fornecem resultados com uma precisão de pelo menos 1 ulp(unidade na última casa decimal), desta forma é possí- vel ter a máxima precisão na computação científica nos seus tipos.
O arredondamento dos operadores aritméticos pode ser controlado usando os tipos intervale cinterval. Funções estão disponíveis para todas as combinações matematica- mente úteis. Constantes literais podem ser convertidas com a máxima exatidão. Todas as funções matemáticas padrão para os tipos de dados numéricos podem ser chamados por seus nomes genéricos e fornecem resultados com garantia de alta precisão para argumen- tos arbitrários admissíveis.
Os tipos em C-XSC são definidos da seguinte forma:
Real: De acordo com [C-XSC 2010], a aritmética de C-XSC é baseada no padrão IEEE para aritmética binária de ponto-flutuante. O tipo de dados real consiste de todos os tipos de ponto-flutuante e valores especiais especificados pelo padrão para números de ponto-flutuante com mantissa de tamanho duplo. Portanto, um número do tipo real tem 64-bit, e a base b do sistema de ponto-flutuante, R = R(b,l,emin, emax), é 2.
Se o compilador de C de um computador não está conforme o padrão, o tipo real uti- liza sua própria aritmética IEEE de ponto flutuante. Portanto, a introdução de um novo tipo de dados é necessário para que se tenha a portabilidade.
Estrutura: Um esboço de um ponto-flutuante é observado na Figura abaixo:
Figura 3.3: Formato de um ponto-flutuante
O bit mais significativo o bit de sinal e é denotado por s. Se ele é um, o número de ponto-flutuante não zero é negativo, caso contrário é positivo. Os outros 63 bits são divi- didos entre a mantissa e o expoente.
Mantissa:O tamanho da mantissa, l, de um número real contém 53 bits. O bit 53 não é explicitamente armazenado. Este valor depende da normalização ou desnormalização na representação de um ponto-flutuante. Com este tamanho de mantissa, números decimais
com um máximo de 15 dígitos fracionários podem ser representados com alta exatidão. Uma vez que um formato binário de ponto-flutuante é usado, é impossível armazenar to- dos os números decimais precisamente. No entanto, pode-se ter constantes decimais com arredondamento controlado dentro de uma variável do tipo real.
Expoente: O expoente e de um ponto-flutuante é armazenado em um campo de 11 bits. Um valor de 1023 é subtraído do valor armazenado para obter o valor do expo- ente real. Isto produz emin= −1022 e emax= 1023. Convertendo para o sistema decimal
−308 ≤ e ≤ 308.
Complex: Este tipo é utilizado para armazenar números complexos z= x + iy ∈ C, onde x denota a parte real, y a parte imaginária e i denota a unidade imaginária√−1.
Interval: Este tipo é utilizado para representar intervalos sobre os números reais de ponto-flutuante:
[a] = [a, a] ={x ∈ R|a ≤ x ≤ a ∈ R}
ou seja, a representa o conjunto de todos os números fechados entro dos limites a, a ∈ R. A notação a o limite inferior e a denota o limite superior do intervalo [a].
Cinterval: Este tipo de dado é utilizado para armazenar complexos intervalares. Eles são definidos como retângulos da forma z = [x] + i[y] ∈ C, onde a parte real [x] ∈ C e a parte imaginária [y] ∈ C, com partes paralelas aos eixos no plano complexo, como indica a Figura 3.4.
Figura 3.4: Complexo Intervalar [3.0,4.5] + i[1.0,2.0]
Dotprecision: Os tipos dotprecision, idotprecision, cdotprecision e cidotprecision são baseados nos tipos de dados real, interval, complex e cinterval respectivamente. Variáveis