Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 04-01-2021
Avatar de aguml
aguml aguml is offline
Miembro
 
Registrado: may 2013
Posts: 885
Poder: 11
aguml Va por buen camino
Revertir números mágicos matemáticamente

Buenas, he visto que los compiladores pueden optimizar las divisiones con constantes, por ejemplo, si divides entre 9 al optimizar se vería algo así:
Código PHP:
mov eax38e38e38
mul esi
mov eax
,edx
shr eax
,
La cosa es invertir eso y que cuando vea ese código pueda obtener el divisor.
He encontrado informacion en inglés y con un nivel de matemáticas que no comprendo y que el inglés no me ayuda porque no sé mucho.
Hasta ahora hago algo como:
(2^(32+s))/M=D
D es divisor
s es el valor de desplazamiento lógico
M es el número mágico .
Esto funciona pero no para todos, por ejemplo con el 62, 63, 70...
Dónde esa formula no sirve y el compilador no hace lo mismo y hace algo así por ejemplo para el 63:
Código PHP:
mov eax,41041041
mul esi
sub esi
,edx
shr esi
,1
add esi
edx
shr esi
,
Como ven enreda bastante más y no sé a que fórmula equivale ni como decidir cuándo debo usar una u otra.
¿Alguien que entienda y pueda ayudarme?

Última edición por aguml fecha: 04-01-2021 a las 22:34:15.
Responder Con Cita
  #2  
Antiguo 05-01-2021
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Esto tiene 2 niveles: Como hace un compilador para optimizar el codigo, y como se optimiza una formula matematica.

Con las matematicas soy un asco, asi que la segunda parte la dejo para otro, pero la primera si se.

Empezemos con la forma mas "simple" de hacer esto: Compila a Pascal/C/Rust/webAssembly y deja que su compilador se encarge del asunto.

Un compilador/interprete se construye como una secuencia de "passes/pasos". La mas simple es "lexing -> AST formation -> code/assembler generation". Pero entre cada pasos(pass) puedes meter otros pasos. Entre ellos se introducen los pasos de optimizacion, los mas comunes:

https://www.geeksforgeeks.org/code-o...mpiler-design/

Estos "pasos" son simplemente REESCRITURAS AL AST, osea, transformar un arbol a otro.

Hay 2 pasos en especial que son utiles: Constant folding y Compile Time Evaluation (y desugaring, que no es un paso concreto, mas bien una tecnica general).

Te pongo un ejemplo concreto usando Rust que es donde mas he trabajado esto.

Nuestro lenguaje: Sabe sumar y usar variables predefinidas

Puedes ejecutarlo sin instalar Rust aqui (con codigo completo):

https://play.rust-lang.org/?version=...1586db6affd7fa
Código PHP:
#[derive(Debug, Clone)]
enum Expr {
    Var(String),                              
//acceso a una variable
    
Number(i64),                           //numero constante
    
Add(Box<Expr>, Box<Expr>),  //suma

* La parte de como definir las variables se usa con un "environment store" osea, un hashtable. El compilador/interpreter va acumulando las variables en el store.

Ahora el lio:

Código PHP:
//El interprete. Para convertilo en compiler, generar codigo en vez de ejecturlo
fn eval(store: &HashMap<StringExpr>, astExpr) -> Expr {
    
dbg!(&ast);
    
match ast {
        
Expr::Var(x) => store[&x].clone(),
        
Expr::Number(num) => Expr::Number(num),
        
Expr::Add(ab) => {
            
let x to_num(store, *a).expect("No es un numero");
            
let y to_num(store, *b).expect("No es un numero");
            
println!("Suma {} + {}"xy);
            
Expr::Number(y)
        }
    }
}

fn main() {
    
let mut variables HashMap::new();
    
variables.insert("a".to_string(), Expr::Number(1));
    
variables.insert("b".to_string(), Expr::Number(2));

    
//a + b
    
let ast Expr::Add(
        
Box::new(Expr::Var("a".into())),
        
Box::new(Expr::Var("b".into())),
    );

    
println!("Sin optimizar....");
    
println!("a + b = {:?}", eval(&variablesast.clone()));

Nuestro lenguaje al usar vbles requiere el uso de memoria en el heap (eso son los Box<...>) dereferenciar pointers y cada vez que salga la variable, interpretarla, que para algo tan idiota como "a=1, b=2; a+b" es mucha vuelta.

Al ejecutar, veras la traza de operacion de como se toca todos los nodos del AST y se evalua en runtime a + b.

Asi que hacemos:

Constant folding

Buscar que vbles son realmente constantes +

Compile time evaluation

Ejecutar al compilar el AST +

Desugaring

Transformar una operacion en otra, en este caso: convertir un paso a + b -> 1 + 2 -> 3, osea desugaring es el termino generico de todo esto.

Esto en este caso es tan simple como:

Código PHP:
fn constant_folding(store: &HashMap<StringExpr>, astExpr) -> Expr {
    
dbg!(&ast);
    if 
let Expr::Add(ab) = ast {
        
println!("Folded!"); //<--Si sale esto se optimizo!
        
let x to_num(store, *a).expect("No es un numero");
        
let y to_num(store, *b).expect("No es un numero");

        
Expr::Number(y)
    } else {
        
ast //paila ir por el camino largo
    
}
}

fn main() {
    
let mut variables HashMap::new();

    
println!("Sin optimizar....");
    
println!("a + b = {:?}", eval(&variablesast.clone()));

    
println!("Haciendo constant folding");
    
let ast constant_folding(&variablesast);
    
println!("{:?} = {:?}", &ast, eval(&variablesast.clone()));


Al ejecutar, veraz que en "println!("{:?} = {:?}", &ast, eval(&variables, ast.clone()));" ast se ha transformado en 3.
__________________
El malabarista.

Última edición por mamcx fecha: 05-01-2021 a las 15:58:32.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Suma de números pares que hay entre dos números Daniel2622 Lazarus, FreePascal, Kylix, etc. 21 26-04-2017 22:47:29
Tablas de multiplicar para todos los números entre dos números Daniel2622 Lazarus, FreePascal, Kylix, etc. 3 22-04-2017 00:47:59
Comparar 2 numeros jzginez OOP 6 18-02-2010 01:41:11
Revertir numeros Jose Meneses Varios 4 23-04-2009 00:01:25
¿Cómo pintar un círculo matemáticamente? aeff Varios 11 12-01-2009 01:06:05


La franja horaria es GMT +2. Ahora son las 16:27:51.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi