Uma coisa que está na minha lista faz algum tempo é fazer testes de velocidade com as várias plaquinhas que eu tenho. Mais pela brincadeira, pois estes testes normalmente não representam direito o desempenho em aplicações reais. E aí me surgiu a ideia de fazer a comparação calculando os dígitos do Pi.
Chovendo no molhado, o Pi é a razão entre a circunferência de um círculo e o seu diâmetro. É um número "irracional", que não pode ser colocado na forma de fração e na forma decimal tem um número infinito de dígitos. Calcular os dígitos do Pi tem ocupado pessoas desde muito tempo atrás (a wikipedia tem uma cronologia).
A partir de 1400 sabe-se que o Pi pode ser calculado através da soma de séries infinitas. Com o advento do computador foram desenvolvidos algorítimos que facilitam e aceleram o cálculo. Na minha busca eu rapidamente achei o seguinte programa (de autoria de Dik T Winter):
- int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;
- for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,
- f[b]=d%--g,d/=g--,--b;d*=b);}
Você talvez encontre uma versão com pequenas diferenças, esta acima calcula os primeiros 800 dígitos do Pi. Este programa está, propositalmente, compactado e ofuscado. Para os meus testes eu fiz uma versão um pouco mais legível e adaptada para compilação na IDE do Arduino:
- /*
- * Calculo dos dígito de Pi
- * Usando o algoritimo Spigot de Rabinowitz e Wagon
- * Adaptação da versão compacta e obsfucada escrita por Dik T. Winter:
- *
- * int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;
- * for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,
- * f[b]=d%--g,d/=g--,--b;d*=b);}
- *
- * Comentários nas declarações copiados de
- * https://stackoverflow.com/questions/4084571/implementing-the-spigot-algorithm-for-%CF%80-pi
- *
- * Daniel Quadros junho/2021
- */
- #define NDIGITS 10000 //max digits to compute
- #define LEN (NDIGITS/4+1)*14 //nec. array length
- int32_t a = 10000; //new base, 4 decimal digits
- int32_t b = 0; //nominator prev. base
- int32_t c = LEN; //index
- int32_t d = 0; //accumulator and carry
- int32_t e = 0; //save previous 4 digits
- int32_t f[LEN+1]; //array of 4-digit-decimals
- int32_t g = 0; //denom previous base
- void setup() {
- delay(1000);
- Serial.begin(115200);
- }
- // Não usado
- void loop() {
- while (Serial.read() != '\n') {
- delay(100);
- }
- Serial.println("PI = ");
- long inicio = millis();
- calcula();
- long tempo = millis() - inicio;
- Serial.println();
- Serial.print ("Tempo = ");
- Serial.print (tempo);
- Serial.println ("ms");
- }
- // Cálculo dos dígitos do Pi
- void calcula() {
- char dig[5] = "0000"; // para fazer o print
- int n = 0; // para mudar de linha a cada 100 dígitos
- c = LEN;
- for(b = 0; b < c; b++) {
- f[b] = a/5;
- }
- e = 0;
- for (; c > 0; c -= 14) {
- d = 0;
- g = c*2;
- b = c;
- for (;;) {
- d += f[b]*a;
- f[b] = d % --g;
- d /= g--;
- if (--b == 0) {
- break;
- }
- d *= b;
- }
- uint16_t val = e+d/a;
- dig[0] = (val / 1000) + '0';
- dig[1] = ((val / 100) % 10) + '0';
- dig[2] = ((val / 10) % 10) + '0';
- dig[3] = (val % 10) + '0';
- Serial.print (dig);
- n += 4;
- if (n == 100) {
- Serial.println();
- n = 0;
- }
- e = d % a;
- }
- }
Mas o que está sendo feito, e porque? Não me arrisco a dizer que entendi completamente, mas aqui vão algumas informações e referências. O algoritmo usado pertence a uma classe chamada "spigot" (torneira): os dígitos vão sendo gerados na ordem e não são usados diretamente no cálculo dos dígitos seguintes. Este algorítimo específico foi criado em 1995 por Stan Wagon and Stanley Rabinowitz.
Algumas características interessantes deste algorítimo:
- Requer somente soma, subtração, multiplicação e divisão de inteiros
- Os dígitos são gerados de 4 em 4
- A quantidade de dígitos a calcular precisa ser definida a priori
- Requer um vetor com 14 inteiros para cada conjunto de 4 dígitos
Eu rodei o programa (acertando o número de dígitos conforme a memória disponível) em algumas placas da minha coleção: Arduino Uno, Raspberry Pi Pico, ESP32, Black Pill (STM32) e Seeduino XIAO. O resultado esta aqui, no meu canal do YouTube.
Nenhum comentário:
Postar um comentário