为什么在C中将1,000,000,000写为1000 * 1000 * 1000?


142

在Apple创建的代码中,有以下行:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

有什么理由表达1,000,000,0001000*1000*1000

为什么不1000^3这样做呢?


45
代码的清晰度和可读性。您不能在C中将或作为分隔符,因此,下一个最好的事情就是从乘法中计算值。^是C中的无关运算符-异或。
Iwillnotexist Idonotexist

54
它尤其适用于持续时间,例如:2 * 60 * 60 ..它很容易注意到,持续了2个小时
。.– Idali

53
我怀疑其中有1,000,000,000个语法无效
狗仔队

15
顺便说一下,现代编程语言还有另一种编写方法,例如在Swift中1_000_000_000。但是,使用时间常数会更加困难。编写30 * 60(30秒,秒)比编写更具可读性1800。实际上,有些语言可以让您编写单元,例如meters,可以保护自己免受错误分配的影响。
苏珊(Sulthan)2013年

29
^是XOR,不是指数或幂运算符。
3Dave

Answers:


200

以乘法方式声明常量的原因之一是提高了可读性,而运行时性能并未受到影响。同样,表明作者正在以乘法的方式思考数字。

考虑一下:

double memoryBytes = 1024 * 1024 * 1024;

显然比:

double memoryBytes = 1073741824;

因为后者乍一看并没有看起来是1024的三次方。

正如Amin Negm-Awad所述,^运算符是二进制XOR。许多语言缺少内置的编译时指数运算符,因此很难实现乘法运算。


13
在确实具有幂运算符的语言中,它不一定是“ ^”。例如,在Fortran中,它是“ **”。
jamesqf

4
您还应该包括一个指向重要警告的链接,该链接来自@chux,请参见下面的答案:stackoverflow.com/a/40637622/1841533(尤其是带有OP标签的“ c”,这很容易受到“手脚”的影响)边运算似乎将所有项限制为较小的类型,因此乘法可能会出现溢出问题)。 securecoding.cert.org/confluence/display/c / ...可能有助于避免一般情况下的发生?
Olivier Dulac

4
我们还应该注意,计算是在编译时完成的。C标准要求实现能够在编译时针对该语言的各种功能来计算常量表达式,并且可以安全地假定,当使用常量表达式时(如本例中所示),它是正确的。

13
存储的内存量是原来的两倍?这似乎是潜在的错误来源。
JAB 2016年

7
@supercat我知道这一点,但是通过使用double,可能会遇到一个情况,例如,您需要一部分内存范围,然后除以x得到子范围的大小...突然之间,您得到了一个小数字节,这可能需要其他逻辑来补偿。
JAB 2016年

73

为什么不1000^3呢?

结果1000^3为1003。^是bit-XOR运算符。

即使它不涉及Q本身,我也要澄清一下。x^y不能总是为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。你可以解释吗?
Mahesh

57
所述^操作装置在XOR C / C ++ /目标C等。在计算器它通常意味着X到所述-γ功率。
陶Zahola

5
ah,1000和3的位不重叠。这看起来错了。
Yakk-Adam Nevraumont

19
这些位确实重叠。但不是1。:-]
阿敏·内格姆·阿瓦德

6
@Yakk:的确如此,它看起来太错了!...我希望很多人不会认为“ A ^ B”总是会给A + B(但我担心有些可能...)
Olivier Dulac

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对于可以精确地表示为的值,也可以简单地使用符号double。当然,这会导致知道是否double可以精确表示整数值-大于1e9的值值得关注。(请参阅DBL_EPSILONDBL_DIG)。

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

5
非常重要的一句话! securecoding.cert.org/confluence/display/c/…在很多情况下可能会有所帮助?
Olivier Dulac

2
A double可以精确表示所有整数,最大为2 ^ 53≈9e15。
Edgar Bonet

3
@EdgarBonet确实,binary64可以表示大约9e15的整数。但是C并没有指定double使用binary64,即使它非常常用。根据C规范,可以精确表示高达1e9左右的值。这取决于您是要编写代码来规范还是依赖于常规做法。
chux-恢复莫妮卡

4
@Patrick 1000和和1000000000000都是整数常量。各自独立地具有选自式intlonglong long。编译器使用整数常量适合的3中的第一种类型。 1000 * 1000 * 1000 * 1000都是用int数学完成1000int。产品溢出32位int1000000000000 当然可以表示为long long(或可能更窄)-没有溢出。目标的类型long long Duration不影响“确定”的“右侧”。
chux-恢复莫妮卡

2
重要的是在乘法中首先放置较宽的类型。使用16位时intlong x = 1000 * 1000 * 1000L;会溢出,而long x = 1000L * 1000 * 1000;不会。
ex nihilo

51

为了提高可读性。

在零(1 000 000 0001,000,000,000)之间放置逗号和空格会产生语法错误,并且1000000000由于代码中包含逗号和空格,因此很难确切看到那里有多少个零。

1000*1000*1000显然是10 ^ 9,因为我们的眼睛可以更轻松地处理这些块。而且,没有运行时开销,因为编译器将用constant替换它1000000000


5
仅供参考,我最近了解了一个数字分隔符的概念。Java已经有一段时间了,而C#7.0可能会得到它。我希望所有语言都具有此功能。:)
iheartcsharp

1
根据使用的上下文1,000,000,000,不会产生语法错误,而只是表示其他含义。例如CMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
罗斯里奇(Ross Ridge)

2
如果您安装VS15预览版,@ JMS10 C#已经拥有它,可以这样写: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 _在数量上支持提高可读性(由Stephen Colebourne首次提出,是对Derek Foster的PROPOSAL: Project Coin / JSR 334的二进制文字答复)。一个人会1_000_000_000在这里写。

从最早的支持到最新的支持,按时间顺序排列:

对于语言来说,这是一个相对较新的功能,以实现它们应该支持的功能(然后是Perl)。就像chux @的一个很好的答案一样,1000*1000...它是部分解决方案,但是即使最终结果是大型类型,也可以使程序员免于溢出乘法的错误。


许多现代编程语言都具有相同的语言,例如Swift。没什么新鲜的。
苏珊(Sulthan)2016年

AFAIK,这来自Perl。PL / M将$用于相同目的,例如:0100 $
0010B

1
不过,这相当新的。Java功能可能已有5年历史了。支持此语法的大多数其他语言都是相当新的-Swift本身才成立几年。Python在3.6中增加了支持,该支持尚未发布。
johncip '16

2
Ada支持整数文字下划线已有33年了。
彼得-恢复莫妮卡

1
@djechlin:我可以随意添加更多信息,大致按时间顺序排列。之前我被弄错了,根据Project Coin线程判断,Stephen Colebourne可能会想到在Fandom和/或Ruby中使用整数下划线。Ruby可能是Perl的想法,而Ada是Perl的想法。
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我不建议您阅读Wikipedia文章来学习语言。
彼得-恢复莫妮卡

0

在C中获得十进制数字的类似效果的另一种方法是使用文字浮点表示法-只要双精度可以表示您想要的数字而不会损失任何精度。

IEEE 754的64位double可以表示任何非负整数<= 2 ^ 53,没有问题。通常,长双精度(80或128位)可能会更远。转换将在编译时完成,因此不会产生运行时开销,并且如果意外地降低了精度并且您拥有良好的编译器,您可能会收到警告。

long lots_of_secs = 1e9;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.