2010-02-17 9 views
6

Quiero disminuir un valor en uno y si llega a cero, configúrelo al valor máximo. ¿Hay alguna forma de hacerlo mediante matemática sin recurrir a if (n-1 == 0) { n = max; }¿Hay alguna manera de implementar esta lógica booleana muy simple usando solo operandos matemáticos (como mod)?

El escenario opuesto de aumentar un valor en uno y luego ponerlo en cero cuando es mayor que max puede lograrse fácilmente usando n = (n + 1) % (max + 1);. Además, esto es aún mejor, ya que puede aumentar en cualquier cantidad (no solo uno) y todavía se "ajustará" correctamente.

Gracias por las respuestas hasta el momento. Para ser claros, quise decir sin ninguna lógica booleana (if/else) u operadores booleanos (!, & &, etc.) en absoluto. Solo tenía curiosidad sobre cómo hacer esto. ¿La respuesta correcta a continuación realmente lo hace más ilegible siempre que se proporcione un comentario? Sería necesario usar eso para el caso más general para restar un número arbitrario y esperar el ajuste correcto.

+0

Ozan hace una buena pregunta a continuación. Por curiosidad, ¿es solo un acertijo lógico o hay alguna razón por la cual alguien debería evitar los constructos básicos del lenguaje? – MightyE

+0

Ver arriba. Usar el si como eso solo funciona si resta uno, y no si está restando un número arbitrario y espera el mismo tipo de ajuste que el mod. – GreenieMeanie

Respuesta

6
n = max - ((max - n +1)%max) 
+7

Eso responde la pregunta y plantea una nueva: ¿por qué uno reemplazaría una declaración simple por una complicada que hace lo mismo? – Ozan

1

El problema es que el operador % en C devuelve un resultado negativo cuando se enfrentan a un dividendo negativo. Esto a menudo no es lo que se necesita.

Si desea una función mod que cumplirá -1 mod n == n-1, a continuación, en C, hay que hacer lo siguiente:

int mod(int a, int b) 
{ 
    return (a%b + b) % b; 
} 

A continuación, puede no

n=mod(n-1, max+1); 

para disminuir n y tienen se ajusta a max cuando n==0. Tenga en cuenta que, en cuanto al caso de incremento, esto funcionará para los tamaños de paso arbitrarios.

+1

En realidad es peor que eso: el operador '%' en C puede devolver un resultado negativo * o * positivo cuando el dividendo es negativo. Todo lo que se requiere es que pueda poner los resultados de '/' y '%' juntos en el número original. –

+0

@Jerry: Eso fue cierto en C89.Sin embargo, el estándar actual de C requiere que la división entera se trunque hacia cero. Junto con el requisito que menciona, esto especifica completamente el operador '%'. –

1

Existen suficientes variaciones en las matemáticas entre los lenguajes que dudo que exista una manera independiente de idioma para hacer esto. Simplemente hay demasiada variación en la forma en que los lenguajes escriben las expresiones para que una sola técnica básica funcione con todos los idiomas posibles.

Si elige un idioma específico, hay muchas posibilidades de que sea posible. Por ejemplo, en C o C++, podría hacer algo como: n = (n-1) + ((n-1) == 0) * max;

En caso de que le importe cómo funciona eso: en C, una comparación (== en este caso) produce un resultado de 0 para falso y 1 para verdadero . Entonces, lo que estamos haciendo es agregar max * 0 cuando/if n-1 != 0, y max * 1 cuando/si n-1 == 0.

-1

¿Por qué no acaba de comparar a 1?

if(n==1) { n = max; }

+0

Lo que pregunté en la pregunta era una alternativa para compararlo tal como es. – GreenieMeanie

5

Si usted está haciendo esto simplemente por razones de rendimiento entonces yo le aconsejaría en contra de ella. % suele ser una operación bastante costosa en la mayoría de las arquitecturas; una simple comparación, bifurcación y adición generalmente será más eficiente. Por supuesto, se aplican las advertencias habituales sobre la optimización especulativa/prematura.

+3

Y la advertencia habitual de que las arquitecturas varían un poco, y cambian bastante rápido y no de manera predecible. He renunciado a intentar adivinar cualquier cosa excepto la localidad de caché. –

+1

Intenté compilar (con optimización completa) y desensamblar, y parece que tienes razón: no solo es la forma original más corta, tiene menos ramas (!). Supongo que en hardware necesitas hacer una división para obtener el módulo, y la división no es barata o fácil. – Ken

0

Puede haber una manera mejor, pero creo que n = max - (max - n + 1) % (max + 1) funciona. Supongo que desea incluir 0 en ambos extremos, ya que para su expresión de incremento sí incluye 0.

-1

En cualquier lenguaje de cortocircuito de evaluación lógica (la mayoría de las lenguas modernas) se puede hacer algo como esto:

--n<=0 && n=max;

Es posible obtener el globo ocular peluda de algunos de sus compañeros de trabajo si su equipo no está acostumbrado a usar & & como operador if-then.

para hacer el incremento de bucle hacia adelante:

++n>max && n=1;

Estos ejemplos están asumiendo un contador indexada 1 ya que su pregunta parece suponer que. 0 indexados equivalentes son:

--n<0 && n=max-1;

++n>=max && n=0;

+0

El --n no funcionaría para un tipo sin firmar que, presumiblemente, es la razón por la que evita la comparación. – Joel

+0

Aún funcionaría para el caso de un índice. Para el caso sin signo indexado cero, esto debería funcionar si el idioma no tiene error en flujo inferior entero: 'n - == 0 && n = max-1'. Sin embargo, OP era independiente del lenguaje, así que asumí que int (mis casos también se romperían si usaba flotación, etc.). – MightyE

0

En realidad se puede hacer también

n = (n - 1) + ((!(n - 1)) * max); 
0

¿Qué tal esto:
n = n * max + (n !!) *norte;

0

Re: no hay booleanos
Pues bien, a través de la magia de la división entera (C-estilo), mi respuesta anterior se puede escribir como:
n = ((max-n)/max) * max + ((max + n-1)/max) * n;

0

Solo para preguntar: ¿por qué quieres evitar una operación booleana?

Si desea evitar el código condicional en su aplicación, puede usar expresiones booleanas que se almacenan en valores booleanos. Esos serán mapeados a las instrucciones SETcc en un i386 y supongo que las instrucciones analógicas existen en otras ISA.

En ese caso, se puede utilizar una expresión booleana y todavía tienen código no condicional y podría usar:

Bajo el supuesto de que un resultado booleano verdadero es igual al ordinal 1 (este es el caso en el código de Delphi) y un valor booleano de falsos iguales a 0 se podría escribir

next := current - 1 + ((1 + max) and -Ord(current = 0)); 

no vote esto abajo porque di una respuesta con operaciones booleanas. Solo quiero comprobar si esta es una solución diferente al problema subyacente.

Aún así: creo que el código condicional es mucho más legible.

Cuestiones relacionadas