Чи гарантовано ціле число float, розділене на себе, дорівнює 1.f?


76

Якщо я напишу:

int x = /* any non-zero integer value */;
float y = x;
float z = y / y;

Є чи zгарантовано точно 1.f?


8
Це вимагало б досить незвичної кількості педантизму, навіть за стандартами C ++, щоб стверджувати, що це std::numeric_limits<int>::max()може бути більше, ніж std::numeric_limits<float>::max().
MSalters

2
@MSalters Ха-ха, я думав про те, щоб включити це, але вирішив, що це занадто глупо. :)
Baum mit Augen

1
@MSalters: FWIW, для більшості x, static_cast<int>(y) != x(якщо обидва 32-біт), але по- z, як і раніше буде дорівнює , 1.0fякщо x == 0тому як чисельник і знаменник не мають ту ж помилку округлення.
Арне Фогель

Якщо два числа xі yдосить великі, і досить близькі одне до одного (не будучи рівними), то x/y, ймовірно, буде 1.fтеж через помилку при перетворенні. Спробуйте ввести це в консолі браузера (який , ймовірно , також використовує IEEE754) і натиснути ENTER: 9223372036854775700/9223372036854775800.
Кассіо Ренан,

1
@ArneVogel: Насправді, + INF / + INF - це NaN, а не 1,0
MSalters

Відповіді:


96

Якщо у вашій реалізації C ++ використовується IEEE754, тоді так, це гарантовано. (Оператор ділення повинен повернути найкраще можливе значення з плаваючою комою).

В тільки виключення для y / y, в загальному, не будучи 1.fє випадки , коли yце NaN, +Inf, -Inf, 0.f, і -0.f, або , якщо ви перебуваєте на платформі , де intнастільки широкий , що деякі випадки нього не можуть бути представлені в floatбез того float, встановленим на +Infабо -Inf1 . Якщо відкласти останню точку, у вашому випадку це означає, що це int x = 0;буде єдиним винятком.

IEEE754 надзвичайно поширений. Але щоб перевірити напевно, протестуйте значення

std::numeric_limits<float>::is_iec559;

1 Платформа, наприклад, із 128-бітовим intта 32-бітовим IEEE754 floatможе виявляти таку поведінку для певних значень x.


2
Я не думаю, що yможе стати NaN.
Baum mit Augen

2
Якщо ви хочете піти цим маршрутом, вам також потрібно додати Inf, -Inf та -0f. :)
Baum mit Augen

2
@BaummitAugen: Є багато бітових шаблонів IEE754, які є всіма NaN, деякі з яких мають бітовий знак. Але, як NaN != NaNі для будь-якого бітового шаблону NaN, безглуздо сперечатися, чи "+ NaN == -NaN".
MSalters

1
Скажімо, це yзначення було як в регістрі, так і в пам'яті, і компілятор вирішив завантажити знаменник з пам'яті. Отже, ви закінчуєте y_from_register / y_from_memory. Якщо регістр має більшу точність, ніж пам'ять, що гарантує, що 1 є найкращим результатом ділення?
Девід Шварц,

1
Інший виняток - коли floatне може містити xзначення.
Нат

33

Ні, не у всіх випадках, навіть для IEEE754.

Наприклад, за допомогою int x = 0;, ви отримаєте NaN. ( Прямий ефір )


Просто підсунув його до моєї відповіді, перш ніж ви це опублікували. Є голос за.
Вірсавія,

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

3
@cat Я можу зрозуміти частину вашої пропозиції "не у всіх випадках", але ваше використання "Наприклад" свідчить про те, що існують інші значення, для яких це саме стосується, і тому особисто я думаю, що відповідь тут зараз краще, ніж відповідь, яку ви запропонували.

@hvd, коли y є infабо 0fабо підписує варіанти тих, то результат також не1f
кіт

3
@cat Питання конкретно стосується цілого числа float, розділеного на себе та float y = x;з int x;.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.