Toda vez que eu uso Math.Round/Floor/Ceiling
eu sempre Math.Round/Floor/Ceiling
para int
(ou talvez long
se necessário). Por que exatamente eles retornam o double
se ele está sempre retornando um inteiro.
O resultado pode não se encheckboxr em um int (ou longo). O alcance de um duplo é muito maior.
Alcance aproximado de dupla: ± 5,0 × 10 −324 a ± 1,7 × 10 308
(Fonte)
Concordo com a resposta de Mark de que o resultado pode não se encheckboxr em um long
, mas você pode se perguntar: e se o C # tivesse um tipo muito mais long
? Bem, aqui está o que acontece em Python com seus números inteiros de comprimento arbitrário:
>>> round(1.23e45) 1229999999999999973814869011019624571608236032
A maioria dos dígitos é “ruído” do erro de arredondamento de ponto flutuante. Talvez parte da motivação para Round
/ Floor
/ Ceiling
retornar em double
em C # era evitar a ilusão de falsa precisão.
Uma explicação alternativa é que o módulo .NET Math
usa o código escrito em C, em que floor e ceil retornam tipos de ponto flutuante.
Intervalo argumentos à parte, nenhuma dessas respostas aborda o que, para mim, é um problema fundamental com o retorno de um número de ponto flutuante quando você realmente quer um inteiro exato. Parece-me que o número de ponto flutuante calculado poderia ser menor ou maior que o número inteiro desejado por um pequeno erro de arredondamento, portanto, a operação de conversão poderia criar um erro de desativação. Eu acho que, em vez de converter, você precisa aplicar uma function inteira (não dupla) round-near ao resultado duplo de floor()
. Ou então escreva seu próprio código. As versões da biblioteca C de floor()
e ceil()
são muito lentas.
Isso é verdade ou estou faltando alguma coisa? Há algo sobre uma representação exata de números inteiros em um padrão de ponto flutuante IEEE, mas não tenho certeza se isso torna o casting seguro.
Eu preferiria ter verificação de intervalo na function (se necessário para evitar estouro) e retornar um longo. Para meu próprio código privado, posso pular a verificação de intervalo. Eu tenho feito isso:
long int_floor(double x) { double remainder; long truncate; truncate = (long) x; // rounds down if + x, up if negative x remainder = x - truncate; // normally + for + x, - for - x //....Adjust down (toward -infinity) for negative x, negative remainder if (remainder < 0 && x < 0) return truncate - 1; else return truncate; }
Existem contrapartes para ceil()
e round()
com diferentes considerações para números negativos e positivos.
Não há nenhuma razão dada nos documentos que eu poderia encontrar. Meu melhor palpite é que, se você estiver trabalhando com duplas, é provável que queira que qualquer operação em duplas retorne um duplo. Arredondá-lo para lançar em um int foi considerado pelo designer de linguagem menos comum, em seguida, arredondamento e mantendo como um duplo.
Você poderia escrever seu próprio método que o converteria em um int para você em aproximadamente 2 linhas de código, e muito menos trabalho do que postar uma pergunta no estouro de pilha …