【问题标题】:How is an integer stored in memory?整数如何存储在内存中?
【发布时间】:2013-09-02 07:18:20
【问题描述】:

这很可能是任何人都会问的最愚蠢的问题,但无论如何我希望我能找到一个明确的答案。

我的问题是 - 整数如何存储在计算机内存中?

在 c# 中,整数的大小为 32 位。 MSDN 说我们可以在整数变量中存储从 -2,147,483,648 到 2,147,483,647 的数字。

据我了解,位只能存储 2 个值,即 0 和 1。如果我只能存储 0 或 1,我将如何在位中存储数字 2 到 9?

更准确地说,假设我有这个代码int x = 5;这将如何在内存中表示,或者换句话说,5 是如何转换为 0 和 1 的,其背后的约定是什么?

【问题讨论】:

  • 作为线索,您可能想搜索“二进制如何工作”、“如何将十进制转换为二进制”等。:-)
  • 我们每天使用的数字只能是 0 到 9,但我们可以表示更大的数字。你刚刚在你的帖子里做到了!这都是关于数字相对于小数的位置。

标签: c# binary twos-complement


【解决方案1】:

它以二进制(以 2 为基数)表示。 Read more about number bases。在 base 2 中,您只需要 2 个不同的符号来表示一个数字。我们通常使用符号01。在我们通常的基础中,我们使用10 不同的符号来表示所有数字,012、...89

为了比较,请考虑一个不适合我们通常系统的数字。比如 14。我们没有 14 的符号,那么我们如何表示呢?很简单,我们只需将两个符号 14 组合起来。 14 以 10 为底表示 1*10^1 + 4*10^0

1110 in base 2 (binary) 表示1*2^3 + 1*2^2 + 1*2^1 + 0*2^0 = 8 + 4 + 2 + 0 = 14。因此,尽管在任一基中都没有足够的符号来用单个符号表示 14,但我们仍然可以在两个基中表示它。

在另一个常用的基数中,基数为 16,也称为十六进制,我们有足够的符号来表示 14,只使用其中一个。您通常会看到 14 使用十六进制符号 e 书写。

对于负整数,我们使用一种方便的表示形式,称为二元补码,它是补码(所有 1s 翻转为 0,所有 0s 翻转为 1s)加上一个。

之所以如此方便,主要有两个原因:

  • 通过查看单个位(我们使用的32 中最重要的位),我们可以立即知道一个数字是正数还是负数。

  • 这在数学上是正确的 x - y = x + -y 使用常规加法,就像你在小学学到的一样。这意味着如果处理器已经有加法,则处理器不需要做任何特殊的事情来实现减法。他们可以简单地找到y 的二进制补码(回想一下,翻转位并加一),然后使用他们已有的加法电路添加xy,而不是使用特殊的减法电路。

【讨论】:

    【解决方案2】:

    这根本不是一个愚蠢的问题。

    让我们从 uint 开始,因为它稍微容易一些。约定是:

    • 一个 uint 中有 32 位。每个位都分配了一个从 0 到 31 的数字。按照惯例,最右边的位是 0,最左边的位是 31。
    • 取每个位数并将 2 提高到该次方,然后将其乘以该位的值。因此,如果第 3 位为 1,则为 1 x 23。如果第 12 位为零,则为 0 x 212
    • 将所有这些数字加起来。这就是价值。

    所以五个将是 00000000000000000000000000000101,因为 5 = 1 x 20 + 0 x 21 + 1 x 22 + .. . 其余的都是零。

    那是uint。整数的约定是:

    • 将值计算为uint
    • 如果该值大于或等于 0 且严格小于 231,那么您就完成了。 int 和 uint 值相同。
    • 否则,从 uint 值中减去 232,这就是 int 值。

    这似乎是一个奇怪的约定。我们使用它是因为事实证明很容易构建以这种格式执行算术运算的芯片。

    【讨论】:

    • 换句话说,uint 使用以 2 为基数。将此与以 10 为基数进行对比,其中一个将 205 表示为 205,因为 205 = 2*10^2 + 0*10^1 + 5*10^0
    【解决方案3】:

    二进制的工作方式如下(作为您的 32 位)。

       1  1  1  1 | 1  1  1  1 | 1  1  1  1 | 1  1  1  1 | 1 1 1 1 | 1 1 1 1 | 1 1 1 1 | 1 1 1 1
    
    2^ 31 30 29 28  27 26 25 24  23 22 21 20  19 18 17 16......................................0
       x
    

    x = 符号位(如果为 1,则为负数,如果为 0,则为正数)

    所以最大的数字是0111111111............1(除了负位之外的所有1),即2^30 + 2 ^29 + 2^28 +...... ...+2^1 + 2^0 或 2,147,483,647。

    最低的是1000000.........0,表示-2^31或-2147483648。

    【讨论】:

    • 二进制补码没有符号位。例如,零没有符号。
    • 它确实有一个符号位。这是一个讨论其工作原理的 SO 问题:stackoverflow.com/questions/1049722/what-is-2s-complement.
    • 关于 sign bit 问题...这取决于您的定义。 1 的补码和 2 的补码中的有符号整数都有一个位,您可以测试它是否为负数,这通常称为表示的 符号位。然而,一些定义要求你能够通过简单地翻转符号位来否定一个数字......你当然不能用 1 或 2 的补码表示。
    【解决方案4】:

    这就是高级语言导致的!?哎呀!

    正如其他人所说,这是一个以 2 为底的计数系统。人类天生就是以 10 为底的计数器,尽管由于某种原因,时间是以 60 为底,而 6 x 9 = 42 以 13 为底。艾伦·图灵显然擅长以 17 为底的心算。

    计算机在 base 2 中运行,因为电子设备很容易打开或关闭 - 代表 1 和 0,这就是 base 2 所需的全部内容。您可以以打开、关闭或关闭电子设备的方式构建电子设备在。。。之间的某处。那将是 3 个状态,允许您进行三级数学(而不是二进制数学)。然而,可靠性降低了,因为很难分辨这三种状态之间的区别,而且电子设备要复杂得多。更多的级别会导致更差的可靠性。

    尽管它是在多级单元闪存中完成的。在这些存储单元中,每个存储单元代表开、关和许多中间值。这提高了容量(每个单元可以存储几个位),但对可靠性来说是个坏消息。这种芯片用于固态驱动器,它们在完全不可靠的边缘运行,以最大限度地提高容量。

    【讨论】:

    • 没有必要以贬义评论开头。有一天你不知道这一点,一天后你知道了。今天是迈克的一天。
    • 有趣的事实:在某些领域普遍使用以 60 为底的起源存在争议,但一个主要起源是巴比伦数学,其中计数符号使用以 10 和 60 为底的组合,以十为单位计数但以 60 而不是 100 结尾,并将其用作更高数字的单位。
    • 是的,这就是高级语言的结果。我还可以指出,不必知道触发器电路中的电压电平代表什么是语言所导致的。您是否因为不知道人字拖中的电压水平而错过了什么?
    • @EricLippert,好吧,让我们看看。对于很多程序员来说,这并不是最盲目的区别。业界存在的问题是,有相当多的编程需要很好地了解源代码的电子后果(以及功率和热量;这些对谷歌等公司来说真的很重要)。例如,有多少程序员知道内存分配实际上是什么,为什么在很多情况下你可能想尽可能避免它?了解您的硬件,以便在重要时编写有用的代码。
    • @EricLippert;此外,我可以追溯到一个你必须知道这些东西才能获得 TTY“Hello, World”的东西的时代。我们当时学到的关于“计算机实际上是什么”的所有知识对于任何有志于升级操作的人来说都具有巨大的价值。另外,作为一个老顽固,我很惊讶有人可以在不了解一些基本知识的情况下达到 C#。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 2012-10-25
    • 2010-12-22
    • 2012-06-28
    • 1970-01-01
    相关资源
    最近更新 更多