Como en programancia101 estamos solo empezando, creo que lo más apropiado es empezar por el principio, pero claro, esto sería si hubiera un principio.
Lo ideal sería poder identificar cuál es la habilidad más importante que debe tener un desarrollador y decir: «¡aha! éste es el truco y éste es el problema que necesitáis para afinar la capacidad X». Pero esto creo que es un problema bastante difícil. ¿Cuál creéis vosotros que debería ser la habilidad número uno del buen programante?
Yo he sido incapaz de decidirme sólo por una, pero sí que he visto una actitud común en muchos programantes avezados: no se conforman con saber que algo funciona, sino que quieren saber por qué funciona, o por qué no funciona, o por qué funciona mejor en tal o cual caso. Saber este tipo de cosas está directamente relacionado con la curiosidad por conocer cómo maneja cada concepto «por dentro» nuestro lenguaje favorito, nuestro entorno, nuestro marco de trabajo…
Una de las típicas preguntas que suelen hacerse cuando se quiere comprobar qué tal maneja alguien los conceptos desde el principio es: ¿sabes darle la vuelta? Sí, exactamente, darle la vuelta a las cosas es un procedimiento poco usual en la «programación estándar», pero nos viene al pelo para empezar a proponer el que se vean las cosas de un modo distinto
Vamos a plantear esta pregunta a distintos niveles:
- la idea más básica sería: ¿sabrías escribir un trozo de código que reciba una cadena de texto y le dé la vuelta? Es decir, si nuestra entrada es «abc», la salida sería «cba»
- Bajando un poco más dentro de nuestros tipos de datos: ¿y un trozo de código que le de la vuelta a los bits de un byte? Es decir, si la entrada es 1, la salida sería 128
- Y para terminar, uno un poco más complejo: en C# (y muchos otros lenguajes) los tipos flotantes se representan mediante el estándar aritmético IEEE 754. ¿Sabrías escribir un trozo de código que le de la vuelta a los bits del exponente y la mantisa de esa representación IEEE 754? Es decir, si la entrada es -118,625, la salida sería -17.180.580.000 (nota: en español la coma «,» es decimal y el punto «.» el separador cada 3 números de la parte entera)
Podéis poner vuestras respuestas, preguntas o ideas en los comentarios o bien poner un post con la solución en vuestro propio blog y dejar aquí un enlace (¡es mejor que mandármelas por mail, porque así todos podemos opinar!)
Preparados, listos… ¡ya! }:)
Bueno, ya que nadie se lanza, pongo mi parte para las 2 primeras preguntas, la última me la tengo que empollar 😉
Para la 1ª, podría ser algo así:
void reverseStringBuffers(char* inputString, char* outputString)
{
int len = strlen(inputString);
for(int i=len-1; i >= 0; i–)
{
outputString[len – i -1] = inputString[i];
}
}
Para la segunda, algo de este estilo (programa completo):
#include «stdafx.h»
#include
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unsigned char input = 0;
short inputNumber = 0;
short output = 0;
cout < < "Enter a number:" << endl; cin >> inputNumber;
input = (unsigned char)inputNumber;
for(unsigned char i=0; i<8; i++)
{
// Mask to the i bit
unsigned char mask = (1 << i); unsigned char masked = input & mask; if(masked != 0) { // bit i is set output += 1 << (7 - i); } } cout << "Output: " << output << endl; return 0; } Sin verificaciones adicionales que habría que hacer de entradas, claro...
Yo pongo mi granito de arena con Visual Basic para el 1, el resto las estoy procesando…
Public Function ReverseString(ByVal String As String)
Dim OutString As String = «»
For I As Integer = 0 to String.Leght – 1
OutString = String.Substring(String.Leght – i, 1) & OutString
End For
Return OutString
End Function
Si hay algún error avisad 🙂
Ala! Pues ya lo aviso yo, esto me pasa por no probarlo antes de enviarlo 🙂
Public Function ReverseString(ByVal InString As String)
Dim OutString As String = «»
For I As Integer = 0 To InString.Length – 1
OutString &= InString.Substring(InString.Length – 1 – I, 1)
Next
Return OutString
End Function
Ese es el código correcto, ahora ya está comprobado que funciona.
Ala! Pues ya lo aviso yo, esto me pasa por no probarlo antes de enviarlo 🙂
Public Function ReverseString(ByVal InString As String)
Dim OutString As String = «»
For I As Integer = 0 To InString.Length – 1
OutString &= InString.Substring(InString.Length – 1 – I, 1)
Next
Return OutString
End Function
Ese es el código correcto, ahora ya está comprobado que funciona.
Hola Ricardo,
Para mi la cualidad principal que debe de tener un buen programador no es diferente a la de cualquier otra persona que se enfrenta a retos diarios en su trabajo. La mejor cualidad en un programador es, sin duda, que sepa hacer buenas preguntas a las personas que tengan las respuestas, así de sencillo. Claro que hay muchas cualidades más técnicas que tener en cuenta pero creo que todas esas se suman a la principal. Lo realmente importante es no perder la capacidad de comunicarse y afrontar en equipo, cada uno asumiendo su rol, cualquier problema al que se les ponga delante.
Saludos.
Bueno ahora entro a Geeks.ms y me topo con la noticia de que este chico maravilla (como dijo Unai) de la programacion esta entre nosotros.
Bienvenido TITAN!!!
Saludos desde Rep. Dom. [:D]
Hace un par de dias mi amigo Ricardo Varela comenzo a bloggear en español (en paralelo con su actual
Esto no me lo esperaba (ni siquiera me lo había planteado) pero el código para el caso 2 en VB.NET es una traducción directa del de C++…
Sub Main()
Console.WriteLine(«Enter a number (0-255):»)
Dim characters As String = Console.ReadLine()
Dim byteNumber As Byte = Byte.Parse(characters)
Dim output As Byte
For i As Byte = 0 To 7
‘ Mask to the i bit
Dim mask As Byte = 1 << i Dim masked As Byte = byteNumber And mask If (masked) Then ' bit i is set output += 1 << (7 - i) End If Next Console.WriteLine("Resultado: " + output.ToString()) Console.ReadLine() End Sub 😉
buenas crases!
Muchísisimas gracias por vuestro tiempo! A los que ya se han animado a probar, espero que el problema os pareciera interesante y/o que hayáis repasado o aprendido algo nuevo en el proceso! A los que no… a qué esperáis! }:D
Miguel: te he dejado una pistilla sobre donde te has quedado atascado en tu blog
Eugenio: ves? si yo siempre te digo que no me gusta VB };P … Peeero, por respeto a mis compis MVPs (encabezados por el gran Guille), mis comentarios:
a) usar substring es un poco matar moscas a cañonazos, prueba a ir directamente por los caracteres de «alguna de las otras formas»
b) palabras-pista a las que «puedes» echar un ojo: String.toCharArray, String.Chars, System.Text.StringBuilder
Alejandro: first post! Tengo que ver que te puedo dar de premio por ser el primerísimo que acepta el reto! }:)
De momento: fantástica la idea de usar C/C++. Mis comentarios aquí debajo:
a) Sobre darle la vuelta a la cadena: tienes un algoritmo de O(n)… serías capaz de hacerlo en O(n/2)? };)
b) Sobre darle la vuelta a un byte, te propongo dos pequeñas variaciones sobre la idea (que es correcta): una, darle la vuelta usando el mismo byte de entrada; dos, cuando el bit i-ésimo está a 1 (// bit i is set)… hay algo mejor que una suma?
Seguiré pendiente de nuevas soluciones, ya sea por comentarios o por crosslink a vuestros blogs };D
Bueno, seguro que hay mjores maneras de hacerlo, a pero esta ha sido la primera intentona y ha funcionado 🙂
public float TestFloat(float f)
{
Byte[] bits;
bits = BitConverter.GetBytes(f);
BitArray ba = new BitArray(bits);
BitArray ba2 = new BitArray(32);
Console.WriteLine(«Source»);
for (int i = 0; i < 32; i++) { Console.Write("{0}", (ba[i] == true ? 1 : 0)); } Console.WriteLine(); // sign ba2[31] = !ba[31]; // exp for (int i = 0; i < 8; i++) { ba2[30-i] = ba[23+i]; } // mantissa for (int i = 0; i < 23; i++) { ba2[22-i] = ba[i]; } Console.WriteLine("Result"); for (int i = 0; i < 32; i++) { Console.Write("{0}", (ba2[i] == true ? 1 : 0)); } Console.WriteLine("nFloat Result"); ba2.CopyTo(bits, 0); float ff = BitConverter.ToSingle(bits, 0); Console.WriteLine(ff); return ff; } Luego si me da tiempo lo optimizo 🙂 Saludos,
Buenas!
Para dar la vuelta a un string… Una pila sería lo más sencillo… Pero sería 2 * O(n) = O(n).
Una pista para dar la vuelta a los bits de un byte en O(n/2)… Divide y vencerás… 😉
Hola! Este artículo de phobeo me ha parecido una idea genial. Pequeños problemas para hacernos escurrir
Gracias Ricardo, jejeje la verdad no me lo pare a pensar mucho, fue lo primero que se me ocurrio hablando con unos amigos por el messenger.
Que conste que me gusta más C# (lo veo más util, no voy a exponer mis razones ya que no quiero empezar con la típica polémica VB vs. C#) pero… llevo más tiempo con VB y de momento me desenvuelvo mejor en él (por poco tiempo :P).
Saludos y gracias por tus consejos, que sepas que voy seguir tu blog como fan nº 1. Felices fiestas!!!
Seguro que este será uno de los blogs ( Programancia101 ) que más asiduamente leeré, lo primero por que
Después de empollarme como funciona el IEEE 754 aquí tengo la respuesta del tercer problema, en un programita completo en C++:
#include «stdafx.h»
#include
using namespace std;
int reverseInt(int Int);
void printBits(int Int);
union IEEESingle
{
float valuef;
int valuei;
};
int _tmain(int argc, _TCHAR* argv[])
{
float *input = new float;
*input = -118.625F;
IEEESingle inputValue;
inputValue.valuef = *input;
// Signo
unsigned int signo = (inputValue.valuei & 0x80000000) == 0x80000000 ? 1 : 0;
// Exponente
int exponente = ((inputValue.valuei >> 23) & 0x000000ff);
// Exponente normalizado
int exponenteNormalizado = ((inputValue.valuei >> 23) & 0x000000ff) – 127;
// Fraccion
unsigned int fraccion = inputValue.valuei & 0x007fffff;
// Invertir exponente
int reversedExponent = ((reverseInt(exponente) >> 24)) & 0x000000ff;
// Invertir fracción, shift 32-23 bits right
int reversedFraction = ((reverseInt(fraccion) >> (32-23)) & 0x007fffff);
// Componer la salida
int singleOutput = (signo < < 31) + (reversedExponent << 23) + reversedFraction; IEEESingle outputValue; outputValue.valuei = singleOutput; cout << " Input bits: "; printBits(inputValue.valuei); cout << endl; cout << "Output bits: "; printBits(outputValue.valuei); cout << endl; cout << "Valor: " << outputValue.valuef; delete input; return 0; } void printBits(int Int) { int mask; int masked; for(int i=31; i>=0; i–)
{
mask = (1 << i); masked = Int & mask; if(masked != 0) { // bit i is set cout << "1"; }else { cout << "0"; } if(i == 31) cout << " "; if(i == 23) cout << " "; } } int reverseInt(int Int) { int mask; int masked; int output = 0; for(int i=0; i<32; i++) { mask = (1 << i); masked = Int & mask; if(masked != 0) { // bit i is set output += 1 << (31 -i); } } return output; } El 'truco' del union es lo que me ha salvado aquí...
En cuanto a las modificaciones que dices, para O(n/2) podría ser algo así:
void reverseStringBuffers(char* inputString, char* outputString)
{
int len = strlen(inputString);
for(int i=len-1; i >= 0; i -= 2)
{
outputString[len – i -1] = inputString[i];
if(i > 0)
outputString[len – i] = inputString[i-1];
}
}
La otra la miro cuando tenga un rato 😉
Seguro que este será uno de los blogs (Programancia101) que más asiduamente leeré, lo primero por que…
Cuando regresaba a casa en el coche he estado pensando sobre las dos soluciones que he propuesto para
Esta versión es mejor:
void reverseString2(char* inputString)
{
int len = strlen(inputString);
for(int i=0; i < len/2; i ++) { // Guardar el char en el null char final. inputString[len] = inputString[i]; inputString[i] = inputString[len-i-1]; inputString[len-i-1] = inputString[len]; } // Restablecer el null char final inputString[len] = ' '; }
Mi Reverse de cadenas… (el truco del XOR lo vi en el blog de Eugenio, creo…)
void reverseString(char strToReverse[])
{
int len = (int) strlen(strToReverse) – 1;
for(int i = 0; i < len; i++ , len--) { strToReverse[i] ^= strToReverse[len]; strToReverse[len] ^= strToReverse[i]; strToReverse[i] ^= strToReverse[len]; } } ...y uno curioso: Esto lee de teclado hasta que se introduzca un asterisco, sin usar variables: getchr() { c=getch(); if(c != '*') getchr(); putchar(c); }
Alejandro: el null char final no hace falta tocarlo, las dos cadenas tendran el ‘