¿Cuánto sabes de C# y .NET? - Soluciones al cuestionario de la Dot Net Conference

En la pasada Dot Net Conference el equipo de Plain Concepts preparó un cuestionario ¿Cuánto sabes de C#? El reto consistía en acertar 5 preguntas relacionadas con C#.

Durante el evento muchas personas lo intentaron, pero muy pocas consiguieron dar las 5 respuestas correctas. Así que desde el equipo de Windows Platform de Plain Concepts hemos decidido compartir el reto y dar las soluciones argumentando el por qué. Así que ¿Cuánto sabes de C#?

Nota: Podéis consultar el código fuente de las preguntas en GitHub.

Pregunta 1

static void Test(out int x, out int y)

{

x = 42;

y = 123;

Console.WriteLine(x == y);

}

  1. Falso
  2. Cierto
  3. Puede ser cierto
  4. No compila

Solución - Pedro González (@pedrogovi)

La palabra reservada out hace que los parámetros del ejemplo sean pasados por referencia. El efecto de pasar parámetros por referencia es que cualquier cambio de estos parámetros dentro del método se refleje fuera del mismo. En este caso, la palabra reservada out tiene el mismo efecto que ref, salvo que esta última requiere que la variable sea inicializada previamente.

En el código que aquí se muestra se están cambiando los valores que tienen la variables que se ha pasado por referencia: x e y.

Si suponemos que la variable que se ha pasado por referencia como parámetro x no es la misma que la variable que se ha pasado como parámetro y, podríamos afirmar que el resultado es que x e y tendrán valores diferentes. Véase el siguiente ejemplo donde se realiza una llamada a dicho método con variables diferentes.

static void Main()

{

int a = 1;

int b = 2;

Test(out a, out b);

}

Sin embargo, si la llamada al método Test se realiza con la misma variable, como se muestra en el ejemplo siguiente, se estaría cambiando el valor de la misma variable y por lo tanto los valores de x e y serían iguales (x = 123, y = 123). No sabemos si x e y van a tener el mismo valor, pero podemos afirmar que podrían tenerlo y la respuesta correcta sería la 3.

static void Main()

{

int a = 1;

Test(out a, out a);

}

Para más información podéis visitar la documentación oficial.

Solución: 3. Puede ser cierto

 

Pregunta 2

static void Main(string[] args)

{

float value = 100000000;

while(value > 0)

{

--value;

}

Console.WriteLine("Value es {0}", value);

}

  1. Value es 0
  2. Value es 0.00000001
  3. Nunca se imprime el valor de Value
  4. No compila

Solución – Francisco Olmedo (@fmolmedo)

Repasamos los posibles puntos de interés:

En primer lugar, la asignación de la variable value es correcta, ya que se hace conversión implícita de entero a float.

Posteriormente, la sentencia --value equivaldría a value = value - 1, por lo que también es correcta.

Por lo tanto, nos queda incidir en la pérdida de precisión por usar una variable de tipo float. Para su representación se utilizan 32 bits, de los cuales 1 es para el signo, 23 para la representación de la mantisa y 8 para el exponente. Por lo tanto, si tenemos 23 bits (24 si consideramos que el bit más significativo se asume a 1) para la mantisa, podemos representar: log10(2^24) ~= 7 dígitos significativos. Por lo tanto, el rango de enteros que se pueden representar con un float sin pérdida de precisión es el siguiente: [-16777216 - 16777216]. El número que le asignamos no entra en ese rango, con lo que, la operación de restar uno no se llevaría a cabo como se espera; y, consecuentemente, no se llegaría nunca a salir del bucle.

Solución: 3. Nunca se imprime el valor de Value

Pregunta 3

int x = 1;

x = x++;

  1. x==1
  2. x==2
  3. No existe el operador ++
  4. No compila

Solución – Sergio Gallardo (@maktub82)

El operador ++ es un operador de increment y puede aparecen antes o después del operando.

Cuando aparece antes del operando (++x) el resultado de la operación es el del operando después de incrementarse. Pero si aparece después del operando (x++), como en nuestro caso, el resultado de la operación es el del operando antes de haberse incrementado.

Por tanto la asignación se hace con el valor original de x, que es 1. Así que la respuesta correcta es x==1.

Sin embargo, si el operador ++ apareciera delante del operando (x = ++x), el resultado de la asignación sería el del operando después de haber sido incrementado y por tanto x valdría 2.

Solución: 1. x==1

Pregunta 4

static void Main(string[] args)

{

double result1 = 3.65d + 0.05d;

float result2 = 3.65f + 0.05f;

Console.WriteLine(result1 == 3.7d);

Console.WriteLine(result2 == 3.7f);

Console.WriteLine(result1 == result2);

}

  1. TRUE, TRUE, TRUE
  2. TRUE, FALSE, TRUE
  3. FALSE, FALSE, FALSE
  4. TRUE, TRUE, FALSE
  5. FALSE, TRUE, TRUE
  6. FALSE, TRUE, FALSE

Solución – Daniel Martín (@danimart1991)

Cuando un ordenador necesita contener datos puede resultar sencillo, por ejemplo, un entero, con su representación estandarizada binaria, o puede resultar muy complicado, por ejemplo, un número decimal. Puede parecer sencillo, divides en dos partes el número, que pueden ser representados por dos enteros, y ambos enteros pueden ser transformados a su representación binaria y guardados en el sistema, pero este concepto puede dar problemas, por ejemplo, al intentar guardar un número irracional, o algo más sencillo, un tercio, al obtener el valor en coma flotante de un tercio, se obtiene un número periódico 0,333..., este valor no puede ser representado de manera sencilla.

Una solución que se propone en muchos sistemas es la aproximación. Esta aproximación, pasa por dar el número próximo más cercano disponible, pero este punto puede dar problemas de cálculo, inclusive en su transformación a binario. Por ejemplo, y tal y como ocurre en la pregunta 4: 3.65d + 0.05d no siempre puede resultar en 3.7d, y dependerá del lenguaje, el compilador y de cómo se realice la acción.

En C# existen varios tipos de números de coma flotante:

-          Float: un número de coma flotante de tipo 32 bit (1 bit para signo, 23 bits para mantisa, y 8 bits de exponente).

-          Double: un número de coma flotante de tipo 64 bit (1 bit para signo, 52 bits de mantisa, y 11 bits de exponente).

 

En el código de la pregunta al guardar el resultado double realiza un redondeo, y guarda el resultado más próximo disponible que es 3.6999999999999997. Al guardar el resultado float, si realiza un redondeo más acorde a lo esperado y si guarda correctamente el valor 3.7, por tanto, al comprarlo, es cierto.

Más información sobre los número es coma flotante en C#

Solución: 6. FALSE, TRUE, FALSE

 

Pregunta 5

static void Main(string[] args)

{

double delta = 0.1;

int i = 0;

double value = 0d;

for (; i < 100; i++)

{

value += delta;

}

Console.WriteLine(value);

Console.ReadLine();

}

  1. Evidentemente no compila
  2. 10
  3. Casi 10
  4. No termina
  5. 1

Solución – Daniel Martín (@danimart1991)

En esta pregunta ocurre lo mismo cuando se guarda el resultado. Conforme se incrementa value se va redondeando, hasta que al final, casi llega a 10. Debido al redondeo del double se queda en 9,99999999999998.

Solución: 3. Casi 10.

Try It!

Podéis descargar el código fuente desde nuestro GitHub y probar todos los ejemplos. Ahora vamos a ver a nuestro compañero Javier Suárez que nos va a explicar depurando en Visual Studio todas las respuestas que hemos visto antes.

https://onedrive.live.com/redir?resid=D81365B2F51A81B5!211057&authkey=!ADeDcXpobAvMKB4&ithint=video%2cmp4

¡Esperamos que os haya gustado! ¿Cuántas preguntas habéis acertado?

Equipo de Windows Platform de Plain Concepts.