Por que Math.Floor (Double) retorna um valor do tipo Double?

103

Preciso obter o valor inteiro do lado esquerdo de um decimal ou duplo. Por Ex: preciso obter o valor 4 de 4,6. Tentei usar a função Math.Floor mas está retornando um valor duplo, por exemplo: está retornando 4.0 de 4.6. A documentação do MSDN diz que ele retorna um valor inteiro. Estou faltando alguma coisa aqui? Ou existe uma maneira diferente de conseguir o que procuro?

radbyx
fonte
2
A documentação do MSDN diz que ele retorna um valor inteiro . A documentação do MSDN informa que Math.Floor retorna System.Double, não inteiro.
banda larga de
Um valor inteiro é efetivamente necessário, mas não significa que possa ser armazenado em um "int" ou "long". Um "duplo" armazena com sucesso todos os valores inteiros em uma faixa muito mais ampla do que apenas "int". Observe que alguns valores inteiros podem ser arredondados quando a parte da mantissa não tem bits suficientes para armazenar todos os dígitos do valor inteiro, quando seu expoente de base 2 vai acima de 52: esse arredondamento de valores inteiros em "double" pode ocorrer para inteiros acima de 2 ^ 52 ou abaixo de -2 ^ 52, mas o resultado ainda será o número inteiro mais próximo representável; se você usar "(longo) Floor (x)", a conversão pode ser totalmente errada.
verdy_p
Observe, entretanto, que o intervalo válido de valores inteiros que podem ser representados em um "duplo" é extremamente grande, com valores absolutos até: (1 + (1 - 2 ^ −52)) × 2 ^ 1023 ≈ 1,7976931348623157E308; é muito mais do que 2 ^ 63-1 com "longo". No entanto, o intervalo de inteiros que podem ser armazenados distintamente é mais restrito, porque um "duplo" tem apenas 52 bits para a mantissa (mais 1 bit implícito para o bit mais significativo, não armazenado), o que significa que "duplo" pode armazenar apenas inteiros exatamente apenas quando seu valor absoluto está abaixo de 2 ^ 53.
verdy_p
Infelizmente, Math.Floor () não retorna um tipo de variável "Número" internamente usando "Longo" se possível, ou "Duplo", caso contrário, apenas para números inteiros arredondados grandes. E a biblioteca padrão de matemática não lida com esse tipo de número de variável unificada. Existem outras bibliotecas matemáticas que implementam um tipo de número unificado, incluindo longos, duplos ou inteiros grandes codificados em decimal compactado ou binário sem perda de intervalo ou precisão compatível.
verdy_p

Respostas:

146

O intervalo de doubleé muito mais amplo do que o intervalo de intou long. Considere este código:

double d = 100000000000000000000d;
long x = Math.Floor(d); // Invalid in reality

O número inteiro está fora da faixa de long- então o que você espera que aconteça?

Normalmente, você sabe que o valor realmente estará dentro do intervalo de intou long, então você o converte:

double d = 1000.1234d;
int x = (int) Math.Floor(d);

mas a responsabilidade por esse elenco recai sobre o desenvolvedor, não sobre Math.Floorsi mesmo. Teria sido desnecessariamente restritivo fazê-lo falhar apenas com uma exceção para todos os valores fora do intervalo de long.

Jon Skeet
fonte
2
Floor retorna a representação inteira de double, e retorna double para cálculos científicos, esta resposta não está correta porque double tem 64 bits e long também tem 64 bits, mas double não pode armazenar dígitos exatos de bits menos significativos mesmo se puder ser armazenado corretamente em muito tempo.
Akash Kava
1
@Jon: como é que você não ponderou sobre o intenso debate sobre como tornar um número positivo negativo em C # ?: stackoverflow.com/questions/1348080/…
MusiGenesis
3
@ Jon: leve o seu tempo. Acontece que a comunidade descobriu que multiplicar um número positivo por -1 o tornará negativo. Tudo está bem no StackOverflow.
MusiGenesis
1
@javapowered: Não, (int) 15.0 não é 0. Alguma outra coisa deu errado, mas não podemos dizer o quê a partir disso. Crie um programa curto, mas completo, que demonstre isso, e depois faça uma pergunta. Eu suspeito que você achará difícil reproduzir ...
Jon Skeet
1
@MusiGenesis: <code> (int) IGNORE_RATIO * Volume </code> é calculado como <code> (int) 0,15 * Volume </code>, mas o typecast aplica-se apenas à proporção, não ao resultado do produto, e você obtém <code> 0 * Volume </code>, ou seja, zero! Use <code> (int) (IGNORE_RATIO * Volume) </code> ao invés para resolver SEU bug.
verdy_p
11

De acordo com o MSDN, Math.Floor (double) retorna um duplo: http://msdn.microsoft.com/en-us/library/e0b5f0xb.aspx

Se você quiser como um int:

int result = (int)Math.Floor(yourVariable);

Posso ver como o artigo do MSDN pode ser enganoso, eles deveriam ter especificado que, embora o resultado seja um "inteiro" (neste caso, significando um número inteiro), ele ainda é do TIPO duplo

Neil N
fonte
Obrigado por sua resposta. Na verdade, eu estava lendo este artigo: msdn.microsoft.com/en-us/library/e0b5f0xb.aspx Mas de qualquer forma, vou tentar sua sugestão. Obrigado.
Bem, é verdade, diz no topo "retorna um inteiro", mas o tipo é especificado abaixo dele: public static double Floor (double d)
Neil N
3
integer! = int( answers.com/integer ) - inteiros podem ser armazenados em Double(veja a resposta de Jon), e há um número infinito de inteiros que não podem ser armazenados em um int.
Shog9
Shog, eu não disse que não podiam. O que eu disse foi "ainda é de TIPO Duplo"
Neil N
1
@ Neil: certo - só queria enfatizar a diferença entre "inteiro" (nome de um conjunto) e int(nome de um tipo).
Shog9
4

Se você só precisa da parte inteira de um número, converta o número em um int. Isso truncará o número na casa decimal.

double myDouble = 4.6;
int myInteger = (int)myDouble;
Jon Seigel
fonte
2
É importante observar que o casting to intse comporta de maneira diferente Floor, para números negativos. Floorsempre truncará para o número mais negativo, enquanto a conversão para inttruncará em direção a 0.
Magnus
0

Floor deixa-o como um duplo para que você possa fazer mais cálculos duplos com ele. Se você quiser isso como um int, lance o resultado de floor como um int. Não lance o duplo original como um inteiro porque as regras para o piso são diferentes (IIRC) para números negativos.

plinto
fonte
0
Convert.ToInt32(Math.Floor(Convert.ToDouble(value)))

Isso lhe dará o valor exato que você deseja, se você pegá- 4.6lo 4como saída.

user3306645
fonte