2012-01-18 10 views
11

Al comparar con un mínimo o un máximo de dos números/funciones, ¿C-cortocircuita si el caso es verdadero para el primero e implicaría verdad para el segundo? Ejemplos específicos de estos casos son¿Tiene comparación con Math.Min o Math.Max ​​short-circuit?

if(x < Math.Max(y, z())) 

y

if(x > Math.Min(y, z())) 

Desde Math.Max(y, z()) devolverá un valor al menos tan grande como y, si x < y entonces no hay necesidad de evaluar z(), que podría tomar un tiempo Situación similar con Math.Min.

que dan cuenta de que estos podrían ser reescritos tanto en la línea de

if(x < y || x < z()) 

con el fin de cortocircuito, pero yo creo que es más claro lo que la comparación es sin volver a escribir. ¿Este cortocircuito?

+3

Supongamos que llama a 'if (x> XYZ (y, z()))' ¿Cómo puede el compilador conocer el resultado de XYZ? Max, Min, Average o cualquier otra cosa? –

+0

@ L.B Gran punto, no había considerado esto de esa manera. – yoozer8

+0

Además, la expresión "cortocircuito" puede no ser equivalente, dependiendo de cómo 'Min' y' Max' manejan NaN. – dan04

Respuesta

18

Como han señalado otros, el compilador no sabe nada sobre la semántica de Min o Max que le permitiría romper la regla de que los argumentos se evalúan antes de que se llame al método.

Si desea escribir su propia, puede hacerlo con bastante facilidad:

static bool LazyLessThan(int x, int y, Func<int> z) 
{ 
    return x < y || x < z(); 
} 

y luego llamarlo

if (LazyLessThan(x, y, z)) 

o

if (LazyLessThan(x, y,()=>z())) 

O para el caso:

static bool LazyRelation<T>(T x, T y, Func<T> z, Func<T, T, bool> relation) 
{ 
    return relation(x, y) || relation(x, z()); 
} 
... 
if (LazyRelation(x, y,()=>z, (a,b)=> a < b))) 
+0

Ese último ejemplo habría sido excelente, si fuera posible agregar un argumento predeterminado, así: bool estático LazyRelation (T x, T y, Func x, Func relation = (a, b) => a zmbq

+3

+1 Gran respuesta, pero seamos honestos: ¿todo es más legible/mantenible que 'if (x Yuck

+0

Diría que es menos legible, porque reemplaza un idioma básico con una función cuya definición debe leer para comprender el código. –

10

No, no siempre se evaluará el cortocircuito y z(). Si desea el comportamiento de cortocircuito debe volver a escribir como lo ha hecho.

+4

La razón de esto es porque el tiempo de ejecución no tiene forma de saber cuáles son los efectos de 'Max()' y 'Min()'. ** Usted ** lo hace, lo que le permite reescribir de una manera más eficiente. – Yuck

2

No, no cortocircuito, al menos en el nivel del compilador de C#. Math.Min o Math.Max son dos llamadas a métodos estáticos ordinarios y el compilador no optimizará en ese sentido.

El orden de evaluación del código será: z(), Math.max, x> ...

Si realmente quiere asegurarse, revisar el código IL.

5

Math.Min() y Math.Max() son métodos como cualquier otro. Deben evaluarse para devolver el valor que se utilizará como segundo argumento en la comparación. Si desea un cortocircuito, tendrá que escribir la condición utilizando el operador || como lo ha demostrado.

3

(nada particularmente nuevo que añadir, sino que pensé que me gustaría compartir los resultados de una prueba me encontré en él.)

Math.max() podría ser fácilmente inline por el CLR de compilador Just-In-Time y desde allí tuve curiosidad de si podría optimizar aún más el código de tal manera que se cortocircuite.

Así que preparé un microbenchmark que evalúa las dos expresiones 1,000,000 de veces cada una. Para z(), utilicé una función que calcula Fib (15) utilizando el método recursivo. Estos son los resultados de ejecutar los dos:

x < Math.Max(y, z()) : 8097 ms 
x < y || x < z()  :  29 ms 

supongo que el CLR no transformará el código de ninguna manera que impide que las llamadas a métodos de ejecución, ya que no sabe (y no comprueba para ver si) la rutina tiene algún efecto secundario.

Cuestiones relacionadas