Recientemente aprendí sobre la programación sin sucursales. Encontré un ejemplo del método min sin sucursales. En pesudocode es algo como esto
function Max(a, b) { return a * (a > b) + b * (a <= b); }Este código funciona solo bajo la condición de que, en el lenguaje usado, verdadero se pueda convertir en 1 y falso en 0. Sin embargo, en c# no parece funcionar, ya que verdadero y falso no son solo alias para 1 y 0, sino valores lógicos reales . ¿Se pueden implementar métodos mínimos y máximos sin sucursales de alguna otra manera en C#?
Usando la sugerencia de @GuruStron, aquí hay un método de extensión:
public static class BoolExt { [StructLayout(LayoutKind.Explicit)] struct TBoolInt32 { [FieldOffset(0)] public bool Bool; [FieldOffset(0)] public int Int; } public static int ToInt32(this bool value) => Unsafe.As<bool, TBoolInt32>(ref value).Int; }Entonces puedes usarlo:
public int Min(int a, int b) => a * (a < b).ToInt32() + b * (a >= b).ToInt32(); Sin embargo, incluso con AgressiveInlining en IL, esto provoca dos llamadas a ToInt32 , por lo que no es realmente más eficiente.
Otra posibilidad es usar la implementación de Math.Sign (no estoy seguro si está en línea, así que lo reimplementé) para crear pruebas que devuelvan 0 o 1:
public static class TestExt { [MethodImpl(MethodImplOptions.AggressiveInlining)] static int IntSign(int value) => (value >> 31) | (int)((uint)(-value) >> 31); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GreaterEqual(this int a, int b) => IntSign(IntSign(a - b) + 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LessThan(this int a, int b) => 1 - a.GreaterEqual(b); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int LesserEqual(this int a, int b) => IntSign(IntSign(b - a) + 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GreaterThan(this int a, int b) => 1 - a.LesserEqual(b); }Puede usar operadores bit a bit y de cambio como este:
int FastMax(int a, int b) { int diff = a - b; int dsgn = diff >> 31; return a - (diff & dsgn); } El operador >> es desplazamiento a la derecha y uso 31 para Int , puedes usar 63 para números long .
FYI: vea este enlace https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators