que múltiplos multiplos los hay entre c++ algorithm number-rounding

c++ - múltiplos - los multiplos de 2 que hay entre 789 y 795



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

OK - Estoy casi avergonzado publicando esto aquí (y lo eliminaré si alguien vota para cerrarlo) 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 interesado en saber cuál es la mejor manera de hacerlo 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 haya aclarado 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

EDITAR: Gracias por todas las respuestas. Aquí es a lo que recurrí:

int roundUp(int numToRound, int multiple) { if(multiple == 0) { return numToRound; } int remainder = numToRound % multiple; if (remainder == 0) { return numToRound; } return numToRound + multiple - remainder; }


Redondea al poder de dos:

Solo 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 seguirá siendo el mismo 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):

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 se corresponde perfectamente con su línea en el conjunto: 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. Como el código es muy pequeño y rápido, podría ser útil inline la función cuando se usa.

Crédito:


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 devolver nada es peligroso.

En segundo lugar, debe verificar que numToRound no sea un múltiplo. De lo contrario, cuando agrega multiple a roundDown , obtendrá la respuesta incorrecta.

En tercer lugar, tus lanzamientos están equivocados. numToRound a un entero, pero ya es un número entero. Debes lanzar 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 números positivos) o alejarse de cero (un número negativo "más grande"). O tal vez no te importa.

Aquí hay una versión con las tres primeras correcciones, pero no me ocupo del 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); }


Encontré un algoritmo que es similar a uno publicado arriba:

int [(| x | + n-1) / n] * [(nx) / | x |], donde x es un valor de entrada de usuario yn 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 idioma.


Esta es una generalización del problema de "¿cómo puedo saber cuántos bytes n bits tomará? (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 }


Este es el enfoque moderno de c ++ que usa una función de plantilla que funciona para float, double, long, int y short (pero no por mucho tiempo, y long double debido a los valores dobles usados).

#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 el soporte para el long double long long y long double con 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::ceil y redondee siempre use std::floor . Mi ejemplo de arriba está redondeando usando std::round .

Cree la función de "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 "planta redonda" 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)); }


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 el código limpio que el rendimiento en seco.


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


Esto funciona cuando el factor siempre será positivo:

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


Esto funciona para mí pero no traté de manejar 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; }


Esto funciona para números positivos, no estoy seguro de lo negativo. Solo usa matemáticas enteras.

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" quiere 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; }


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 potencias 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 (que significa redondeado 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


Para cualquiera que busque una respuesta corta y dulce. Esto es lo que usé Sin contabilidad de negativos.

n - (n % r)

Eso devolverá el factor anterior.

(n + r) - (n % r)

Regresará el próximo. Espero que esto ayude a alguien. :)


Para numToRound negativo:

Debería ser realmente fácil hacerlo, pero el operador estándar de módulo% no maneja los 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 devuelve 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); }


Probablemente sea más seguro lanzar a flotadores y usar ceil () - a menos que sepas que la división int va a producir el resultado correcto.


Sin condiciones:

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

Esto funciona como redondear desde cero para los números negativos

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

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

Tests

Si multiple es una potencia de 2

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

Tests


Yo uso una combinación de módulo para anular la suma del resto si x ya es un múltiplo:

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

Encontramos el inverso del resto módulo que con el divisor de nuevo para anular si es el divisor en sí, luego agregue x .

round_up(19, 3) = 21


bueno, para empezar, ya que 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;


do:

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

y para su ~ / .bashrc:

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


puede ser esto puede ayudar:

int RoundUpToNearestMultOfNumber(int val, int num) { assert(0 != num); return (floor((val + num) / num) * num); }


Para siempre redondear

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

normalRound (5, 10) -> 10

normalRound (10, 10) -> 10


/// Rounding up ''n'' to the nearest multiple of number ''b''. /// - Not tested for negative numbers. /// /see http://.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) ); }} }


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 punto fijo, redondeando allí y luego convirtiendo de nuevo. Maneja los negativos al redondear LEJOS de 0. También maneja una ronda negativa al valor al esencialmente convertir la función en redondeada.

Una versión int específica se ve así:

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; }

Que es más o menos la respuesta del plinto, con el soporte de entrada negativo agregado.


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 quisieras redondear, sugeriría usar un método ceil () en lugar del +0.5


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 + múltiples desbordamientos

sugeriría usar enteros sin signo en su lugar, que tiene un comportamiento de desbordamiento definido.

Obtendrá una excepción es múltiple == 0, pero de todos modos no es un problema bien definido en ese caso.


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