2 //min y max entran en conflicto con la windows.h, son rebautizadas en Windows
\r
11 //XXX Pensado para andar con unsigned's (si anda con otra cosa es casualidad =)
13 template < typename T >
18 typedef T atomic_type;
19 enum sign_type { positive, negative };
20 typedef typename std::vector< T > chunk_type;
21 typedef typename chunk_type::size_type size_type;
22 typedef typename chunk_type::iterator iterator;
\r
23 typedef typename chunk_type::const_iterator const_iterator;
\r
24 typedef typename chunk_type::reverse_iterator reverse_iterator;
\r
25 typedef typename chunk_type::const_reverse_iterator const_reverse_iterator;
27 // Constructores (después de construído, el chunk siempre tiene al menos
29 // Constructor default (1 'átomo con valor 0)
30 number(): chunk(1, 0) {}
31 // Constructor a partir de buffer (de 'átomos') y tamaño
32 // Copia cada elemento del buffer como un 'átomo' del chunk
33 // (el átomo menos significativo es el chunk[0] == buf[0])
34 number(atomic_type* buf, size_type len, sign_type sign = positive):
35 chunk(buf, buf + len), sign(sign)
37 // Constructor a partir de un buffer (de 'átomos') terminado en 0
38 // FIXME (en realidad está 'roto' este contructor porque no puedo
39 // inicializar números con un átomo == 0 en el medio)
40 number(atomic_type* buf, sign_type sign = positive): sign(sign)
41 { while (*buf) chunk.push_back(*(buf++)); fix_empty(); }
42 // Constructor a partir de un 'átomo' (lo asigna como único elemento del
44 number(atomic_type n, sign_type sign = positive):
45 chunk(1, n), sign(sign) {} // copia una vez n en el vector
46 // TODO constructor a partir de string.
49 number& operator++ () { carry(0); return *this; }
50 number& operator+= (const number& n);
51 // Devuelve referencia a 'átomo' i del chunk (no debería ser necesario
52 // si la multiplicación es un método de este objeto).
53 atomic_type& operator[] (size_type i) { return chunk[i]; }
55 // Iteradores (no deberían ser necesarios)
56 iterator begin() { return chunk.begin(); }
57 iterator end() { return chunk.end(); }
58 const_iterator begin() const { return chunk.begin(); }
59 const_iterator end() const { return chunk.end(); }
\r
60 reverse_iterator rbegin() { return chunk.rbegin(); }
\r
61 reverse_iterator rend() { return chunk.rend(); }
\r
62 const_reverse_iterator rbegin() const { return chunk.rbegin(); }
\r
63 const_reverse_iterator rend() const { return chunk.rend(); }
\r
72 // Pone un chunk en 0 para que sea un invariante de representación que
73 // el chunk no sea vacío (siempre tenga la menos un elemento).
74 void fix_empty() { if (!chunk.size()) chunk.push_back(0); }
75 // Propaga carry a partir del 'átomo' i (suma 1 al 'átomo' i propagando
77 void carry(size_type i)
82 if (!chunk[i]) carry(i+1); // Overflow
84 else chunk.push_back(1);
88 template < typename T >
89 number< T >& number< T >::operator+= (const number< T >& n)
93 size_type fin = std::min(chunk.size(), n.chunk.size());
\r
94 size_type i; //problema de VC++, da error de redefinición
\r
96 // "intersección" entre ambos chunks
97 // +-----+-----+------+------+
99 // +-----+-----+------+------+
100 // +-----+-----+------+
101 // | | | | <--- chunk de n
102 // +-----+-----+------+
104 // |------------------|
105 // Esto se procesa en este for
106 for (i = ini; i < fin; ++i)
108 chunk[i] += n.chunk[i] + c;
109 if (chunk[i] || (!n.chunk[i] && !c)) c = 0; // OK
110 else c = 1; // Overflow
112 // si mi chunk es más grande que el del otro, sólo me queda
114 if (chunk.size() >= n.chunk.size())
116 if (c) carry(fin); // Propago carry
120 // +-----+-----+------+
122 // +-----+-----+------+
123 // +-----+-----+------+------+
124 // | | | | | <--- chunk de n
125 // +-----+-----+------+------+
128 // Esto se procesa en este for
129 // (suma los chunks de n propagando algún carry si lo había)
131 fin = n.chunk.size();
132 for (i = ini; i < fin; ++i)
134 chunk.push_back(n.chunk[i] + c); // Agrego nuevo átomo
135 if (chunk[i] || !c) c = 0; // OK
136 else c = 1; // Overflow
138 // Si me queda algún carry colgado, hay que agregar un "átomo"
140 if (c) chunk.push_back(1); // Último carry
144 template < typename T >
145 number< T > operator+ (const number< T >& n1, const number< T >& n2)
147 number< T > tmp = n1;
152 template < typename T >
153 std::ostream& operator<< (std::ostream& os, const number< T >& n)
155 // FIXME sacar una salida bonita en ASCII =)
\r
156 std::copy(n.rbegin(), n.rend(), std::ostream_iterator< T >(os, " "));