Нуль як константа?


15

Нещодавно я натрапив на цю ідіому програмування:

const float Zero = 0.0;

який потім використовується для порівнянь:

if (x > Zero) {..}

Хтось може пояснити, чи це насправді ефективніше читання чи технічніше, ніж:

if (x > 0.0) {..}

ПРИМІТКА. Я можу придумати інші причини, щоб визначити цю константу, я просто цікавлюсь її використанням у цьому контексті.


31
Розробники планують перенести код у Всесвіт, де закони математики різні?
vaughandroid

6
Якщо серйозно, то я не можу придумати жодної вагомої причини для цього. Єдині пояснення, які я можу придумати, - це надто завзяті стандарти кодування, або деякі чорти, які почули "магічні числа - це погано", але не розуміють, чому (або що буде магічним числом) ...
vaughandroid

@Baqueta -У альтернативному Всесвіті? Я думаю, вони там уже жили! Що стосується магічних чисел, я згоден, однак я використовую правило, згідно з яким все, крім 0 і 1, повинно бути постійним.
NWS

1
Якщо xтип має float, тоді він x > 0.0примушує просуватися до double, що може бути менш ефективним. Це не є вагомою причиною для використання названої константи, лише для того, щоб переконатися, що ваші константи мають правильний тип (наприклад 0f, float(0)або decltype(x)(0)).
Майк Сеймур

1
@JoSo: якщо чесно, тип 13.37ні float, це double. Тож якщо ви хотіли floatтоді, можливо, ваш викладач був правильний. У деяких контекстах (наприклад, присвоєння поплавцю) 13.37буде неявно перетворено на те, floatщо ви хотіли, а в інших контекстах (наприклад, відрахування типу шаблону) цього не буде, тоді як static const floatзавжди починається як тип, який ви намітили. Отже, більш безпечний для типу. Зверніть увагу, так би і було 13.37f! Існують й інші причини уникнення макросу, ніж "безпека типу", тому так само ймовірно, що викладач наводив вам поганий аргумент.
Стів Джессоп

Відповіді:


29

Можливими причинами є тип кешування, іменування або примушування

Кешування (не застосовується)

Ви хочете уникнути витрат на створення об’єкта під час акту порівняння. У Java прикладом може бути

BigDecimal zero = new BigDecimal ("0.0");

це передбачає досить важкий процес створення і його краще обслуговувати за допомогою наданого статичного методу:

BigDecimal zero = BigDecimal.ZERO;

Це дозволяє проводити порівняння, не несучи повторних витрат на створення, оскільки BigDecimal попередньо кешується JVM під час ініціалізації.

У випадку, що ви описали, примітив виконує ту саму роботу. Це значною мірою зайве з точки зору кешування та продуктивності.

Іменування (малоймовірно)

Оригінальний розробник намагається надати єдиний режим іменування для загальних значень у всій системі. Це має певні достоїнства, особливо для незвичайних значень, але щось таке ж базове, як нульове, варто лише у випадку попереднього випадку кешування.

Тип примусу (швидше за все)

Оригінальний розробник намагається примусити певний примітивний тип, щоб переконатися, що порівняння приведені до їх правильного типу та, можливо, до певного масштабу (кількість десяткових знаків). Це нормально, але просте ім'я "нуль", ймовірно, недостатньо детально для цього випадку використання, оскільки ZERO_1DP є більш відповідним виразом наміру.


2
+1 для вимушеного типу. Я додам, що в таких мовах, як C ++, які дозволяють оператору перевантажувати, визначати константу і використовувати typedef, зберігали б тип змінної в точно одному місці і дозволяли змінити її, не змінюючи код.
Blrfl

3
Тип примусу, швидше за все, не те, що вони намагалися, проте це найкраще пояснення, чому це можна зробити!
NWS

7
Для вимушеного типу я, мабуть, краще просто скористатися 0.0f.
Свиш

Тип примушування іноді може бути корисним у vb.net, коли виконання побітових операторів на байтах дає результат байтів. Казати byteVar1 = byteVar2 Or CB128здається трохи приємніше, ніж byteVar1 = byteVar2 Or CByte(128). Звичайно, мати правильний числовий суфікс для байтів було б краще. Оскільки C # розкручує операнди побіжно операторам intнавіть тоді, коли результат гарантовано впишеться в a byte, проблема там не настільки актуальна.
supercat

Я не впевнений у тому, щоб мати постійне ім'я як нуль для '0', але іноді це допомагає в читанні коду; наприклад, наявність цієї константи для нуля - "ROOT_TYPE_ID = 0" допоможе написати заяву на зразок if (id! = ROOT_TYPE_ID) {..}
Tech Junkie

6

Це через "інструментальне нанизування"

Можлива причина, яку я не бачу тут, - це те, що багато якісних інструментів позначають використання магічних чисел . Часто поганою практикою є магічні числа, кинуті в алгоритм, не роблячи їх чітко видимими для змін пізніше, особливо якщо вони дублюються в декількох місцях коду.

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

І коли це відбувається, іноді ви стикаєтесь з вибором:

  • позначаючи їх як помилкові позитиви, якщо інструмент дозволяє це (як правило, спеціально відформатований коментар, який дратує людей, які НЕ використовують цей інструмент)
  • або вилучення цих значень константам, важливо це чи ні.

Про продуктивність

Це залежить від мови, яку я здогадуюсь, але це досить поширене явище на Java і не впливає на продуктивність, оскільки значення вказуються під час компіляції, якщо вони є реальними константами static final. Це не вплине на C або C ++, якщо вони будуть оголошені як константи або навіть як макроси перед процесором.


5

Це може мати сенс, оскільки воно чітко визначає Zeroтип float.

Принаймні, в C і C ++ значення 0.0має тип double, а еквівалент float- 0.0f. Тож якщо припустити, що xти порівнюєш, це теж завжди є floatприказкою

x > 0.0

в той час як на самому ділі сприяють xдо doubleвідповідати типу , 0.0який може привести до проблем (з випробуваннями рівності особливо). Порівняння без перетворення, звичайно, було б

x > 0.0f

що робить те саме, що

float Zero = 0.0; // double 0.0 converted to float  
x > Zero

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


1

Перш за все, тут нуль визначається як float, ні int. Звичайно, це нічого не впливає на порівняння, але в інших випадках, коли ця константа використовується, це може мати значення.

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


1

Він майже точно такий же ефективний під час виконання (якщо ваш компілятор не дуже примітивний) і дуже трохи менш ефективний під час компіляції.

Щодо того, чи це читабельніше, ніж x > 0... пам’ятайте, що є люди, які чесно, щиро, думають, що COBOL була чудовою ідеєю і із задоволенням працювати - і тоді є люди, які точно так само думають про C. (Слух то , що існують навіть деякі програмісти з тим же думка про C ++!) іншими словами, ви НЕ збираєтеся отримати загальне згоду з цього питання, і це, ймовірно , не варто боротьба закінчилася.


0

[це] це насправді є більш ефективним, читабельним чи технічним, ніж:

if (x > 0.0) {..}

Якщо ви писали загальний (тобто нетиповий) код, дуже можливо. zero()Функція може застосовуватися до будь-якого алгебраїчного типу або будь-якого типу , який представляє собою групу WRT доповнення. Це може бути ціле число, це може бути значення з плаваючою комою, це може бути навіть функція, якщо ваша змінна - це, скажімо, сама функція в межах деякого лінійного простору (наприклад, x є лінійною функцією вигляду z -> a_x * z + b_x), а потім zero()забезпечує функцію з a і b, обидва є zero()базовим типом.

Тож можна очікувати такого коду, скажімо, на C ++, можливо, (хоча zero()це не дуже поширений AFAIK), або в Джулії, а може й інших мовах.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.