Навіщо писати 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.