Преобразование в int vs floor

120

Есть ли разница между ними:

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

Насколько я понимаю, в обоих случаях результат одинаковый. Есть ли разница в скомпилированном коде?

OgreSwamp
источник
1
немного лучше с floor, но будьте осторожны, это doubleне для float. C99 также имеет floorfдля float.
Йенс Густедт
2
Таким образом, у них будет тот же результат, пока бар положительный
Zac
1
(примечание: на C ++, пожалуйста, #include<cmath>используйте std::floor)
user202729
Какой тип bar?
chux
@chux Неважно, деление на 3,0 все равно
приведет к удвоению

Ответы:

194

Приведение к int будет усечено до нуля. floor()будет усекаться до отрицательной бесконечности. Это даст вам другие значения, если они barбудут отрицательными.

Джеймс Карран
источник
15
Я думаю, вы попали в точку здесь. Другое отличие, если floor()таково намерение, заключается в том, что значение barслишком велико, чтобы поместиться в int.
Fred Larson
Есть ли у вас источник этого заявления?
Hellogoodbye
1
Даже если результат положительный, это не гарантировано. Смотрите это и это .
user202729
27

Как было сказано ранее, для положительных чисел они одинаковы, но для отрицательных чисел они отличаются. По правилу int округляется в сторону 0, а пол - в сторону отрицательной бесконечности.

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

При этом также есть разница во времени выполнения. В моей системе я рассчитал, что заброс как минимум в 3 раза быстрее, чем на полу.

У меня есть код, который требует работы с ограниченным диапазоном значений, включая отрицательные числа. И он должен быть очень эффективным, поэтому мы используем для этого следующую функцию:

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

Конечно, это не сработает для очень больших значений x (вы столкнетесь с некоторыми проблемами переполнения) и для отрицательных значений ниже -100000 и т. Д. Но я установил, что он будет как минимум в 3 раза быстрее, чем пол, что было действительно критично. для нашего приложения. Отнеситесь к нему с недоверием, протестируйте его на своей системе и т. Д., Но это стоит рассмотреть ИМХО.

Брис Ребсамен
источник
«Я сделал так, чтобы он был как минимум в 3 раза быстрее, чем пол» -> OP использует float, а не double- возможно, doubleваше приложение. Если в C, обязательно используйте floorf()с floats.
chux - Восстановить Монику
@chux Я думаю, единственная причина, по которой есть какая-то разница, заключается в том, что приведение позволяет оптимизировать время компиляции. Так что это преобразование могло быть полностью удалено во время выполнения.
ClydeTheGhost
9

SO 101, не меняйте свой вопрос после того, как люди ответят на ваш вопрос, вместо этого напишите новый вопрос.

Как вы думаете, почему у них будет такой же результат?

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...
AndersK
источник
1
Что вы имеете в виду fabs? Вопрос был о том floor. Этаж 0.33333... есть 0.
Аарон Франке
2
@AaronFranke исходный вопрос был изменен. кажется, за 8 лет многое может произойти ;-) обратите внимание, что в других ответах та же предпосылка
AndersK 05
4

РЕДАКТИРОВАТЬ: потому что вопрос мог быть изменен из-за путаницы между fabs()и floor().

Учитывая исходные строки примера вопроса:

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

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

Разница в том, что если столбец отрицательный, результат будет отрицательным для первого и положительным для второго. Первое будет усечено до целого числа, а второе вернет полное десятичное значение, включая дробную часть.

Amardeep AC9MF
источник
3

Да. fabsвозвращает абсолютное значение своего аргумента, а приведение к int вызывает усечение деления (до ближайшего целого числа), поэтому результаты почти всегда будут разными.

warrenm
источник
2

Есть два основных отличия:

  1. Как указывали другие, приведение к целому числу будет усекаться до нуля, тогда как floor()всегда будет усекаться до отрицательной бесконечности; это другое поведение для отрицательного операнда.

  2. Никто (пока), похоже, не указал на другое различие - если ваш аргумент больше или равен MAX_INT+1(или меньше -MAX_INT-1), то приведение к an intприведет к отбрасыванию самых верхних битов (C, вероятно) или неопределенному поведению ( C ++ и, возможно, C). Например, если у вас int32 бита, у вас будет только знаковый бит плюс 31 бит данных. Таким образом, использование этого с doubleбольшим размером приведет к непредвиденным результатам.

abligh
источник
2.а Точное условие для преобразования в intпереполнение - аргумент больше или равен INT_MAX+1. Симметрично, условие потери значимости состоит в том, что аргумент меньше или равен INT_MIN-1.
Паскаль Куок
1
2.b. Переполнение при преобразовании из числа с плавающей запятой в целое число является неопределенным поведением в C ++. Это не приводит к «отбрасыванию самых верхних битов». См. (Хотя он написан для C): blog.frama-c.com/index.php?post/2013/10/09/…
Pascal Cuoq
0

(int) xэто просьба сохранить целую часть x(здесь нет округления)

fabs(x)= | x | так что это>= 0 ;

Пример: (int) -3.5возврат -3; fabs(-3.5)возвращается3.5 ;

В общем, fabs (x) >= xдля всех x;

x >= (int) x если x >= 0

x < (int) x если x < 0

Пол Хоанг
источник
х = -3 фаб (-3) = 3 (целое) -3 = -3; Я думаю, что последнее неравенство сохраняется. Не могли бы вы подробнее объяснить, почему это неправильно?
Пол Хоанг
Извините, я имел в виду -3,5, приведенный вами пример. -3> -3,5
Dennis Zickefoose
3
Последний оператор должен по-прежнему быть «x <= int (x) if x <0», а не «x <(int) x if x <0»: отрицательные целые числа остаются неизменными.
Tomasz Gandor