Introdução
Quanto mais informações nós temos sobre a ferramenta que nós utilizamos, mais assertivas e robustas serão as soluções que projetamos nela. Partindo desta premissa, vamos dar uma beliscada em alguns limites do AdvPL, relacionados a strings e precisão numérica.
Strings em AdvPL
A linguagem AdvPL permite que, uma variável que contenha o tipo “C” (Caractere) seja capaz de armazenar e lidar com uma sequência de zero ou mais bytes, onde cada byte têm o valor de 0 a 255. Na prática, uma variável caractere no AdvPL é um container de valor variável para números inteiros de 0 a 255. Por exemplo, uma string contendo apenas a letra “A” (maiúscula) , é representada na memória do servidor de aplicação por um byte contendo o valor decimal “65”. Da mesma forma, qualquer arquivo no disco, em qualquer formato ou extensão, nada mais é do que uma sequência de bytes. A questão toda reside na interpretação da sequência de bytes para cada formato de arquivo, e para isso devemos considerar a interface em questão.
Porém, o foco no momento são limites, certo? Então, uma variável do tipo Caractere no AdvPL pode conter 1MB -1 bytes. São 1048575 caracteres, desde a primeira versão do AP5 em 1999. Caso seja necessário manipular strings maiores em memória, é possivel fragmentar a string e colocá-la em elementos de um array.
Recentemente foi implementada uma configuração no TOTVS Application Server, disponível a partir da Build 7.00.131227A (Vide nota de documentação na TDN no link http://tdn.totvs.com/pages/viewpage.action?pageId=161349880), para permitir aumentar o tamanho máximo de uma string no AdvPL.
POrém, devemos lembrar que, quanto maior a String na memória, mais lentas e pesadas vão ficar as operações com ela, como buscas e trocas ( at, substr, stuff ), e o limite aumentado vale apenas para o TOTVS Application Server: Configurar o limite máximo de String para 2 MB não vai permitir você gravar essa string “inteira” em um registro no banco de dados, mesmo usando uma configuração para aumentar o tamanho de bytes suportados por um campo “M” Memo usando um banco relacional através do DBAccess, o limite de campo Memo é 1 MB. Essa mesma string com mais de 1 MB, você não vai conseguir trazer ela inteira pra dentro de um componente GET de múltiplas linhas na interface para edição.
Números em AdvPL
Já uma variável numérica no AdvPL é representada em memória usando uma variável de ponto flutuante de precisão dupla. São usados 8 bytes, e o número armazenado pode ser imenso, porém a precisão máxima respeitada por este numero são 15 digitos significativos. Isto é, um número inteiro na casa dos fantastilhões, a partir do 16o dígito da esqueda para a direita, não é mais “confiável”, e isto não vai causar erro de estouro no AdvPL, apenas o número não reflete a realidade.
Por exemplo: A divisão 321654987023 / 13, têm com resultado 24742691309.46153846 (…) Neste calculo, foi utilizada a calculadora do Windows, e considerando o resultado até a 8a casa decimal. Agora, vamos contar quantos dígitos tem este numero da esquerda para a direita, ignorando o ponto decimal: São 11 dígitos inteiros, e 8 decimais, somando 19 dígitos. Podemos afirmar no Advpl que o resultado até o 15o dígito é íntegro. Segure abaixo um fonte de exemplo realizando esta conta com AdvPL:
user function pocn1() local n1 := 321654987023 local n2 := 13 local n3 n3 := n1 / n2 conout(str(n3,20,6)) return
Numero mostrado no console : “24742691309.46149800”
Numero correto : “24742691309.46153846”
O fonte AdvPL converte o numero para string, para poder mostrá-lo no console, porém o tamanho do número extrapola a precisão do AdvPL, até a 3a casa decimal os resultados estão iguais, e a partir da 4a casa decimal o resultado difere. Se este número tivesse menos dígitos inteiros, a precisão decimal poderia ser maior, mas ainda limitada a 10 casas decimais. Logo, quanto maior a parte inteira do número em ponto flutuante, menor é a sua parte decimal que mantém a precisão no cálculo.
Para lidar corretamente com estas aproximações, dentro dos limites suportados em um cálculo, limitamos a precisão do resultado usando as funções Round() e NoRound(), para truncar ou arredondar um resultado de uma divisão, por exemplo.
Decimais de ponto fixo
Para suprir a necessidade de sistemas específicos, que precisam de uma precisão numérica maior do que a nativa do AdvPL, foi criado um novo tipo numérico “F” , conhecido como Decimal de Ponto Fixo , ou Fixed Size Decimal. Através de uma série de funções ( http://tdn.totvs.com/display/tec/Decimais+de+Ponto+Fixo ), podemos criar e manipular números com até 128 dígitos significativos. Porém, a aritmética destes números também é feita através destas funções. Não foi implementada interoperabilidade com os operadores aritméticos padrão da linguagem, apenas algumas funções numéricas nativas da linguagem suportam diretamente um argumento do tipo “F”.
Vamos ver o mesmo exemplo acima, reescrito para usar decimais de ponto fixo:
user function pocn2() local n1 := DEC_CREATE ( "321654987023", 12,0 ) local n2 := DEC_CREATE ( "13", 2,0 ) local n3 := DEC_DIV(n1,n2) Local n4 := DEC_RESCALE(n3,8,2) conout(cvaltochar(n4)) return
A conta é realizada, e o resultado da divisão cria um novo numero decimal de ponto fixo com uma precisão “imensa”. Como nós queremos o resultado pelo menos até a 8a casa decimal, usamos DEC_RESCALE() para re-definir a precisão máxima de decimais do número, e cValToChar() para convertê-lo para string, para ser mostrado no log de console. O Resultado esperado é : “24742691309.46153846”
Uma coisa interessante sobre a utilização das funções DEC_ … o valor decimal de ponto fixo no AdvPL é criado dentro do runtime da linguagem mediante estas funções. Este valor não é suportado para gravação no DBAccess no formato “F” Fized-Size. A camada de dados do AdvPL provê ainda os dados numéricos com os mesmos limites originais. Neste caso, se for necessário gravar um número com esta precisão, por hora ele deve ser gravado na base de dados como uma string, e re-convertido para “F” na memória caso necessário realizar operações aritméticas com ele.
Conclusão
Existem vários limites no AdvPL, apenas alguns estão documentados na TDN, e outros limites serão explorados em tópicos posteriores. Alguns limites são muito grandes, mas não é uma boa prática chegar perto desses limites, sob pena da aplicação tornar-se muito pesada. Quanto menores e mais bem organizadas são as informações e os algoritmos, mais leve fica a aplicação.
Até o próximo post, pessoal 😉