Este programa realiza diversos experimentos sobre el cumplimiento
de la Ley de Benford en direrentes areas.
Benford.Test consiste en una serie de pruebas que se realizan una tras
otra, dependiento de su primera funcion If() de control y contiene
algoritmos recursivos para la creacion de secuencias de operaciones basicas
y aleatorias.
La ley de Benford, tambien conocida como ley del primer digito, enuncia
que, en los numeros de la vida real, el primer digito mas frecuente es
el 1, luego el 2, luego el 3, ..., luego el 8 y finalmente el menos
frecuente es el 9.
Esta Ley de Benford parece comprobarse tanto en hechos relacionados con el
mundo natural o con el social, por ejemplo, la longitud de rios, los
totales de facturas, los precios de acciones, el numero de habitantes de
las poblaciones, las distancias estelares, en las cifras resultantes de la
realizacion de calculos con otras cifras, etc.
Antes que Frank Benford, Simon Newcomb, astronomo y matematico, en 1881
observo que las primeras paginas de las tablas de logaritmos estaban mas
usadas que las finales, de lo que dedujo que los digitos iniciales de los
numeros no son equiprobables sino que el 1 era el digito inicial mas
frecuente, luego 2 y asi hasta el 9 que es el menos frecuente y establecio
una primera aproximacion a la funcion de distribucion de esta probabilidad.
Frank Benford, fisico, en 1938 establecio esta funcion de distribucion con
mas precision y la comprobo en diferentes dominios.
La ley de Benford establece que la primera cifra no nula n (n = 1, 2, 3, 4,
..., 9) ocurre con una probabilidad igual a (Log10(n + 1) - Log10(n)).
Ademas de otros experimentos, se dispone de un banco de 2000 datos que
corresponden al acumulado del trafico de subida mas el trafico de bajada en
bytes para un periodo de dias para un conjunto de 2000 direcciones MAC,
Media Access Control address.
La hipotesis es que este banco de 2000 datos esta manipulado y no
corresponde a la realidad del trafico.
Puede plantearse el siguiente experimento,
seleccionar varios bancos de 2000 datos reales de trafico por MAC y para un
periodo, registrados en una condiciones muy similares a las del banco de
datos del que se sospecha y aplicar a estos bancos de prueba y al banco
sospechoso la Ley de Benford.
Se pueden establecer los 3 posibles resultados siguientes:
a) Si ninguno de los bancos sigue la Ley de Benford, entonces podria
concluirse que el trafico por MAC no sigue esta ley y no podria
concluirse nada sobre el banco sospechoso con este experimento.
b) Si todos los bancos siguen la Ley de Benford, entonces podria concluirse
que el trafico por MAC si sigue esta ley y tampoco podria concluirse
nada sobre el banco sospechoso con este experimento,
pudiera ser autentico o falseado de tal forma que cumpliera la Ley de
Benford.
c) Si todos los bancos de prueba siguen la Ley de Benford pero el sospecho
no la sigue entonces se podria concluir que el banco de datos de trafico
por MAC efectivamente ha sido manipulado o generado de alguna forma para
ser aportado como una prueba digital falsa y que no corresponde a la
realidad.
Cientificamente el experimento hay que hacerlo con varios bancos de trafico
real.
En este caso, por simplicidad, se ha seleccionado solo 1 banco de 2000
datos de trafico por MAC captados de la realidad, trafico de subida mas
trafico de bajada.
La conclusion puede deducirse claramente al final de este programa y
existiran otras formas de analisis, pero el objetivo de este programa es
realizarlo con la Ley de Benford.
Benford.Test pruebas de la Ley de Bendford con diferentes casos y uno forense
Inclusiones
Set datIncConstantes
Text makSepSet OpeBasSet BenDigSet BenLawText BenFmtFunciones de nombre corto
Text F(Real numDat)Funciones: Comunes a todos los experimentos
Real BenFstDig(Real numDat)Set BenEval(Real numCic, Code funCod)Set BenView(Text expTit, Real numCic, Code funCod)Funciones: Para cada experimento
Real BenOpeSecRnd(Real numUno, Real numDos, Real numOpe)Real BenOpeTreRnd(Real ranMin, Real ranMax, Real numOpe)Pruebas
Set tst001Set tst002Set tst003Set tstFor//////////////////////////////////////////////////////////////////////////////
Set datInc = Include("trafico/bytespermac.tol");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Inclusion de 2 muestras de trafico en bytes.", datInc);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Text makSep = "\n"+Repeat("_", 72)+"\n";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Separador de trazas de ejecucion.", makSep);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set OpeBas = SetOfText("+", "-", "*", "/");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto con las 4 operaciones basicas +, -, * y /.", OpeBas);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set BenDig = SetOfReal(1, 2, 3, 4, 5, 6, 7, 8, 9);
//////////////////////////////////////////////////////////////////////////////
PutDescription("Digitos del 1 al 9.", BenDig);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set BenLaw = EvalSet(BenDig, Real (Real fstDig)
{ Log10(fstDig+1) - Log10(fstDig) });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Probabilidad del 1,2,...9 segun la Ley de Benford.", BenDig);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Text BenFmt = "%.5lf";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Formato general para sacar los resultados.", BenFmt);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Text F(Real numDat) // Numero de entrada
//////////////////////////////////////////////////////////////////////////////
{
Case(
numDat <: BenDig, FormatReal(numDat, "%1.0lf"), // Un solo digito
EQ(numDat, Round(numDat)), FormatReal(numDat, "%7.0lf"), // Un entero
TRUE, FormatReal(numDat, BenFmt)) // Con decimales
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un numero como texto con 4 decimales, si es entero sin decimales.
Es una version reducida para este programa de la funcion F() mas usual.",
F);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Real BenFstDig(Real numDat) // Un numero
//////////////////////////////////////////////////////////////////////////////
{
Real numAbs = Abs(numDat); // Valor Absoluto
Floor(numAbs / (10^Floor(Log10(numAbs))))
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el primer digito, de 1 a 9, de un numero.",
BenFstDig);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set BenEval(Real numCic, // Numero de veces que se ha de evaluar
Code funCod) // Funcion que hay que evaluar
//////////////////////////////////////////////////////////////////////////////
{
Set resSet = For(1, numCic, funCod); // Evalua funCod numCic veces
Set fstSet = EvalSet(resSet, BenFstDig); // Extrae el primer digito
// Selecciona del 1 al 9, por si la funcion retornara algun error (?).
Set fstChk = Select(fstSet, Real(Real fstDig) { fstDig <: BenDig });
// Añadir 1 representante de cada numero para que salgan todos
Set fstCat = BenDig << fstChk;
// Clasificar, la de los 1, la de los 2, ..., la de los 9
Set fstCla = Classify(fstCat, Real(Real a, Real b) { Compare(a, b) });
// Ordenar las clases 1º el 1, luego el 2, ..., finalmente el 9
// con comparar el primer elemento de cada clase basta
Set fstSrt = Sort(fstCla, Real(Set a, Set b) { Compare(a[1], b[1]) });
// Numero de ocurrencias de cada clase, recordar que hay que quitar una
Set fstCrd = EvalSet(fstSrt, Real(Set claSet) { Card(claSet)-1 });
Real numTot = SetSum(fstCrd); // Numero total de ejecuciones validas,
// Si la funcion funCod no ha dado errores tendria que ser igual a numCic
Real chkTot = If(numTot == numCic, TRUE, // Todo correcto
{
Text WriteLn("De "+F(numCic)+" han sido validas "+F(numTot));
FALSE // Error en alguna
});
// Calculo de la frecuencia
Set fstFrq = EvalSet(fstCrd, Real(Real digCrd) { digCrd / numTot })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado
de haber evaluado la funcion funCod numCic veces.",
BenEval);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set BenView(Text expTit, // Titulo del experimento
Real numCic, // Numero de veces que se ha de evaluar
Code funCod) // Funcion que hay que evaluar
//////////////////////////////////////////////////////////////////////////////
{
Set expFrq = BenEval(numCic, funCod); // Evalua funCod numCic veces
Text tabTit = "D | Benford | "+Compact(F(numCic))+" ciclos de "+expTit;
Real lenTit = TextLength(tabTit);
Text linTit = Repeat("_", lenTit);
Text WriteLn("\n"+linTit+"\n"+tabTit+"\n"+linTit);
Set expTab = EvalSet(BenDig, Set(Real fstDig)
{
Real benTeo = BenLaw[fstDig]; // Valor teorico
Real fstFrq = expFrq[fstDig]; // Frecuencia resultante
Text WriteLn(F(fstDig)+" | "+F(benTeo)+" | "+F(fstFrq));
Real errQua = ((fstFrq - benTeo) / benTeo) ^ 2; // Calculo del error
[[ fstDig, benTeo, fstFrq, errQua]]
});
Text WriteLn(linTit);
Real benSum = SetSum(BenLaw); // Total de frecuencias de Benford
Real expSum = SetSum(expFrq); // Total de frecuencias del experimento
Set expErr = Traspose(expTab)[4]; // Conjunto de errores
Real errSum = SetSum(expErr); // Error del experimento
Text WriteLn("Sum "+FormatReal(benSum, BenFmt)+" | "+
FormatReal(expSum, BenFmt)+" | error "+F(errSum));
//Text WriteLn(linTit);
Extract(expTab, 1, 2, 3) // Tabla digito, Benford, experimento
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado
de haber evaluado la funcion funCod numCic veces y, como efecto lateral,
a) visualiza por pantalla la comparativa del resultado con la Ley de Benford
y b) el error.",
BenView);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Real BenOpeSecRnd(Real numUno, // Primer numero de entrada
Real numDos, // Segundo numero de entrada
Real numOpe) // Numero de operaciones a realizar
//////////////////////////////////////////////////////////////////////////////
{
If(numOpe <= 0, numDos, // No hay ya mas operaciones que hacer
{
Real numRnd = Floor(Rand(1, Card(OpeBas)+1)); // Numero aleatorio
Text opeTxt = OpeBas[numRnd]; // Operador como texto
Code opeCod = FindCode("Real", opeTxt); // Operador Tol de Real
Real newVal = opeCod(numUno, numDos); // Realiza la operacion
// Text WriteLn(F(numUno)+" "+opeTxt+" "+F(numDos)+" = "+F(newVal));
BenOpeSecRnd(numDos, newVal, numOpe-1)
})
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el resultado de realizar a partir de 2 numeros de entrada, numUno y
numDos, una secuencia de numOpe operaciones de suma, resta, multiplicacion y
division aleatorias y equiprobables.
La secuencia se realiza como una recursion lineal.",
BenOpeSecRnd);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Real BenOpeTreRnd(Real ranMin, // Minimo del rango de aletorios
Real ranMax, // Maximo del rango de aletorios
Real numOpe) // Numero de operaciones a realizar
//////////////////////////////////////////////////////////////////////////////
{
Real numRnd = Floor(Rand(1, Card(OpeBas)+1)); // Numero aleatorio
Text opeTxt = OpeBas[numRnd]; // Operador como texto
Code opeCod = FindCode("Real", opeTxt); // Operador Tol de Real
If(numOpe <= 1, opeCod(Rand(ranMin, ranMax),
Rand(ranMin, ranMax)), // Operacion final
{
Real numLft = Floor(numOpe/2); // La mitad para la izquierda
Real numRht = numOpe - numLft; // La otra mitad para la derecha
opeCod(BenOpeTreRnd(ranMin, ranMax, numLft), // Izquierda
BenOpeTreRnd(ranMin, ranMax, numRht)) // Derecha
})
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el resultado de realizar a partir de 1 rango de entrada, determinado
por ranMin y ranMax, una secuencia de numOpe operaciones de suma, resta,
multiplicacion y division aleatorias y equiprobables.
La construccion se realiza por la expansion de un arbol binario con tantos
nodos de operacion como determine numOpe.",
BenOpeTreRnd);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set tst001 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
Set tstR01 = BenView(
"numeros aleatorios de distribucion uniforme", 1000,
Real(Real posCic) { Rand(0,1) });
Set tstS01 = BenView(
" 4 operaciones secuenciales basicas + - * /", 1000,
Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 4)})
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Numeros aleatorios frente a operaciones aleatorias.", tst001);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set tst002 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
Set tstS02 = BenView(
"10 operaciones secuenciales basicas + - * /", 2000,
Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 10)});
Set tstS04 = BenView(
" 5 operaciones secuenciales basicas + - * /", 4000,
Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 5)})
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Comparar nº de ciclos contra nº de operaciones.", tst002);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set tst003 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
Set tstS03 = BenView(
" 7 operaciones secuenciales basicas + - * /", 3000,
Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 7)});
Set tstT03 = BenView(
" 7 operaciones en arbol basicas + - * /", 3000,
Real(Real posCic) { BenOpeTreRnd(0, 1, 7)});
Set tstE03 = BenView(
"exponencial de numeros aleatorios entre 0 y 1", 3000,
Real(Real posCic) { Exp(Rand(-10,10)) })
});
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Compararcion de la generacion en secuencia de operaciones, en arbol binario
de operaciones y la exponencial de numeros aleatorios.",
tst003);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set tstFor = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
Set tstD02 = BenView(
"trafico dudoso, acumulado en bytes", Card(TraDud),
Real(Real posCic) { TraDud[posCic] });
Set tstC02 = BenView(
"trafico controlado, acumulado en bytes", Card(TraChk),
Real(Real posCic) { TraChk[posCic] })
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Analiza el caso de informatica forense.", tstFor);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nBenford.Test make: end");
//////////////////////////////////////////////////////////////////////////////
// FILE : make.tol
// AUTHOR : http://www.asolver.com
// CLASS : Estadística; Forense; Algoritmia
// VERSION : Tol 1.1.1; Tol 2.0.1 con reservas
// PURPOSE : Este programa realiza diversos experimentos sobre el cumplimiento
// de la Ley de Benford en direrentes areas.
//
// Benford.Test consiste en una serie de pruebas que se realizan una tras
// otra, dependiento de su primera funcion If() de control y contiene
// algoritmos recursivos para la creacion de secuencias de operaciones basicas
// y aleatorias.
//
// La ley de Benford, tambien conocida como ley del primer digito, enuncia
// que, en los numeros de la vida real, el primer digito mas frecuente es
// el 1, luego el 2, luego el 3, ..., luego el 8 y finalmente el menos
// frecuente es el 9.
//
// Esta Ley de Benford parece comprobarse tanto en hechos relacionados con el
// mundo natural o con el social, por ejemplo, la longitud de rios, los
// totales de facturas, los precios de acciones, el numero de habitantes de
// las poblaciones, las distancias estelares, en las cifras resultantes de la
// realizacion de calculos con otras cifras, etc.
// _
// Antes que Frank Benford, Simon Newcomb, astronomo y matematico, en 1881
// observo que las primeras paginas de las tablas de logaritmos estaban mas
// usadas que las finales, de lo que dedujo que los digitos iniciales de los
// numeros no son equiprobables sino que el 1 era el digito inicial mas
// frecuente, luego 2 y asi hasta el 9 que es el menos frecuente y establecio
// una primera aproximacion a la funcion de distribucion de esta probabilidad.
//
// Frank Benford, fisico, en 1938 establecio esta funcion de distribucion con
// mas precision y la comprobo en diferentes dominios.
// La ley de Benford establece que la primera cifra no nula n (n = 1, 2, 3, 4,
// ..., 9) ocurre con una probabilidad igual a (Log10(n + 1) - Log10(n)).
// _
// Ademas de otros experimentos, se dispone de un banco de 2000 datos que
// corresponden al acumulado del trafico de subida mas el trafico de bajada en
// bytes para un periodo de dias para un conjunto de 2000 direcciones MAC,
// Media Access Control address.
//
// La hipotesis es que este banco de 2000 datos esta manipulado y no
// corresponde a la realidad del trafico.
//
// Puede plantearse el siguiente experimento,
// seleccionar varios bancos de 2000 datos reales de trafico por MAC y para un
// periodo, registrados en una condiciones muy similares a las del banco de
// datos del que se sospecha y aplicar a estos bancos de prueba y al banco
// sospechoso la Ley de Benford.
//
// Se pueden establecer los 3 posibles resultados siguientes:
// a) Si ninguno de los bancos sigue la Ley de Benford, entonces podria
// concluirse que el trafico por MAC no sigue esta ley y no podria
// concluirse nada sobre el banco sospechoso con este experimento.
// b) Si todos los bancos siguen la Ley de Benford, entonces podria concluirse
// que el trafico por MAC si sigue esta ley y tampoco podria concluirse
// nada sobre el banco sospechoso con este experimento,
// pudiera ser autentico o falseado de tal forma que cumpliera la Ley de
// Benford.
// c) Si todos los bancos de prueba siguen la Ley de Benford pero el sospecho
// no la sigue entonces se podria concluir que el banco de datos de trafico
// por MAC efectivamente ha sido manipulado o generado de alguna forma para
// ser aportado como una prueba digital falsa y que no corresponde a la
// realidad.
//
// Cientificamente el experimento hay que hacerlo con varios bancos de trafico
// real.
// En este caso, por simplicidad, se ha seleccionado solo 1 banco de 2000
// datos de trafico por MAC captados de la realidad, trafico de subida mas
// trafico de bajada.
// La conclusion puede deducirse claramente al final de este programa y
// existiran otras formas de analisis, pero el objetivo de este programa es
// realizarlo con la Ley de Benford.
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// INCLUDE
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nBenford.Test make: begin");
//////////////////////////////////////////////////////////////////////////////
Set datInc = Include("trafico/bytespermac.tol");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Inclusion de 2 muestras de trafico en bytes.", datInc);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// CONSTANTS
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Text makSep = "\n"+Repeat("_", 72)+"\n";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Separador de trazas de ejecucion.", makSep);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set OpeBas = SetOfText("+", "-", "*", "/");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto con las 4 operaciones basicas +, -, * y /.", OpeBas);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set BenDig = SetOfReal(1, 2, 3, 4, 5, 6, 7, 8, 9);
//////////////////////////////////////////////////////////////////////////////
PutDescription("Digitos del 1 al 9.", BenDig);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set BenLaw = EvalSet(BenDig, Real (Real fstDig)
{ Log10(fstDig+1) - Log10(fstDig) });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Probabilidad del 1,2,...9 segun la Ley de Benford.", BenDig);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Text BenFmt = "%.5lf";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Formato general para sacar los resultados.", BenFmt);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// SHORTNAMES
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Text F(Real numDat) // Numero de entrada
//////////////////////////////////////////////////////////////////////////////
{
Case(
numDat <: BenDig, FormatReal(numDat, "%1.0lf"), // Un solo digito
EQ(numDat, Round(numDat)), FormatReal(numDat, "%7.0lf"), // Un entero
TRUE, FormatReal(numDat, BenFmt)) // Con decimales
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un numero como texto con 4 decimales, si es entero sin decimales.
Es una version reducida para este programa de la funcion F() mas usual.",
F);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// FUNCTIONS: Comunes a todos los experimentos
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Real BenFstDig(Real numDat) // Un numero
//////////////////////////////////////////////////////////////////////////////
{
Real numAbs = Abs(numDat); // Valor Absoluto
Floor(numAbs / (10^Floor(Log10(numAbs))))
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el primer digito, de 1 a 9, de un numero.",
BenFstDig);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set BenEval(Real numCic, // Numero de veces que se ha de evaluar
Code funCod) // Funcion que hay que evaluar
//////////////////////////////////////////////////////////////////////////////
{
Set resSet = For(1, numCic, funCod); // Evalua funCod numCic veces
Set fstSet = EvalSet(resSet, BenFstDig); // Extrae el primer digito
// Selecciona del 1 al 9, por si la funcion retornara algun error (?).
Set fstChk = Select(fstSet, Real(Real fstDig) { fstDig <: BenDig });
// Añadir 1 representante de cada numero para que salgan todos
Set fstCat = BenDig << fstChk;
// Clasificar, la de los 1, la de los 2, ..., la de los 9
Set fstCla = Classify(fstCat, Real(Real a, Real b) { Compare(a, b) });
// Ordenar las clases 1º el 1, luego el 2, ..., finalmente el 9
// con comparar el primer elemento de cada clase basta
Set fstSrt = Sort(fstCla, Real(Set a, Set b) { Compare(a[1], b[1]) });
// Numero de ocurrencias de cada clase, recordar que hay que quitar una
Set fstCrd = EvalSet(fstSrt, Real(Set claSet) { Card(claSet)-1 });
Real numTot = SetSum(fstCrd); // Numero total de ejecuciones validas,
// Si la funcion funCod no ha dado errores tendria que ser igual a numCic
Real chkTot = If(numTot == numCic, TRUE, // Todo correcto
{
Text WriteLn("De "+F(numCic)+" han sido validas "+F(numTot));
FALSE // Error en alguna
});
// Calculo de la frecuencia
Set fstFrq = EvalSet(fstCrd, Real(Real digCrd) { digCrd / numTot })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado
de haber evaluado la funcion funCod numCic veces.",
BenEval);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set BenView(Text expTit, // Titulo del experimento
Real numCic, // Numero de veces que se ha de evaluar
Code funCod) // Funcion que hay que evaluar
//////////////////////////////////////////////////////////////////////////////
{
Set expFrq = BenEval(numCic, funCod); // Evalua funCod numCic veces
Text tabTit = "D | Benford | "+Compact(F(numCic))+" ciclos de "+expTit;
Real lenTit = TextLength(tabTit);
Text linTit = Repeat("_", lenTit);
Text WriteLn("\n"+linTit+"\n"+tabTit+"\n"+linTit);
Set expTab = EvalSet(BenDig, Set(Real fstDig)
{
Real benTeo = BenLaw[fstDig]; // Valor teorico
Real fstFrq = expFrq[fstDig]; // Frecuencia resultante
Text WriteLn(F(fstDig)+" | "+F(benTeo)+" | "+F(fstFrq));
Real errQua = ((fstFrq - benTeo) / benTeo) ^ 2; // Calculo del error
[[ fstDig, benTeo, fstFrq, errQua]]
});
Text WriteLn(linTit);
Real benSum = SetSum(BenLaw); // Total de frecuencias de Benford
Real expSum = SetSum(expFrq); // Total de frecuencias del experimento
Set expErr = Traspose(expTab)[4]; // Conjunto de errores
Real errSum = SetSum(expErr); // Error del experimento
Text WriteLn("Sum "+FormatReal(benSum, BenFmt)+" | "+
FormatReal(expSum, BenFmt)+" | error "+F(errSum));
//Text WriteLn(linTit);
Extract(expTab, 1, 2, 3) // Tabla digito, Benford, experimento
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado
de haber evaluado la funcion funCod numCic veces y, como efecto lateral,
a) visualiza por pantalla la comparativa del resultado con la Ley de Benford
y b) el error.",
BenView);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// FUNCTIONS: Para cada experimento
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Real BenOpeSecRnd(Real numUno, // Primer numero de entrada
Real numDos, // Segundo numero de entrada
Real numOpe) // Numero de operaciones a realizar
//////////////////////////////////////////////////////////////////////////////
{
If(numOpe <= 0, numDos, // No hay ya mas operaciones que hacer
{
Real numRnd = Floor(Rand(1, Card(OpeBas)+1)); // Numero aleatorio
Text opeTxt = OpeBas[numRnd]; // Operador como texto
Code opeCod = FindCode("Real", opeTxt); // Operador Tol de Real
Real newVal = opeCod(numUno, numDos); // Realiza la operacion
// Text WriteLn(F(numUno)+" "+opeTxt+" "+F(numDos)+" = "+F(newVal));
BenOpeSecRnd(numDos, newVal, numOpe-1)
})
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el resultado de realizar a partir de 2 numeros de entrada, numUno y
numDos, una secuencia de numOpe operaciones de suma, resta, multiplicacion y
division aleatorias y equiprobables.
La secuencia se realiza como una recursion lineal.",
BenOpeSecRnd);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Real BenOpeTreRnd(Real ranMin, // Minimo del rango de aletorios
Real ranMax, // Maximo del rango de aletorios
Real numOpe) // Numero de operaciones a realizar
//////////////////////////////////////////////////////////////////////////////
{
Real numRnd = Floor(Rand(1, Card(OpeBas)+1)); // Numero aleatorio
Text opeTxt = OpeBas[numRnd]; // Operador como texto
Code opeCod = FindCode("Real", opeTxt); // Operador Tol de Real
If(numOpe <= 1, opeCod(Rand(ranMin, ranMax),
Rand(ranMin, ranMax)), // Operacion final
{
Real numLft = Floor(numOpe/2); // La mitad para la izquierda
Real numRht = numOpe - numLft; // La otra mitad para la derecha
opeCod(BenOpeTreRnd(ranMin, ranMax, numLft), // Izquierda
BenOpeTreRnd(ranMin, ranMax, numRht)) // Derecha
})
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el resultado de realizar a partir de 1 rango de entrada, determinado
por ranMin y ranMax, una secuencia de numOpe operaciones de suma, resta,
multiplicacion y division aleatorias y equiprobables.
La construccion se realiza por la expansion de un arbol binario con tantos
nodos de operacion como determine numOpe.",
BenOpeTreRnd);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// TEST
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nBenford.Test make: process");
//////////////////////////////////////////////////////////////////////////////
Set tst001 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
Set tstR01 = BenView(
"numeros aleatorios de distribucion uniforme", 1000,
Real(Real posCic) { Rand(0,1) });
Set tstS01 = BenView(
" 4 operaciones secuenciales basicas + - * /", 1000,
Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 4)})
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Numeros aleatorios frente a operaciones aleatorias.", tst001);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set tst002 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
Set tstS02 = BenView(
"10 operaciones secuenciales basicas + - * /", 2000,
Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 10)});
Set tstS04 = BenView(
" 5 operaciones secuenciales basicas + - * /", 4000,
Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 5)})
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Comparar nº de ciclos contra nº de operaciones.", tst002);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set tst003 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
Set tstS03 = BenView(
" 7 operaciones secuenciales basicas + - * /", 3000,
Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 7)});
Set tstT03 = BenView(
" 7 operaciones en arbol basicas + - * /", 3000,
Real(Real posCic) { BenOpeTreRnd(0, 1, 7)});
Set tstE03 = BenView(
"exponencial de numeros aleatorios entre 0 y 1", 3000,
Real(Real posCic) { Exp(Rand(-10,10)) })
});
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Compararcion de la generacion en secuencia de operaciones, en arbol binario
de operaciones y la exponencial de numeros aleatorios.",
tst003);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Set tstFor = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
Set tstD02 = BenView(
"trafico dudoso, acumulado en bytes", Card(TraDud),
Real(Real posCic) { TraDud[posCic] });
Set tstC02 = BenView(
"trafico controlado, acumulado en bytes", Card(TraChk),
Real(Real posCic) { TraChk[posCic] })
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Analiza el caso de informatica forense.", tstFor);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// END
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nBenford.Test make: end");
2015 asolver.com | Aviso legal | XHTML | Δ Θ Ξ | Creative Commons | Mapa y funciones del sitio