Jump to content

bitcount em C, já implementaram, vale a pena?


Omesmo

Recommended Posts

2 minutes ago, DixieJoe said:

Então você programa em Assembly?

Legal.

Veja os exemplos que mandei pro omesmo que tem rotinas em Assembly que eu comprei de um programador da Servia há muitos anos atrás. Tem os fontes e alguns exemplos.

 

As rotinas dele voam... Chegam a 300.000.000 de conjuntos gerados e filtrados por segundo.

 

 

 

SIm, mas Assembly para plataforma dos micro - controladores ( PIC, 8051 ), tal qual fazia com 8080, 8085, Z80, anos 80 e 90 !

 

mas não programa em Assembly para PC, muitos processadores diferentes, complicado portar cada caso :) 

 

depois darei uma olhadinha nos códigos, quem sabe, consiga entender algo :) 

Link to comment
Share on other sites

Agora, DixieJoe disse:

Maravilha, eolocos!

 

Tentei programar algumas coisas para PIC mas apanhei muito e desisti, kkk

 

 

Eu e meu filho fizemos algumas tentativas de dispenser de álcool gel automatico usando micro-controladores PIC

(no auge da pandemia).

 

Funcionava até bem, mas não tivemos grana para investir e fazer marketing.

  • Like 1
Link to comment
Share on other sites

7 minutes ago, DixieJoe said:

Maravilha, eolocos!

 

Tentei programar algumas coisas para PIC mas apanhei muito e desisti, kkk

 

 

 

PIC só é complicado nos primeiros dias :)

 

depois piora :) 

 

mas eu gosto de programar em Assembly, dá uns nós na cabeça, mas é muito legal :) 

 

porém, eu só faço isto, quando há um trabalho específico, sob encomenda, para a área médica !

 

efetuo todo o trabalho, desenho mecânico, elétrico, eletrônico, cálculos dos circuitos, programação e finalmente, monto um protótipo e entrego ao cliente.

 

mas, não coloco um centavo meu no projeto, o cliente banca tudo, no final, recebo minha grana e pronto :) 

Link to comment
Share on other sites

mas de volta o tópico :) 

 

eu não sei fazer a tal comparação entre "strings" ( da loteria ) de outra forma, então converto tudo em bits, e simplesmente varro os 2 arrays ao mesmo tempo e comparo bit a bit ! 

 

em Perl, é possível verificar de modo fácil, se uma dezena está dentro de um array:

 

if ( $dezena ~ @array ) {  $counter++ } 

Link to comment
Share on other sites

4 minutes ago, Eolocos said:

mas de volta o tópico :) 

 

eu não sei fazer a tal comparação entre "strings" ( da loteria ) de outra forma, então converto tudo em bits, e simplesmente varro os 2 arrays ao mesmo tempo e comparo bit a bit ! 

 

em Perl, é possível verificar de modo fácil, se uma dezena está dentro de um array:

 

if ( $dezena ~ @array ) {  $counter++ } 

 

 

assim, se quiser usar o Diagrama de Venn, que o @sorel gosta tanto, fica mais fácil:

 

if ( $dezena ~ @array1 && $dezena ~ @array2 ) { push @array3, $dezena }

Edited by Eolocos
o burrinho aqui errou o nome do diagrama !
Link to comment
Share on other sites

2 minutos atrás, Eolocos disse:

 

 

assim, se quiser usar o Diagrama de Venn, que o @sorel gosta tanto, fica mais fácil:

 

if ( $dezena ~ @array1 && $dezena ~ @array2 ) { push @array3, $dezena }

troço complicado, quando sorel aparecer vc se vira com ele tá, mas se vc entende isso deve ser facil entender o sorel

mas no caso acho que isso faz um força bruta testa dentro de um loop


em vba eu faço algo como
for c=1 to final
if combinação(bit(c)) then cont=cont+1

combinação seria uma matriz com o tamanho da loteria com cada dezena setada em sua posição

mais ou menos isso
mas procesadores tem instruções proprias de comparar e contar bit em um intenge
eu uso isso para transformar a combinação em um inteiro

Function combin_para_inteiro(matriz1 As Range) As Long
    Dim i As Long
    Dim num As Long
    arr1 = matriz1.Value2
    For i = 1 To UBound(arr1, 2)
        num = num + 2 ^ (arr1(1, i) - 1)
    Next i
    
    combin_para_inteiro = num
End Function



 

 

  • Like 1
  • Haha 1
Link to comment
Share on other sites

@DixieJoepo vc falou que nao gostou do gpt
eu pedi a ele para converter um assembly daquele em c , pode até pedi uma explicação da funcionalidade

"só nao sei se está falando a verdade kkkk"

 

; function LotIndex( Lot:LotMap ): LongInt; far;

LotIndex PROC FAR Lot:DWORD
        PUBLIC LotIndex
        xor  eax, eax           ; Index := 0
        les  si, Triangle
        mov  ecx, Lot
@@41:   jecxz @@44
@@42:   shr  ecx, 1             ; Inc(x)
        jc   @@43               ; if x in ...
        add  si, 4              ; Inc(j)
        jmp  @@42
@@43:   add  eax, es:[si]       ; Index := Index + ...
        add  si, 128            ; Inc(i)
        jmp  @@41
@@44:   mov  edx, eax
        shr  edx, 16
        ret
LotIndex ENDP
Citar

Sim, é possível converter o código assembly em uma função equivalente em C. A conversão depende da arquitetura do processador em que o código assembly será executado. Abaixo, segue um exemplo de como a função em assembly poderia ser escrita em C para a arquitetura x86:

ong LotIndex(long Lot)
{
    long Index = 0;
    char* Triangle = (char*)0x12345678; // endereço da variável Triangle

    while (Lot != 0)
    {
        if (Lot & 1)
        {
            Triangle += 4;
        }
        else
        {
            Index += *((int*)Triangle);
            Triangle += 128;
        }
        Lot >>= 1;
    }

    return (Index >> 16);
}

Neste exemplo, a função em C tem a mesma assinatura da função em assembly, com um parâmetro do tipo long e um valor de retorno do tipo long. A função usa uma variável Index para acumular o valor da soma e um ponteiro Triangle para apontar para a variável correspondente em memória. O endereço da variável Triangle foi definido como 0x12345678 como exemplo. É necessário alterar esse valor para o endereço correto da variável na memória.

A lógica do loop em C é equivalente à do loop em assembly. A verificação de paridade de Lot é realizada usando o operador & para testar se o bit menos significativo é 1. A operação de deslocamento é realizada usando o operador >>. As operações de adição e incremento de ponteiro são realizadas usando os operadores + e +=. O tipo do ponteiro Triangle foi definido como char*, mas pode ser alterado para o tipo correto, dependendo da arquitetura e do tipo de dados armazenados na variável.

Por fim, o valor retornado é obtido a partir do valor acumulado em Index e deslocado 16 bits para a direita, para obter a metade superior do valor.

 

  • Like 1
Link to comment
Share on other sites

1 minuto atrás, DixieJoe disse:

A questão é saber se está correto e se funciona!

 

a ia deu uma descrição completa antes disso ,
dependendo de como se faz a pergunta e das informações que se apresenta ela até que é bem responsiva

tipo aquele gerador de combinações assembly para pb
ele deu uma descrição do que faz  o problema é que pedir para gfazer em C e ela fez em swift kkkk, eu nem tinha reparado até ler o nome
 

  • Like 1
Link to comment
Share on other sites

16 minutos atrás, Omesmo disse:

tipo aquele gerador de combinações assembly para pb
ele deu uma descrição do que faz  o problema é que pedir para gfazer em C e ela fez em swift kkkk, eu nem tinha reparado até ler o nome
 

no sufoco consegui fazer ele gerar em C
as vezes é necessário reiniciar o chat ou criar um do zero, senao ele se confunde nas coisas que ele mesmo disse

 

Citar
consegue montar o mesmo codigo dentro da linguagem "C" ?
 
 

Sim, é possível traduzir o código do PowerBASIC para C. No entanto, é importante lembrar que o código original contém algumas variáveis e declarações globais, e que essas variáveis precisariam ser replicadas de alguma forma em C.

Abaixo está uma tradução aproximada do código do PowerBASIC para C. Esta tradução é apenas um ponto de partida e pode precisar ser ajustada para atender às necessidades específicas do projeto:

#include <stdio.h>
#include <stdlib.h>

#define MAX_COMBS 51000000

long lotto_combs[MAX_COMBS * 7];
long *ptr2_lotto_combs;

long number_of_combinations = 0;
long *ptr2_number_of_combinations;

long full_number = 0;
long *ptr2_full_number;

void generate_combinations() {
    asm {
        push ebx
        push ecx
        push edx
        push esi
        push edi
        
        mov esi, ptr2_lotto_combs
        mov edi, ptr2_number_of_combinations
        mov ebx, ptr2_full_number

        mov edx, 1
        mov eax, [ebx]
        mov ecx, [eax]
        shl ecx, 1

        mov [edi], 0

    startloop:
        mov [esi+edx-1], 1
        call next_combination
        cmp [eax], 0
        jne add_combination
        jmp endloop

    add_combination:
        add [edi], 1

    endloop:
        cmp edx, ecx
        jne startloop

        pop edi
        pop esi
        pop edx
        pop ecx
        pop ebx
    }
}

void next_combination() {
    asm {
        push ebx
        push ecx
        push edx
        push esi

        mov esi, ptr2_lotto_combs
        mov ebx, ptr2_full_number
        mov edx, 7

        loop1:
            dec edx
            mov ecx, [esi+edx-1]
            cmp ecx, [ebx]
            je loop1
            mov [esi+edx-1], ecx+1
            mov eax, edx
            mul eax
            sub eax, edx
            mov edx, 6
            div edx
            mov ecx, [esi+eax*6-6]
            mov ebx, [esi+edx*6-6]
            cmp ecx, ebx
            jb loop1

        pop esi
        pop edx
        pop ecx
        pop ebx
    }
}

int main() {
    ptr2_lotto_combs = &lotto_combs[0];
    ptr2_number_of_combinations = &number_of_combinations;
    ptr2_full_number = &full_number;

    // Aqui é necessário definir o valor de full_number antes de chamar a função generate_combinations()

    generate_combinations();

    // O resultado das combinações geradas pode ser acessado através de lotto_combs[] usando a fórmula lotto_combs[(i-1)*6+j]
}
#include <stdio.h>

// Define global variables
#define MAX_COMBS 51000000
unsigned char lotto_combs[MAX_COMBS * 7];
unsigned char *ptr2_lotto_combs = &lotto_combs[0];
long number_of_combinations = 0;
long *ptr2_number_of_combinations = &number_of_combinations;
long full_number = 0;
long *ptr2_full_number = &full_number;

void generate_combinations() {
    __asm {
        mov ebx, 1         // i = 1
        mov ecx, [ptr2_lotto_combs]
        mov eax, [ptr2_number_of_combinations]
        mov edx, [ptr2_full_number]
        jmp start

    loop_i:
        inc ebx            // i++
        cmp ebx, [eax]     // if i > number_of_combinations, exit loop
        jg end_loop

    start:
        mov esi, ebx
        mov edi, ecx

    loop_j:
        mov [edi], esi
        inc edi
        shr esi, 8
        cmp edi, ecx + 6   // if j == 6, exit loop
        je end_j_loop
        jmp loop_j

    end_j_loop:
        inc [eax]          // increment number_of_combinations
        add ecx, 7         // increment lotto_combs pointer
        jmp loop_i

    end_loop:
    }
}

int main() {
    ptr2_lotto_combs = &lotto_combs[0];
    ptr2_number_of_combinations = &number_of_combinations;
    ptr2_full_number = &full_number;

    full_number = 49;     // set full_number to 49 (total number in pool)
    generate_combinations();

    // Test access to combinations
    printf("Combination 1, number 1: %d\n", lotto_combs[0] * 6 + 0);
    printf("Combination 1, number 2: %d\n", lotto_combs[0] * 6 + 1);
    printf("Combination 1, number 3: %d\n", lotto_combs[0] * 6 + 2);
    printf("Combination 1, number 4: %d\n", lotto_combs[0] * 6 + 3);
    printf("Combination 1, number 5: %d\n", lotto_combs[0] * 6 + 4);
    printf("Combination 1, number 6: %d\n", lotto_combs[0] * 6 + 5);

    printf("Combination 2, number 1: %d\n", lotto_combs[7] * 6 + 0);
    printf("Combination 2, number 2: %d\n", lotto_combs[7] * 6 + 1);
    printf("Combination 2, number 3: %d\n", lotto_combs[7] * 6 + 2);
    printf("Combination 2, number 4: %d\n", lotto_combs[7] * 6 + 3);
    printf("Combination 2, number 5: %d\n", lotto_combs[7] * 6 + 4);
    printf("Combination 2, number 6: %d\n", lotto_combs[7] * 6 + 5);

    return 0;
}

Note that the generated combinations

 

 

  • Like 1
Link to comment
Share on other sites

32767 49151 81919 147455 278527 540671 1064959 2113535 4210687 8404991 16793599
  57343 90111 155647 286719 548863 1073151 2121727 4218879 8413183 16801791
    106495 172031 303103 565247 1089535 2138111 4235263 8429567 16818175
      204799 335871 598015 1122303 2170879 4268031 8462335 16850943
        401407 663551 1187839 2236415 4333567 8527871 16916479
          794623 1318911 2367487 4464639 8658943 17047551
            1581055 2629631 4726783 8921087 17309695
              3153919 5251071 9445375 17833983

 

 

This sequence of numbers appears to be a pattern of values that increase by multiplying the previous value by 1.5 and then adding 1. Here's the first few numbers in the sequence with this calculation:

32767

32767 * 1.5 + 1 = 49151

49151 * 1.5 + 1 = 81919

81919 * 1.5 + 1 = 147455

147455 * 1.5 + 1 = 278527

278527 * 1.5 + 1 = 540671

540671 * 1.5 + 1 = 1064959

1064959 * 1.5 + 1 = 2113535

2113535 * 1.5 + 1 = 4210687

4210687 * 1.5 + 1 = 8404991

8404991 * 1.5 + 1 = 16793599

 

kkk esse gpt as vezes tem preguiça

 

  • Like 1
Link to comment
Share on other sites

12 hours ago, Omesmo said:

troço complicado, quando sorel aparecer vc se vira com ele tá, mas se vc entende isso deve ser facil entender o sorel

mas no caso acho que isso faz um força bruta testa dentro de um loop


em vba eu faço algo como
for c=1 to final
if combinação(bit(c)) then cont=cont+1

combinação seria uma matriz com o tamanho da loteria com cada dezena setada em sua posição

mais ou menos isso
mas procesadores tem instruções proprias de comparar e contar bit em um intenge
eu uso isso para transformar a combinação em um inteiro

Function combin_para_inteiro(matriz1 As Range) As Long
    Dim i As Long
    Dim num As Long
    arr1 = matriz1.Value2
    For i = 1 To UBound(arr1, 2)
        num = num + 2 ^ (arr1(1, i) - 1)
    Next i
    
    combin_para_inteiro = num
End Function



 

 

 

não achei complicado não, achei até bonitinho :) 

 

o operador ~ simplesmente busca se a $dezena está dentro do array, não importa a posição !

se estiver dentro dos 2 arrays, então está também dentro do array3, push coloca a tal $dezena dentro do array3

 

mas só uso isto quando não importa onde dentro do array está :) 

 

quanto ao Sorel,

 

na minha opinião, é uma pessoa muito inteligente, com mil ideias, porém, o raciocínio dele é muito rápido para mim, eu não consigo acompanhar tudo o que ele posta, e olha que já li trocentas postagens dele

Link to comment
Share on other sites

@Sorel é de outro planeta!!! ele está aqui tentando replicar o conhecimento mas como nosso planeta está ainda em evolução agente não consegue acompanhá-lo. kkk

 

@Eolocos Entender de Assembly é pra poucos. Quando mexia com gps tentei aprender pra quebrar software mas é muito difícil...fiquei 03 meses debruçado lendo e praticando diariamente (quase perco a mulher, ela pensava que eu tinha outra, só dava bola pro notebook...kkk)...desisti...mas até hoje a "Ida Pro" me perturba nos meus sonhos.

 

 

 


“Quem conhece os outros é inteligente. Quem conhece a si mesmo é iluminado. Quem vence os outros é forte. Quem vence a si mesmo é invencível.” 

Lao Tsé

\[,,]/

Link to comment
Share on other sites

Em 17/02/2023 em 12:25, Omesmo disse:

algum programador já usou contagem de bits em C para conferencia em loterias?

quais métodos implementaram?

é bom na velocidade ou nao é coisa de outro mundo?
vale a pena implementar?

 

 

@Jimmy seria bom mudar o nome mudar o nome dessa seção para  "programas & programação para loterias, assim atenderia tbm a implementação de codigos

Olá, @Omesmo

 

Eu uso contagem de bits para programas de loteria. É a forma mais rápida para se trabalhar com poucas operações de máquina em loterias, o que torna o programa bem mais rápido.

 

A minha experiência em si não é com C, tendo em vista que hoje em dia não é considerado uma linguagem "moderna", mas, sim, com Nim, que compila para C. Ou seja, no final das contas eu uso C só que com uma camada de abstração de Nim.

 

Vamos lá. Há alguns anos eu fiz 10 implementações de countbits diferentes.

Implementação 01: conta os bits por subtração em um loop while.

Implementação 02: conta os bits por deslocamento

Implementação 03: "Counting bits set, in parallel" (contagem de bits definidos, em paralelo) => https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel

Implementação 04: Conta os bits usando uma tabela de consulta de 8 bits usando um while loop até cobrir todos os bits

Implementação 05: Conta os bits usando uma tabela de consulta de 8 bits fazendo a soma aninhada de acordo com a quantidade de bits, sem precisar de um while loop

Implementação 06: Conta os bits usando uma tabela de consulta de 8 bits fazendo a soma aninhada de acordo com a quantidade de bits, sem precisar de um while loop (diferença quase nula da implementação anterior)

Implementação 07: Conta os bits usando uma tabela de consulta de 16 bits usando um while loop até cobrir todos os bits

Implementação 08: Conta os bits usando uma tabela de consulta de 16 bits fazendo a soma aninhada de acordo com a quantidade de bits, sem precisar de um while loop

Implementação 09: Conta os bits usando uma tabela de consulta de 16 bits fazendo a soma aninhada de acordo com a quantidade de bits, sem precisar de um while loop (diferença quase nula da implementação anterior)

Implementação 10: Conta os bits usando a instrução de processador POPCNT

 

Depois de fazer as implementações, resolvi construir um pequeno benchmark para descobrir qual se saia melhor. Abaixo mostro os resultados:

 

Fazendo uma única operação de contagem:

Spoiler
=countbits01 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 144
MedDeltaT: 144
MinT: 144
MaxT: 144
zOut: 20

=countbits02 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 160
MedDeltaT: 160
MinT: 160
MaxT: 160
zOut: 20

=countbits03 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 44
MedDeltaT: 44
MinT: 44
MaxT: 44
zOut: 20

=countbits04 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 376
MedDeltaT: 376
MinT: 376
MaxT: 376
zOut: 20

=countbits05 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 376
MedDeltaT: 376
MinT: 376
MaxT: 376
zOut: 20

=countbits06 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 392
MedDeltaT: 392
MinT: 392
MaxT: 392
zOut: 20

=countbits07 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 648
MedDeltaT: 648
MinT: 648
MaxT: 648
zOut: 20

=countbits08 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 580
MedDeltaT: 580
MinT: 580
MaxT: 580
zOut: 20

=countbits09 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 596
MedDeltaT: 596
MinT: 596
MaxT: 596
zOut: 20

=countbits10 1866120613 1=
CpuTime: 0.0
Times: 1
SumDeltaT: 40
MedDeltaT: 40
MinT: 40
MaxT: 40
zOut: 20

 

 

Fazendo 100 operações de contagem:

Spoiler
=countbits01 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 7416
MedDeltaT: 74
MinT: 72
MaxT: 148
zOut: 20

=countbits02 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 9992
MedDeltaT: 99
MinT: 96
MaxT: 160
zOut: 20

=countbits03 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 4580
MedDeltaT: 45
MinT: 44
MaxT: 48
zOut: 20

=countbits04 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 5436
MedDeltaT: 54
MinT: 48
MaxT: 404
zOut: 20

=countbits05 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 6760
MedDeltaT: 67
MinT: 64
MaxT: 424
zOut: 20

=countbits06 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 6648
MedDeltaT: 66
MinT: 60
MaxT: 404
zOut: 20

=countbits07 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 6128
MedDeltaT: 61
MinT: 56
MaxT: 584
zOut: 20

=countbits08 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 6620
MedDeltaT: 66
MinT: 60
MaxT: 616
zOut: 20

=countbits09 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 6724
MedDeltaT: 67
MinT: 60
MaxT: 684
zOut: 20

=countbits10 1866120613 100=
CpuTime: 0.0
Times: 100
SumDeltaT: 3840
MedDeltaT: 38
MinT: 36
MaxT: 40
zOut: 20

 

 

Entendendo os resultados:

countbitsXX N V

Onde:

XX é o número da implementação

N é o número que irá contar os bits

V é a quantidade de vezes que irá contar os bits de N

 

CpuTime = tempo gasto pela CPU para executar o processo atual em segundos

Times = V, ou seja, quantidade de vezes que irá contar os bits

SumDeltaT = soma de de ticks de CPU gastos para executar o processo

MedDeltaT = média de ticks de CPU gasto para cada execução de contagem (SumDeltaT div Times)

MinT = menor ticks de CPU registrado em uma única contagem de bits

MaxT = maior ticks de CPU registrado em uma única contagem de bits

zOut = resultado, ou seja, quantos bits definidos possui o número N

 

Diante essa análise, pode-se classificar às duas melhores implementações, que são a 10 e a 03. O melhor dessas implementações, que elas são de tempo constante, ou seja, o tempo gasto não muda se tiver mais ou menos bits definidos. Já a implementação 01 e 02 não são de tempo constantes, pois pode ser mais rápida se tiver um único bit definido e mais lerda se tiver 32 bits definidos.

 

Observações:

1) Interessante é do teste que executa mais vezes a mesma contagem. É possível ver que o CPU, de forma inteligente, já começa a usar o cache e executar a tarefa de forma mais rápida se comparar com o benchmark que executa uma única vez a contagem.

2) Os benchmarks não são feitos a frio, pois uso um "aquecimento" de CPU utilizando operações de ponto flutuante por, aproximadamente, 1 segundo antes de começar de fato a medição das operações do benchmark.

3) Meu processador é um mobile, que possui turbo boost. Para realizar os benchmarks eu travo o clock dele na frequência base de 2.8ghz e não deixo ele fazer o turbo boost.

4) As desvantagens de usar tabelas de consultas de 8 bits são de ocupar 256 bytes de memória ram para pré-alocar a tabela. Já a tabela de consulta de 16 bits o número de bytes sobe para 65535 (65KB). Para computadores atuais isso é insignificante.

5) A instrução POPCNT foi implementada pela Intel na microarquitetura Nehalem, de 2008. Já a AMD implementou na microarquitetura K10 (Barcelona), de 2007 [1]

  • Like 3
Link to comment
Share on other sites

rockavera

 

Obrigado pelas explicações!

 

Essa contagem do item 03 (counting in parallel), eu tinha visto há algum tempo.

Mas como é em C, eu acabei "ficando com medo" e abandonei.

 

Já sua versão de POPCNT deve depender do processador de sua máquina, correto?

 

Supondo que minha máquina (usa um Intel i5 antigo..., acredita ser possível uar essa função para contar valores que estejam em um bitstring com até 100 bits (para Lotomania, por exemplo). Ou 80 para Quina?

 

Alguma dica de como usar? Quero dizer, como "quebrar" o bitString em Integers de 32 bits ou 64 bits e contar separadamente e depois somar...

Confesso que estou totalmente perdido quanto a como fazer algo parecido.

 

Agradeço sua disposição em me ajudar a entender isso, por favor.

  • Like 3
Link to comment
Share on other sites

36 minutos atrás, DixieJoe disse:

Essa contagem do item 03 (counting in parallel), eu tinha visto há algum tempo.

Mas como é em C, eu acabei "ficando com medo" e abandonei.

@DixieJoe não é difícil traduzir o código de contagem paralela para outras linguagens, tendo em vista que só usa operações de bit (and), operações de deslocamento (shift right) e operações matemáticas (adição, multiplicação e subtração).

 

36 minutos atrás, DixieJoe disse:

Já sua versão de POPCNT deve depender do processador de sua máquina, correto?

Estava tomando café-da-tarde e lembrei que esqueci de botar nas observações sobre a instrução POPCNT. A intel implementou na microarquitetura Nehalem, de 2008. Já a AMD implementou na microarquitetura K10 (Barcelona), de 2007. [1]

 

Não é difícil descobrir se seu processador suporta ou não POPCNT, sendo possível fazer isso em tempo de execução e caso não suporte, basta definir para usar outra forma que seja mais portável, igual a contagem em paralelo. Alguns compiladores C até trazem builtins para você determinar isso em tempo de execução. Caso não tenha, a forma mais simples é consultar o retorno de uma instrução CPUID, que praticamente toda linguagem possui, ou em pacote ou como extensão de linguagem.

 

36 minutos atrás, DixieJoe disse:

Supondo que minha máquina (usa um Intel i5 antigo..., acredita ser possível uar essa função para contar valores que estejam em um bitstring com até 100 bits (para Lotomania, por exemplo). Ou 80 para Quina?

 

Alguma dica de como usar? Quero dizer, como "quebrar" o bitString em Integers de 32 bits ou 64 bits e contar separadamente e depois somar...

Confesso que estou totalmente perdido quanto a como fazer algo parecido.

Vamos lá, para um computador amd64 (ou seja, 64 bits) será possível contar até 64 bits por vez com POPCNT. Então, para 100bits, você terá que usar 2 instruções POPCNT. O mesmo acontece para 80.

 

Agora a forma de quebrar os bits, depende de como está implementado essa linguiça de bits. Por exemplo, em computadores de 32 bits quando se precisa usar 64 bits, você usa dois inteiros de 32 bits para fazer um de 64 bits. Então, para quebrar 64 bits em duas partes de 32 bits basta usar operador AND com uma máscara de bits e deslocamentos.

Exemplo o número 9223372043297226750 (precisa de 64 bits). A representação em bits é: 1000000000000000000000000000000101111111111111111111111111111110.

 

A parte superior é representada por esses 32 bits: 10000000000000000000000000000001

A parte inferior por esses: 01111111111111111111111111111110

 

Exemplo em C :

#include <stdio.h>

int main() {
  unsigned long long int a = 9223372043297226750ULL;
  unsigned long int low = a & 0xFFFFFFFFULL;
  unsigned long int high = a >> 32;

  printf("%llu\n", a);
  printf("Low: %lu\n", low);
  printf("High: %lu\n", high);
  
  return 0;
}

Exemplo em Nim:

let
  a = 9223372043297226750'u64
  lo = uint32(a and 0xFFFFFFFF'u64)
  hi = uint32(a shr 32)

echo a
echo "low: ", lo
echo "high: ", hi

Ambas as implementações irão imprimir:

9223372043297226750
low: 2147483646
high: 2147483649

 

Claro que cada linguagem tem suas especificidades.

  • Like 3
Link to comment
Share on other sites

2 horas atrás, rockcavera disse:

A minha experiência em si não é com C, tendo em vista que hoje em dia não é considerado uma linguagem "moderna", mas, sim, com Nim, que compila para C. Ou seja, no final das contas eu uso C só que com uma camada de abstração de Nim.

em comparação o ruim do c é que nao tem um coletor de lixo e tudo tem que ser feito manualmente

no geral  a maiorias das linguagens modernas seguiram o C

o rum para mim é a estrutura e operadores  (){}; :: && ...

claro que com o tempo e uso se acostuma , mas merds pq fizeram assim, seria tão dificil fazer um compilador que usasse uma estrutura mais "humana" igual o basic que usa operadores usados igual na matemática?
por isso o basic é tão facil de se pegar, é pq já aprendemos parte no colegio mesmo e nem é em programação, fora que acompanhar a estrutura de codigos mais complexos é mais facil ainda mais com loops e ifs alinhados

sobre o POPCNT, acho que tem a partir do intel i de primeira geração no sse4.2 e acho que trabalha com 128 bit que de qualquer forma tem que ser dividido numa matriz

 

ao meu ver se for transformar uma matriz de dezenas em um inteiro acho que valeria mais a pena já dividir na conversão
de 1 a 32, inteiro A
de 33 a 64 = valor -32 , inteiro B

bem, eu estou só com um az1100 amd e-350 apu all in one , muito ruim, consegui até compilar usando o dev-c++ mas tenho paciência de jó nao , então vou dar um tempo no aprendizado

 

  • Like 1
  • Haha 1
Link to comment
Share on other sites

21 hours ago, Varelo said:

@Sorel é de outro planeta!!! ele está aqui tentando replicar o conhecimento mas como nosso planeta está ainda em evolução agente não consegue acompanhá-lo. kkk

 

@Eolocos Entender de Assembly é pra poucos. Quando mexia com gps tentei aprender pra quebrar software mas é muito difícil...fiquei 03 meses debruçado lendo e praticando diariamente (quase perco a mulher, ela pensava que eu tinha outra, só dava bola pro notebook...kkk)...desisti...mas até hoje a "Ida Pro" me perturba nos meus sonhos.

 

 

 


“Quem conhece os outros é inteligente. Quem conhece a si mesmo é iluminado. Quem vence os outros é forte. Quem vence a si mesmo é invencível.” 

Lao Tsé

\[,,]/

 

Rapaz, 

 

Assembly para quebrar software e GPS ?!!!

 

tu não é fraco não, hein ?

 

bom, com relação à troca esposa / programação, no teu caso, creio que fez a escolha certa.

 

mas, eu tenho uns conhecidos, que a troca não seria vantajosa não :) 

 

esposas muito mais complicadas que aprender Assembly em mandarim ou cantones !

Link to comment
Share on other sites

um codigo em assembler do programa oscover que gerar v,k,t,m=b

    .386
    .model flat, stdcall
    option casemap :none   ; case sensitive

; #########################################################################

    include \masm32\include\windows.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc

    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib

    combinations PROTO :DWORD,:DWORD

; #########################################################################

    szText MACRO Name, Text:VARARG
      LOCAL lbl
        jmp lbl
          Name db Text,0
        lbl:
      ENDM

    m2m MACRO M1, M2
      push M2
      pop  M1
    ENDM

    return MACRO arg
      mov eax, arg
      ret
    ENDM

.code

; ##########################################################################


LibMain proc hInstDLL:DWORD, reason:DWORD, unused:DWORD

            szText LmTitle,"Cover Functions"

        .if reason == DLL_PROCESS_ATTACH
            szText ATTACHPROCESS,"PROCESS_ATTACH"

            return TRUE
            ; -----------------------------
            ; If error at startup, return 0
            ; System will abort loading DLL
            ; -----------------------------

        .elseif reason == DLL_PROCESS_DETACH
            szText DETACHPROCESS,"PROCESS_DETACH"

        .elseif reason == DLL_THREAD_ATTACH
            szText ATTACHTHREAD,"THREAD_ATTACH"

        .elseif reason == DLL_THREAD_DETACH
            szText DETACHTHREAD,"THREAD_DETACH"
            
        .endif

        ret

LibMain Endp

; ##########################################################################

; *** Count the number of bits in DWORD
bitCount proc STDCALL number:DWORD

    sub    eax,eax
    mov    ecx,number
    cmp    eax,ecx
    je    noBits
bitLp:
    inc    eax
    mov    ebx,ecx
    dec    ebx
    and    ecx,ebx 
    jne    bitLp
noBits:
    ret

bitCount endp

; *** Count combinations of subsets in full set n!/k!(n-k)!
combinations proc STDCALL subSet:DWORD,fullSet:DWORD

    sub    edx,edx
    push    edx
    mov    eax,subSet
    bts    edx,eax
    dec    edx
nextLp:
    sub    ecx,ecx
    mov    ebx,edx
bitLp:
    inc    ecx
    mov    eax,ebx
    dec    eax
    and    ebx,eax
    jnz    bitLp
    cmp    ecx,subSet
    jne    badCount
    inc    DWORD PTR [esp]
    mov    eax,edx
    dec    eax
    or    edx,eax
badCount:
    inc    edx
    mov    eax,fullSet
    bt    edx,eax
    jnc    nextLp
    pop    eax

    ret

combinations endp

; *** Count how many cover sets are contained within a list of source sets
; *** ignore sets with MSb on
checkCover proc STDCALL cover:DWORD,subSet:DWORD,fullSet:DWORD,setList:DWORD

    push    edi
    push    esi
    sub    edx,edx
    push    edx
    mov    eax,subSet
    bts    edx,eax
    dec    edx

    mov    esi,setList
    lea    edi,subSet
nextTestSet:
    sub    ebx,ebx
    add    ebx,edx
    jz    badCount
    sub    ecx,ecx
bitLp:
    inc    cx
    mov    eax,ebx
    dec    eax
    and    ebx,eax
    jnz    bitLp
    cmp    cx,[edi]
    jge    isGoodCnt
badCount:
    bt    ecx,16
    jc    isBadCover
nextComb:
    inc    edx
    mov    ebx,fullSet
    bt    edx,ebx
    jnc    nextTestSet
    jmp    finished
isGoodCnt:
    bts    ecx,16
    jc    isCoverTest
    jne    nextComb
isBadCover:
    lea    edi,cover
testSetLp:
    add    ebx,[esi]
    jz    endTestSet
    add    esi,4
    bt    ebx,31
    jnc    notFlagged
    sub    ebx,ebx
notFlagged:
    and    ebx,edx
    jz    testSetLp
    sub    cx,cx
    jmp    bitLp
isCoverTest:
    inc    DWORD PTR [esp]
    mov    eax,edx
    dec    eax
    or    edx,eax
endTestSet:
    mov    esi,setList
    sub    ecx,ecx
    lea    edi,subSet
    jmp    nextComb
finished:
    pop    eax
    pop    esi
    pop    edi

    ret

checkCover endp

; *** calculate how many unique combinations are covered by each set in list
rankSets proc STDCALL cover:DWORD,subSet:DWORD,fullSet:DWORD,setList:DWORD

LOCAL    setAddr:DWORD

    push    edi
    push    esi
    mov    esi,setList
    sub    eax,eax
notZero:
    add    eax,4
    cmp    DWORD PTR [esi+eax],0
    jne    notZero
    invoke    GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT, eax
    push    eax

    mov    eax,subSet
    sub    edx,edx
    bts    edx,eax
    dec    edx
nextCheck:
    lea    edi,subSet
    mov    ebx,edx
    sub    ecx,ecx
    mov    setAddr,ecx
bitLp:
    inc    cx
    mov    eax,ebx
    dec    eax
    and    ebx,eax
    jnz    bitLp
    cmp    cx,[edi]
    bts    ecx,16
    jge    goodCount
    jc    nextSet
    jmp    nextComb
goodCount:
    jnc    isCover
    cmp    ebx,setAddr
    jne    notUnique
    mov    setAddr,esi
    jmp    nextSet
isCover:
    jne    nextComb
    lea    edi,cover
    mov    esi,setList
nextSet:
    add    ebx,[esi]
    je    endList
    add    esi,4
    and    ebx,edx
    je    nextSet
    sub    cx,cx
    jmp    bitLp
endList:
    add    ebx,setAddr
    je    notUnique
    sub    ebx,setList
    add    ebx,[esp]
    mov    esi,ebx
    inc    DWORD PTR [esi-4] 
notUnique:
    mov    eax,edx
    dec    eax
    or    edx,eax
nextComb:
    inc    edx
    mov    eax,fullSet
    bt    edx,eax
    jnc    nextCheck

    pop    eax
    pop    esi
    pop    edi
    ret

rankSets endp

; *** search for the best set to add to a set list
bestSet proc STDCALL cover:DWORD,subSet:DWORD,fullSet:DWORD,setList:DWORD

LOCAL    condition:DWORD
LOCAL    workList:DWORD
LOCAL    coverCntr:DWORD
LOCAL    bestCover:DWORD
LOCAL    newBestSet:DWORD

    push    edi
    push    esi
    mov    condition,6
    sub    eax,eax
    mov    bestCover,eax
    invoke    combinations,subSet,fullSet
    shl    eax,4
    invoke    GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT, eax
    push    eax
    mov    eax,setList
    mov    workList,eax
    mov    eax,cover
stageLp:
    push    DWORD PTR [esp] 
    sub    edx,edx
    bts    edx,eax
    dec    edx
nextCheck:
    mov    ebx,edx
    lea    edi,condition
    and    ecx,20000H
    jnz    bitLp
    lea    edi,subSet
bitLp:
    inc    cx
    mov    eax,ebx
    dec    eax
    and    ebx,eax
    jnz    bitLp
    cmp    cx,[edi]
    bts    ecx,16
    jge    goodCount
    jc    noBits
    jmp    nextComb

goodCount:
    jnc    isComb
    bt    ecx,17
    jnc    isCover
; *** stage two - count a cover for this draw set
    inc    DWORD PTR coverCntr 
    jmp    noBits
isComb:
    jne    nextComb
    mov    esi,workList
noBits:
    add    ebx,[esi]
    je    endSetList
    add    esi,4
    sub    cx,cx
    and    ebx,edx
    lea    edi,cover
    jne    bitLp
    jmp    noBits
endSetList:
    bt    ecx,17
    jnc    incListAddr
    mov    eax,coverCntr
    mov    coverCntr,ebx
    cmp    eax,bestCover
    jle    isCover
    mov    bestCover,eax
    mov    newBestSet,edx
    jmp    isCover
incListAddr:
    mov    esi,[esp]
    mov    [esi],edx
    add    DWORD PTR [esp],4 
isCover:
    mov    eax,edx
    dec    eax
    or    edx,eax
nextComb:
    inc    edx
    mov    eax,fullSet
    bt    edx,eax
    jnc    nextCheck

; *** move to stage two - find best set of six numbers to cover all uncovered combinations
    pop    eax
    mov    eax,[esp]
    mov    workList,eax
    sub    ebx,ebx
    mov    coverCntr,ebx
    mov    eax,condition
    bts    ecx,17
    jnc    stageLp
    pop    eax
    invoke    GlobalFree,eax
    mov    eax,newBestSet

    pop    esi
    pop    edi

    ret

bestSet endp

; ##########################################################################

End LibMain

  • Like 1
Link to comment
Share on other sites

@Bruno Cintraaté hj não aprendeu a usar o editor do fórum para colocar código? Só lembrando que já tentei te ensinar umas 2 vezes, inclusive com print. Quando se cola código fora da caixa de código, o código pode ser alterado por um encode de entities html, em linguagens que o recuo importa como escopo pode perder espaço... São vários problemas. Então fica de novo essa dica, quem sabe na próxima.

 

Edit: comentário rabugento? Sim. Mas colar um código dessa forma pode atrasar a vida de alguém que tenta compilar isso e não funciona, devido a falta de cautela de quem não usa dos meios corretos para publicar o código.

  • Sad 1
Link to comment
Share on other sites

estava vendo os codigos gerados pelo gpt e reparei nisso
if (__builtin_popcount(i) == k) { // verifica se i tem exatamente k bits definidos

__builtin_popcount(i)

pesquisando vi que apesar de nao ser padrão do C tem compilador que incorpora funções desse tipo como o GCC

para int use __builtin_popcount(n)

para int longo use __builtin_popcountl(n)

para long long int use __builtin_popcountll(n)

o problema é que parece que precisaria fazer um para cada tipo, se fosse escolhido o tipo em tempo de execução ficaria mais lento

 

pedi para o gpt montar um contador de bits para 100bits usando assembly numa função c
 

#include <stdint.h>

uint64_t popcnt_100bits(const void *ptr)
{
    uint64_t count;
    __asm__ volatile (
        "movdqu xmm0, [%[ptr]] \n"
        "movdqu xmm1, [%[ptr]+16] \n"
        "movdqu xmm2, [%[ptr]+32] \n"
        "movdqu xmm3, [%[ptr]+48] \n"
        "movdqu xmm4, [%[ptr]+64] \n"
        "pshufb xmm5, xmm0 \n"
        "pshufb xmm6, xmm1 \n"
        "pshufb xmm7, xmm2 \n"
        "pshufb xmm8, xmm3 \n"
        "pshufb xmm9, xmm4 \n"
        "popcnt %[count], xmm5 \n"
        "popcnt %%rdx, xmm6 \n"
        "add %[count], %%rdx \n"
        "popcnt %%rcx, xmm7 \n"
        "add %[count], %%rcx \n"
        "popcnt %%rbx, xmm8 \n"
        "add %[count], %%rbx \n"
        "popcnt %%rsi, xmm9 \n"
        "add %[count], %%rsi \n"
        : [count] "=r" (count)
        : [ptr] "r" (ptr)
        : "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "memory"
    );
    return count;
}
Citar

Neste código, a função C popcnt_100bits chama o código em assembly que conta o número de bits definidos como 1 em um número de 100 bits. A função C declara uma variável count para armazenar o resultado do cálculo em assembly. A instrução __asm__ volatile é usada para incorporar o código assembly em uma função C.

Os registradores xmm0 a xmm9 são usados para armazenar os valores dos registradores SIMD SSE, e a opção memory é usada para notificar o compilador que a função pode acessar a memória. A opção r é usada para especificar que o ponteiro ptr é passado como um registrador. A opção =r é usada para especificar que a variável count é passada como um registrador de saída. As instruções movdqu, pshufb e popcnt são as mesmas que as usadas no código em assembly que eu apresentei anteriormente.

eu adoraria fazer funções em dll para usar em planilhas

apesar da maioria das coisas que eu faço funcionar muito bem em vba tem uns testes meus que demora muito pelo grande numero de testes que faz

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...