C ++: redondeando al múltiplo más cercano de un número

168

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
Robben_Ford_Fan_boy
fuente
3
Tiene un error en su lógica. Digamos que quiero redondear 4 al múltiplo más cercano de 2. roundDown = (4/2) * 2 = 4; redondeo = 4 + 2; entonces roundCalc = 6. Supongo que querría devolver 4 en ese caso.
Niki Yoshiuchi el
Esto no funciona para el redondeo (30,30). Se da 60 como respuesta, que aún debe dar 30 como respuesta ..
bsobaid
@bsobaid: Mira mi respuesta en la parte inferior. Es un poco más simple que otras soluciones aquí, aunque esas también deberían funcionar
Niklas B.
3
Sus casos de prueba son ejemplos que faltan notoriamente que involucran números negativos, casos donde la división es exacta, casos donde la división es casi exacta y casos donde los números están muy cerca de los límites del rango de int.
1
Robben_Ford_Fan_boy, la edición con la respuesta que buscabas debería eliminarse. Si difiere de las respuestas dadas, puede publicar su propia respuesta. Tal como están las cosas, esa respuesta tiene problemas que deberían abordarse en la sección de respuestas.
chux - Restablece a Mónica el

Respuestas:

161

Esto funciona para números positivos, no estoy seguro sobre negativos. Solo usa matemática entera.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = numToRound % multiple;
    if (remainder == 0)
        return numToRound;

    return numToRound + multiple - remainder;
}

Editar: Aquí hay una versión que funciona con números negativos, si por "arriba" quieres decir un resultado que siempre es> = la entrada.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = abs(numToRound) % multiple;
    if (remainder == 0)
        return numToRound;

    if (numToRound < 0)
        return -(abs(numToRound) - remainder);
    else
        return numToRound + multiple - remainder;
}
Mark Ransom
fuente
+1 En mi opinión, definitivamente la solución más agradable y legible.
Robben_Ford_Fan_boy
1
Agregue if(number<0){ multiple = multiple*(-1); }al comienzo para redondear los números negativos en la dirección correcta
Josh
44
@ Josh: ¿Por qué usar la multiplicación? if(number<0) multiple = -multiplees mas facil.
md5
Esto no funciona para el redondeo (30,30). Da 60 como respuesta, aún debe dar 30 como respuesta.
bsobaid
@bsobaid imposible. La if (remainder == 0)prueba debe ocuparse de ese caso. Funciona para mí: ideone.com/Waol7B
Mark Ransom
114

Sin condiciones:

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    return ((numToRound + multiple - 1) / multiple) * multiple;
}

Esto funciona como redondear desde cero para números negativos

EDITAR: versión que funciona también para números negativos

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    int isPositive = (int)(numToRound >= 0);
    return ((numToRound + isPositive * (multiple - 1)) / multiple) * multiple;
}

Pruebas


Si multiplees una potencia de 2 (más rápido en ~ 3.7 veces http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )

int roundUp(int numToRound, int multiple) 
{
    assert(multiple && ((multiple & (multiple - 1)) == 0));
    return (numToRound + multiple - 1) & -multiple;
}

Pruebas

TipoDragon
fuente
24
+1 para el poder de la versión 2. Muy útil ya que evita totalmente el costo de multiplicaciones, divisiones o módulos.
Nikos C.
¿Estás seguro de que estos algoritmos no tienen condiciones previas? ¿Qué pasa con los números negativos? El comportamiento parece estar indefinido en pre-C ++ 11 .
cubuspl42
> ¿Qué pasa con los números negativos? Como se describe, esto funciona para números negativos como redondear desde cero.
KindDragon
Leí "redondeando hacia arriba" como redondeando hacia el infinito positivo, no redondeando desde cero.
8
Tenga en cuenta que & ~(x - 1)es lo mismo que & -xpara la aritmética del complemento a dos.
Todd Lehman
39

Esto funciona cuando el factor siempre será positivo:

int round_up(int num, int factor)
{
    return num + factor - 1 - (num - 1) % factor;
}

Editar: esto vuelve round_up(0,100)=100. Consulte el comentario de Paul a continuación para obtener una solución que regrese round_up(0,100)=0.

xlq
fuente
1
Parece ser el caso más corto que maneja el caso 'ya-un-múltiple'.
harningt
1
La mejor solución en términos de número de operaciones costosas. Solo usa una sola división y no multiplicación
Niklas B.
3
round_up (0, 100) == 100 en lugar de 0 como en la respuesta aceptada
Gregory
77
¿No debería ser num + factor - 1 - (num + factor - 1) % factor?
Paul
66
num - 1 - (num - 1) % factor + factorrealiza el mismo cálculo sin el riesgo de desbordamiento de enteros.
24

Esta es una generalización del problema de "¿cómo puedo saber cuántos bytes tomarán n bits? (A: (n bits + 7) / 8).

int RoundUp(int n, int roundTo)
{
    // fails on negative?  What does that mean?
    if (roundTo == 0) return 0;
    return ((n + roundTo - 1) / roundTo) * roundTo; // edit - fixed error
}
pedestal
fuente
1
Esto no se redondea al siguiente múltiplo de un número.
aaaa bbbb
77
Me gusta esta solución porque si roundTo será una potencia de 2, puede eliminar el / y * y terminar con nada más que operaciones baratas (x = roundTo - 1; return (n + x) & ~ x;)
Trejkaz
@Trejkaz no. Debería ser (x = roundTo - 1; return (n+x)&~roundTo;)como en mi respuesta
KindDragon
@KindDragon que produce el resultado incorrecto para mí, pero si lo corrijo para decir ~ x en lugar de ~ roundTo, obtengo el resultado esperado. En Java 8 de todos modos.
Trejkaz
@KindDragon: la máscara AND debe ser 0xFFF...000, no 0xFFF7FFFo 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) & ~xo (n-roundTo+1) & -roundTo.
Peter Cordes
14
int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 return ((numToRound - 1) / multiple + 1) * multiple;  
}

Y no hay necesidad de perder el tiempo con las condiciones

doron
fuente
11

Para cualquiera que busque una respuesta breve y dulce. Esto es lo que usé. No contabilizar los negativos.

n - (n % r)

Eso devolverá el factor anterior.

(n + r) - (n % r)

Volveremos la próxima. Espero que esto ayude a alguien. :)

aaron-bond
fuente
9
float roundUp(float number, float fixedBase) {
    if (fixedBase != 0 && number != 0) {
        float sign = number > 0 ? 1 : -1;
        number *= sign;
        number /= fixedBase;
        int fixedPoint = (int) ceil(number);
        number = fixedPoint * fixedBase;
        number *= sign;
    }
    return number;
}

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:

int roundUp(int number, int fixedBase) {
    if (fixedBase != 0 && number != 0) {
        int sign = number > 0 ? 1 : -1;
        int baseSign = fixedBase > 0 ? 1 : 0;
        number *= sign;
        int fixedPoint = (number + baseSign * (fixedBase - 1)) / fixedBase;
        number = fixedPoint * fixedBase;
        number *= sign;
    }
    return number;
}

Cuál es más o menos la respuesta del zócalo, con el soporte de entrada negativa agregado.

Delfín
fuente
He probado el código float roundUp con double, me funciona. Realmente resuelve mi problema.
Ashif
1
¿Qué pasa 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?
Troyseph
8

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).

#include <cmath>
#include <iostream>

template<typename T>
T roundMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::round(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}

int main()
{
    std::cout << roundMultiple(39298.0, 100.0) << std::endl;
    std::cout << roundMultiple(20930.0f, 1000.0f) << std::endl;
    std::cout << roundMultiple(287399, 10) << std::endl;
}

Pero puede agregar fácilmente soporte para long longy long doublecon la especialización de plantilla como se muestra a continuación:

template<>
long double roundMultiple<long double>( long double value, long double multiple)
{
    if (multiple == 0.0l) return value;
    return std::round(value/multiple)*multiple;
}

template<>
long long roundMultiple<long long>( long long value, long long multiple)
{
    if (multiple == 0.0l) return value;
    return static_cast<long long>(std::round(static_cast<long double>(value)/static_cast<long double>(multiple))*static_cast<long double>(multiple));
}

Para crear funciones para redondear, use std::ceily para redondear siempre hacia abajo std::floor. Mi ejemplo de arriba es redondear usando std::round.

Cree la función de plantilla "redondear hacia arriba" o mejor conocida como "techo redondo" como se muestra a continuación:

template<typename T>
T roundCeilMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::ceil(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}

Cree la función de plantilla "redondear hacia abajo" o mejor conocida como "piso redondo" como se muestra a continuación:

template<typename T>
T roundFloorMultiple( T value, T multiple )
{
    if (multiple == 0) return value;
    return static_cast<T>(std::floor(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}
Flovdis
fuente
1
más 1, aunque algunas personas pueden encontrar más razonable devolver 0 cuando mulitple == 0
stijn
3
Tenga cuidado, porque la conversión de int64_t a double puede ser con pérdida, por lo que no es tan genérico como puede parecer.
Adrian McCarthy
@AdrianMcCarthy Sí, debe crear las especializaciones de plantilla correctas como se muestra arriba. Como puede ver, implemento dos funciones adicionales para long longy long double. Obviamente, lo mismo debe hacerse para las otras dos funciones.
Flovdis
Creo que este es, con mucho, el más lento de todos, pero no debería ser así. Todo lo que necesita hacer es std :: enable_if_t y hacer dos ramas para enteros y flotantes. También podría hacer un mejor uso de los numeric_limits y ver si la mantisa es lo suficientemente grande como para ajustarse realmente al valor. Eso agregaría seguridad.
los cerdos
5

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 multiplea roundDown, obtendrá la respuesta incorrecta.

En tercer lugar, tus yesos están equivocados. Lanzas numToRounda 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:

int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 else if(numToRound % multiple == 0)
 {
  return numToRound
 }

 int roundDown = (int) (( (double) numToRound / multiple ) * multiple);
 int roundUp = roundDown + multiple; 
 int roundCalc = roundUp;
 return (roundCalc);
}
Mike Caron
fuente
@Peter ¿Lo es? Supuse que int / intdevolvería un int, que no es lo que queríamos.
Mike Caron el
int / int de hecho devuelve un int, pero eso es precisamente lo que quieres. Por ejemplo, numToRound = 7, multiple = 3. 7/3 = 2.
Peter Ruderman
4

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í):

// number: the number to be rounded (ex: 5, 123, 98345, etc.)
// pow2:   the power to be rounded to (ex: to round to 16, use '4')
int roundPow2 (int number, int pow2) {
    pow2--;                     // because (2 exp x) == (1 << (x -1))
    pow2 = 0x01 << pow2;

    pow2--;                     // because for any
                                //
                                // (x = 2 exp x)
                                //
                                // subtracting one will
                                // yield a field of ones
                                // which we can use in a
                                // bitwise OR

    number--;                   // yield a similar field for
                                // bitwise OR
    number = number | pow2;
    number++;                   // restore value by adding one back

    return number;
}

El número de entrada permanecerá igual si ya es un múltiplo.

Aquí está la salida x86_64 que GCC da con -O2o -Os(9Sep2013 Build - godbolt GCC en línea):

roundPow2(int, int):
    lea ecx, [rsi-1]
    mov eax, 1
    sub edi, 1
    sal eax, cl
    sub eax, 1
    or  eax, edi
    add eax, 1
    ret

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 inlinela función al usarlo.


Crédito:

haneefmubarak
fuente
1
Exactamente lo que estaba buscando. ¡Gracias!
kiyo
1
int roundUpPow2 (int num, int pow2) {return num + (pow2 - 1) & ~ (pow2 - 1); } es aproximadamente un 30% más rápido y más fácil de usar (pasa 16 no 4 para redondear al siguiente múltiplo de 16.
Axel Rietschin
3

Estoy usando:

template <class _Ty>
inline _Ty n_Align_Up(_Ty n_x, _Ty n_alignment)
{
    assert(n_alignment > 0);
    //n_x += (n_x >= 0)? n_alignment - 1 : 1 - n_alignment; // causes to round away from zero (greatest absolute value)
    n_x += (n_x >= 0)? n_alignment - 1 : -1; // causes to round up (towards positive infinity)
    //n_x += (_Ty(-(n_x >= 0)) & n_alignment) - 1; // the same as above, avoids branch and integer multiplication
    //n_x += n_alignment - 1; // only works for positive numbers (fastest)
    return n_x - n_x % n_alignment; // rounds negative towards zero
}

y para poderes de dos:

template <class _Ty>
bool b_Is_POT(_Ty n_x)
{
    return !(n_x & (n_x - 1));
}

template <class _Ty>
inline _Ty n_Align_Up_POT(_Ty n_x, _Ty n_pot_alignment)
{
    assert(n_pot_alignment > 0);
    assert(b_Is_POT(n_pot_alignment)); // alignment must be power of two
    -- n_pot_alignment;
    return (n_x + n_pot_alignment) & ~n_pot_alignment; // rounds towards positive infinity (i.e. negative towards zero)
}

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:

n_Align_Up(10, 100) = 100
n_Align_Up(110, 100) = 200
n_Align_Up(0, 100) = 0
n_Align_Up(-10, 100) = 0
n_Align_Up(-110, 100) = -100
n_Align_Up(-210, 100) = -200
n_Align_Up_POT(10, 128) = 128
n_Align_Up_POT(130, 128) = 256
n_Align_Up_POT(0, 128) = 0
n_Align_Up_POT(-10, 128) = 0
n_Align_Up_POT(-130, 128) = -128
n_Align_Up_POT(-260, 128) = -256
los cerdos
fuente
He estado usando tu n_Align_Up_POTdesde 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.
user1593842
2

Probablemente sea más seguro lanzarlo a flotadores y usar ceil (), a menos que sepa que la división int producirá el resultado correcto.

Martin Beckett
fuente
1
Tenga en cuenta que double solo puede contener 54 bits de significado en máquinas basadas en x86. Si tiene entradas de 64 bits, finalmente fallará.
los cerdos
El doble estándar IEEE754 no puede, pero los cpus x64 tienen un punto flotante interno de 80 bits, por lo que las operaciones en un solo número son confiables
Martin Beckett
1
Si bien eso es cierto, usted tiene muy poco control sobre ese redondeo desde C / C ++. Depende de la configuración de las palabras de control y en realidad puede redondear a menos de 80 bits. También tiene SSE y otros conjuntos de instrucciones SIMD que no tienen ese intermedio extendido (el compilador de vectorización podría usarlos fácilmente).
los cerdos
2
int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple

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

Michal Ciechan
fuente
2

bueno para empezar, ya que realmente no entiendo lo que quieres hacer, las líneas

int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc); 

definitivamente podría acortarse a

int roundUp = roundDown + multiple;
return roundUp;
Jesse Naugher
fuente
2

puede ser esto puede ayudar:

int RoundUpToNearestMultOfNumber(int val, int num)
{
  assert(0 != num);
  return (floor((val + num) / num) * num);
}
Arsen
fuente
¿Por qué usar floor y la división de enteros? No hay nada al piso. Si fuera doble, al menos podría heredar el manejo de valores negativos.
los cerdos
2

Para redondear siempre

int alwaysRoundUp(int n, int multiple)
{
    if (n % multiple != 0) {
        n = ((n + multiple) / multiple) * multiple;

        // Another way
        //n = n - n % multiple + multiple;
    }

    return n;
}

alwaysRoundUp (1, 10) -> 10

alwaysRoundUp (5, 10) -> 10

alwaysRoundUp (10, 10) -> 10


Para redondear siempre

int alwaysRoundDown(int n, int multiple)
{
    n = (n / multiple) * multiple;

    return n;
}

alwaysRoundDown (1, 10) -> 0

alwaysRoundDown (5, 10) -> 0

alwaysRoundDown (10, 10) -> 10


Para redondear la forma normal

int normalRound(int n, int multiple)
{
    n = ((n + multiple/2)/multiple) * multiple;

    return n;
}

normalRound (1, 10) -> 0

normalRondo (5, 10) -> 10

normalRondo (10, 10) -> 10

onmyway133
fuente
2

Redondear al múltiplo más cercano que resulta ser una potencia de 2

unsigned int round(unsigned int value, unsigned int multiple){
    return ((value-1u) & ~(multiple-1u)) + multiple;
}

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 gccel cuerpo de esta función genera 8 instrucciones de ensamblaje sin división ni ramas.

round(  0,  16) ->   0
round(  1,  16) ->  16
round( 16,  16) ->  16
round(257, 128) -> 384 (128 * 3)
round(333,   2) -> 334
Anne Quinn
fuente
1

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.

Joshua Wade
fuente
1

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.

public static int mod(int x, int n) 
{
    return ((x % n) + n) % n;
}

public static int roundUp(int numToRound, int multiple) 
{
    return numRound + mod(-numToRound, multiple);
}
usuario990343
fuente
1

Esto es lo que haría:

#include <cmath>

int roundUp(int numToRound, int multiple)
{
    // if our number is zero, return immediately
   if (numToRound == 0)
        return multiple;

    // if multiplier is zero, return immediately
    if (multiple == 0)
        return numToRound;

    // how many times are number greater than multiple
    float rounds = static_cast<float>(numToRound) / static_cast<float>(multiple);

    // determine, whether if number is multiplier of multiple
    int floorRounds = static_cast<int>(floor(rounds));

    if (rounds - floorRounds > 0)
        // multiple is not multiplier of number -> advance to the next multiplier
        return (floorRounds+1) * multiple;
    else
        // multiple is multiplier of number -> return actual multiplier
        return (floorRounds) * multiple;
}

El código puede no ser óptimo, pero prefiero un código limpio que un rendimiento en seco.

Gotcha
fuente
Lanzar el intto floatpierde fácilmente la precisión y genera respuestas incorrectas.
chux - Restablece a Mónica el
1
int roundUp (int numToRound, int multiple)
{
  return multiple * ((numToRound + multiple - 1) / multiple);
}

a pesar de que:

  • no funcionará para números negativos
  • no funcionará si numRound + desbordamientos múltiples

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.

usuario3392484
fuente
1

C:

int roundUp(int numToRound, int multiple)
{
  return (multiple ? (((numToRound+multiple-1) / multiple) * multiple) : numToRound);
}

y para tu ~ / .bashrc:

roundup()
{
  echo $(( ${2} ? ((${1}+${2}-1)/${2})*${2} : ${1} ))
}
nhed
fuente
1

Utilizo una combinación de módulo para anular la adición del resto si xya es un múltiplo:

int round_up(int x, int div)
{
    return x + (div - x % div) % div;
}

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.

round_up(19, 3) = 21
Nick Bedford
fuente
1

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í.

int RoundUp(int n, int multiple)
{
    // prevent divide by 0 by returning n
    if (multiple == 0) return n;

    // calculate the rounded down version
    int roundedDown = n / multiple * multiple;

    // if the rounded version and original are the same, then return the original
    if (roundedDown == n) return n;

    // handle negative number and round up according to the sign
    // NOTE: if n is < 0 then subtract the multiple, otherwise add it
    return (n < 0) ? roundedDown - multiple : roundedDown + multiple;
}
weatx
fuente
Falla con RoundUp(INT_MIN, -1)como n / multiplees intel desbordamiento.
chux - Restablece a Mónica el
1

Creo que esto debería ayudarte. He escrito el siguiente programa en C.

# include <stdio.h>
int main()
{
  int i, j;
  printf("\nEnter Two Integers i and j...");
  scanf("%d %d", &i, &j);
  int Round_Off=i+j-i%j;
  printf("The Rounded Off Integer Is...%d\n", Round_Off);
  return 0;
}
Neel
fuente
0
/// Rounding up 'n' to the nearest multiple of number 'b'.
/// - Not tested for negative numbers.
/// \see http://stackoverflow.com/questions/3407012/
#define roundUp(n,b) ( (b)==0 ? (n) : ( ((n)+(b)-1) - (((n)-1)%(b)) ) )

/// \c test->roundUp().
void test_roundUp() {   
    // yes_roundUp(n,b) ( (b)==0 ? (n) : ( (n)%(b)==0 ? n : (n)+(b)-(n)%(b) ) )
    // yes_roundUp(n,b) ( (b)==0 ? (n) : ( ((n + b - 1) / b) * b ) )

    // no_roundUp(n,b) ( (n)%(b)==0 ? n : (b)*( (n)/(b) )+(b) )
    // no_roundUp(n,b) ( (n)+(b) - (n)%(b) )

if (true) // couldn't make it work without (?:)
{{  // test::roundUp()
    unsigned m;
                { m = roundUp(17,8); } ++m;
    assertTrue( 24 == roundUp(17,8) );
                { m = roundUp(24,8); }
    assertTrue( 24 == roundUp(24,8) );

    assertTrue( 24 == roundUp(24,4) );
    assertTrue( 24 == roundUp(23,4) );
                { m = roundUp(23,4); }
    assertTrue( 24 == roundUp(21,4) );

    assertTrue( 20 == roundUp(20,4) );
    assertTrue( 20 == roundUp(19,4) );
    assertTrue( 20 == roundUp(18,4) );
    assertTrue( 20 == roundUp(17,4) );

    assertTrue( 17 == roundUp(17,0) );
    assertTrue( 20 == roundUp(20,0) );
}}
}
Adolfo
fuente
0

Esto está obteniendo los resultados que busca para enteros positivos:

#include <iostream>
using namespace std;

int roundUp(int numToRound, int multiple);

int main() {
    cout << "answer is: " << roundUp(7, 100) << endl;
    cout << "answer is: " << roundUp(117, 100) << endl;
    cout << "answer is: " << roundUp(477, 100) << endl;
    cout << "answer is: " << roundUp(1077, 100) << endl;
    cout << "answer is: " << roundUp(52,20) << endl;
    cout << "answer is: " << roundUp(74,30) << endl;
    return 0;
}

int roundUp(int numToRound, int multiple) {
    if (multiple == 0) {
        return 0;
    }
    int result = (int) (numToRound / multiple) * multiple;
    if (numToRound % multiple) {
        result += multiple;
    } 
    return result;
}

Y aquí están los resultados:

answer is: 100
answer is: 200
answer is: 500
answer is: 1100
answer is: 60
answer is: 90
Dave
fuente
0

Creo que esto funciona:

int roundUp(int numToRound, int multiple) {
    return multiple? !(numToRound%multiple)? numToRound : ((numToRound/multiple)+1)*multiple: numToRound;
}
usuario13783520
fuente
-1

Esto funciona para mí pero no traté de manejar los negativos

public static int roundUp(int numToRound, int multiple) {
    if (multiple == 0) {
        return 0;
    } else if (numToRound % multiple == 0) {
    return numToRound;
    }

    int mod = numToRound % multiple;
    int diff = multiple - mod;
    return numToRound + diff;
}
usuario1100538
fuente
-3

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)

nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;
Indivelope
fuente
¿comprobaste tu idea antes de enviarla? no da una respuesta
correcta
Eso ni siquiera es un código válido.
user13783520