Por que o Math.Round / Floor / Ceiling não retorna longo ou int?

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 …