У ролях до int vs floor


120

Чи є різниця між цими:

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

Як я розумію, обидва випадки мають однаковий результат. Чи є різниця в складеному коді?


1
трохи краще floor, але будьте обережні, що це doubleне для float. C99 також має floorfдля float.
Jens Gustedt

2
Таким чином, вони мають такий самий результат, якщо бар є позитивним
Зак

1
(зверніть увагу: на C ++ будь ласка #include<cmath>та використовуйте std::floor)
user202729

Якого типу bar?
chux

@chux Не має значення, поділ на 3.0 все одно зробить його подвійним
каалус

Відповіді:


193

Передача в int скорочуватиметься до нуля. floor()буде скорочуватися до негативної нескінченності. Це дасть вам різні значення, якщо вони barбули негативними.


15
Я думаю, ти тут вдарив цвях по голові. Ще одна відмінність, якщо floor()це є наміром, полягає в тому, якщо значення barзанадто велике, щоб вмістити його int.
Фред Ларсон

Чи є у вас якесь джерело для цього твердження?
HelloGoodbye

1
Навіть коли результат позитивний, це не гарантується. Дивіться це і це .
користувач202729

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 рази швидше, ніж підлога" -> ОП використовується float, ні double- можливо, це doubleбуло вашою заявою. Якщо в C, не забудьте використовувати floorf()з floats.
chux

@chux Я думаю, що єдиною причиною є будь-яка різниця в тому, що амплуа дозволяє оптимізувати час компіляції. Так що конверсія фактично може бути повністю видалена під час виконання.
ClydeTheGhost

9

ТАК 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...

1
Що ви маєте на увазі під fabs? Питання було про те floor. Підлога 0.33333... є 0.
Аарон Франке

2
@AaronFranke початкове запитання було змінено. здається, що може статися за 8 років ;-) зауважте, що інші відповіді мають таку саму передумову
AndersK

4

EDIT: Оскільки питання, можливо, було змінено через плутанину між fabs()та floor().

Дано оригінальні рядки прикладів запитань:

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

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

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


3

Так. fabsповертає абсолютне значення свого аргументу, а передача на int викликає усічення поділу (до найближчого int), тому результати майже завжди будуть різними.


2

Є дві основні відмінності:

  1. Як зазначали інші, відведення до цілого числа скорочуватиметься до нуля, тоді як floor()завжди буде скорочуватися до негативної нескінченності; це різна поведінка для негативного операнда.

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


2.а. Точною умовою перетворення в intпереповнення є те, що аргумент більший або рівний INT_MAX+1. Симетрично умовою підтоку є те, що аргумент нижчий або дорівнює INT_MIN-1.
Паскаль Куок

1
2.b. Переповнення в перетворенні з плаваючою комою в ціле число є невизначеною поведінкою в C ++. Це не «призводить до того, що найбільший біт опускається». Дивіться (хоча це написано для С): blog.frama-c.com/index.php?post/2013/10/09/…
Паскаль Куок

0

(int) x- це запит зберегти цілу частину x(тут немає округлення)

fabs(x)= | х | так що це >= 0;

Наприклад: (int) -3.5повертає -3; fabs(-3.5)повертає 3.5;

Загалом fabs (x) >= xдля всіх х;

x >= (int) x якщо x >= 0

x < (int) x якщо x < 0


x = -3 fabs (-3) = 3 (int) -3 = -3; Я думаю, що останні нерівності мають місце. Чи можете ви детальніше зупинитися на тому, чому це неправильно?
Пол Хоанг

Вибачте, я мав на увазі -3,5, приклад, який ви навели. -3> -3,5
Dennis Zickefoose

3
Останнє твердження все одно має бути "x <= int (x), якщо x <0", а не "x <(int) x, якщо x <0": від'ємні цілі числа залишаються однаковими.
Томаш Гандор
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.