Si tienes razón, tu código funciona.
La aproximación por probabilidad que implemente a un byte es la mas sencilla de entender, claro ineficiente por que prueba bit por bit si debe de ser o no modificado, la desviación estandar es muy baja y la media siempre esta sobre el % indicado por "Cuantos"
En fin, estoy de acuerdo que la versión por probabilidad NO hace exactamente lo que pide el programa, sin embargo es muy acercado a lo que se pide.
He realizado un nuevo código que funciona de byte en byte y NO UTILIZA PROBABILIDAD,Funciona Byte a Byte por que en algún punto el modulo de ruido se debe de acoblar a un modulo "Canal" cosa que no voy a discutir aqui.
Esta en forma de Clase por que necesitamos tener control de variables internas y llevar registro de cuales bits ya modificamos.
Dejo el codigo por si a alguien le sirve, el algoritmo de ordenamiento se puede mejorar, para dejarlo simple utilice el ordenamiento burbuja. Cámbienlo por el que les guste.
El programa utiliza objeto de clase Noise y genera una lista previa de los bits que va a modificar, y solo modifica dichos bits cuando le mandan un byte que contenga el indice de bit mencionado.
Este programa no sabe a priori cuantos bytes le van a enviar, por lo que el ciclo de "cuantos" por cada 100 solo se cumple cuando el numero de bits que se le a enviado es múltiplo de 100.
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define LEN 25
class Noise
{
private:
unsigned char cuantos;
unsigned char valor;
int index_nibble;
int lista_actual;
int *lista;
int next;
void generar_lista();
void ordenar_lista();
public:
unsigned int recibidos;
unsigned int modificados;
Noise(unsigned char _cuantos, unsigned char _valor);
~Noise();
char modificar(char b);
};
Noise::Noise(unsigned char _cuantos, unsigned char _valor) {
cuantos = _cuantos;
valor = _valor;
index_nibble = 0;
recibidos = 0;
modificados = 0;
lista = new int[cuantos];
srand(time(NULL));
generar_lista();
}
Noise::~Noise() {
delete lista;
}
void Noise::generar_lista() {
lista_actual = 0;
int no_duplicados[100] = {0};
int i = 0,r;
while(i < cuantos) {
do {
r = rand() % 100;
}while(no_duplicados[r] == 1);
no_duplicados[r] = 1;
//printf("Numero random %i\n",r);
lista[i] = r;
i++;
}
ordenar_lista();
next = lista[lista_actual];
}
void Noise::ordenar_lista() {
int i,j,aux;
i = 1;
while(i<cuantos) {
j = 0;
while(j<(cuantos-1)) {
if(lista[j] > lista[j+1]) {
aux = lista[j];
lista[j] = lista[j+1];
lista[j+1] = aux;
}
j++;
}
i++;
}
/*
Solo para imprimir las siguientes lineas se pueden omitir
*/
/*
printf("Lista Ordenada: ");
i = 0;
while(i< cuantos) {
printf("%i\t",lista[i++]);
}
printf("\n");
*/
}
char Noise::modificar(char b) { //Se divide el byte recibido en nibbles para trabajar correctamente con divisores de 100, ya que 8 no es divisible entre 100
int i;
int entrar = 1;
int bit_offset;
char nibble[2];
recibidos+=8;
/*
Lo siguiente es hardware dependiente pero me da flojera realizar la prueba... Supongo que la mayoria utilizara little endian
*/
nibble[0] = b & 0x0F;
nibble[1] = b & 0xF0;
nibble[1] = nibble[1] >> 4;
//printf("Numero separado en nibbles '%c' : [%i,%i]\n",b,nibble[0],nibble[1]);
i = 0;
while(i < 2) {
entrar = 1;
//printf("Evaluando index nibble %i, buscando %i, index actual de la lista %i:%i\n",index_nibble,next/4,lista_actual,lista[lista_actual]);
while(entrar && index_nibble == next/4) {
bit_offset = next % 4;
//printf("Encontrado., bit a modificar %i\n",bit_offset);
if(valor) {
nibble[i] |= 1 << bit_offset;
}
else {
nibble[i] &= ~(1 << bit_offset);
}
lista_actual++;
if(lista_actual < cuantos) {
next = lista[lista_actual];
}
else {
entrar = 0;
}
modificados++;
}
index_nibble++;
if(index_nibble == 25) {
index_nibble = 0;
generar_lista();
}
i++;
}
return nibble[0] + (nibble[1] << 4);;
}
int main() {
char mensaje[LEN+1];
unsigned int i = 0;
Noise noise(1,1); //10 bytes modificados por cada 100
memset(mensaje,'A',LEN);
printf("Mensaje antes del Ruido: %s\n",mensaje);
while(i < LEN) {
mensaje[i] = noise.modificar(mensaje[i]);
i++;
}
printf("Mensaje despues del Ruido: %s\n",mensaje);
printf("%u/%u\n",noise.modificados,noise.recibidos);
}
Aun asi, yo sigo prefiriendo la funcion por PROBABILIDAD, ya que es la mas sencilla y rapida de implementar. Y funciona bien digan lo que digan en el largo plazo se comporta aproximadamente se esperaba y funcionaria aun mejor si la distribucion de los nimeros pseudo-aleatorios fuera mas uniforme.
char noise(char byte,unsigned char cuantos, unsigned char valor) {
int i = 0;
recibidos+= 8;
while(i < 8) {
if((rand() % 100) < cuantos
) { modificados++;
if(valor) {
byte |= 1 << i;
}
else {
byte &= ~(1 << i);
}
}
i++;
}
return byte;
}