Numbers in Dart
Learn how Dart numbers are slightly different on the web, when that might matter, and how you might adjust your code.
Aplicações Dart frequentemente têm como alvo múltiplas plataformas. Por exemplo, uma aplicação Flutter pode ter como alvo iOS, Android e a web. O código pode ser o mesmo, desde que a aplicação não dependa de bibliotecas específicas da plataforma ou use números de uma forma que é dependente da plataforma.
Esta página tem detalhes sobre as diferenças entre implementações de números nativas e web, e como escrever código para que essas diferenças não importem.
Dart number representation
#
No Dart, todos os números são parte da hierarquia de tipo comum Object,
e existem dois tipos numéricos concretos e visíveis ao usuário:
int, representando valores inteiros, e double, representando valores fracionários.
Dependendo da plataforma, esses tipos numéricos têm implementações diferentes e ocultas. Em particular, Dart tem dois tipos muito diferentes de alvos para os quais compila:
- Native: Na maioria das vezes, um processador móvel ou desktop de 64 bits.
- Web: JavaScript como o motor de execução principal.
A tabela a seguir mostra como os números Dart são geralmente implementados:
| Representation | Native int |
Native double |
Web int |
Web double |
|---|---|---|---|---|
| 64-bit signed two's complement | ✅ | |||
| 64-bit floating point | ✅ | ✅ | ✅ |
Para alvos nativos, você pode assumir que
int mapeia para uma representação inteira com sinal de 64 bits e
double mapeia para uma representação de ponto flutuante IEEE de 64 bits
que corresponde ao processador subjacente.
Mas na web, onde Dart compila para e interopera com JavaScript,
existe uma única representação numérica:
um valor de ponto flutuante de precisão dupla de 64 bits.
Por eficiência, Dart mapeia tanto int quanto double para essa representação única.
A hierarquia de tipo visível permanece a mesma,
mas os tipos de implementação ocultos subjacentes são
diferentes e entrelaçados.
A figura a seguir ilustra os tipos específicos da plataforma (em azul)
para alvos nativos e web.
Como a figura mostra,
o tipo concreto para int em nativo implementa apenas a interface int.
No entanto, o tipo concreto para int na web implementa
tanto int quanto double.
Um int na web é representado como
um valor de ponto flutuante de precisão dupla sem parte fracionária.
Na prática, isso funciona muito bem:
ponto flutuante de precisão dupla fornece 53 bits de precisão inteira.
No entanto, valores int são sempre também valores double,
o que pode levar a algumas surpresas.
Differences in behavior
#A maioria dos cálculos aritméticos de inteiros e doubles tem essencialmente o mesmo comportamento. No entanto, há diferenças importantes—particularmente quando seu código tem expectativas rígidas sobre precisão, formatação de strings ou tipos de tempo de execução subjacentes.
Quando os resultados aritméticos diferem, como descrito nesta seção, o comportamento é específico da plataforma e sujeito a mudanças.
Precision
#
A tabela a seguir demonstra como algumas expressões numéricas
diferem devido à precisão.
Aqui, math representa a biblioteca dart:math,
e math.pow(2, 53) é 253.
Na web, inteiros perdem precisão após 53 bits. Em particular, 253 e 253+1 mapeiam para o mesmo valor devido ao truncamento. Em nativo, esses valores ainda podem ser diferenciados porque números nativos têm 64 bits—63 bits para o valor e 1 para o sinal.
O efeito do overflow é visível ao comparar 263-1 a 263. Em nativo, o último causa overflow para -263, como esperado para aritmética de complemento de dois. Na web, esses valores não causam overflow porque são representados de forma diferente; são aproximações devido à perda de precisão.
| Expression | Native | Web |
|---|---|---|
math.pow(2, 53) - 1 |
9007199254740991 |
9007199254740991 |
math.pow(2, 53) |
9007199254740992 |
9007199254740992 |
math.pow(2, 53) + 1 |
9007199254740993 |
9007199254740992 |
math.pow(2, 62) |
4611686018427387904 |
4611686018427388000 |
math.pow(2, 63) - 1 |
9223372036854775807 |
9223372036854776000 |
math.pow(2, 63) |
-9223372036854775808 |
9223372036854776000 |
math.pow(2, 64) |
0 |
18446744073709552000 |
Identity
#
Em plataformas nativas, double e int são tipos distintos:
nenhum valor pode ser tanto um double quanto um int ao mesmo tempo.
Na web, isso não é verdade.
Devido a essa diferença,
identidade pode diferir entre plataformas,
embora igualdade (==) não.
A tabela a seguir mostra algumas expressões que usam igualdade e identidade. As expressões de igualdade são as mesmas em nativo e web; as expressões de identidade geralmente são diferentes.
| Expression | Native | Web |
|---|---|---|
1.0 == 1 |
true |
true |
identical(1.0, 1) |
false |
true |
0.0 == -0.0 |
true |
true |
identical(0.0, -0.0) |
false |
true |
double.nan == double.nan |
false |
false |
identical(double.nan, double.nan) |
true |
false |
double.infinity == double.infinity |
true |
true |
identical(double.infinity, double.infinity) |
true |
true |
Types and type checking
#
Na web, o tipo int subjacente é como um subtipo de double:
é um valor de precisão dupla sem uma parte fracionária.
De fato, uma verificação de tipo na web do tipo x is int
retorna true se x for um número (double) com
uma parte fracionária de valor zero.
Como resultado, o seguinte é verdadeiro na web:
- Todos os números Dart (valores do tipo
num) sãodouble. - Um número Dart pode ser tanto um
doublequanto umintao mesmo tempo.
Esses fatos afetam verificações is e propriedades runtimeType.
Um efeito colateral é que double.infinity é interpretado como um int.
Como este é um comportamento específico da plataforma,
pode mudar no futuro.
| Expression | Native | Web |
|---|---|---|
1 is int |
true |
true |
1 is double |
false |
true |
1.0 is int |
false |
true |
1.0 is double |
true |
true |
(0.5 + 0.5) is int |
false |
true |
(0.5 + 0.5) is double |
true |
true |
3.14 is int |
false |
false |
3.14 is double |
true |
true |
double.infinity is int |
false |
true |
double.nan is int |
false |
false |
1.0.runtimeType |
double |
int |
1.runtimeType |
int |
int |
1.5.runtimeType |
double |
double |
Bitwise operations
#
Por razões de performance na web,
operadores bitwise (&, |, ^, ~) e de deslocamento (<<,>>,
>>>) em int
usam os equivalentes nativos do JavaScript.
No JavaScript, os operandos são truncados para inteiros de 32 bits
que são tratados como não assinados.
Esse tratamento pode levar a resultados surpreendentes em números maiores.
Em particular, se os operandos são negativos ou não cabem em 32 bits,
é provável que produzam resultados diferentes entre nativo e web.
A tabela a seguir mostra como plataformas nativas e web tratam operadores bitwise e de deslocamento quando os operandos são negativos ou próximos de 32 bits:
| Expression | Native | Web |
|---|---|---|
-1 >> 0 |
-1 |
4294967295 |
-1 ^ 2 |
-3 |
4294967293 |
math.pow(2, 32).toInt() |
4294967296 |
4294967296 |
math.pow(2, 32).toInt() >> 1 |
2147483648 |
0 |
(math.pow(2, 32).toInt()-1) >> 1 |
2147483647 |
2147483647 |
String representation
#
Na web, Dart geralmente delega ao JavaScript para converter um número em uma string
(por exemplo, para um print).
A tabela a seguir demonstra como
converter as expressões na primeira coluna pode levar a resultados diferentes.
| Expression | Native toString() |
Web toString() |
|---|---|---|
1 |
"1" |
"1" |
1.0 |
"1.0" |
"1" |
(0.5 + 0.5) |
"1.0" |
"1" |
1.5 |
"1.5" |
"1.5" |
-0 |
"0" |
"-0.0" |
math.pow(2, 0) |
"1" |
"1" |
math.pow(2, 80) |
"0" |
"1.2089258196146292e+24" |
What should you do?
#Geralmente, você não precisa mudar seu código numérico. Código Dart tem sido executado em plataformas nativas e web por anos, e diferenças na implementação de números raramente são um problema. Código comum e típico—como iterar através de um intervalo de pequenos inteiros e indexar uma lista—se comporta da mesma forma.
Se você tem testes ou asserções que comparam resultados de strings, escreva-os de uma maneira resiliente à plataforma. Por exemplo, suponha que você está testando o valor de expressões de string que têm números embutidos:
void main() {
var count = 10.0 * 2;
var message = "$count cows";
if (message != "20.0 cows") throw Exception("Unexpected: $message");
}
O código anterior tem sucesso em plataformas nativas mas falha na web
porque message é "20 cows" (sem decimal) na web.
Como alternativa, você pode escrever a condição da seguinte forma,
para que passe tanto em plataformas nativas quanto web:
if (message != "${20.0} cows") throw ...
Para manipulação de bits, considere operar explicitamente em pedaços de 32 bits,
que são consistentes em todas as plataformas.
Para forçar uma interpretação assinada de um pedaço de 32 bits,
use int.toSigned(32).
Para outros casos onde a precisão importa,
considere outros tipos numéricos.
O tipo BigInt
fornece inteiros de precisão arbitrária tanto em nativo quanto em web.
O pacote fixnum
fornece números assinados estritos de 64 bits, mesmo na web.
Use esses tipos com cuidado:
eles geralmente resultam em código significativamente maior e mais lento.
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. Página atualizada pela última vez em 2026-11-12. Ver código-fonte ou relatar um problema.
Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.