如果32位计算机只能处理最大2 ^ 32的数字,为什么我可以写1000000000000(万亿)而不使计算机崩溃?


370

32位计算机只能存储符号整数多达2 31 - 1。
这就是为什么我们已经用完IPv4地址,并已进入了64位时代。

然而,2数量31 - 1(2,147,483,647)不是作为我似乎能够没有我的机器崩溃显示细数1万亿(1,000,000,000,000)一样大。

有人可以解释为什么吗?


35
这个问题是有缺陷的。32位计算机可以处理比2 ^ 32大得多的数字。他们一直在做,用“长”等。它们最多只能在一个寄存器中存储2 ^ 32,但是编写软件来绕过此问题。一些现代语言甚至没有给定数字长度的问题。
JFA 2014年

23
请保持话题性,礼貌性和与问题的技术方面相关的评论。已经有将近50个笑话评论已被删除,我们希望避免锁定帖子。谢谢。
nhinkle

6
这个问题写得有点草率。“写”和“显示”数字1000000000000是什么意思?我想,当您写问题时,您写的数字是1000000000000,并且您的网络浏览器会很好地显示它,但是对于以前使用过计算机的任何人来说,这都不奇怪。这个问题要求免费翻译。
HelloGoodbye 2014年

7
据估计,人类意识大约持有50位(我在某处读取)。因此问题不是“如何10^9在PC不崩溃的情况下进行写?” 而是“我该如何书写10^(18)而不会崩溃?”
哈根·冯·埃岑

1
32位计算机只能存储最多2 ^ 32-1的UNSIGNED整数。2 ^ 32-1甚至不等于2,147,483,647 ... 300票赞成,没有人意识到吗?
Koray Tugay,2015年

Answers:


784

我通过询问另一个问题来回答您的问题:

您如何指望6?

您可能会用一只手数到最大数量,然后在手指用尽时继续使用第二只手。计算机做同样的事情,如果它们需要表示一个大于单个寄存器可以容纳的值,则它们将使用多个32位块来处理数据。


16
有趣,@ codename。那您如何指望32或更多(即2 ^ 5用尽一次)?;)举起另一只手的比喻是好的……即使二进制延迟了举起另一只手的需要。 我想看到的是,随着脚手灵巧,可以计数到1,024或更多,以便进一步用二进制数进行计数-多达1,048,575!:)这可能是20位子板电源。:P
J0e3gan 2014年

14
请保持话题性,并与讨论此答案的技术方面相关。此答案已删除了60多个笑话评论,我们希望避免锁定帖子。
nhinkle

@ codename-容易,您可以将一个手指分配为堆栈指针。一旦手指用完,就将金额添加到堆栈中并重新开始计数。
Makach 2014年

@codename是您在哪里学到的?我是从弗雷德里克·波尔(Frederik Pohl)那里首先听到的,请参见例如这里hjkeen.net/halqn/f_pohl3.htm
赞恩(Zane)

2
我认为这不是有关问题的答案。@ Bigbio2002的回答是正确的。此处的“ 1000000000000”不是数字,而是文本,就像“ adsfjhekgnoregrebgoregnkevnregj”一样。您的发言是对的,但我强烈认为这不是正确的答案。看到如此多的投票...
师父大师

398

您是正确的,一个32位整数不能包含大于2 ^ 32-1的值。但是,此32位整数的值以及它在屏幕上的显示方式是完全不同的两件事。内存中未使用32位整数表示打印的字符串“ 1000000000000”。

要从字面上显示数字“ 1000000000000”,需要13个字节的内存。每个单独的字节最多可以保存255个值。它们都不能保存整个数字值,但是可以分别解释为ASCII字符(例如,字符' 0'由十进制值48,二进制值表示00110000),它们可以串成一种对您(人类)有意义的格式。


编程中的一个相关概念是类型转换,即计算机将如何解释0s和1s 的特定流。如以上示例所示,它可以解释为数值,字符或什至完全是其他内容。尽管32位整数可能无法保存1000000000000的值,但使用完全不同的解释,32位浮点数将能够。

关于计算机如何在内部处理和处理大量数字,存在64位整数(可容纳多达160亿个值),浮点值以及可以与任意大数一起使用的专用库。数字。


22
实际上,这大部分是正确的,但并非完全正确。一个32点浮点数不太可能能够准确地表示1000000000000。它将表示一个非常非常接近所需数字的数字,但并不完全是该数字。
Tim B

6
@TimB:您听说过decimal32格式吗?它是IEEE 754-2008标准的一部分。这种格式能够正确表示该数字:)
VX

15
是的,那可以。但是,这不是人们所说的“ float”时所指的格式,通常指的是当前计算机中标准浮点处理器存储和使用的32位浮点数。
Tim B

2
@TimB确实。与可以表示为float32的数字最接近的数字是999999995904
greggo 2014年

4
@TimB:但是一个64位浮点数可以很容易地1000000000000准确表示。是10 ^ 12或2 ^ 12 * 5 ^ 12; 5 ^ 12需要28位尾数。
基思·汤普森

191

首先,最重要的是,32位计算机在单个机器字中最多可以存储2³²-1的数字。机器字是CPU可以自然处理的数据量(即,对这种大小的数据的操作是在硬件中实现的,通常执行速度最快)。32位CPU使用32位组成的字,因此它们可以在一个字中存储0到2³²-1的数字。

二,1万亿万亿是两回事。

  • 1万亿是数字的抽象概念
  • 1000000000000是文本

1一次,然后按012次,即可输入文本。1输入10输入0。看到?您正在输入字符。字符不是数字。打字机根本没有CPU或内存,它们很好地处理了这些“数字”,因为它只是文本。

证明万亿不是一个数字,而是文本:它可能意味着1万亿(十进制),4096(二进制)或281474976710656(十六进制)。在不同的系统中它具有更多的含义。1000000000000的含义是数字,存储它是一个不同的故事(我们稍后会再讲)。

要存储文本(在编程中称为string1000000000000,您需要14个字节(每个字符一个,再加上一个终止NULL字节,基本上意味着“字符串在此结束”)。那是4个机器单词。3和一半就足够了,但是正如我所说,对机器字的操作最快。让我们假设ASCII用于文本存储,所以在内存中看起来就像这样:(对应转换为ASCII码01二进制,在一个单独的行每个单词)

00110001 00110000 00110000 00110000
00110000 00110000 00110000 00110000
00110000 00110000 00110000 00110000
00110000 00000000 00000000 00000000

一个字中包含四个字符,其余的将移至下一个。其余的将移至下一个字,直到所有内容(包括第一个NULL字节)都适合为止。

现在,回到存储数字。它的工作原理与溢出文本一样,但是它们从右到左都是适合的。听起来可能很复杂,所以这里有个例子。为了简单起见,我们假设:

  • 我们的假想计算机使用十进制而不是二进制
  • 一个字节可以容纳数字 0..9
  • 一个字由两个字节组成

这是一个空的2字内存:

0 0
0 0

让我们存储数字4:

0 4
0 0

现在让我们添加9:

1 3
0 0

请注意,两个操作数都适合一个字节,但不适合结果。但是我们还有一个可供使用。现在让我们存储99:

9 9
0 0

同样,我们使用了第二个字节来存储数字。让我们添加1:

0 0
0 0

糟糕...这就是整数溢出,是许多严重问题的成因,有时甚至是非常昂贵的问题

但是,如果我们期望溢出会发生,我们可以这样做:

0 0
9 9

现在添加1:

0 1
0 0

如果删除字节分隔的空格和换行符,它将变得更加清晰:

0099    | +1
0100

我们已经预测可能会发生溢出,并且可能需要更多的内存。用这种方式处理数字的速度不如用单个单词填入数字的速度快,它必须在软件中实现。在32位CPU中添加对两个32位字数字的支持实际上使其成为64位CPU(现在它可以在本地以64位数字运行,对吗?)。

我上面描述的所有内容也适用于具有8位字节和4字节字的二进制存储器,其工作方式几乎相同:

00000000 00000000 00000000 00000000 11111111 11111111 11111111 11111111    | +1
00000000 00000000 00000000 00000001 00000000 00000000 00000000 00000000

但是,将此类数字转换为十进制是很棘手的。(但对于十六进制来说效果很好


21
您的答案读得很少。OP显然是在谈论数字,而不是文字:large as the number 1 trillion (1000000000000)。此外,你几乎在谈论高精度计算,但你从来没有真正提到任何条款对你说的话....
MirroredFate

12
“ 1万亿”也是一个字符串
Elzo Valugi 2014年

3
@ElzoValugi是的。我必须找到某种方式来表示抽象数字的概念,而不是代表数字的字符串。我相信“ 1万亿”是一种更好且不太模糊的方法(请参见答案)。
gronostaj 2014年

25
@MirroredFate我不同意“显然是在谈论数字”。OP说“显示良好”,这显然在向我讲文字“ 1000000000000” ...
2014年

4
@yannbane'A'是一个字符,而不是数字。'?' 是字符而不是数字。“ 1”是一个字符,而不是数字。字符只是符号。它们可以代表数字或数字,但绝对不是数字。“ 1”可以代表一,十,十万,一千,依此类推,它只是一个代表数字的符号,可以是数字或数字的一部分。“ 10”(字符串)可以表示两个或八个或十个或十六个等。但是当您说有十个苹果时,您使用的数字为十,每个人都知道您的意思。字符和数字之间存在巨大差异。
gronostaj 2014年

40

您还可以写“此声明是虚假的”而不会导致计算机崩溃:) @Scott的答案在某些计算框架上是正确的,但是您“写”大量的问题意味着它只是纯文本,至少直到它被解释了。

编辑:现在少嘲讽用不同方式的更多有用信息的数量可以存储在内存中。我将以更高的抽象性来描述它们,即现代程序员可能在将代码转换为机器代码以执行之前编写代码。

必须将计算机上的数据限制为某种类型,并且这种类型的计算机定义描述了可以对该数据执行哪些操作以及如何执行(即比较数字,连接文本或对布尔值进行XOR)。您不能简单地将文本添加到数字中,就像不能将数字乘以文本一样,因此其中一些值可以在类型之间转换。

让我们从无符号整数开始。在这些值类型中,所有位都用于存储有关数字的信息。你是一个的例子32位无符号整数,其中来自任何值02^32-1可以被存储。是的,根据所使用平台的语言或体系结构,您可以使用16位整数或256位整数。

如果您想消极怎么办?直观上,带符号的整数是游戏的名称。公约是从分配的所有值-2^(n-1)2^(n-1)-1-这样,我们避免处理两种方式来写的混乱+0-0。因此,一个32位带符号整数将保存一个从-2147483648到的值2147483647。整洁,不是吗?

好的,我们已经介绍了整数,即没有小数部分的数字。表达这些信息比较棘手:非整数部分只能合理地位于0和之间1,因此用来描述它的每多一个位都会提高其精度:1 / 2、1 / 4、1 / 8 ...问题是,您不能精确地将简单的小数表示0.1为分母的总和,分母只能具有2的幂!将数字存储为整数会更容易,但是同意将基数(小数点)放进去吗?这称为定点数,我们在其中存储1234100但同意将其作为1234.100替代阅读的约定。

用于计算的相对较常见的类型是floating point。它的工作方式确实很整洁,它使用一位存储符号值,然后使用一点存储指数和有效位数。有一些定义这种分配的标准,但是对于32位浮点数,您可以存储的最大数量是压倒性的

(2 - 2^-23) * 2^(2^7 - 1) ≈ 3.4 * 10^38

但是,这是以精度为代价的。浏览器中可用的JavaScript使用64位浮点数,但仍然无法解决问题。只需将其复制到地址栏中,然后按Enter。剧透警报:结果将不会0.3

javascript:alert(0.1+0.2);

还有更多替代类型,例如Microsoft .NET 4.5 BigInteger,理论上没有上限或下限,必须以“批”为单位进行计算;但是也许更引人入胜的技术是那些了解数学的技术,例如Wolfram Mathematica引擎,它可以精确地与infinity等抽象值一起使用。


8
您可以在现实中做到这一点。尝试在《星际迷航》中做到这一点。由于所有的火花和烟雾,只是退后一步。
迈克尔·彼得罗塔

这不完全是定点的工作方式。实际上,这是一个系统,其中数字按比例缩放和偏差以产生小数点。在您的示例中,比例为1/1000,但也有如下定点数(尤其是在计算机图形学中):0 = 0.0、255 = 1.0-比例为1/255。
Andon M. Coleman 2014年

31

关键是要了解计算机如何编码数字。

的确,如果一台计算机坚持使用一个单词(在32位系统上为4个字节)使用数字的简单二进制表示形式存储数字,则32位计算机最多只能存储2 ^ 32的数字。但是,还有许多其他方式可以对数字进行编码,具体取决于您希望通过数字实现什么。

一个示例是计算机如何存储浮点数。计算机可以使用多种不同的方式对它们进行编码。标准IEEE 754定义了对大于2 ^ 32的数字进行编码的规则。粗略地,计算机可以通过将32位划分为代表数字的一些数字的不同部分和代表数字的大小的其他位(即指数10 ^ x)来实现。这允许更大的范围的数量,但会影响精度(在很多情况下都可以)。当然,计算机也可以使用一个以上的单词进行此编码,从而提高了可用编码数字的大小的精度。IEEE标准的简单十进制32版本允许数字的精度为大约7个十进制数字,并且其数量级最大为10 ^ 96。

但是,如果需要更高的精度,还有许多其他选择。显然,您可以无限制地在编码中使用更多的单词(尽管会影响性能的转换和转换为编码格式)。如果您想探索一种实现方法,可以使用Excel的一个很棒的开源插件,该插件使用一种编码方案,允许数百位的计算精度。该加载项称为Xnumbers,可在此处获得。该代码在Visual Basic中不是最快的方法,但是具有易于理解和修改的优点。这是学习计算机如何实现较长数字编码的好方法。而且您可以在Excel中试用结果,而不必安装任何编程工具。


24

这都是您的问题。

您可以在纸上任何您喜欢的数字。尝试在白纸上写上万亿点。它缓慢且无效。这就是为什么我们有一个10位数字的系统来表示这些大数字。我们甚至可以使用诸如“ million”,“ trillion”之类的大数字来命名,因此您不必one one one one one one one one one one one...大声说出来。

32位处理器被设计为使用正好为32个二进制数字的内存块来最快,最有效地工作。但是我们人们通常使用10位数字系统,而计算机是电子的,则使用2位系统(二进制)。数字32和64恰好是2的幂。百万和一兆是10的幂。例如,与许多65536相比,使用这些数字进行操作更容易。

当我们在纸上书写时,我们会将大数字分解为数字。计算机将数字分解为更多的数字。我们可以写下我们喜欢的任何数字,如果我们这样设计的话,计算机也可以写下。


15

32位和64位是指存储器地址。您的计算机内存就像邮政信箱,每个邮箱都有不同的地址。CPU(中央处理单元)使用这些地址来寻址RAM(随机存取存储器)上的存储器位置。当CPU只能处理16位地址时,您只能使用32mb RAM(当时看起来很大)。使用32位时,它达到了4 + gb(在当时看来是巨大的)。现在我们有了64位地址,RAM达到了TB(看起来非常大)。
但是,程序可以为存储数字和文本之类的事情分配多个内存块,这取决于程序,并且与每个地址的大小无关。因此,程序可以告诉CPU,我将使用10个地址块进行存储,然后存储一个非常大的数字或10个字母字符串或其他内容。
旁注:内存地址由“指针”指向,因此32位和64位值表示用于访问内存的指针的大小。


2
除细节外,答案都很好-16位地址空间为您提供了64kb,而不是32mb,像286这样的机器具有24位地址(为16mb)。同样,使用64位地址,您可以超越TB级-更像是16 EB-TB大约是当前一代主板/ CPU所施加的限制类型-而不是地址的大小。
Phil

4
32位是指机器字的大小,而不是内存地址。正如Phil所提到的,286是16位CPU,但使用24位通过内存分段进行寻址。x86 CPU是32位,但使用36位寻址。参见PAE
gronostaj 2014年

@gronostaj井x86具有从386到Pentium的32位寻址。
Ruslan 2014年

支持,因为这是这里唯一正确的答案-32位是指32位存储器寻址,而不是32位算术。
user1207217 2014年

@ user1207217:?? 那么根据您的推理,例如Z80或8080是16位处理器(因为16位内存寻址和内存总线)?
pabouk 2014年

13

因为显示数字是使用单个字符而不是整数完成的。数字中的每个数字都用单独的字符文字表示,其整数值由所使用的编码定义,例如'a',用ascii值表示97,而用'1'表示49。在此处检查ascii表
用于显示“ a”和“ 1”是相同的。它们是字符文字,而不是整数。在32位平台中,每个字符文字的最大值为255,以8位或1字节大小存储该值(这取决于平台,但是8位是最常见的字符大小),因此可以将它们分组在一起并且可以显示。它们可以显示多少个单独的字符取决于您的RAM。如果只有1个字节的RAM,则只能显示一个字符;如果只有1GB的RAM,则可以很好地显示1024 * 1024 * 1024个字符(太懒了。)

但是,此限制适用于计算,但是我想您对IPV4标准感兴趣。尽管它并不完全与计算机的bit-size,这在某种程度上影响了标准。创建IPV4标准时,他们将ip值存储为32位整数。现在,一旦您确定了尺寸,它便成为标准尺寸。我们对互联网的了解都依赖于此,然后我们用光了IP地址来分配。因此,如果将IP标准修改为具有64位,则所有东西都将停止工作,包括您的路由器(我认为这是正确的)和其他网络设备。因此,必须创建一个新的标准,只需将32位整数与128位整数交换即可。并调整其余标准。硬件制造商只需要声明他们支持这一新标准,它就会大受欢迎。虽然不是那么简单,但是我想您已经明白了。

免责声明:这里提到的大多数观点都符合我的假设。为了简化起见,我可能错过了要点。我对数字不好,所以一定错过了一些数字,但是我的意思是要回答OP的回答,为什么它不会使PC崩溃。


2
我没有投票,但是您的答案有很多问题。1在ASCII中为0x31,而不是0x1。1 GB = 1024 ^ 3B。在引入32位CPU之前发明了IPv4,因此说地址是以32位整数存储的,这与OP的问题相冲突。最后,IPv6使用的是128位地址,而不是64位。
gronostaj 2014年

13

在处理器中,有“单词”。有不同的词。人们说“ 32位处理器”时,主要指的是“存储器总线宽度”。该词由不同的“字段”组成,这些字段是指与传输(24位)和控制(其他位)相对应的计算机子系统。我可能对确切的数字有误,请通过手册确定自己的确切数字。

完全不同的方面是计算。SSE和MMX指令集可以存储长整数。在不损失生产力的前提下,最大长度取决于当前的SSE版本,但始终约为64位的倍数。

当前的Opteron处理器可以处理256位宽的数字(我不确定整数,但可以肯定使用浮点数)。

摘要:(1)总线宽度未直接与计算宽度相连;(2)甚至不同的字(内存字,寄存器字,总线字等)也未相互连接,否则它们的公约数大约为8或16或24.许多处理器甚至使用6位字(但它的历史记录)。


并非如此,原始的Pentium处理器即使是32位处理器,也具有用于高内存带宽的64位数据总线。8088是带有8位数据总线的16位处理器。
doug65536

10

通常,计算设备的目的是接受,处理,存储和发出数据。底层硬件仅仅是帮助执行这四个功能的机器。没有软件,它就无法做到。

软件是告诉机器如何接受数据,如何处理数据,如何存储数据以及如何将其提供给他人的代码。

基础硬件将始终具有局限性。对于32位计算机,处理数据的大多数寄存器只有32位宽。但是,这并不意味着机器不能处理2 ^ 32以上的数字,这意味着如果您要处理更大的数字,则机器可能需要一个以上的周期来接受,处理和存储该数字。或发出它。

该软件告诉机器如何处理数字。如果该软件设计为处理大数,则它将向CPU发送一系列指令,告诉其如何处理大数。例如,您的数字可以由两个32位寄存器表示。如果要在数字上加1,234,软件会告诉CPU首先在低位寄存器上加1,234,然后检查溢出位以查看该加法是否导致该数字对于低位寄存器而言太大。如果是这样,则将1加到高位寄存器。

就像教小学生加进位一样,可以告诉CPU处理大于单个寄存器中可以容纳的数字。对于大多数通用数学运算,对于任何实际大小的数字,都是如此。


10

不同之处在于我们在计算机中存储数据的方式。

您是正确的,对于理论上的8位计算机,我们只能在单个处理器寄存器或内存地址中存储2 ^ 8的值。(请记住,根据所使用的处理器,内存体系结构等的不同,“机器”可能会有所不同。但是现在,让我们继续使用假设的“定型”机器。)

对于理论上的16位计算机,寄存器/内存位置中的最大值为2 ^ 16,对于32位计算机,最大值为2 ^ 32,依此类推。

多年来,程序员已经设计出各种各样的方法来存储和处理大于单个处理器寄存器或存储器地址中可以存储的数字。存在许多方法,但是它们都涉及使用多个寄存器/存储器地址来存储大于其“本机”寄存器/存储器位置宽度的值。

所有这些方法的好处在于,机器可以存储/处理大于其本机容量的值。缺点是几乎所有方法都需要多个机器指令/读取/等。处理这些数字。对于偶尔出现的大量用户,这不是问题。当处理大量的大量(大内存地址尤其是)所涉及的开销会减慢速度。

因此,通常希望使寄存器,存储器位置和存储器地址硬件“更宽”,以便“本地”处理大量数字,从而可以用最少的操作数来处理这些数字。

由于数字大小是无限的,因此处理器寄存器/内存大小/寻址始终是本机数字大小与实现越来越大的宽度所涉及的成本之间的平衡。


8

32位计算机在一个机器字中最多只能存储2 ^ 32的数字,但这并不意味着它们不能处理更大的数据实体。

32位计算机的含义通常是数据总线和地址总线为32位宽,这意味着计算机可以一次处理4 GB的内存地址空间,并一次通过数据总线发送四个字节的数据。

但是,这并不限制计算机处理更多数据,它只需要在通过数据总线发送数据时将数据分成四个字节的块即可。

常规的Intel 32位处理器可以在内部处理128位数字,这使您可以毫无问题地处理类似100000000000000000000000000000000000000000000的数字。

您可以处理比计算机大得多的数字,但是计算必须由软件完成,CPU没有处理大于128位数字的指令。(它可以以浮点数的形式处理更大的数字,但随后只有15位精度。)


6

只需在其他答案中添加注释,因为这是该问题中一个非常重要的事实,已经被遗漏了。

“ 32位”是指存储器地址的宽度。它与寄存器大小无关。许多32位CPU可能具有64位甚至128位寄存器。特别是对于x86产品线,最近的全都是64位的消费类CPU具有多达256位的特殊用途寄存器。

寄存器宽度和地址宽度之间的这种差异自古以来就存在,那时我们只有4位寄存器和8位地址,反之亦然。

很容易看出,不管寄存器大小如何,存储大量数字都没有问题,如其他答案所述。

不论大小如何,寄存器也可以使用更大的数量进行计算的原因是,太大的计算可以分解为几个较小的,适合寄存器的计算(只是稍微复杂一点)事实上)。


这不是真的。64位指的是不一致的,但是寄存器宽度为64位的系统通常称为64位。维基百科说:“ 64位计算机体系结构通常具有64位宽的整数和寻址寄存器”。是的,现代的x86(或AMD-64)产品线具有庞大的专用寄存器,但它们具有64位主寄存器并可以访问48-52位的内存。较早的x86系统具有32位主寄存器并可以访问24-36位存储器,而8086被称为16位芯片,具有16位宽的寄存器并可以访问20位存储器。
prosfilaes 2014年

@prosfilaes这是很多有价值的信息,我指的是这些信息(我和您一样都忘记了细节)。随时将其编辑为答案。
mafu 2014年

6

已经给出的答案实际上是很好的,但是它们倾向于从不同角度解决这个问题,因此不完整。我认为它们也有点技术性。

因此,仅是为了澄清其他答案中暗示但未明确表达的内容,我认为这是问题的症结所在:

您在问题中混淆了几个概念,其中一个(“ 32位”)实际上可以指代各种不同的事物(并且不同的答案采用不同的解释)。这些概念都与在各种计算上下文中使用(或可用)的位数(1和0)有关(我的意思是希望通过下面的示例进行阐明),但是这些概念在其他方面无关

明确地:

  • “ IPv4 / 6”是指Internet协议,它是一组定义如何在Internet上打包和解释信息的规则。IPv4和IPv6之间的主要区别(或至少最广为人知的区别)是IPv6中的地址空间(即可用于区分网络上不同位置的地址集)更大。这与在网络上发送的每个数据包中的多少位分配给(即留出目的)标识该包的发送方和预期的接收方有关。
    • 非计算类比:每个数据包就像通过蜗牛邮件发送的一封信,地址空间就像您在信封上写地址和返回地址时“允许”使用的字符数。
    • 到目前为止,我还没有在其他任何答案中提到此问题。
  • 通常可以将计算机内存“字”(32位和64位)视为计算机使用或“思考”的最小数据段。这些数据位共同构成其他数据位,例如大块文本或更大的整数。
  • 32位指针可能是单词,也可能不是单词,但是它们还是被原子地处理的(即,不能分解成更小的组件的单个单元)。指针是计算机可以在内存中记录任意数据块的位置的最低级别的方法。请注意,计算机(或实际上是操作系统)使用的指针大小限制了单个指针可以访问的内存范围,因为指针可以“指向”尽可能多的内存位置因为指针本身有可能的值。这类似于IPv4限制可能的Internet地址范围的方式,但没有限制例如特定网页中可能存在的数据量。然而,指针大小不限制数据本身到该指针可以指向的大小。(有关允许数据大小超出指针范围的方案的示例,请查看Linux的inode指针结构。请注意,“指针”一词的用法与典型用法略有不同,因为指针通常是指指向的指针。随机存取内存,而不是硬盘空间。)
    • 非计算类比:嗯……这有点棘手。也许用于索引库资料的Dewey十进制系统有点相似?或任何索引系统,真的。
    • 请参阅SiteNook的答案
    • 请注意,我对上述指针的解释省略了一些细微的细节,可以说并不是完全正确的。但是,在程序员直接使用指针工作的编程语言中,我所描绘的思维模式通常足以满足实际目的。
  • 数字,一个计算机是“能够显示”不(出于实用的目的)由计算机的硬件或操作系统的限制; 它们像其他任何文本一样被对待。

注意,这并不是要成为短语“ 32位”的全面解释列表。

额外的功劳:要真正了解数字和计算机内存的原始块之间的基本哲学区别,请阅读有关Turing机器的一些文章


我认为对IPv4的引用是要指出,IPv4地址的数量实际上限制为带符号的32位整数的长度,而IPv6使用128位,因此可以具有多个数量级的地址。
Clonkex

@Clonkex可能,尽管绝对不是问题所在。
Kyle Strand'7

5

例如,如果您在计算器中写入1000000000000,则计算机会将其计算为带小数点实型数字。您提到的32位限制会触及所有不带小数点的所有整数类型数字。不同的数据类型使用不同的方法来获取位/字节。

整数类型数字:此表可以帮助您理解要点(http://msdn.microsoft.com/zh-cn/library/296az74e.aspx)。这触及了C ++的限制。例如,Int64类型号的限制为-9223372036854775808至9223372036854775807。

实型数字:实型数字包含带浮点数指数的值,您可以输入大得多的数字,但准确性/精度有限。(http://msdn.microsoft.com/zh-cn/library/6bs3y5ya.aspx)例如,C ++中的LDBL(大双精度)的最大指数为308,因此,您可以输入或具有结果编号9.999 x 10^308,表示您将理论上有308(+1)个数字,9但只有15个最重要的数字将被用来表示它,其余的将丢失,这是因为精度有限。

此外,存在不同的编程语言,并且它们可能具有数量限制的不同实现。因此,您可以想象,专用应用程序可以比C ++处理更大(和/或更精确/精确)的数字。


这个“答案”是不正确的:计算器使用BCD数字表示法以避免截断错误。IE 0.1十进制不能精确表示为有限长度的二进制数。
木屑

5

如果您想要一个典型的Linux系统上有多少个程序处理大量处理和输出的实际示例:

libgmp- 在GNU多精度运算库就是为了这个目的在Linux系统上使用最广泛的图书馆。一个简单的例子,将2 ^ 80乘以1000:

#include <gmp.h>

// Each large integer uses the mpz_t type provided by libgmp
mpz_t a_large_number;
mpz_t base;
mpz_t result;

// Initalize each variable
mpz_init(a_large_number);
mpz_init(base);
mpz_init(result);

// Assign the number 2 to the variable |base|
mpz_set_ui(base, 2);

// Raise base^80 (2^80), store the result in |a_large_number|
mpz_pow_ui(a_large_number, base, 80);

// Multiply |a_large_number| by 1000, store the result in |result|
mpz_mul_ui(result, a_large_number, 1000);

// Finally, output the result in decimal and hex notation
gmp_printf("decimal: %Zd, hex: %ZX\n", result, result);

因此,基本上它与使用常规+-* /运算符相同,只是使用一个库来分解数字并将其内部存储为多个机器字大小(即32位)的数字。还有scanf()类型函数,用于处理将文本输入转换为整数类型。

的结构mpz_t与斯科特·张伯伦(Scott Chamberlain)的用两只手计数到6的示例完全一样。它基本上是一个由机器单词大小mp_limb_t类型组成的数组,当数字太大而无法容纳一个机器单词时,GMP将使用倍数mp_limb_t来存储数字的高/低部分。


5

在您的脑海中,您只会知道10个不同的数字。0到9。在您的大脑内部,它的编码方式肯定与在计算机中不同。

计算机使用位对数字进行编码,但这并不重要。那只是工程师选择编码的方式,但是您应该忽略它。您可以认为它是一台32位计算机,具有超过40亿个不同值的唯一表示形式,而我们人类却具有10个不同值的唯一表示形式。

每当我们必须理解更大的数量时,我们都会使用系统。最左边的数字是最重要的。它比下一个重要得多。

一台能够区分40亿个不同值的计算机,同样必须使一组值中最左边的值的重要性是该组中下一个值的40亿倍。实际上,计算机根本不在乎。它不会为数字分配“重要性”。程序员必须编写特殊的代码来解决这一问题。

每当一个值大于唯一符号的数量(在人类头脑中为9)时,您就在左侧的数字上加一个。

3+3=6

在这种情况下,数字仍然适合单个“插槽”

5+5=10. This situation is called an overflow.

因此,人类总是会遇到没有足够的独特符号的问题。除非计算机具有用于处理此问题的系统,否则它将只写0,而忘记会有多余的数字。幸运的是,在这种情况下,计算机具有一个“溢出标志”。

987+321 is more difficult.

您可能在学校学习了一种方法。一种算法。该算法非常简单。首先添加最左边的两个符号。

7+1=8, we now have ...8 as the result so far

然后,您移至下一个插槽并执行相同的添加。

8+2=10, the overflow flag is raised. We now have ...08, plus overflow.

由于我们有一个溢出,这意味着我们必须在下一个数字上加1。

9+3=12, and then we add one due to overflow. ...308, and we had another overflow.

没有更多可添加的数字,因此我们只创建了一个插槽和插入器1,因为引发了溢出标志。

1308

计算机的操作方式完全相同,不同之处在于计算机具有2 ^ 32甚至更好的2 ^ 64个不同的符号,而不是像人类一样只有10个符号。

在硬件级别,计算机使用完全相同的方法处理单个位。幸运的是,这对于程序员来说是抽象的。位只有两位数字,因为这很容易在电源线中表示。指示灯点亮或熄灭。

最后,计算机可以将任何数字显示为简单的字符序列。那就是计算机最擅长的。用于在字符序列和内部表示之间进行转换的算法非常复杂。


看来,我知道36个,但通常只使用16个。
Kyle Strand 2014年

“一台计算机使用位对数字进行编码,但这并不重要。” 在用户询问大约32位字以及如何使用它们存储大于2 ^ 32-1的数字的情况下,这一点非常重要。
HörmannHH

在大脑的记忆中如何编码数字并不重要。您有数量有限的表示形式;大多数人学会了10种不同的符号。在大脑内部,这可能以数千个神经元和突触的形式表示。在计算机中,它以电力或电力线上无电的形式表示。从编程的角度来看-或在学习数学时,这根本不重要,除非在极少数情况下直接针对一组特定的CPU进行编程。他要的是32位和64位,而不是单个位。
frodeborli 2014年

3

因为您不是在显示数字(就计算机而言),而是显示字符串或数字序列。当然,我猜有些处理数字的应用程序(例如计算器)可以处理这样的数字。我不知道他们使用了什么技巧……我敢肯定,还有其他一些更详尽的答案可以解决这个问题。


0

该答案的大部分内容最初来自此答案(在该其他问题标记为重复之前写的)。因此,我讨论了使用8位值(即使这个问题询问的是32位值),但这没关系,因为8位值在概念上更易于理解,并且相同的概念适用于较大的值,例如32位算术。

当您将两个8位数字相加时,可以获得的最大数字(0xFF + 0xFF = 1FE)。实际上,如果将两个8位数字相乘,则可获得的最大数字(0xFF * 0xFF = 0xFE01)仍然是16位,是8位的两倍。

现在,您可能假设x位处理器只能跟踪x位。(例如,一个8位处理器只能跟踪8位。)这是不准确的。8位处理器以8位块的形式接收数据。(这些“块”通常有一个正式术语:“字”。在8位处理器上,使用8位字。在64位处理器上,可以使用64位字。)

因此,当您为计算机提供3个字节时:
字节#1:MUL指令
字节#2:高位字节(例如0xA5)
字节#3:低位字节(例如0xCB)
计算机可以生成以下结果:超过8位。CPU可能会生成如下结果:
0100 0000 0100 0010 xxxx xxxx xxxx xxxx 1101 0111
aka:
0x4082xxxxD7
现在,让我为您解释一下:
0x仅表示以下数字为十六进制。
我将暂时详细讨论“ 40”。
82是“ A”寄存器的一部分,该寄存器是一系列8位。
xx和xx是另外两个寄存器的一部分,分别称为“ B”寄存器和“ C”寄存器。我没有用零或一填充这些位的原因是“ ADD”指令(发送给CPU)可能导致这些位未被该指令更改(而本例中我使用的大多数其他位可能会被更改,除了一些标志位)。
D7将适合更多的位,称为“ D”寄存器。
寄存器只是一块内存。寄存器内置于CPU中,因此CPU无需访问RAM棒上的内存即可访问寄存器。

因此,0xA5乘以0xCB的数学结果为0x82D7。

现在,为什么将这些位拆分为A和D寄存器而不是A和B寄存器,或C和D寄存器?好吧,再次,这是我正在使用的示例场景,在概念上与真实的汇编语言(Intel x86 16位,如Intel 8080和8088以及许多较新的CPU使用)非常相似。可能存在一些通用规则,例如“ C”寄存器通常用作计数操作的索引(对于循环而言是典型的),而“ B”寄存器则用于跟踪有助于指定存储位置的偏移量。因此,对于某些常见的算术函数,“ A”和“ D”可能更常见。

每条CPU指令应具有一些文档,供汇编程序的人员使用。该文档应指定每个指令使用哪些寄存器。(因此,有关使用哪个寄存器的选择通常由CPU的设计人员指定,而不是由汇编语言程序员指定。尽管有一定的灵活性。)

现在,回到上面的示例中的“ 40”:这是一系列位,通常称为“标志寄存器”。标志寄存器中的每个位都有一个名称。例如,如果结果大于可以存储结果一个字节的空间,则CPU可能会设置一个“溢出”位。(“溢出”位通常用缩写为“ OF”来表示。这是一个大写的o,而不是零。)软件可以检查该标志的值并注意到“问题”。使用此位通常是由高级语言来进行的,因此,初学者通常不了解如何与CPU标志进行交互。但是,汇编程序员通常可以以与其他变量非常相似的方式访问其中一些标志。

例如,您可能有多个ADD指令。一个ADD指令可能将16位结果存储在A寄存器和D寄存器中,而另一条指令可能只是将8个低位存储在A寄存器中,忽略D寄存器,并指定溢出位。然后,稍后(将A寄存器的结果存储到主RAM中之后),您可以使用另一条ADD指令,该指令仅将8个高位存储在一个寄存器(可能是A寄存器)中。是否需要使用溢出标志可能会取决于您使用的乘法指令。

(通常也有一个“下溢”标志,以防您减去太多而无法达到所需的结果。)

只是向您展示事情变得多么复杂:
Intel 4004是4位CPU
Intel 8008是8位CPU。它有一个名为A,B,C和D
的8位寄存器。Intel8086是16位CPU。它具有名为AX,BX,CX和DX的16位寄存器。
英特尔80386是32位CPU。它具有名为EAX,EBX,ECX和EDX的32位寄存器。
Intel x64 CPU具有名为RAX,RBX,RCX和RDX的64位寄存器。x64芯片可以运行16位代码(在某些操作模式下),并且可以解释16位指令。这样做时,组成AX寄存器的位是组成EAX寄存器的位的一半,也就是组成RAX寄存器的位的一半。因此,无论何时更改AX的值,也都在更改EAX和RAX,因为AX使用的那些位是RAX使用的位的一部分。(如果您将EAX更改为65,536的倍数,则低16位不变,因此AX不会更改。如果您将EAX更改为非65,536的倍数,那么也会影响AX )

除了我已经提到的标志和寄存器之外,还有更多的标志和寄存器。我只是选择了一些常用的例子来提供一个简单的概念示例。

现在,如果您使用的是8位CPU,则在写入内存时,可能会遇到一些限制,即不能引用4位或16位地址,而只能引用8位地址。具体细节因CPU而异,但是如果您有此类限制,则CPU可能正在处理8位字,这就是为什么CPU最常被称为“ 8位CPU”的原因。


我觉得我的答案有些重复了这个问题的其他一些答案。但是,当我第一次编写内容时并没有注意到这一点,因为我是为另一个问题编写的。另外,虽然我很欣赏Animism的回答,其中包括一些用C语言编写的代码,但我仍感到内容提供了一些有关Assembly如何工作的详细信息,这更接近于CPU的实际操作/设计。因此,我的答案并不是试图成为优于所有其他答案的高级答案,而只是补充性的;添加其他观点和更多见解
TOOGAM
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.