Skip to content
This page has been auto-translated and may contain errors.View in English

Números e aritmética ​

Números aparecem em praticamente todo programa que você escreve. Um carrinho de compras soma um preço. Um jogo atualiza uma pontuação. Um script conta quantas vezes algo aconteceu. O Python oferece operadores aritméticos que funcionam como a matemática do papel, além de alguns outros que vale a pena conhecer desde o início.

Os operadores aritméticos do Python cobrem o conjunto padrão, além de divisão inteira, módulo e exponenciação. Alguns comportamentos são diferentes de outras linguagens de formas que importam na prática: / sempre retorna um float, a divisão inteira arredonda para o infinito negativo, e o módulo segue a semântica de módulo verdadeiro.

Os inteiros do Python não têm overflow (aquele estouro ou erro que você encontra em linguagens com inteiros de tamanho fixo): eles crescem tanto quanto a memória permitir. Os floats são os decimais de precisão dupla usuais, adequados para a maioria dos casos, mas nunca exatos para valores monetários. Os operadores aritméticos seguem as definições matemáticas em vez da convenção de C que muitas linguagens copiam: // é a divisão de piso (arredonda para o infinito negativo) e % carrega o sinal do divisor, não do dividendo. Ambas as escolhas mantêm o mesmo resultado independentemente de as entradas serem positivas ou negativas, que é o comportamento que você quer para ciclos e "wrapping".

Os operadores ​

Os quatro operadores da matemática (+, -, *, /) funcionam exatamente como você esperaria. O Python adiciona três outros que você usará constantemente: divisão inteira, resto e exponenciação.

Os quatro operadores padrão se comportam como esperado, com uma regra importante: / sempre retorna um float, mesmo quando o resultado é um número inteiro. Os três operadores adicionais estendem o que você consegue expressar sem esforço extra.

Cada operador está ligado a um método dunder (um método com nome de sublinhados duplos que o Python chama nos bastidores): + para __add__, // para __floordiv__, % para __mod__, ** para __pow__, e assim por diante. Na prática, isso significa que suas próprias classes podem definir esses métodos e passar a funcionar com + ou * diretamente, do mesmo jeito que um número embutido. Misturar um int e um float em uma mesma operação sempre resulta em um float, e / retorna um float independentemente do que você passar a ele.

python
price = 12.99
quantity = 3

print(price * quantity)   # 38.97
print(price + 2)          # 14.99
print(price - 1.00)       # 11.99
OperadorNomeExemploResultado
+Adição5 + 38
-Subtração5 - 32
*Multiplicação5 * 315
/Divisão5 / 31.6666...
//Divisão inteira5 // 31
%Resto5 % 32
**Exponenciação5 ** 3125
JunoOs operadores+, -, *, / funcionam como a matemática do papel. Os três extras vale a pena aprender desde já: // divide até chegar a um número inteiro, % te entrega o resto, e ** eleva a uma potência. Eu uso % muito mais do que imaginava que usaria.
JunoOs operadores Os quatro básicos funcionam como esperado, com uma regra para guardar: / sempre retorna um float. Os extras são // para divisão inteira, % para o resto, e ** para exponenciação. Cada um deles evita que você escreva uma função auxiliar.
JunoOs operadores Todo operador é encaminhado para um dunder, então uma classe que define __add__ ou __mul__ se conecta direto a + e *. A mistura de int e float sempre amplia para float, e / retorna um float independentemente do que você passar.

Divisão: / vs // ​

/ sempre entrega o resultado decimal exato, mesmo que a resposta seja um número inteiro. // descarta a parte fracionária e arredonda para o infinito negativo. Para números positivos isso significa cortar a parte decimal, mas para negativos isso vai um passo além, se afastando do zero:

/ sempre retorna um float, independentemente de as entradas serem inteiras. // retorna o piso do resultado: o maior inteiro que é menor ou igual ao resultado verdadeiro. Para números positivos isso é o mesmo que truncar. Para negativos, não é:

/ é a divisão verdadeira e sempre retorna um float. // é a divisão de piso: ela arredonda o quociente verdadeiro para o infinito negativo em vez de cortar em direção ao zero, que é o que muitas outras linguagens fazem. O motivo pelo qual isso importa na prática: // e % do Python satisfazem a == (a // b) * b + (a % b) para qualquer entrada inteira, negativos inclusive. A divisão por truncamento quebra essa identidade nos negativos, então qualquer lógica de ciclo ou "wrapping" que você escrever aqui permanece correta sem precisar tratar o sinal como caso especial.

python
10 / 2     # 5.0   (sempre float, mesmo quando a divisão é exata)
10 / 3     # 3.3333333333333335

10 // 3    # 3
7 // 2     # 3
-7 // 2    # -4    (arredonda para o infinito negativo, não para zero)

Na maior parte do tempo você vai usar // com números positivos. Guarde o comportamento com negativos na memória para quando eles aparecerem.

JunoDivisão: / vs /// sempre devolve um decimal, mesmo quando a divisão é exata: 4 / 2 é 2.0. // descarta a parte fracionária, mas cuidado com os negativos: -7 // 2 é -4, não -3, porque ele arredonda para baixo em vez de cortar. Isso me pegou na primeira vez que usei.

O Python chama isso de divisão de piso porque aplica a função matemática de piso (floor). Outras linguagens cortam em direção ao zero, dando um resultado diferente para negativos. O nome // já é uma dica: divide, depois aplica o piso.

JunoDivisão: / vs /// sempre retorna um float, até 4 / 2 dá 2.0. // arredonda para baixo em vez de truncar, então -7 // 2 é -4. Para números positivos os dois parecem iguais, a diferença só aparece nos negativos.

// calcula floor(a / b), não um truncamento. Funciona com floats também: 7.5 // 2 é 3.0, o quociente com piso aplicado devolvido como um float em vez de um int.

JunoDivisão: / vs //// arredonda o quociente para baixo, então satisfaz a == (a // b) * b + (a % b) em qualquer entrada, negativos e tudo mais. Essa é a propriedade em que você deve confiar para lógica de ciclos. Note que um operando float faz // retornar um float, como em 7.5 // 2 dando 3.0.

O operador de resto % ​

% te dá o que sobra depois de uma divisão inteira. Se 10 // 3 é 3 (porque 3 cabe em 10 três vezes), então 10 % 3 é 1 (porque 3 × 3 = 9, e 10 - 9 = 1). O uso mais comum é verificar se um número é par ou ímpar.

% é o operador de módulo. Verificar par/ímpar é o uso mais comum, mas ele se generaliza para qualquer problema de ciclo ou "wrapping": manter um contador dentro de um intervalo, distribuir itens entre grupos, repetir uma sequência. O padrão é sempre valor % limite, que retorna algo entre 0 e limite - 1.

O % do Python é módulo verdadeiro: o resultado sempre carrega o sinal do divisor. Muitas outras linguagens usam o sinal do dividendo, então dariam -1 onde o Python dá 2 para -7 % 3. A resposta do Python decorre de definir módulo como a - (a // b) * b com // arredondando para o infinito negativo. O ganho é que valor % limite permanece dentro de 0 a limite - 1 mesmo quando valor fica negativo, então um índice que faz "wrap" no fim de uma lista cai dentro do intervalo sem precisar de uma verificação extra.

python
10 % 3    # 1
10 % 2    # 0  (divide exatamente)
10 % 7    # 3

6 % 2     # 0  (par)
7 % 2     # 1  (ímpar)
JunoO operador de resto %% é o que sobra depois de uma divisão inteira. 10 % 3 é 1 porque 3 cabe em 10 três vezes, com 1 de sobra. Na maioria das vezes você vai encontrá-lo na verificação de par/ímpar: n % 2 é 0 para par, 1 para ímpar.
JunoO operador de resto %% é módulo, e vai muito além de par/ímpar: sempre que você precisar manter um valor dentro de um intervalo, valor % limite o encaixa entre 0 e limite - 1. Contadores, atribuição de grupos, ciclos que se repetem, tudo no mesmo formato.
JunoO operador de resto %% segue o sinal do divisor, então -7 % 3 é 2, não -1. É isso que permite que valor % limite permaneça dentro do intervalo mesmo com entradas negativas, sem precisar de verificação extra para um índice que faz "wrap".

Exponenciação ** ​

** eleva um número a uma potência. Use dois asteriscos, não o símbolo ^ (que significa outra coisa no Python):

** é exponenciação. Também funciona com floats, o que permite expressar raízes como potências fracionárias em vez de precisar de uma função separada:

** eleva a uma potência, e a forma com potência fracionária é bem útil: n ** 0.5 é uma raiz quadrada sem precisar importar nada. Dois operandos int dão um int, qualquer operando float dá um float. Uma coisa a saber antes de usar isso em trabalhos que exigem precisão ou envolvem números grandes: 9 ** 0.5 passa pela matemática de float, então pode resultar em 2.9999999999999996 em alguns casos. Quando a exatidão importa, math.isqrt() para raízes inteiras e math.pow() são as ferramentas a considerar, abordadas no capítulo Módulos.

python
2 ** 10    # 1024
3 ** 3     # 27
9 ** 0.5   # 3.0  (raiz quadrada: elevar à potência 0.5)
JunoExponenciação **** eleva um número a uma potência, então 2 ** 10 é 1024. Uma potência fracionária te dá uma raiz: 9 ** 0.5 é 3.0. A única armadilha é o símbolo: use **, não ^, que faz algo totalmente diferente no Python.
JunoExponenciação **** é exponenciação, e aceita floats, então 9 ** 0.5 te dá uma raiz quadrada sem precisar de uma função separada. Use a forma com potência fracionária quando quiser uma raiz rápida direto na expressão.
JunoExponenciação ** Dois ints dão um int, qualquer float dá um float. O problema com o truque da raiz via ** 0.5 é que ele passa pela matemática de float e pode ter um pequeno desvio, então use math.isqrt() ou math.pow() quando a exatidão for importante.

Precedência de operadores ​

O Python segue a ordem matemática padrão: exponenciação primeiro, depois multiplicação e divisão, depois adição e subtração. Quando estiver em dúvida, use parênteses. Eles deixam a intenção clara e não custam nada:

O Python segue a ordem padrão PEMDAS/BODMAS. A parte que costuma confundir: /, // e % compartilham o mesmo nível de precedência e são avaliados da esquerda para a direita quando misturados. Parênteses não custam nada; use-os sempre que a ordem não estiver clara à primeira vista:

Precedência do maior para o menor entre os operadores aritméticos: **, depois o - unário (um sinal de menos na frente de um único valor), depois * / // % (da esquerda para a direita quando compartilham o mesmo nível), depois + -. A armadilha que costuma pegar em código real: -2 ** 2 é -(2 ** 2), que é -4, porque ** tem precedência maior que o menos à frente. Se em algum momento você elevar ao quadrado um valor que pode ser negativo, coloque parênteses como em (-2) ** 2, ou o sinal ficará errado sem nenhum erro para te avisar.

python
2 + 3 * 4      # 14, não 20
2 ** 3 + 1     # 9,  não 512
10 - 4 / 2     # 8.0, não 3.0

(2 + 3) * 4    # 20
10 / (2 + 3)   # 2.0
JunoPrecedência de operadores Mesma ordem da matemática do papel: potências primeiro, depois multiplicação e divisão, depois soma e subtração. Quando a ordem não estiver clara à primeira vista, adicione parênteses. Eles não custam nada e deixam bem claro o que você quis dizer.
JunoPrecedência de operadores Ordem PEMDAS padrão, com um detalhe: /, // e % ficam todos no mesmo nível e são executados da esquerda para a direita quando misturados. Essa regra da esquerda para a direita é a parte que as pessoas costumam interpretar errado, então use parênteses sempre que o agrupamento não estiver claro.
JunoPrecedência de operadores A armadilha é o menos unário ter precedência menor que **, então -2 ** 2 é -4. Eleve ao quadrado qualquer coisa que possa ser negativa como (-2) ** 2, ou o sinal se inverte sem nenhum erro para avisar.

Como int e float interagem ​

O Python tem uma regra consistente: / sempre retorna um decimal, até 4 / 2 dá 2.0. Qualquer operação que misture um número inteiro e um decimal também resulta em um decimal. Quando você precisar de um número inteiro, use // ou converta com int().

As regras de tipo são previsíveis: / sempre retorna float. // e % com dois inteiros retornam int. Qualquer operação que misture int e float retorna float. Isso significa que 4 / 2 é 2.0, não 2, o que importa quando você precisa de um inteiro (por exemplo, para usar como índice).

A regra é fixa e vale a pena internalizar: int se amplia para float sempre que os dois se misturam, / sempre retorna um float, e // retorna um int apenas quando ambos os operandos são int. O bug que isso evita é um float acabar em algo que precisa de um número inteiro, como um índice de lista ou uma chave de dicionário, onde 2.0 e 2 não são intercambiáveis. Quando um cálculo pode produzir um float e você precisa de um int, converta com int() naquele ponto em vez de esperar que a divisão dê um resultado inteiro.

python
4 / 2      # 2.0   (float, sempre)
4 // 2     # 2     (int)
4 + 2      # 6     (int)
4 + 2.0    # 6.0   (float)
4 * 0.5    # 2.0   (float)
JunoComo int e float interagem/ sempre dá um decimal, então 4 / 2 é 2.0, não 2. Misture um número inteiro com um decimal em qualquer operação e você recebe um decimal de volta. Quando precisar de um número inteiro, use // ou coloque em int().
JunoComo int e float interagem/ é sempre float, // e % em dois inteiros permanecem int, e qualquer int misturado com um float sai como float. O que costuma pegar as pessoas é 4 / 2 ser 2.0 quando você queria um índice.
JunoComo int e float interagem Um float perdido saindo de / quebra qualquer coisa que precise de um int exato, como um índice ou uma chave de dicionário onde 2.0 não é 2. Converta com int() naquele ponto em vez de confiar que a divisão vai dar um resultado inteiro.

Precisão de float ​

Existe uma pegadinha que surpreende quase todo mundo em algum momento:

python
0.1 + 0.2   # 0.30000000000000004

Esse errinho não é um bug do Python. Computadores armazenam números decimais em binário, e alguns valores como 0.1 não podem ser representados de forma exata. É parecido com o fato de 1/3 não poder ser escrito de forma exata em decimal. Para a maioria dos cálculos do dia a dia isso não importa. Para exibir valores monetários, round() ou o especificador de formato :.2f mantêm a saída organizada.

Floats oferecem cerca de 15 a 16 dígitos decimais significativos de precisão. A imprecisão aparece porque algumas frações não podem ser armazenadas de forma exata em binário, então 0.1 + 0.2 produz 0.30000000000000004. Esse desvio só aparece quando você inspeciona o valor bruto; formatar com :.2f ou round() esconde isso na saída.

Para trabalhos financeiros onde fracções de centavo se acumulam, o Python oferece decimal.Decimal na biblioteca padrão, com aritmética exata em base 10. Isso é abordado no capítulo Módulos.

Um float armazena números em binário (base 2), e qualquer fração cujo denominador não seja uma potência de dois (como 1/10) não tem forma binária exata, da mesma forma que 1/3 não tem forma decimal exata. É por isso, e só por isso, que 0.1 + 0.2 resulta em 0.30000000000000004. O erro por operação é minúsculo, mas ele se acumula ao longo de uma cadeia longa de operações aritméticas, então duas formas diferentes de calcular o mesmo total podem discordar nos últimos dígitos.

A regra que evita esse bug: nunca use float para valores monetários, e nunca teste floats por igualdade exata com ==. Use decimal.Decimal quando precisar de aritmética exata em base 10 (faturamento, contabilidade), ou fractions.Fraction quando precisar de razões exatas sem arredondamento nenhum. Os dois vêm na biblioteca padrão do Python, abordados no capítulo Módulos.

JunoPrecisão de float Computadores armazenam decimais em binário, e alguns valores como 0.1 não têm forma binária exata, então 0.1 + 0.2 resulta em 0.30000000000000004. Não é um bug do Python, toda linguagem faz isso. Para a saída do dia a dia, round() ou :.2f mantêm tudo organizado.
JunoPrecisão de float O binário não consegue representar todo decimal de forma exata, então 0.1 + 0.2 se desvia para 0.30000000000000004. Tranquilo para a maioria dos cálculos, e :.2f ou round() arruma a exibição. Quando os centavos precisam bater exatamente, mude para decimal.Decimal.
JunoPrecisão de float A regra que te salva: nenhum float para valores monetários, e nunca == em floats, já que o erro se acumula ao longo de uma cadeia de operações. Use decimal.Decimal para base 10 exata e fractions.Fraction para razões exatas.

Literais numéricos legíveis ​

O Python permite colocar sublinhados em literais numéricos para tornar números grandes mais legíveis. O Python os ignora completamente; eles existem para você:

Sublinhados são válidos em qualquer lugar dentro de um literal numérico e são removidos durante a análise, sem efeito nenhum no valor. Úteis como separadores de milhar em constantes e para agrupar dígitos em literais binários ou hexadecimais:

Os sublinhados são removidos antes de o Python enxergar o valor, então eles não têm efeito nenhum sobre ele. Funcionam tanto em inteiros quanto em floats e em literais com base (0xFF_FF, 0b1010_0001, 1_234.567_890), o que os torna úteis para agrupar bytes em uma constante hexadecimal, não só milhares em uma decimal. As únicas restrições: um sublinhado não pode ficar no início, no fim, ou ao lado de um ponto decimal ou de um marcador de expoente.

python
population = 8_100_000_000
distance_km = 384_400
pi_approx = 3.141_592_653
JunoLiterais numéricos legíveis Coloque sublinhados em um número longo para deixá-lo legível: 8_100_000_000 é o mesmo valor que 8100000000. O Python os ignora completamente, eles existem para os seus olhos, não para o interpretador.
JunoLiterais numéricos legíveis Sublinhados são válidos em qualquer lugar dentro de um literal numérico e desaparecem no momento da análise, então o valor não muda. Bons como separadores de milhar em constantes, e igualmente úteis para agrupar dígitos em binário ou hexadecimal.
JunoLiterais numéricos legíveis Sublinhados são apenas cosméticos em inteiros, floats e literais com base, então 0xFF_FF e 0b1010_0001 ficam mais fáceis de ler. As únicas regras: não no início, no fim, ou ao lado de um ponto decimal ou marcador de expoente.

Funções embutidas úteis ​

abs() ​

abs() retorna o valor absoluto: sempre positivo, independentemente do sinal da entrada. Use-a quando o que importa é a distância de um número até zero, não a direção.

abs() retorna a magnitude de um número. Funciona com inteiros e floats. Útil para cálculos de distância, margens de erro, e qualquer situação em que a direção não importa e você só precisa do tamanho do valor.

abs() retorna a magnitude de um número, com o tipo de retorno correspondendo à entrada: um int entra e sai um int, um float sai um float. O uso do dia a dia é comparar a distância entre dois valores e um alvo sem se importar de que lado eles caem, por exemplo abs(measured - expected) < tolerance como uma verificação de tolerância, que fica mais claro do que duas comparações contra um intervalo com sinal.

python
abs(-5)     # 5
abs(3.7)    # 3.7
abs(-0.5)   # 0.5
Junoabs()abs() tira o sinal e devolve o tamanho positivo: abs(-5) é 5, abs(3.7) é 3.7. Use quando o que importa é a distância de um número até zero, não para qual lado ele se inclina.
Junoabs()abs() dá a magnitude de um int ou float, descartando a direção. É a forma limpa de escrever verificações de distância e margem de erro, em qualquer lugar em que o sinal não faça parte da pergunta.
Junoabs()abs() preserva o tipo da entrada, um int continua sendo int. O padrão que vale guardar é abs(measured - expected) < tolerance: uma verificação de tolerância em vez de duas comparações em torno de um intervalo com sinal.

round() ​

round() arredonda para o número inteiro mais próximo por padrão. Passe um segundo argumento para manter uma quantidade específica de casas decimais:

python
round(3.7)          # 4
round(3.2)          # 3
round(3.14159, 2)   # 3.14

Uma coisa que vale saber: round(2.5) dá 2, não 3. O Python arredonda para o número par mais próximo quando um valor está exatamente na metade entre duas opções.

round() usa o arredondamento bancário: quando o valor está exatamente na metade, ele arredonda para o número par mais próximo, em vez de sempre arredondar para cima. Isso minimiza o erro acumulado em trabalhos estatísticos, mas pode te surpreender se você espera que 0.5 sempre arredonde para cima:

python
round(2.5)   # 2  (arredonda para o par mais próximo)
round(3.5)   # 4
round(4.5)   # 4  (não 5)
round(3.14159, 2)   # 3.14

round() usa arredondamento para o par mais próximo (arredondamento bancário): um empate exato vai para o inteiro par mais próximo, não sempre para cima. Isso evita que os erros de arredondamento se acumulem em uma direção só ao longo de uma longa coluna de números, e é por isso que esse é o padrão para trabalhos estatísticos. Duas cautelas práticas. Primeiro, um empate em float muitas vezes não é um empate exato depois de convertido para binário, então round(2.675, 2) dá 2.67, não 2.68, porque 2.675 não pode ser armazenado de forma exata. Segundo, quando você precisar de um arredondamento monetário previsível, faça isso com decimal.Decimal e um modo de arredondamento explícito, em vez de confiar em round() sobre floats.

python
round(2.5)   # 2
round(3.5)   # 4
round(4.5)   # 4
Junoround()round(x) vai para o número inteiro mais próximo, round(x, n) mantém n casas decimais. A surpresa: um valor exatamente na metade arredonda para o número par mais próximo, então round(2.5) é 2, não 3.
Junoround()round() usa arredondamento bancário, então metades exatas vão para o número par mais próximo: round(2.5) é 2, round(4.5) é 4. Isso reduz o viés em trabalhos agregados, mas pode te pegar se você assumia que metades sempre arredondam para cima.
Junoround() Arredondamento bancário mais representação binária significa que round(2.675, 2) é 2.67, já que 2.675 não é um empate exato por debaixo dos panos. Para valores monetários, arredonde com decimal.Decimal e um modo escolhido, em vez de confiar em round() sobre floats.

divmod() ​

divmod() te dá o quociente e o resto em uma única chamada. Ela retorna um par de valores, uma tupla (abordada no capítulo Tuplas e conjuntos), que você pode atribuir a dois nomes ao mesmo tempo:

divmod(a, b) é equivalente a (a // b, a % b), mas calculado em um único passo. Use-a quando precisar dos dois valores de qualquer forma: paginação, conversão de tempo, ou distribuição de itens em grupos.

divmod(a, b) faz a divisão uma única vez e retorna tanto o quociente de piso quanto o resto do módulo em um par, evitando que você recalcule a mesma divisão através de // e depois %. Ela fica mais limpa nos lugares em que você precisa das duas partes de qualquer forma: conversão de tempo (divmod(seconds, 60)), paginação, ou organização de itens em linhas de tamanho fixo.

python
divmod(10, 3)   # (3, 1): quociente 3, resto 1
divmod(7, 2)    # (3, 1)
divmod(9, 3)    # (3, 0)

quotient, remainder = divmod(10, 3)
print(quotient)    # 3
print(remainder)   # 1
Junodivmod()divmod(a, b) devolve o quociente e o resto juntos: divmod(10, 3) é (3, 1). Você pode desempacotar os dois de uma vez com quotient, remainder = divmod(10, 3).
Junodivmod()divmod(a, b) é (a // b, a % b) em um único passo. Use quando precisar das duas partes, como em conversão de tempo ou paginação, em vez de calcular a divisão duas vezes.
Junodivmod() Uma divisão, os dois resultados: divmod() evita o trabalho redundante de // e % separados. Fica melhor onde você quer as duas partes de qualquer forma, como em divmod(seconds, 60) ou na organização de linhas.

Na prática ​

Uma calculadora de gorjeta:

python
bill = 45.50
tip_rate = 0.18
tip = round(bill * tip_rate, 2)
total = round(bill + tip, 2)

print(f"Bill:  ${bill}")
print(f"Tip:   ${tip}")
print(f"Total: ${total}")

round() mantém a saída parecendo dinheiro, em vez de uma longa sequência de casas decimais.

Contando páginas para paginação e acompanhando o progresso como uma porcentagem:

python
total_items = 153
items_per_page = 10

full_pages, leftover = divmod(total_items, items_per_page)
total_pages = (total_items + items_per_page - 1) // items_per_page

print(f"Full pages: {full_pages}, leftover: {leftover}")
print(f"Total pages needed: {total_pages}")   # 16
python
total_files = 847
processed_files = 312

percent = round(processed_files / total_files * 100, 1)
print(f"Progress: {processed_files}/{total_files} ({percent}%)")

A fórmula de divisão de teto (n + d - 1) // d é um truque clássico com inteiros para arredondar para cima sem converter para float.

Normalização min-max e variação percentual: dois padrões que aparecem constantemente em trabalhos com dados:

python
# normalização min-max: escala um valor para o intervalo de 0.0 a 1.0
value = 75
minimum = 0
maximum = 100

normalised = (value - minimum) / (maximum - minimum)
print(f"Normalised: {normalised:.2f}")   # 0.75

# variação percentual entre duas medições
before = 1_200
after = 1_380

change = (after - before) / before * 100
print(f"Change: {change:.1f}%")          # 15.0%

Ambos os padrões se reduzem a uma razão: um valor relativo a um intervalo de referência ou a uma magnitude de referência. A precisão do float é suficiente para a maioria dos trabalhos analíticos; o erro acumulado só importa quando o cálculo encadeia dezenas de operações ou envolve valores que diferem em muitas ordens de grandeza.