2010-03-08 7 views
33

número entero dinámico será cualquier número de 0 a 150.¿Cómo encuentro el siguiente múltiplo de 10 de cualquier número entero?

es decir, - número de devolución 41, la necesidad de retorno 50. Si el número es 10 necesidad de volver 10. Número es 1 necesidad de volver 10.

Fue ¿Pensando que podría usar la función de techo si modifico el entero como un decimal ...? luego usa la función de techo y vuelve a decimal?
Lo único que también debería saber es si el número es 1, 2 o 3 dígitos (es decir, 7 vs 94 vs 136)

¿Hay una mejor manera de lograr esto?

gracias,

+1

para aclarar algo que varias personas han comentado, tenga en cuenta que el dominio de esta función está limitada a los números enteros 0-150. – bta

+10

No entiendo, ¿qué pasa con esta simple pregunta? ¿Es realmente un juego de ingenio? –

+8

@ralu: Las preguntas más simples siempre reciben los votos por aquí, porque muy pocas personas miran las difíciles. –

Respuesta

69
n + (10 - n % 10) 

¿Cómo funciona esto. El operador% evalúa al resto de la división (por lo que 41 % 10 evalúa a 1, mientras que 45 % 10 evalúa a 5). Restar eso de 10 evalúa cuánto cuánto necesita para llegar al siguiente múltiplo.

El único problema es que esto a su vez 40 en 50. Si no desea que se necesitaría añadir una comprobación para asegurarse de que no es ya un múltiplo de 10.

if (n % 10) 
    n = n + (10 - n % 10); 
+1

Ah, esto es más rápido que el mío. – Harvey

+1

Normalmente elegiría un enfoque matemático entero (que funciona debido al redondeo implícito debido a los tipos de argumentos). Me gusta este enfoque, ya que no tiene efectos implícitos y, por lo tanto, es menos probable que falle. –

+0

Él ya cubrió ese caso en su respuesta, Matthew. –

0

En pseudo código:

number = number/10 
number = ceil(number) 
number = number * 10 

En Python:

import math 
def my_func(x): 
    return math.ceil(x/10) * 10 

Eso debería hacerlo. Tenga en cuenta que el código anterior arrojará un número entero a un flotante/doble para la aritmética, y se puede cambiar de nuevo a un número entero para el retorno final. He aquí un ejemplo con el encasillamiento explícita

En Python (con encasillamiento):

import math 
def my_func(x): 
    return int(math.ceil(float(x)/10) * 10) 
+0

Solo si el número es de coma flotante o me falta algo? –

+0

El número se puede convertir a coma flotante para la aritmética y volver a formar un número entero durante el retorno. –

+2

Para Python, una solución mucho más agradable es simplemente 'n + -n% 10'. Sin embargo, esto no funcionará en C debido a la diferente semántica de las divisiones que involucran números negativos. –

5

Cómo sobre el uso de enteros de matemáticas:

N=41 
N+=9 // Add 9 first to ensure rounding. 
N/=10 // Drops the ones place 
N*=10 // Puts the ones place back with a zero 
+0

No coincide con los requisitos de OP. –

+0

que calculará el piso, para obtener el techo primero agregue 9 – cobbal

+0

@cobbal: gracias, me lo perdí. – Harvey

2

que podría hacer el número mod 10. Luego tomar ese resultado de resta desde el diez. Luego agrega ese resultado al original.

if N%10 != 0 #added to account for multiples of ten 
    a=N%10 
    N+=10-a 
+0

No funciona para números negativos. –

+0

Mismo error. Cambia 10 a 20. – AnT

+0

@Jive Dadson: El requisito de entrada era un número entero de 0 a 150, por lo que -ve no es un problema en este caso. – Clifford

34

Usted puede hacer esto mediante la realización de una división entera por 10 redondeo, y luego multiplicando el resultado por 10.

Para dividir A por B redondeo al alza, añadir B - 1 a A y luego dividirlo por B usando la división "ordinario" número entero

Q = (A + B - 1)/B 

por lo tanto, para su problema específico la cosa, mientras que en conjunto se lo Aceptar la siguiente manera

A = (A + 9)/10 * 10 

Esto "snap" A a la siguiente mayor múltiplo de 10.

La necesidad de la división y de la alineación aparece con tanta frecuencia que normalmente en mis programas que tendría macros para dividir números enteros sin signo [] con redondeo al alza

#define UDIV_UP(a, b) (((a) + (b) - 1)/(b)) 

y para alinear un número entero a la siguiente límite de

#define ALIGN_UP(a, b) (UDIV_UP(a, b) * (b)) 

lo que haría que el aspecto anterior como

A = ALIGN_UP(A, 10); 

P.S. No sé si necesita esto ampliado a números negativos. Si lo hace, se debe tener cuidado de hacerlo correctamente, dependiendo de lo que necesite como resultado.

+3

+1 Esta es la única solución aritmética de números enteros hasta el momento que realmente funciona cuando n = 10 sin una prueba condicional adicional. –

+1

Bueno, esto es en realidad un idioma bastante conocido y ampliamente utilizado. Me sorprende que fui el primero en mencionarlo. – AnT

+0

Yo también. Estoy sorprendido de la cantidad de respuestas que en realidad eran * incorrectas * para empezar (el caso n = 10 también se mencionó específicamente en la pregunta). –

3

en C, de una sola línea:

int inline roundup10(int n) { 
    return ((n - 1)/10 + 1) * 10; 
} 
+0

lo siento, ahora funciona :) – Utaal

+0

No funciona para números negativos. –

+1

@Jive Dadson: los números negativos están fuera del dominio de la pregunta del OP – bta

3

Tenga en cuenta que las respuestas basa en el div y operadores mod ("/" y "%") no funcionará para los números negativos sin una if-test, porque C y C++ implementan esos operadores incorrectamente para números negativos. (-3 mod 5) es 2, pero C y C++ calculan (-3% 5) como -3.

Puede definir sus propias funciones div y mod. Por ejemplo,

int mod(int x, int y) { 
    // Assert y > 0 
    int ret = x % y; 
    if(ret < 0) { 
    ret += y; 
    } 
    return ret; 
} 
+1

OP especificó que esta función solo funcionará en los números 0-150. – bta

21

¿Qué hay de ((n + 9)/10) * 10?

Rendimientos 0 => 0, 1 => 10, 8 => 10, 29 => 30, 30 => 30, 31 => 40

+1

Esta parece ser la solución más simple. –

+0

Er ... '(n + 9)/10' produce' 8 => 1', no '8 => 10' como indica en su publicación. Probablemente olvidaste multiplicar el resultado por '10'. – AnT

+0

@ AndreyT:>. bta

1
n + (((9 - (n % 10)) + 1) % 10) 
+0

Esto funciona para entradas negativas (redondeando correctamente hacia + Infinity), pero de lo contrario es más lento y se compila con un código peor que las otras opciones. –

0
round_up(int i) 
{ 
     while(i%10) { 
      i++; 
     } 
     return(i); 
} 
6

tl; dr: ((n + 9)/10) * 10 compila al mejor código (más rápido) de asm en más casos, y es fácil de leer y entender para las personas que saben lo que hace la división de enteros en C. Es un modismo bastante común.

No he investigado cuál es la mejor opción para algo que necesita funcionar con n negativo, ya que es posible que desee redondear desde cero, en lugar de seguir hacia + Infinito, dependiendo de la aplicación.


En cuanto a las operaciones de C utilizados por las diferentes sugerencias, la luz-peso mayor es Mark Dickinson (en los comentarios):

(n+9) - ((n+9)%10) 

Se parece más eficiente que la brecha directo/multiplican sugerido por un par de personas (incluyendo @bta): ((n + 9)/10) * 10, porque solo tiene un complemento en lugar de un multiplicador. (n+9 es una subexpresión común que sólo tiene que ser calculada una vez).

Resulta que ambos compilar a código literalmente idénticos, usando el truco compilador de convertir division by a constant en un multiply and shift, see this Q&A for how it works. A diferencia de una instrucción de hardware div que cuesta lo mismo ya sea que use el cociente, el resto o ambos resultados, el método mul/shift toma pasos adicionales para obtener el resto. Entonces el compilador ve que puede obtener el mismo resultado de un cálculo más barato y termina compilando ambas funciones con el mismo código.

Esto es cierto en x86, ppc, and ARM, y todas las otras arquitecturas que he visto en el explorador del compilador Godbolt. En la primera versión de esta respuesta, vi un sdiv para el %10 en Godbolt's gcc4.8 para ARM64, pero ya no está instalado (¿quizás porque estaba mal configurado?) ARM64 gcc5.4 no hace eso.

Godbolt tiene MSVC (CL) instalado ahora, y algunas de estas funciones se compilan de forma diferente, pero no me he tomado el tiempo para ver cuál compila mejor.


Tenga en cuenta que en la salida de gcc para x86, se multiplica por 10 se hace barato con lea eax, [rdx + rdx*4] hacer n * 5, a continuación, add eax,eax duplicar esa. imul eax, edx, 10 tendría una latencia de 1 ciclo más en Intel Haswell, pero sería más corta (una menos uop). gcc/sonido metálico no lo uso incluso con -Os -mtune=haswell:/


la respuesta aceptada (n + 10 - n % 10) es incluso más barato para calcular: n+10 puede ocurrir en paralelo con n%10, por lo que la cadena de dependencias es un paso más corto. Compila una instrucción menos.

Sin embargo, da la respuesta incorrecta para múltiplos de 10: p. Ej. 10 -> 20. La solución sugerida usa un if(n%10) para decidir si hacer algo. Esto se compila en un cmov, por lo que es más largo y peor que el código de @ Bta. Si vas a usar un condicional, hazlo para obtener resultados sanos para las entradas negativas.


Así es como se comportan todas las respuestas sugeridas, incluyendo para las entradas negativas:

./a.out | awk -v fmt='\t%4s' '{ for(i=1;i<=NF;i++){ a[i]=a[i] sprintf(fmt, $i); } } END { for (i in a) print a[i]; }' 
     i  -22  -21  -20  -19  -18  -12  -11  -10  -9  -8  -2  -1  0  1  2  8  9  10  11  12   18  19  20  21  22 
    mark  -10  -10  -10  -10  0  0  0  0  0  0  0  0  0  10  10  10  10  10  20  20   20  20  20  30  30 
    igna  -10  -10  -10  0  0  0  0  0  10  10  10  10  10  10  10  10  10  20  20  20   20  20  30  30  30 
    utaal -20  -20  -20  -10  -10  -10  -10  -10  0  0  0  0  0  10  10  10  10  10  20  20   20  20  20  30  30 
    bta  -10  -10  -10  -10  0  0  0  0  0  10  10  10  10  10  10  10  10  10  20  20   20  20  20  30  30 
    klatchko -10  -10  -10  -10  0  0  0  0  0  0  0  0  0  10  10  10  10  10  20  20   20  20  20  30  30 
    branch -10  -10  -20  0  0  0  0  -10  10  10  10  10  0  10  10  10  10  10  20  20   20  20  20  30  30 

(transpose awk program)

n + (((9 - (n % 10)) + 1) % 10) obras de Ignacio "correctamente" para enteros negativos, el redondeo hacia + Infinity , pero es mucho más costoso de computar. Requiere dos operaciones de módulo, por lo que es esencialmente el doble de costoso. Compila aproximadamente el doble de instrucciones x86, haciendo aproximadamente el doble del trabajo de las otras expresiones.

programa Resultado de impresión (igual que los enlaces Godbolt anteriores)

#include <stdio.h> 
#include <stdlib.h> 

int f_mark(int n) { return (n+9) - ((n+9)%10); }     // good 
int f_bta(int n) { return ((n + 9)/10) * 10; }     // compiles to literally identical code 

int f_klatchko(int n) { return n + 10 - n % 10; }     // wrong, needs a branch to avoid changing multiples of 10 
int f_ignacio(int n) { return n + (((9 - (n % 10)) + 1) % 10); } // slow, but works for negative 
int roundup10_utaal(int n) { return ((n - 1)/10 + 1) * 10; } 

int f_branch(int n) { if (n % 10) n += (10 - n % 10); return n; } // gcc uses cmov after f_accepted code 

int main(int argc, char**argv) 
{ 
    puts("i\tmark\tigna\tutaal\tbta\tklatch\tbranch"); 
    for (int i=-25 ; i<25 ; i++) 
    if (abs(i%10) <= 2 || 10 - abs(i%10) <= 2) // only sample near interesting points 
     printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\n", i, f_mark(i), f_accepted(i), 
      f_ignacio(i), roundup10_utaal(i), f_bta(i), f_branch(i)); 
} 
1
int n,res; 
... 

res = n%10 ? n+10-(n%10) : n; 

o

res = (n/10)*10 + ((n % 10) ? 10:0); 
Cuestiones relacionadas