Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - eferion

#501
Programación C/C++ / Re: Template Nodo
30 Abril 2014, 08:14 AM
Los templates tienen que estar definidos e implementados SIEMPRE en el archivo de cabecera... no puedes poner implementación en un cpp.

La razón es que los templates se compilan sobre la marcha. Un template es un manual de instrucciones que permite crear clases... cada vez que el compilador se encuentra un uso del template que no existe aún, hace una compilación del template específica para ese uso... por esta razón se exige que los templates no tengan código en los cpp.
#502
Cita de: cacacolass en 30 Abril 2014, 05:12 AM
P.D: Había pasado 'i' como parámetro para no volverlo a declarar de nuevo en la función. Pensé que no tenía nada de malo.

Cuando tu pasas una variable como argumento de una función se realizan las siguientes acciones (por dar una idea):

* Se hace una copia de la variable.
* Se llama a la función.
* Se recupera la copia de la variable.

Cuando tu la declaras directamente como variable local:

* Se crea la variable ( bien en el stack, bien en los registros del procesador, depende de las optimizaciones del programa )

Pasar una variable como argumento es, como norma general, más costoso y confuso que declarar la variable como local.

Lo de confuso lo entenderás cuando te encuentres con una función ( yo lo he vivido ) con 78 argumentos.
#503
Programación C/C++ / Re: Memoria dinamica?
29 Abril 2014, 18:07 PM
Es mas impprtante, desde mi punto de vista, saber como funcionan las cosas a saber aprovechar al máximo las características del lenguaje.

Sabiendo como funcionan puedes adaptarte a nuevas necesidades... Si no lo sabes mas vale que conozcas alguna utilidad que sirva para tus necesidades...
#504
Cita de: Blaster en 29 Abril 2014, 16:47 PM
Y el 0x80000000 de donde lo sacaste, que valor tiene y por que necesariamente debe ser este el indicado para hacer la comparación binario con dato

Saludos..

Un int típico son 32 bytes. Unsigned int usa los mismos 32 bits, la diferencia es que al no usar bit de signo, amplía el rango posible de valores positivos.

Si tu pasas el número 0x80000000 a binario tienes el número:


8    0    0    0    0    0    0    0
1000 0000 0000 0000 0000 0000 0000 0000


Como ves, esa "máscara" junto con el operador binario and "&" permite saber si el dígito de mayor peso de una secuencia de 32 bits es 1 o 0... "X & 0x80000000" únicamente arrojará un resultado diferente a 0 cuando el bit de mayor peso sea 1... independientemente del estado del resto de los bits.

Si el tipo unsigned int ocupase un tamaño diferente a los ya comentados 32 bits habría que reajustar la máscara.
#505
Programación C/C++ / Re: Memoria dinamica?
29 Abril 2014, 16:33 PM
Cita de: vangodp en 29 Abril 2014, 16:17 PM
¿Es mejor usar c o c++ para la memoria dinámica?Digo por que lo que tengo son mas preguntas que respuestas.

Si estás programando en C, usa las funciones de C... si estás en C++, usa new y delete.

internamente, new llama a malloc y después llama al constructor de la clase. Hasta aquí nada nuevo. La potencia real de usar new es que puedes "customizar" la forma en la que se hacen las reservas de memoria para optimizar el proceso.

No olvidemos que malloc está pensado para hacer reservas grandes de memoria... con reservas pequeñas es altamente ineficiente.

Una inmejorable reseña sobre este tema se puede encontrar en el tema 4 del libro: "Modern C++ Design", de Andrei Alexandrescu

Cita de: vangodp en 29 Abril 2014, 16:17 PM
¿En c++ alloc permite crear objetos no típicos de c como clases?

malloc o calloc únicamente reservan memoria, como te he comentado en el punto anterior, "new" se encarga de llamar al constructor correspondiente para inicializar correctamente el objeto.

Cita de: vangodp en 29 Abril 2014, 16:17 PM
¿Las tablas se pueden redimensionar usando new y delete de cpp? Dicen algunos que use la clase vector solamente¿Es que no hay otra forma forma? =(

new y delete, como tales, no permiten hacer realloc, al menos que yo sepa.

Lo que sucede es que C++ te permite encapsular operaciones de realloc dentro de una clase, por lo que desde fuera es algo que te resulta transparente.

La gracia de usar contenedores en vez de memoria dinámica "a pelo" es que puedes delegar parte del trabajo. Los contenedores ya implementan la lógica necesaria para evitar lagunas de memoria... obviamente puedes gestionar la memoria tu directamente, pero tendrás que reinventar la rueda.

Es importante recordar que la programación, contra creencia popular de los ignorantes, es un trabajo bastante laborioso... todo lo que puedas evitar reescribir bienvenido sea ( te ahorras tiempo, dinero y bugs ).

Cita de: vangodp en 29 Abril 2014, 16:17 PM
¿Es verdad que no se puede mezclar esas cosillas XDD??

A estas alturas ya sabrás que "new" hace un "malloc" por detrás, al igual que "delete" hace un "free"... lo que sucede es que estos usos estan "centralizados".

Lo que sí es importante es recordar que "al cesar lo que es del cesar", es decir, si reservas con malloc, liberas con free... y si creas con new... lo eliminas con delete, cualquier otra combinación puede ser potencialmente peligrosa.

Dicho esto, el mayor problema de mezclar en tu código instrucciones new con malloc es que luego tienes que asignar correctamente los free y los delete... ¿por qué te vas a complicar la vida de forma gratuíta?

Cita de: vangodp en 29 Abril 2014, 16:17 PM
En fin...¿Cual es mejor  y por que lo es  o para que es mejor cada cosa?

Volviendo a mi primera respuesta:

"Si estás programando en C, usa malloc, calloc y realloc... si estás en C++, usa new y delete"

Cita de: vangodp en 29 Abril 2014, 16:17 PM
Gracias de antemano chicos. ¡Mucha suerte! ^^

Un placer ser de utilidad.

Un saludo.
#506
La función BinToString convierte a string la representación binaria del número.

Tal y como están estructurados los datos me parecía que era más fácil calcular la representación en base 10 de la siguiente forma:

* Creo un string con valor por defecto: "0"
* Recorro el array binario, empezando por los bits de mayor peso.
* Para cada iteración, multiplico el resultado del string por 2.
* Si el bit de turno en la iteración es '1', se lo sumo al string del resultado.

Los dos últimos pasos se realizan conjuntamente con la función Mul2AddN ( lo que viene a significar, multiplica por dos y suma N, donde N será 0 o 1 según proceda ).

la expresión:

Código (cpp) [Seleccionar]
(data & 0x80000000 )? 1 : 0

sirve para evaluar el bit de mayor peso de cada "tramo" de "unsigned int"... recordemos que está toda la representación metida en un vector.

Para poder evaluar los 32 bits de cada tramo tengo que hacer un desplazamiento binario, sustituyendo el bit de mayor peso por el siguiente... esto se hace con la siguiente línea:

Código (cpp) [Seleccionar]
data <<= 1;

Dicho con un ejemplo práctico la mecánica es la siguiente:


Número en binario: 1100101
resultado inicial: "0"

1a iteracion:
 "data & 0x800...": 1
 resultado = "0" * 2 + 1 = "1"

2a iteracion:
 "Data & 0x800...": 1
 resultado = "1" * 2 + 1 = "3"

3a iteracion:
 "Data & 0x800...": 0
 resultado = "3" * 2 + 0 = "6"

4a iteracion:
 "Data & 0x800...": 0
 resultado = "6" * 2 + 0 = "12"

5a iteracion:
 "Data & 0x800...": 1
 resultado = "12" * 2 + 1 = "25"

6a iteracion:
 "Data & 0x800...": 0
 resultado = "25" * 2 + 0 = "50"

7a iteracion:
 "Data & 0x800...": 1
 resultado = "50" * 2 + 1 = "101"

resultado final: "101"


modificado:

Cita de: vangodp en 29 Abril 2014, 15:51 PM
¿ves lo que digo?  :laugh: :laugh: :laugh:

Puede que tu digas que tu código no sea para tanto :laugh: lo que no sabes es lo limitado que es la gente detrás de la pantalla. :D
Cuando el saber hace parte de tu día a día ignoras que la gente no sabe tanto como tu, te imaginas que todos tenemos la misma capacidad pero en realidad a algunos nos cuesta mas que a otros. Tener paciencia con nosotros lo novatos.  ;D
Lo que haces es grande, ayudas a la gente y no exiges nada a cambio, yo no podría pagar semejante ayuda con dinero. Así que al menos digo ¡¡¡Gracias*1000!!! ;-)

No soy grande...camino junto a ellos ^^

Tu comentario me halaga, no lo puedo negar. Pero casi me pones a la altura de un semidios o algo así y tampoco es para tanto.

Muchas veces, cosas de estas son del tipo "idea feliz"... cuando las comprendes, ves que muchísimas veces la solución es más sencilla de lo que aparenta.

En cualquier caso, también ha quedado claro en algunos hilos que no soy infalible... sobretodo si posteo desde el móvil XDDDDD. Pero bueno, se hace lo que se puede con tal de ayudar.

Un saludo.
#507
Eres un exagerado. Su funcionamiento tampoco es tan complicado.

Lo único que hace la clase es almacenar el número en un vector de tipo "unsigned int". Lo he hecho así porque las operaciones matemáticas sobre tipos int o uint son más rápidas que ir carácter a carácter ( en el caso de almacenar el número en un string )... además, como efecto secundario, consume menos memoria.
#508
Código (cpp) [Seleccionar]

#include <bitset>
#include <iostream>
#include <string>
#include <vector>

class BigNum
{
  public:

    BigNum( int number = 0 );

    BigNum( const std::string& number );

    BigNum operator+( const BigNum& number );

    std::string ToBinString( ) const;

    std::string ToString( ) const;

  private:

    bool _negative;
    std::vector< unsigned int > _number;

    void Mul10AddN( unsigned int number );

    std::string Mul2( const std::string& number ) const;

    std::string Mul2AddN( const std::string& number, int carry ) const;

    void FromString( const std::string& number );
};

BigNum::BigNum( int number )
  : _negative( false )
{
  if ( number < 0 )
  {
    _negative = true;
    number = -number;
  }
  else if ( number > 0 )
    _number.push_back( number );
}

BigNum::BigNum( const std::string& number )
{
  FromString( number );
}

BigNum BigNum::operator +( const BigNum& number )
{
//  if ( number1._negative != number2._negative )
//  {
//    if ( number1._negative )
//    {
//      BigNum temp = number1;
//      temp._negative = false;
//      return number2 - temp;
//    }
//    else
//    {
//      BigNum temp = number2;
//      temp._negative = false;
//      return number1 - temp;
//    }
//  }

  BigNum to_return;
  to_return._negative = _negative;

  unsigned int carry = 0;
  unsigned int max = (_number.size( ) > number._number.size( ) )? _number.size( )
                                                                : number._number.size( );

  for ( unsigned int i=0; i < max; i++ )
  {
    unsigned long long temp = 0;

    if ( i < _number.size( ) )
      temp = static_cast< unsigned long long >( _number[ i ] );

    if ( i < number._number.size( ) )
      temp += static_cast< unsigned long long >( number._number[ i ] );

    temp += carry;

    to_return._number.push_back( static_cast< unsigned int >(temp & 0xFFFFFFFF) );
    carry = static_cast< unsigned int >(temp >> 32);
  }

  if ( carry != 0 )
    to_return._number.push_back( static_cast< unsigned int >( carry ) );

  return to_return;
}

std::string BigNum::ToBinString( ) const
{
  std::string to_return;

  for ( unsigned int i=_number.size( ) - 1; i < _number.size( ); i-- )
  {
    std::bitset< 32 > bits( static_cast< int >( _number[ i ] ) );
    to_return += bits.to_string( );
  }

  while ( to_return[ 0 ] == '0' )
    to_return.erase( to_return.begin( ) );

  int i = static_cast< int >( to_return.size( ) ) - 4;
  while ( i > 0 )
  {
    to_return.insert( i, 1, ' ' );
    i -= 4;
  }
  return to_return;
}

std::string BigNum::ToString() const
{
  std::string to_return = "0";

  for ( auto it = _number.rbegin( ); it != _number.rend( ); ++it )
  {
    int data = *it;
    for ( int i=0; i< 32; i++ )
    {
      to_return = Mul2AddN( to_return, (data & 0x80000000)? 1 : 0 );
      data <<= 1;
    }
  }

  return to_return;
}

void BigNum::Mul10AddN(unsigned int number)
{
  if ( _number.empty( ) )
  {
    _number.push_back( number );
    return;
  }

  unsigned long long carry = static_cast< unsigned long long >( number );
  unsigned long long ten = 10;
  for ( unsigned int i = 0; i < _number.size( ); i++ )
  {
    unsigned long long temp = static_cast< unsigned long long >( _number[ i ] ) * ten + carry;

    _number[ i ] = static_cast < unsigned int >( temp & 0xFFFFFFFF);
    carry = ( temp >> 32 );
  }

  if ( carry != 0 )
    _number.push_back( static_cast< unsigned int >( carry ) );
}

std::string BigNum::Mul2AddN(const std::string& number, int carry ) const
{
  std::string to_return;

  for ( auto it = number.rbegin( ); it != number.rend( ); ++it )
  {
    int temp = (*it - '0') * 2 + carry;

    if ( temp >= 10 )
    {
      temp -= 10;
      carry = 1;
    }
    else
      carry = 0;

    to_return.insert( 0, 1, temp + '0' );
  }

  if ( carry != 0 )
    to_return.insert( 0, 1, carry + '0' );

  return to_return;
}

void BigNum::FromString(const std::string& number)
{
  unsigned int i=0;
  if ( number[ i ] == '-' )
  {
    _negative = true;
    i++;
  }
  else
    _negative = false;

  _number.clear( );

  for ( ; i < number.length( ); i++ )
  {
    unsigned int digit = number[ i ] - 0x30;
    Mul10AddN( digit );
  }
}

int main( )
{
  BigNum a( 100 );
  BigNum b( "9000000000000" );

  BigNum c = a + b;

  std::cout << a.ToString( ) << std::endl
            << "+" << std::endl
            << b.ToString( ) << std::endl
            << "=" << std::endl
            << c.ToString( ) << std::endl;

  a = BigNum( "123456123456123456123456123456123123" );
  b = BigNum( "876543211234567876543212345678");
  c = a + b;


  std::cout << a.ToString( ) << std::endl
            << "+" << std::endl
            << b.ToString( ) << std::endl
            << "=" << std::endl
            << c.ToString( ) << std::endl;
}


Como es de esperar... ni está optimizada ni completa... está hecha en un rato para satisfacer el insaciable apetito de vangodp... pero vale de ejemplo.

actualizado: Ahora también imprime el string en base 10.
#509
¿Y hacerte una clase para manejar números grandes?

También puedes aprovechar alguna clase ya existente en internet para realizar esta tarea.

Si estás programando en C el tema de las clases ya no te sirve... pero aún así sigue habiendo opciones.
#510
Cita de: IEAX en 29 Abril 2014, 05:52 AM
Te equivocaste ahí, se puede utilizar y controlar la memoria sino fijate el siguiente link:

http://msdn.microsoft.com/en-us/library/chfa2zb8.aspx


B#

Puedes hacer un delete directamente y que, en ese preciso momento, se libere la memoria dinámica??? no, verdad??? de hecho ni tan siquiera existe el operador "delete"... pues eso.

Lo que tu comentas es que en determinadas partes del código ( sobretodo para tener compatibilidad con código nativo ), se permite el uso de punteros "crudos" al más puro estilo C++ tradicional... pero tu no puedes elegir libremente el ciclo de vida real de un objeto en la plataforma .NET.