2008-11-18 13 views
19

quiero el resultado de una ecuación redondeada al entero más cercano. p.C#: ¿Cómo hago matemáticas simples, con redondeo, en enteros?

137 * (3/4) = 103 

Tenga en cuenta el siguiente código incorrecto.

int width1 = 4; 
int height1 = 3; 

int width2 = 137; 
int height2 = width2 * (height1/width1); 

¿Cuál es la forma correcta de realizar cálculos "enteros" en C#?

es lo que realmente tienen que hacer:

int height2 = (int)Math.Round(
     (float)width2 * ((float)height1/(float)width1) 
    ); 
+7

Es triste que después de un año todavía tenga que volver para hacer referencia a esta pregunta con el fin de averiguar cómo hacer las matemáticas en C#. En Delphi solo escribiría "137 * 3/4" y funcionaría. Pero no C#, C# te obliga a orar a los dioses del compilador antes de que puedas hacer lo que quieras. –

Respuesta

16

Como se ha dicho anteriormente, usted debe hacer la multiplicación antes de la división. De todos modos se puede escribir su expresión con la fundición sólo el divisor:

int height2 = (int)Math.Round(width2 * (height1/(float)width1)); 
3
int height2 = (width2 * height1)/width1; 
+0

Esta solución solo se redondea y no se redondeará si es necesario. Por ejemplo, si ancho1 = (ancho2 * alto1 +1), entonces (ancho2 * alto1)/ancho1 da como resultado 0, no 1. En otras palabras, si el divisor es ligeramente más grande que el dividendo, entonces la división entera producirá 0 mientras el punto flotante la división con redondeo producirá 1. – Catch22

+0

@ Catch22 - Sí, ese es un punto excelente. La versión con conversiones flotantes es una mejor respuesta. –

0

El elaborado en el mensaje de Jeffery, ya que por lo general una mejor oportunidad de decimales necesarios truncadas de lo que tiene de desbordamiento de un entero de 32 bits (y porque la división de multiplicación & es conmutativa), generalmente debe hacer la multiplicación antes de la división.

3

Do multiplicación primero (siempre y cuando no sean propensos a desbordarse) y la segunda división.

3/4 == 0 en matemáticas número entero (número entero de matemáticas no redondea en la división, se trunca).

Si realmente necesita redondeo, usted tiene que o bien trabajan en punto fijo, punto flotante, o jugar con el módulo.

+0

Con la ventaja de un año de retrospectiva: ¿puedes explicar * por qué * debo hacer la multiplicación primero? –

+1

La multiplicación termina cambiando los dígitos a la izquierda. La división se desplaza hacia la derecha. Si la multiplicación no da como resultado un desbordamiento, no se pierde precisión. Es muy probable que la división pierda precisión ya que perderá bits (si divide por 2, pierde 1 bit, si divide por 16 pierde 4, etc.). – plinth

0
int height2 = ((width2 * height1 * 10) + 5)/(width1 * 10); 

Antes de cualquier división entera, comprobar para asegurarse de que el divisor no es cero. También tenga en cuenta que esto supone un cociente positivo. Si es negativo, el redondeo debe ser -5, no +5.

+0

no ayuda. todavía obtiene 102 – Steven

+0

Debe ser "int height2 = ((ancho2 * alto1 * 10) + ancho1 * 5)/(ancho1 * 10);" – RenniePet

1

fijaré el código incorrecto mediante la adición de cero líneas de código:

float width1 = 4; 
float height1 = 3; 

float width2 = 137; 
float height2 = width2 * (height1/width1); 

usted debe utilizar flotadores para las variables que posiblemente pueden contener decimales. Esto incluye alturas calculadas a partir de proporciones. Siempre puedes convertir a int más tarde si eso es un problema.

+1

Los valores originales son enteros y solo pueden contener números enteros. La pregunta es, entonces, cómo hacer matemáticas con ellos. Si estuviera realizando operaciones de coma flotante, lo habría preguntado. (en realidad, no realmente, ya que las matemáticas FP no tendrían el problema) –

1

Nunca moldee a flotar, tiene aún menos precisión que un entero de 32 bits. Si va a usar punto flotante, siempre use doble en lugar de flotante.

+0

Dado que estaré redondeando a un entero de 32 bits de todos modos, ¿qué importancia tiene el dígito significativo en el octavo lugar después del decimal y el flotante? ¿no? –

+0

es decir, es 79.99999999 peor que 79.99999999999 –

+0

Sí. 32 bit int tiene 9 dígitos, pero el float de 32 bit es solo 7. Y recuerda: el código que ocasionalmente da una respuesta ligeramente incorrecta es el peor tipo de error, ¡mucho peor que obtener una respuesta completamente incorrecta! – rwallace

2

Creo que esta es la manera más elegante de hacer esto:

Math.round(myinteger * 0.75); 

Usando 0,75 en lugar de 3/4 implícitamente echarlo a un doble/flotador y por qué no utilizar las funciones predeterminadas que se proporcionan para ¿esta?

+0

Math.round (...) devuelve un doble y no un int (por lo que habrá más casting involucrado) http://msdn.microsoft.com/en-us/library/75ks3aby.aspx – craastad

0

conversiones a convertir siempre redondas, de manera:

int height2 = Convert.ToInt32(width2 * height1/(double)width1); 
1

tropecé con esta pregunta. La respuesta de Aaron parece casi correcta para mí. Pero estoy seguro de que necesitas especificar el punto medio si tu problema es un problema del "mundo real".Así que mi respuesta, basado en el código de Aaron, es

int height2 = (int)Math.Round(width2 * (height1/(float)width1),MidpointRounding.AwayFromZero); 

para ver la diferencia de que ejecute código en la consola

Console.WriteLine((int)Math.Round(0.5)); 
    Console.WriteLine((int)Math.Round(1.5)); 
    Console.WriteLine((int)Math.Round(2.5)); 
    Console.WriteLine((int)Math.Round(3.5)); 
    Console.WriteLine((int)Math.Round(0.5, MidpointRounding.AwayFromZero)); 
    Console.WriteLine((int)Math.Round(1.5, MidpointRounding.AwayFromZero)); 
    Console.WriteLine((int)Math.Round(2.5, MidpointRounding.AwayFromZero)); 
    Console.WriteLine((int)Math.Round(3.5, MidpointRounding.AwayFromZero)); 
    Console.ReadLine(); 

Para más detalles puedes mirar la this artículo.

0

Un enfoque razonablemente eficaz si la división final será un número par y el resultado siempre será positivo es dividir por la mitad ese valor, agregar uno y dividir por dos. Si el resultado puede ser negativo, si es posible, agregue una cantidad que haga que todo sea positivo, realice el cálculo y luego reste una cantidad correspondiente después.

Si la división final será por un número impar, multiplique el numerador y el denominador por 2, luego proceda como se indicó anteriormente. Por ejemplo, para calcular un * 5/7, redondeado, calcule (a*10+1)>>1. Lo que hay que tener en cuenta es que puede necesitar ampliar sus valores a un tipo numérico más grande para evitar el desbordamiento o, si eso no es posible, subdividir la división en partes. Por ejemplo, para calcular un * 14/15, puede calcular ((a * 4/3 * 7)/5 + 1)/2. Ese cálculo aún puede desbordarse si a es demasiado grande, pero el rango permitido será tres veces más grande que si se hubiera evaluado sin dividir por 3 antes de la otra división. Tenga en cuenta que subdividir la operación hará que el redondeo sea ligeramente menos preciso, pero lo suficientemente cerca para muchos propósitos.

+0

Hay algo mal con su primer ejemplo, te estás perdiendo la división por 7. Y tu primera oración dice algo diferente de lo que estás haciendo en todos tus ejemplos, por lo que puedo entender. – RenniePet

+0

@RenniePet: ¿Eso es mejor? – supercat

1

Seis años (redondeados) después, aquí está mi contribución, un pequeño truco que aprendí hace mucho tiempo, y estoy sorprendido de que nadie más haya mencionado aquí.

La idea es redondear agregando la mitad del divisor al numerador antes de hacer la división.

int height2 = (width2 * height1 + width1/2)/width1; 

En realidad, no necesariamente recomendaría hacerlo en casos, como los OP, donde el divisor es una variable. En su lugar, puede ser mejor utilizar Math.Round(), ya que es mucho más fácil de entender.

Pero en los casos en que el divisor es una constante, utilizo este truco. Así que en lugar de

int height2 = width2 * height1/4; // No rounding 

que haría uso de

int height2 = (width2 * height1 + 2)/4; 

Esto es un ejemplo más típico

private static Size ResizeWithPercentage(Size oldSize, int resizePercentage) 
    { 
    return new Size((oldSize.Width * resizePercentage + 50)/100, 
        (oldSize.Height * resizePercentage + 50)/100); 
    } 

Otra posibilidad es combinar este truco con la idea mencionada por dongilmore y supercat que en vez de tener una división por dos especificada o implícita, puedes multiplicar el numerador y el denominador por dos.

int height2 = (width2 * height1 * 2 + width1)/(width1 * 2); 

Esto da mejores respuestas en casos donde el divisor es, o puede ser, un número impar.

Cuestiones relacionadas