Fundido para int x chão


120

Existe alguma diferença entre estes:

float foo1 = (int)(bar / 3.0);
float foo2 = floor(bar / 3.0);

Pelo que entendi, ambos os casos têm o mesmo resultado. Existe alguma diferença no código compilado?


1
um pouco melhor com floor, mas cuidado, pois isso doublenão é para float. C99 também tem floorfpara float.
Jens Gustedt

2
Portanto, eles têm o mesmo resultado, desde que a barra seja positiva
Zac

1
(nota: em C ++ por favor #include<cmath>e use std::floor)
user202729

Que tipo é bar?
chux - Reintegrar Monica

@chux Não importa, dividir por 3,0 fará com que seja dobrado de qualquer maneira
Kaalus,

Respostas:


193

A conversão para um int truncará em direção a zero. floor()irá truncar em direção ao infinito negativo. Isso fornecerá valores diferentes se barforem negativos.


15
Eu acho que você acertou o prego na cabeça aqui. Outra diferença, se floor()for a intenção, é se o valor de baré muito grande para caber em int.
Fred Larson

Você tem alguma fonte para essa declaração?
HelloGoodbye

1
Mesmo quando o resultado é positivo, não é garantido. Veja isso e isso .
user202729

27

Como foi dito antes, para números positivos eles são iguais, mas diferem para números negativos. A regra é que int arredonda para 0, enquanto floor arredonda para infinito negativo.

floor(4.5) = (int)4.5 = 4
floor(-4.5) = -5 
(int)(-4.5) = -4

Dito isso, também há uma diferença no tempo de execução. No meu sistema, eu calculei que a fundição é pelo menos 3 vezes mais rápida do que o chão.

Tenho um código que precisa da operação de piso de uma faixa limitada de valores, incluindo números negativos. E precisa ser muito eficiente, então usamos a seguinte função para isso:

int int_floor(double x) 
{ 
    return (int)(x+100000) - 100000; 
}

É claro que isso falhará para valores muito grandes de x (você terá alguns problemas de estouro) e para valores negativos abaixo de -100000, etc. para nosso aplicativo. Tome-o com um grão de sal, teste-o em seu sistema, etc. mas vale a pena considerar IMHO.


"Eu marquei para ser pelo menos 3 vezes mais rápido do que o chão" -> OP está usando float, não double- talvez doublefosse sua aplicação. Se em C, certifique-se de usar floorf()com floats.
chux - Reintegrar Monica

@chux Acho que a única razão pela qual há alguma diferença é que o elenco permite uma otimização em tempo de compilação. Portanto, essa conversão pode ter sido completamente removida durante a execução.
ClydeTheGhost

9

SO 101, não mude sua pergunta depois que as pessoas responderem à sua pergunta, em vez disso, escreva uma nova pergunta.

Por que você acha que eles terão o mesmo resultado?

float foo = (int)(bar / 3.0) //will create an integer then assign it to a float

float foo = fabs(bar / 3.0 ) //will do the absolute value of a float division

bar = 1.0

foo1 = 0;
foo2 = 0.33333...

1
O que você quer dizer com fabs? A questão era sobre floor. O chão de 0.33333... é 0.
Aaron Franke

2
@AaronFranke a pergunta original foi modificada. parece que muita coisa pode acontecer em 8 anos ;-) observe que outras respostas têm a mesma premissa
AndersK

4

EDIT: Porque a pergunta pode ter sido modificada devido à confusão entre fabs()e floor().

Dadas as linhas de exemplo da pergunta original:

1.  float foo = (int)(bar / 3.0);

2.  float foo = fabs(bar / 3.0);

A diferença é que se a barra for negativa, o resultado será negativo com a primeira, mas positivo com a segunda. O primeiro será truncado para um número inteiro e o segundo retornará o valor decimal completo incluindo a parte fracionária.


3

Sim. fabsretorna o valor absoluto de seu argumento, e a conversão para int causa o truncamento da divisão (até o int mais próximo), portanto, os resultados quase sempre serão diferentes.


2

Existem duas diferenças principais:

  1. Como outros apontaram, a projeção para um inteiro truncará em direção a zero, enquanto floor()sempre truncará em direção ao infinito negativo; este é um comportamento diferente para um operando negativo.

  2. Ninguém (ainda) parece ter apontado outra diferença - se o seu argumento for maior ou igual a MAX_INT+1(ou menor que -MAX_INT-1), então a conversão para um intresultará na perda dos bits mais importantes (C, provavelmente) ou comportamento indefinido ( C ++ e possivelmente C). Por exemplo, se seu intfor de 32 bits, você terá apenas um bit de sinal mais 31 bits de dados. Portanto, usar isso com um de doubletamanho grande vai produzir resultados indesejados.


2.a. A condição exata para a conversão para intestouro é que o argumento seja maior ou igual a INT_MAX+1. Simetricamente, a condição para o estouro negativo é que o argumento seja menor ou igual a INT_MIN-1.
Pascal Cuoq

1
2.b. O estouro na conversão de ponto flutuante para inteiro é um comportamento indefinido em C ++. Isso não “resulta na perda dos bits mais elevados”. Veja (embora seja escrito para C): blog.frama-c.com/index.php?post/2013/10/09/…
Pascal Cuoq

0

(int) xé uma solicitação para manter a parte inteira de x(não há arredondamento aqui)

fabs(x)= | x | de modo que é >= 0;

Ex: (int) -3.5retorna -3; fabs(-3.5)retorna 3.5;

Em geral, fabs (x) >= xpara todo x;

x >= (int) x E se x >= 0

x < (int) x E se x < 0


x = -3 fábricas (-3) = 3 (int) -3 = -3; Acho que as últimas desigualdades se mantêm. Você pode explicar mais por que está errado?
Paul Hoang

Desculpe, eu quis dizer -3,5, o exemplo que você deu. -3> -3,5
Dennis Zickefoose

3
A última declaração ainda deve ser "x <= int (x) se x <0", e não "x <(int) x se x <0": inteiros negativos permanecem os mesmos.
Tomasz Gandor
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.