OK, estoy casi avergonzado de publicar esto aquí (y lo eliminaré si alguien vota para cerrar) ya que parece una pregunta básica.
¿Es esta la forma correcta de redondear a un múltiplo de un número en C ++?
Sé que hay otras preguntas relacionadas con esto, pero estoy especialmente interesado en saber cuál es la mejor manera de hacer esto en C ++:
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return numToRound;
}
int roundDown = ( (int) (numToRound) / multiple) * multiple;
int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc);
}
Actualización: lo siento, probablemente no he dejado en claro la intención. Aquí hay unos ejemplos:
roundUp(7, 100)
//return 100
roundUp(117, 100)
//return 200
roundUp(477, 100)
//return 500
roundUp(1077, 100)
//return 1100
roundUp(52, 20)
//return 60
roundUp(74, 30)
//return 90
int
.Respuestas:
Esto funciona para números positivos, no estoy seguro sobre negativos. Solo usa matemática entera.
Editar: Aquí hay una versión que funciona con números negativos, si por "arriba" quieres decir un resultado que siempre es> = la entrada.
fuente
if(number<0){ multiple = multiple*(-1); }
al comienzo para redondear los números negativos en la dirección correctaif(number<0) multiple = -multiple
es mas facil.if (remainder == 0)
prueba debe ocuparse de ese caso. Funciona para mí: ideone.com/Waol7BSin condiciones:
Esto funciona como redondear desde cero para números negativos
EDITAR: versión que funciona también para números negativos
Pruebas
Si
multiple
es una potencia de 2 (más rápido en ~ 3.7 veces http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )Pruebas
fuente
& ~(x - 1)
es lo mismo que& -x
para la aritmética del complemento a dos.Esto funciona cuando el factor siempre será positivo:
Editar: esto vuelve
round_up(0,100)=100
. Consulte el comentario de Paul a continuación para obtener una solución que regreseround_up(0,100)=0
.fuente
num + factor - 1 - (num + factor - 1) % factor
?num - 1 - (num - 1) % factor + factor
realiza el mismo cálculo sin el riesgo de desbordamiento de enteros.Esta es una generalización del problema de "¿cómo puedo saber cuántos bytes tomarán n bits? (A: (n bits + 7) / 8).
fuente
(x = roundTo - 1; return (n+x)&~roundTo;)
como en mi respuesta0xFFF...000
, no0xFFF7FFF
o algo, por lo que desea la negación del complemento de 2 (-
: menos) con una potencia de 2, o un cambio de bits en uno menos que una potencia de 2 (el complemento de uno inverso,~
tilde no menos). Entonces(n+x) & ~x
o(n-roundTo+1) & -roundTo
.Y no hay necesidad de perder el tiempo con las condiciones
fuente
Para cualquiera que busque una respuesta breve y dulce. Esto es lo que usé. No contabilizar los negativos.
Eso devolverá el factor anterior.
Volveremos la próxima. Espero que esto ayude a alguien. :)
fuente
Esto funciona para cualquier número flotante o base (por ejemplo, puede redondear -4 al 6,75 más cercano). En esencia, se está convirtiendo en un punto fijo, redondeando allí y luego volviendo a convertir. Maneja los negativos redondeando LEJOS desde 0. También maneja un redondeo negativo al valor, esencialmente convirtiendo la función en roundDown.
Una versión específica de int se parece a:
Cuál es más o menos la respuesta del zócalo, con el soporte de entrada negativa agregado.
fuente
double round(double value, double multiple) { double sign = value; multiple = std::copysign(multiple, 1.0); value = std::copysign(value, 1.0); return std::copysign(multiple * std::ceil(value / multiple), sign); }
o cambiar el techo por redondeo para obtener redondeo?Este es el enfoque moderno de c ++ que utiliza una función de plantilla que funciona para float, double, long, int y short (pero no para long long y long double debido a los valores dobles utilizados).
Pero puede agregar fácilmente soporte para
long long
ylong double
con la especialización de plantilla como se muestra a continuación:Para crear funciones para redondear, use
std::ceil
y para redondear siempre hacia abajostd::floor
. Mi ejemplo de arriba es redondear usandostd::round
.Cree la función de plantilla "redondear hacia arriba" o mejor conocida como "techo redondo" como se muestra a continuación:
Cree la función de plantilla "redondear hacia abajo" o mejor conocida como "piso redondo" como se muestra a continuación:
fuente
long long
ylong double
. Obviamente, lo mismo debe hacerse para las otras dos funciones.En primer lugar, su condición de error (múltiple == 0) probablemente debería tener un valor de retorno. ¿Qué? No lo sé. Tal vez quieras lanzar una excepción, eso depende de ti. Pero, no devolver nada es peligroso.
En segundo lugar, debe verificar que numToRound ya no sea un múltiplo. De lo contrario, cuando agregue
multiple
aroundDown
, obtendrá la respuesta incorrecta.En tercer lugar, tus yesos están equivocados. Lanzas
numToRound
a un entero, pero ya es un entero. Necesitas convertir a doblar antes de la división, y volver a int después de la multiplicación.Por último, ¿qué quieres para los números negativos? Redondear "hacia arriba" puede significar redondear a cero (redondear en la misma dirección que los números positivos) o alejarse de cero (un número negativo "mayor"). O tal vez no te importa.
Aquí hay una versión con las tres primeras correcciones, pero no trato el problema negativo:
fuente
int / int
devolvería un int, que no es lo que queríamos.Redondear al poder de dos:
En caso de que alguien necesite una solución para números positivos redondeados al múltiplo más cercano de una potencia de dos (porque así es como terminé aquí):
El número de entrada permanecerá igual si ya es un múltiplo.
Aquí está la salida x86_64 que GCC da con
-O2
o-Os
(9Sep2013 Build - godbolt GCC en línea):Cada línea de código C corresponde perfectamente con su línea en el ensamblaje: http://goo.gl/DZigfX
Cada una de esas instrucciones es extremadamente rápida , por lo que la función también es extremadamente rápida. Dado que el código es tan pequeño y rápido, puede ser útil para
inline
la función al usarlo.Crédito:
fuente
Estoy usando:
y para poderes de dos:
Tenga en cuenta que ambos valores negativos redondos hacia cero (eso significa redondear a infinito positivo para todos los valores), ninguno de ellos se basa en el desbordamiento firmado (que no está definido en C / C ++).
Esto da:
fuente
n_Align_Up_POT
desde que lo vi dentro de la clase TList de Delphi. Tiene sus restricciones, como que la alineación (múltiple) es una potencia de 2, pero eso rara vez es un problema porque lo uso principalmente para obtener / verificar la alineación correcta para SMID. Es increíble y parece que no mucha gente lo sabe.Probablemente sea más seguro lanzarlo a flotadores y usar ceil (), a menos que sepa que la división int producirá el resultado correcto.
fuente
C ++ redondea cada número hacia abajo, por lo que si agrega 0.5 (si es 1.5 será 2) pero 1.49 será 1.99, por lo tanto, 1.
EDITAR: lo siento, no vi que deseaba redondear, sugeriría usar un método ceil () en lugar del +0.5
fuente
bueno para empezar, ya que realmente no entiendo lo que quieres hacer, las líneas
definitivamente podría acortarse a
fuente
puede ser esto puede ayudar:
fuente
Para redondear siempre
alwaysRoundUp (1, 10) -> 10
alwaysRoundUp (5, 10) -> 10
alwaysRoundUp (10, 10) -> 10
Para redondear siempre
alwaysRoundDown (1, 10) -> 0
alwaysRoundDown (5, 10) -> 0
alwaysRoundDown (10, 10) -> 10
Para redondear la forma normal
normalRound (1, 10) -> 0
normalRondo (5, 10) -> 10
normalRondo (10, 10) -> 10
fuente
Redondear al múltiplo más cercano que resulta ser una potencia de 2
Esto puede ser útil cuando se asigna a lo largo de líneas de caché, donde el incremento de redondeo que desea es una potencia de dos, pero el valor resultante solo necesita ser un múltiplo de él. En
gcc
el cuerpo de esta función genera 8 instrucciones de ensamblaje sin división ni ramas.fuente
Encontré un algoritmo que es algo similar a uno publicado anteriormente:
int [(| x | + n-1) / n] * [(nx) / | x |], donde x es un valor de entrada del usuario y n es el múltiplo que se está utilizando.
Funciona para todos los valores x, donde x es un número entero (positivo o negativo, incluido cero). Lo escribí específicamente para un programa C ++, pero esto básicamente se puede implementar en cualquier lenguaje.
fuente
Para numToRound negativo:
Debería ser realmente fácil hacer esto, pero el módulo estándar% operator no maneja números negativos como uno podría esperar. Por ejemplo -14% 12 = -2 y no 10. Lo primero que debe hacer es obtener un operador de módulo que nunca devuelva números negativos. Entonces roundUp es realmente simple.
fuente
Esto es lo que haría:
El código puede no ser óptimo, pero prefiero un código limpio que un rendimiento en seco.
fuente
int
tofloat
pierde fácilmente la precisión y genera respuestas incorrectas.a pesar de que:
sugeriría usar enteros sin signo en su lugar, lo que ha definido un comportamiento de desbordamiento.
Obtendrá una excepción es múltiple == 0, pero de todos modos no es un problema bien definido en ese caso.
fuente
C:
y para tu ~ / .bashrc:
fuente
Utilizo una combinación de módulo para anular la adición del resto si
x
ya es un múltiplo:Encontramos el inverso del resto y luego el módulo que con el divisor nuevamente para anularlo si es el divisor mismo y luego sumar
x
.fuente
Aquí está mi solución basada en la sugerencia del OP y los ejemplos dados por todos los demás. Como la mayoría de la gente lo buscaba para manejar números negativos, esta solución hace exactamente eso, sin el uso de funciones especiales, es decir, abdominales y similares.
Al evitar el módulo y usar la división, el número negativo es un resultado natural, aunque se redondea hacia abajo. Después de calcular la versión redondeada hacia abajo, realiza los cálculos necesarios para redondear, ya sea en dirección negativa o positiva.
También tenga en cuenta que no se utilizan funciones especiales para calcular nada, por lo que hay un pequeño aumento de velocidad allí.
fuente
RoundUp(INT_MIN, -1)
comon / multiple
esint
el desbordamiento.Creo que esto debería ayudarte. He escrito el siguiente programa en C.
fuente
fuente
Esto está obteniendo los resultados que busca para enteros positivos:
Y aquí están los resultados:
fuente
Creo que esto funciona:
fuente
Esto funciona para mí pero no traté de manejar los negativos
fuente
Aquí hay una solución súper simple para mostrar el concepto de elegancia. Básicamente es para instantáneas de cuadrícula.
(pseudocódigo)
fuente