¿Hay MulDiv en C#?

esta ahí MulDiv

WINBASEAPI
int
WINAPI
MulDiv(
    _In_ int nNumber,
    _In_ int nNumerator,
    _In_ int nDenominator
    );

en C# o un equivalente a él?

o debo implementarlo?

Editar: ¡sin PInvoking!

preguntado el 12 de junio de 12 a las 20:06

4 Respuestas

Esta es una mejora de la sugerencia de Hans Passant, pero incluye el redondeo de +0.5 según los documentos de MSDN:

public static int MulDiv(int number, int numerator, int denominator)
{
    return (int)(((long)number * numerator + (denominator >> 1)) / denominator);
}

Nota: Este código utiliza el operador de desplazamiento a la derecha para obtener el máximo rendimiento.

Respondido 31 Jul 14, 18:07

Esta función API se remonta a la versión 3 de Windows, una versión de Windows de 16 bits. Muy posiblemente antes, no tengo la edad suficiente. Donde fue un poco difícil conseguir que un compilador de C multiplicara dos números de 16 bits (dos enteros), obtuviera un resultado intermedio de 32 bits y lo dividiera por un número de 16 bits para obtener un resultado de 16 bits. La operación era bastante común, calcular un tamaño de letra por ejemplo.

Una de las grandes cargas de Microsoft es que una vez que publican una función api, tienen que mantenerla hacia, a menos que sea totalmente incompatible con los cambios necesarios en el sistema operativo. Nada asqueroso sobre MulDiv(), el int Sin embargo, los argumentos obtuvieron un impulso automático a 32 bits, lo que hace que la función sea completamente innecesaria. Pero los programas escritos para Win3 todavía compilan, backcompat es sagrado.

Fue un pequeño error sobrecargar la API con esto, pero la motivación era fuerte, bastante difícil de meter un sistema de ventanas en 640 kilobytes. Exponer cosas que ya están allí porque el sistema operativo lo necesita realmente ayuda a reducir los bytes. Otras funciones api como esa son wprintf(), lstrcpyXxx(), etc. Funciones de tiempo de ejecución de Core C y posible disponible hoy, incluso mantenido a través del cambio a Unicode. Un registro arqueológico de Windows.

No tiene sentido pinvocarlo, C# no tiene problemas para hacer esto:

public static int MulDiv(int number, int numerator, int denominator) {
    return (int)(((long)number * numerator) / denominator);
}

Use el comprobado palabra clave si desea una excepción de desbordamiento.

Respondido el 12 de junio de 12 a las 21:06

La razón para P/Invocar MulDiv es obtener el mismo comportamiento de redondeo y desbordamiento. Ver msdn.microsoft.com/en-us/library/aa383718(v=VS.85).aspx por todos los detalles sangrientos. - Gabe

Bueno, menos mal que mencioné el comprobado palabra clave, supongo :) Captura y devuelve -1, suponiendo que sea realmente útil. Los números mágicos en una función Cap api también están obsoletos desde hace mucho tiempo. - Hans Passant

Borraste mi pregunta? Sentí que era una pregunta legítima preguntar por qué sintió que MulDiv era un error a pesar de la motivación para ello. - millie smith

Haga clic en el botón Hacer una pregunta si desea hacer una pregunta. - Hans Passant

No hay suficiente contenido ni relevancia general en mi pregunta para hacer una nueva pregunta sobre SO. Mi pregunta tampoco está basada en hechos. Le pido su opinión en función de su respuesta aquí, por lo que es un comentario a su respuesta aquí. Editar: si va a estar de mal humor y eliminar mis comentarios, al menos elimine los suyos y arregle su MulDiv para que realmente se redondee. Estás haciendo un mal uso de tus privilegios de eliminación. - millie smith

No, esto no está disponible de fábrica. Necesitas hacer Invocar.

Puede implementarlo usted mismo, por supuesto:

//truncation is unnecessary if you want to continue using a long
//the truncation can never overflow so it is unchecked
var result = unchecked((int)(nNumber * (long)nNumerator / nDenominator));

Respondido el 12 de junio de 12 a las 22:06

No, no quiero invocarlo - Abanoub

Acabo de preguntar, así que si ya existe una implementación, ¡no hay necesidad de perder el tiempo implementando una! - Abanoub

Seguro. Afortunadamente, el CLR admite entradas de 64 bits para que pueda hacerlo usted mismo en una línea a toda velocidad. - usr

No creo que esto redondee lo mismo que MulDiv. - Gabe

@Gabe, ¿puedes ser más específico? Esto está usando valores intermedios de 64 bits. Tiene total precisión. - usr

Si desea dejar en claro que se esforzará por manejar el caso en el que dos números enteros de 32 bits pueden generar un valor mayor que un número entero de 32 bits, puede usar Math.BigMul, luego simplemente divida el resultado y convertirlo de nuevo a un número entero. Veo, como se indica en otras respuestas, el soporte de .NET para enteros de 64 bits aparentemente proporciona todos los beneficios que necesitaría que antes tendría MulDiv (y algo más).

int result = unchecked((int)(System.Math.BigMul(nNumber, nNumerator) / nDenominator));

Respondido 14 Oct 13, 17:10

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.