Aquí hay un contador monótono. Aunque no estoy seguro si puedes llamarlo simple.
Suponiendo que ONE
y ZERO
están siempre en registros, entonces esto debería compilarse a 5 instrucciones. (7 o 8 si VEX-codificación no se utiliza)
inline __m128i nextc(__m128i x){
const __m128i ONE = _mm_setr_epi32(1,0,0,0);
const __m128i ZERO = _mm_setzero_si128();
x = _mm_add_epi64(x,ONE);
__m128i t = _mm_cmpeq_epi64(x,ZERO);
t = _mm_and_si128(t,ONE);
t = _mm_unpacklo_epi64(ZERO,t);
x = _mm_add_epi64(x,t);
return x;
}
Código de prueba (MSVC):
int main() {
__m128i x = _mm_setr_epi32(0xfffffffa,0xffffffff,1,0);
int c = 0;
while (c++ < 10){
cout << x.m128i_u64[0] << " " << x.m128i_u64[1] << endl;
x = nextc(x);
}
return 0;
}
de salida:
18446744073709551610 1
18446744073709551611 1
18446744073709551612 1
18446744073709551613 1
18446744073709551614 1
18446744073709551615 1
0 2
1 2
2 2
3 2
Ligeramente mejor versión sugerido por @ Norbert P. Guarda 1 instrucción sobre mi solución original.
inline __m128i nextc(__m128i x){
const __m128i ONE = _mm_setr_epi32(1,0,0,0);
const __m128i ZERO = _mm_setzero_si128();
x = _mm_add_epi64(x,ONE);
__m128i t = _mm_cmpeq_epi64(x,ZERO);
t = _mm_unpacklo_epi64(ZERO,t);
x = _mm_sub_epi64(x,t);
return x;
}
¿Por qué necesita visitar 2^128 valores? Ninguna computadora en la tierra es capaz de hacer eso. ¿No puedes usar un int de 64 bits? – usr
De acuerdo, en un procesador con una velocidad de reloj del orden de gigahertz, puede consumir un número en cada ciclo durante aproximadamente 584 años antes de que se agote un contador de 64 bits. – Damon