Зачем писать 1000000000 как 1000 * 1000 * 1000 на C?

143

В коде, созданном Apple, есть такая строка:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

Есть ли причина выражать 1,000,000,000как 1000*1000*1000?

Почему не 1000^3в этом отношении?

Утка
источник
46
Четкость и читабельность кода. Вы не можете использовать, или 'в качестве разделителей в C, поэтому следующий лучший вариант - вычислить значение путем умножения. ^ - несвязанный оператор в C - исключающее ИЛИ.
Iwillnotexist Idonotexist
54
он особенно используется для таких длительностей, как: 2 * 60 * 60 .. его легко заметить, что это для 2
часов
53
С одной стороны, я подозреваю, что 1000000000 недопустимый синтаксис
папараццо
15
Кстати, в современных языках программирования есть альтернативные способы написания того же самого, например, на Swift 1_000_000_000. Однако с постоянными времени это труднее. Писать легче 30 * 60(30 минут в секундах), чем писать 1800. На самом деле существуют языки, которые позволят вам писать модули, например meters, позволяющие защитить себя от неправильных назначений.
Sulthan
29
^- это XOR, а не показатель степени или оператор мощности.
3ave

Ответы:

202

Одна из причин объявлять константы мультипликативным способом - это улучшить читаемость, при этом это не повлияет на производительность во время выполнения. Также, чтобы указать, что писатель думал о числе в мультипликативной манере.

Учти это:

double memoryBytes = 1024 * 1024 * 1024;

Это явно лучше, чем:

double memoryBytes = 1073741824;

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

Как упомянул Амин Негм-Авад, ^оператор является двоичным XOR. Во многих языках отсутствует встроенный оператор возведения в степень во время компиляции, отсюда и умножение.

Петр Фальковски
источник
13
И в языках, в которых есть оператор возведения в степень, это не обязательно '^'. В Фортране, например, это '**'.
jamesqf
4
Вы также должны включить ссылку, указывающую на важное предостережение, данное в ответе ниже, от @chux: stackoverflow.com/a/40637622/1841533 (особенно если OP помечен как "c", который очень восприимчив к этому 'правому боковая операция, похоже, имеет все термины, ограниченные меньшим типом, и поэтому умножение может переполнить проблему). securecoding.cert.org/confluence/display/c/… может помочь избежать их в общем случае?
Olivier Dulac
4
Также следует отметить, что вычисления выполняются во время компиляции. Стандарт C требует, чтобы реализация могла вычислять константные выражения во время компиляции для различных функций языка, и мы можем с уверенностью предположить, что это верно, когда константное выражение используется, как в этом примере.
ouah
13
Сохранение количества памяти в двойном размере? Это похоже на потенциальный источник ошибки.
JAB
7
@supercat Я знаю об этом, но при использовании double у вас может быть случай, когда, скажем, вам нужна часть диапазона памяти, вы делите на, xчтобы получить размер поддиапазона ... и вдруг у вас есть дробная byte, для компенсации которой может потребоваться дополнительная логика.
JAB
73

А почему бы и нет 1000^3?

Результат 1000^3- 1003. ^- это битовый оператор XOR.

Даже если это не касается самого Q, добавлю уточнение. не всегда x^yдает оценку, как в примере вопрошающего. Вы должны xor каждый бит. В случае примера:x+y

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

Но

1111101001₂ (1001₁₀)
0000000011₂ (3₁₀)
1111101010₂ (1002₁₀)
Амин Негм-Авад
источник
3
сэр, я не понимаю, как 1003 ^ 3 равно 1003. Google и Mac Calculator показывают 1000 ^ 3 = 1 000 000 000. Вы можете объяснить?
Махеш
58
^Оператор исключающих средств в C / C ++ / Objective-C и т.д. В вычислителях это обычно означает й-к-у власти.
Tamás Zahola
5
Ба, биты 1000 и 3 не перекрываются. Это выглядит так неправильно.
Yakk - Adam Nevraumont
19
Биты действительно перекрываются. Но не единицы. : -]
Амин Негм-Авад
6
@Yakk: действительно, это выглядит так неправильно! ... Я надеюсь, что многие люди не подумают, что "A ^ B" всегда дает A + B (но я боюсь, что некоторые могут ...)
Оливье Дюлак
72

Есть причины не использовать 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нотацию для значений, которые точно могут быть представлены как double. Конечно, это приводит к знанию того, doubleможно ли точно представить целое числовое значение - что вызывает беспокойство при значениях больше 1e9. (См. DBL_EPSILONИ DBL_DIG).

long Duration = 1000000000;
// vs.
long Duration = 1e9;
chux - восстановить Монику
источник
5
Очень важное замечание! securecoding.cert.org/confluence/display/c/… может помочь во многих случаях?
Olivier Dulac
2
A doubleможет точно представлять все целые числа до 2 ^ 53 ≈ 9e15.
Эдгар Боне
3
@EdgarBonet Истинно, что binary64 может представлять целое число до 9e15. Но C не определяет doubleиспользование binary64, хотя он очень часто используется. Согласно спецификации 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
К вашему сведению, есть концепция разделителей цифр, о которой я недавно узнал. У 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 также становится _разделителем :)
Уэйн Вернер
2
А в C ++ недавно появился 'разделитель в C ++ 14, так что вы можете использовать 1'000'000'000. (Это было выбрано, потому что 1,000,000,000могло быть неверно истолковано как оператор запятой или 4 различных параметра, и _1_000_000_000это действительное (но, вероятно, неправильное) имя переменной.)
Джастин Тайм - Восстановить Монику
27

Для удобочитаемости. Для сравнения, Java поддерживает _числа для улучшения читаемости (впервые предложено Стивеном Колебурном в ответ на ПРЕДЛОЖЕНИЕ Дерека Фостера: двоичные литералы для Project Coin / JSR 334). Здесь можно было бы написать 1_000_000_000.

Примерно в хронологическом порядке, от самой старой поддержки до самой новой:

Это относительно новая функция для языков, позволяющая понять, что они должны поддерживать (а также Perl). Как и в превосходном ответе chux @, 1000*1000...это частичное решение, но оно открывает программисту возможность ошибок из-за переполнения умножения, даже если конечный результат имеет большой тип.

Джехлин
источник
То же самое есть во многих современных языках программирования, например Swift. Ничего нового.
Sulthan
AFAIK, это происходит из Perl. PL / M использовали $ для той же цели, например: 0100 $ 0010B
ninjalj
1
Это является довольно новым, хотя. Функциональности Java, возможно, 5 лет. Большинство других языков, поддерживающих этот синтаксис, довольно новы - самому Swift всего несколько лет. Python добавляет поддержку в версии 3.6, которая еще не выпущена.
johncip
2
Ада поддерживает подчеркивание в целочисленных литералах уже 33 года.
Питер - Восстановите Монику
1
@djechlin: Я позволил себе добавить больше информации, примерно в хронологическом порядке. Раньше я ошибался, судя по ветке Project Coin, Стивен Коулборн, вероятно, взял идею подчеркивания в целочисленных литералах от Фэндома и / или Руби. Руби, вероятно, позаимствовал идею у Perl, а Perl - у Ada.
ninjalj
7

Возможно, будет проще прочитать и вызвать ассоциации с 1,000,000,000формой.

С технической точки зрения, думаю, нет никакой разницы между прямым числом и умножением. В любом случае компилятор сгенерирует его как постоянное число в миллиард.

Если говорить о objective-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. Как правило, long double (80 или 128 бит) может идти даже дальше. Преобразования будут выполняться во время компиляции, поэтому нет накладных расходов во время выполнения, и вы, вероятно, получите предупреждения, если произойдет неожиданная потеря точности и у вас хороший компилятор.

long lots_of_secs = 1e9;
jschultz410
источник