
Se a escala for diferente de zero, cálculos com %, como 3%2 e 46%4, tendem a gerar 0. Como o algoritmo é projetado com uma escala diferente de 0?
bc
scale=10
print 4%3 // output 0
Responder1
Omanual de comandodiz o seguinte sobre como BC calcula o módulo:
O resultado da expressão é o “resto” e é calculado da seguinte forma. Para calcular a%b, primeiroa/bé calculado para escalar dígitos. Esse resultado é usado para calcularuma - (uma/b) * bà escala do máximo de escala+escala(b) e escala(a).Se a escala for definida como zero e ambas as expressões forem números inteiros, esta expressão será a função de resto inteiro.
EDITAR: Examinei o código-fonte do GNU BC e descobri que o operador mod estende o operador de divisão. Em outras palavras, o módulo é calculado como subproduto da divisão. Baseia-se na divisão inteira para calcular o módulo. Quando
scale
é definido, porém a divisão inteira não ocorre.
Tente isso em BC:
bc
scale = 0
print 5/2
scale = 5
print 5/2
voce deveria pegar:
2 << Integer Division
2.50000 << NOT integer division!
Agora vamos inserir esses números da mesma forma que BC faz. O manual diz que usaa-(a/b)*bcalcular. Vamos inserir nossos dois resultados, aquele resultante da divisão inteira e aquele com valor scale
diferente de 0.
a - ( a/b ) * b
5 - ( 2 ) * 2 = 1 << CORRECT!
5 - ( 2.5 ) * 2 = 0 << VERY WRONG!
Sem divisão inteira:
a - ( a/b ) * b == a - ( a ) == 0
É por isso que a escala deve ser definida como 0 para que o módulo funcione corretamente.
A questão parece surgir do design do BC e de como ele lida com números com uma 'escala'. Para que o módulo funcione corretamenteprecisamos de divisão inteira.
Háoutromuitoferramentas mais avançadasque são gratuitos e de código aberto para essa finalidade, e recomendo que você os use.
Responder2
A resposta do user272970 é ótima. Aqui está um 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 ); }
Isso (usando auto oldscale
) torna oldscale
local para a função. Sem isso, configurar oldscale
from int()
fmod() substituirá o oldscale
que está tentando ser salvo fmod()
, deixando scale
definido como 1000 em vez do que você tinha antes de chamar fmod()
.
Adicionei essas funções ~/.bcrc
e configurei a BC_ENV_ARGS
variável de ambiente como ~/.bcrc
. Isso carregará essas funções toda vez que você executar o bc. Portanto, agora posso executar fmod(x,y)
a qualquer momento em bc, sem precisar definir manualmente essas funções todas as vezes.
ps scale
de 1000 pode ser um exagero na maioria dos casos
Responder3
Eu resolvi assim:
inteiro
definir int(x) { escala antiga=escala; escala=0; x=x/1; escala=escala antiga; retorno(x); }
módulo
definir mod(x,y) { escala antiga=escala; escala=1000; x = x - y * int(x/y); escala=escala antiga; retorno(x); }
HTH
Responder4
Como outra resposta já disse, é o resultado da definição a%b
de as (a-(a/b)*b)
, avaliada no atual scale
. Isso significa que se você quiser que ele atue como um módulo inteiro, você precisará usá-lo com scale=0
.
No entanto, discordo que esteja "errado". É uma ferramenta potencialmente útil, especialmente para avaliar erros.
scale=5
1/3
> .33333
1%3
> .00001
O que estamos perdendo se representarmos 7/13
como decimal de 4 dígitos .5384
?
scale=4
7/13
> .5384
7%13
> .0008
Aparentemente 0.0008/13
.
E por último, por não insistir em usar números inteiros, pode ser usado para extrair uma parte de um decimal.
scale=1
123.456/1
> 123.4
123.456%1
> .056