entero

entero

Si la escala es distinta de cero, los cálculos con %, como 3%2 y 46%4, tienden a generar 0. ¿Cómo se diseña el algoritmo con una escala distinta de 0?

bc
scale=10
print 4%3   // output 0

Respuesta1

Elmanual de comandodice esto sobre cómo BC calcula el módulo:

El resultado de la expresión es el "resto" y se calcula de la siguiente manera. Para calcular a%b, primeroa/bse calcula a escala de dígitos. Ese resultado se utiliza para calculara - ( a/b ) * ba la escala del máximo de escala+escala(b) y escala(a).Si la escala se establece en cero y ambas expresiones son números enteros, esta expresión es la función de resto de enteros.


EDITAR: Miré el código fuente de GNU BC y descubrí que el operador mod extiende el operador de división. En otras palabras, el módulo se calcula como un subproducto de la división. Se basa en la división de enteros para calcular el módulo. Cuando scalese establece, sin embargo, no se produce la división de enteros.

Pruebe esto en BC:

bc
scale = 0
print 5/2

scale = 5
print 5/2

deberías obtener:

2        << Integer Division
2.50000  << NOT integer division!

Ahora conectemos estas cifras como lo hace BC. El manual dice que usaa-(a/b)*bcalcular. Conectemos nuestros dos resultados, el que resulta de la división de enteros y el que tiene un valor scaledistinto de 0.

a - ( a/b ) * b
5 - ( 2   ) * 2  = 1  << CORRECT!
5 - ( 2.5 ) * 2  = 0  << VERY WRONG!

Sin división de números enteros:

a - ( a/b ) * b == a - (  a  ) == 0

Es por eso que la escala debe establecerse en 0 para que el módulo funcione correctamente.
El problema parece surgir del diseño de BC y de cómo maneja los números con una "escala". Para que el módulo funcione correctamentenecesitamos división entera.

Hayotromuchoherramientas más avanzadasque son gratuitos y de código abierto para este propósito, y te recomiendo que los uses.

Respuesta2

La respuesta del usuario272970 es genial. Aquí hay un ajuste:

define int(x) { auto oldscale; oldscale=scale; scale=0; x=x/1; scale=oldscale; return( x ); }
define fmod(x,y) { auto oldscale; oldscale=scale; scale=1000; x = x - y * int(x/y); scale=oldscale; return( x ); }

Esto (usando auto oldscale) hace que oldscalela función sea local. Sin eso, configurar oldscaledesde int()fmod() sobrescribirá el oldscaleque está intentando guardarse fmod(), dejando scaleel valor 1000 en lugar de lo que tenía antes de llamar fmod().

Agregué estas funciones ~/.bcrcy configuré la BC_ENV_ARGSvariable de entorno en ~/.bcrc. Eso cargará estas funciones cada vez que ejecute bc. Así que ahora puedo ejecutar fmod(x,y)en cualquier momento que esté en bc sin tener que definir manualmente esas funciones cada vez.

ps scalede 1000 puede ser excesivo en la mayoría de los casos

Respuesta3

Lo resolví de esta manera:

entero

definir int(x) { escala antigua=escala; escala=0; x=x/1; escala=escala antigua; retorno(x); }

módulo

define mod(x,y) { escala antigua=escala; escala=1000; x = x - y * int(x/y); escala=escala antigua; retorno(x); }

HT

Respuesta4

Como ha dicho otra respuesta, es el resultado de definir a%bcomo (a-(a/b)*b), evaluado en el momento actual scale. Esto significa que si desea que actúe como un módulo entero, debe usarlo con scale=0.

Sin embargo, no estoy de acuerdo con que sea "incorrecto". Es una herramienta potencialmente útil, especialmente para evaluar errores.

scale=5
1/3
> .33333
1%3
> .00001

¿Qué estamos perdiendo si lo representamos 7/13como decimal de 4 dígitos .5384?

scale=4
7/13
> .5384
7%13
> .0008

Aparentemente 0.0008/13.

Y, por último, como no insiste en utilizar números enteros, se puede utilizar para extraer una parte de un decimal.

scale=1
123.456/1
> 123.4
123.456%1
> .056

información relacionada