Навіщо писати 1 000 000 000 як 1000 * 1000 * 1000 в C?


142

У коді, створеному Apple, є такий рядок:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

Чи є якась причина виразити 1,000,000,000як 1000*1000*1000?

Чому б не 1000^3з цього питання?


45
Чіткість та читаність коду. Ви не можете ставити або як "роздільники в C", тому наступне найкраще - обчислити значення з множення. ^ - неспоріднений оператор в С - винятково АБО.
— Iwillnotexist Idonotexist

54
він особливо використовується для тривалості, як: 2 * 60 * 60 .. легко помітити, що це на 2 години ..
— Ідалі

53
Для одного я підозрюю, що 1 000 000 000 є неправдивим синтаксисом
— папараццо

15
До речі, сучасні мови програмування мають альтернативний спосіб писати те саме, наприклад у Swift 1_000_000_000. Однак із константами часу це складніше. Писати краще 30 * 60(30 хвилин за секунди), ніж читати, ніж писати 1800. Насправді існують мови, які дозволять писати одиниці, наприклад meters, дозволяючи захистити себе від поганих завдань.
— Султан

29
^- це XOR, а не показник чи оператор живлення.
— 3Dave

Відповіді:


200

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

Врахуйте це:

double memoryBytes = 1024 * 1024 * 1024;

Це явно краще, ніж:

double memoryBytes = 1073741824;

оскільки останній, на перший погляд, не виглядає третьою силою 1024 року.

Як згадував Амін Негм-Авад, ^оператор є двійковим XOR. У багатьох мовах не вистачає вбудованого оператора експоненції часу компіляції, отже, множення.


13
І в мовах, які мають оператор експоненції, це не обов'язково '^'. Наприклад, у Fortran це "**".
— jamesqf

4
Ви повинні також включати в себе посилання , що вказує на важливе застереження, дане у відповідь нижче, від @chux: stackoverflow.com/a/40637622/1841533 (особливо в ОП з тегами «с», який дуже чутливий до цього «RIGH рук Здається, в боковій операції всі терміни обмежені меншим типом, і тому множення може переповнювати проблему). securecoding.cert.org/confluence/display/c/… може допомогти уникнути цих у загальному випадку?
— Олів'є Дулак

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

13
Збереження кількості пам'яті як подвійне? Це здається потенційним джерелом помилок.
— JAB

7
@supercat Я знаю про це, але, використовуючи подвійний, у вас може виникнути випадок, коли, скажімо, ви хочете частину діапазону пам'яті, ви розділите на, xщоб отримати розмір піддіапазону ... і раптом у вас є дробовий байт, який може потребувати додаткової логіки для компенсації.
— JAB

73

Чому ні 1000^3?

Результат 1000^31003. ^Оператор біт-XOR.

Навіть це не стосується самого Q, я додаю уточнення. x^yце НЕ завжди обчислюватися , x+yяк це робить в прикладі запитувача в. Доводиться ходити по шматочках. У випадку прикладу:

1111101000₂ (1000₁₀)
0000000011₂ (3₁₀)
1111101011₂ (1003₁₀)

Але

1111101001₂ (1001₁₀)
0000000011₂ (3₁₀)
1111101010₂ (1002₁₀)

3
сер, мені не ясно, як 1003 ^ 3 - це 1003. Калькулятор Google і Mac показує 1000 ^ 3 = 1 000 000 000. ти можеш пояснити?
— Махеш

57
^Оператор виключають коштів в C / C ++ / Objective-C і т.д. В обчислювачах це зазвичай означає й-к-у влади.
— Тамас Захола

5
Так, біти 1000 і 3 не перетинаються. Це виглядає так неправильно.
— Якк - Адам Невраумон

19
Біти перекриваються. Але не 1-е. : -]
— Амін Негм-Авад

6
@Yakk: дійсно, це виглядає так неправильно! ... Я сподіваюсь, що багато людей не подумають, що "A ^ B" завжди дає A + B (але я боюся, що деякі можуть ...)
— Олів'є Дулак

71

Є причини не використовувати 1000 * 1000 * 1000.

З 16-біт int, 1000 * 1000переливається. Тож використання 1000 * 1000 * 1000зменшує мобільність.

У 32-розрядному intваріанті наступний перший рядок коду переповнюється.

long long Duration = 1000 * 1000 * 1000 * 1000;  // overflow
long long Duration = 1000000000000;  // no overflow, hard to read

Запропонуйте, щоб значення провідних даних відповідало типу призначення для читабельності, переносимості та правильності.

double Duration = 1000.0 * 1000 * 1000;
long long Duration = 1000LL * 1000 * 1000 * 1000;

Також можна було б просто використовувати eпозначення для значень, які точно представлені як a double. Звичайно, це призводить до того, чи doubleможна точно представляти ціле число значення - щось, що стосується значень більше 1e9. (Див. DBL_EPSILONІ DBL_DIG).

long Duration = 1000000000;
// vs.
long Duration = 1e9;

5
Дуже важливе зауваження! securecoding.cert.org/confluence/display/c/… може допомогти у багатьох випадках?
— Олів'є Дулак

2
A doubleможе точно представляти всі цілі числа до 2 ^ 53 ≈ 9e15.
— Едгар Бонет

3
@EdgarBonet Правда, що binary64 може представляти ціле число до приблизно 9e15. Але C не вказує doubleвикористання бінарного64, хоча він дуже часто використовується. Згідно зі специфікацією C, значення до 1e9 або близько того є точно представними. Це залежить від того, чи хочете ви кодувати специфікації або покладатися на звичайну практику.
— chux

4
@Patrick Обидва 1000і 1000000000000є цілими константами . Кожен незалежно від має тип, обраний із int, longабо long long. Компілятор використовує перший тип з тих 3, в яких ціла константа вписується. 1000 * 1000 * 1000 * 1000робиться з intматематикою, як кожен 1000в а int. Продукт переповнюється 32-бітним int. 1000000000000 це, безумовно, репрезентабельно як long long(або, можливо, вужчий) - без переливу. Тип цілі long long Durationне впливає на цю "праву частину детемінації =".
— chux

2
Розміщення ширшого типу спочатку у множенні важливо. З 16-бітним int, long x = 1000 * 1000 * 1000L;переповнюється, тоді як long x = 1000L * 1000 * 1000;ні.
— ex nihilo

51

Для читабельності.

Розміщення коми і пробілів між нулями ( 1 000 000 000або 1,000,000,000) призведе до синтаксичної помилки, а наявність 1000000000у коді ускладнює точне визначення кількості нулів.

1000*1000*1000стає очевидним, що це 10 ^ 9, тому що наші очі можуть легше обробляти шматки. Крім того, немає витрат на виконання, оскільки компілятор замінить його постійним 1000000000.


5
FYI, існує концепція розділювачів цифр, про яку я дізнався нещодавно. У Java це є вже деякий час, і C # 7.0 може отримати його. Я б хотів, щоб усі мови мали цю особливість, що стосується цукерок. :)
— iheartcsharp

1
Залежно від контексту використання 1,000,000,000 який не використовує синтаксичну помилку, це означатиме щось інше. НаприкладCMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
— Росс Ридж

2
@ JMS10 C # вже є, якщо встановити попередню версію VS15, можна записати як1_000_000_000
— user1306322

2
Python отримує і _як роздільник :)
— Wayne Werner

2
А C ++ нещодавно отримав 'роздільник, в C ++ 14, тож ви можете використовувати 1'000'000'000. (Вибрано його через те, що 1,000,000,000його можна неправильно інтерпретувати як оператор коми або 4 різних параметра, і _1_000_000_000є дійсним (але, ймовірно, поганим) ім'ям змінної.)
— Час Джастіна - Поновіть Моніку

27

Для читабельності. Для порівняння, Java підтримує _чисельність для поліпшення читабельності (вперше запропонована Стівеном Колбурном як відповідь на Пропозиція Дерека Фостера: Бінарні літерали для проектної монети / JSR 334). Тут можна було б написати 1_000_000_000.

Приблизно в хронологічному порядку, від найдавнішої підтримки до найновішої:

Це відносно нова функція для мов зрозуміти, що вони повинні підтримувати (і тоді є Perl). Як і в чудовій відповіді chux @, 1000*1000...це часткове рішення, але відкриває програмісту помилки від переповнення множення, навіть якщо кінцевий результат великого типу.


Багато сучасних мов програмування мають однакове, наприклад, Swift. Нічого нового.
— Султан

AFAIK, це походить від Perl. PL / M використовували $ з тією ж метою, наприклад: 0100 $ 0010B
— ninjalj

1
Хоча це досить нове. Функція Java, можливо, 5 років. Більшість інших мов, що підтримують цей синтаксис, є досить новими - самому Свіфтові лише кілька років. Python додає підтримку в 3.6, яка ще не була випущена.
— johncip

2
Ада підтримує підкреслення в цілих буквах вже 33 роки.
— Пітер - Відновіть Моніку

1
@djechlin: Я взяв на себе сміливість додавати більше інформації, приблизно в хронологічному порядку. Я раніше помилявся, судячи з нитки Project Coin, Стівен Колборн, ймовірно, взяв ідею підкреслення в цілих літералах від Fandom та / або Ruby. Імовірно, Рубі взяла ідею від Perl, а Perl - від Ada.
— ніндзя

7

Можливо, простіше читати і отримувати деякі асоціації з 1,000,000,000формою.

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

Якщо ви говорите про aim-c, то 1000^3це не спрацює, оскільки немає такого синтаксису для pow (це xor). Натомість pow()функцію можна використовувати. Але в цьому випадку це не буде оптимальним, це буде виклик функції виконання, а не константа, створена компілятором.


3

Для ілюстрації причин розглянемо наступну програму тестування:

$ cat comma-expr.c && gcc -o comma-expr comma-expr.c && ./comma-expr
#include <stdio.h>

#define BILLION1 (1,000,000,000)
#define BILLION2 (1000^3)

int main()
{
        printf("%d, %d\n", BILLION1, BILLION2);
}
0, 1003
$

1
@pjvandehaar Я б не рекомендував вивчати мову, читаючи статті Вікіпедії.
— Пітер - Відновіть Моніку

0

Ще один спосіб досягти подібного ефекту в C для десяткових чисел - це використання буквальних позначень з плаваючою комою - до тих пір, поки подвійний може представляти потрібне вам число без втрати точності.

64-розрядний подвійний IEEE 754 може представляти будь-яке невід'ємне ціле число <= 2 ^ 53 без проблем. Зазвичай довгий подвійний (80 або 128 біт) може піти навіть далі. Перетворення буде здійснено під час компіляції, тому немає накладних витрат часу, і ви, швидше за все, отримаєте попередження, якщо станеться несподівана втрата точності та у вас хороший компілятор.

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