visual unitarios unitarias tutorial tests studio pruebas net mvc carga automatizadas c# floating-point double numeric

c# - unitarios - Conversión de flotación a doble: ¿la mejor afirmación en una prueba unitaria?



pruebas unitarias tutorial (3)

Para comparar dos valores de punto flotante, ibm sugiere a prueba de abs(a/b - 1) < epsilon

un msnd indica que la propiedad Epsilon refleja el valor positivo más pequeño que es significativo en las operaciones numéricas o comparaciones cuando el valor de la instancia es cero.

así que en realidad deberías revisar

Math.Abs(d/(double)f) - 1) < float.Epsilon)

Dadas las afirmaciones

float f = 7.1f; double d = f;

¿Qué podemos afirmar en una prueba unitaria sobre d?

Por ejemplo, esto no funciona:

Console.WriteLine(d == 7.1d); // false Console.WriteLine(d < 7.1d + float.Epsilon); // true by luck Console.WriteLine(d > 7.1d - float.Epsilon); // false (less luck)

La mejor manera que encontré hasta ahora es volver a convertir el valor:

float f2 = (float)d; Console.WriteLine(f2 == f); // true

Lo que sería lo mismo que la forma bruta de decir.

Console.WriteLine(d == 7.1f); // 7.1f implicitly converted to double as above

Esta pregunta NO es acerca de la precisión de doble y flotante en general, sino realmente SOLO sobre la cuestión pragmática de cómo una prueba unitaria puede describir mejor los límites de d. En mi caso, d es el resultado de una conversión que se produce en el código generado por la generación de código ligero. Al probar esta generación de código, tengo que hacer afirmaciones sobre el resultado de esta función y esto finalmente se reduce a la simple pregunta anterior.


Su "mejor manera" es afirmar que su código generado devuelve algo que es, dentro del margen de error de float , 7.1 . Esto puede ser lo que desea comprobar, en cuyo caso, continuar.

Por otro lado, es posible que desee afirmar que su código generado devuelve específicamente el resultado de la conversión de 7.1f a un double , en cuyo caso podría hacer:

Console.WriteLine(d == (double)f);

Esto es más estricto: su prueba afirma que d está dentro de un rango pequeño, mientras que la prueba anterior afirma que d es un valor específico.

Realmente depende de para qué usarás d . Si es un caso en el que las cosas van a salir mal si no es el valor exacto, pruebe el valor exacto, pero si está bien estar dentro de un valor float del valor, compárelo con el valor float .


(float) d == f .

Otra respuesta sugirió d == (double) f , pero esta es una prueba inútil porque (double) f realiza la misma conversión que d = f realiza implícitamente. Entonces, lo único que esta afirmación podría estar probando es si algún aspecto de la implementación está roto (p. Ej., El compilador implementó una de las conversiones incorrectamente y de una manera diferente a la otra), algún mecanismo externo cambió d o f entre la asignación y La aserción o el código fuente se rompieron de modo que d no era ni double ni float ni ningún tipo que pueda contener el valor de f exactamente o la asignación d = f no se realizó.

En general, no esperamos ningún error de punto flotante, ya que, en cada implementación normal de punto flotante, la conversión de una precisión más estrecha a una precisión más amplia del mismo radix no tiene errores, ya que la precisión más amplia puede representar cada valor que la precisión más estrecha puede . En situaciones poco comunes, un formato de punto flotante más amplio podría tener un rango de exponente más pequeño. Solo en este caso, o en formatos de punto flotante definidos perversamente, la conversión a un formato más amplio podría causar un cambio en el valor. En estos casos, realizar la misma conversión no detectaría el cambio.

En cambio, convertimos del formato más ancho al formato más estrecho. Si d difiere de f , esta conversión tiene la posibilidad de detectar el error. Por ejemplo, supongamos que f contenía 0x1p-1000, pero, por alguna razón, eso no se puede representar en el formato de d , por lo que se redondea a cero. Entonces (float) d == f evalúa como (float) 0 == 0x1p-1000 , luego a 0 == 0x1p-1000 , luego a false . Además, esta prueba puede detectar los mismos errores que la otra sugerencia: una implementación dañada, alteración de d o f , un tipo incorrecto de d y una asignación faltante de d = f .

Aparte de eso, ¿qué errores intentaría detectar con una afirmación aquí?