为何在编程时使用其他数字基数


35

我和我的同事一直在思考,以找出为什么有人会以除10为底的底数来编程数字。

我建议您也许可以通过将变量放置在要使用的正确基数中来优化较长的方程(例如,如果您只有5组东西而没有余数,则可以使用5基数),但是我不确定如果是真的。

有什么想法吗?


6
您是否有提出这个问题的具体示例?以2为基础或以16为基础的事物显然具有其优势,因为计算机更容易理解。
KDiTraglia 2012年

4
“在基数中编程数字”应该是什么意思?有数字。期。它们在内部以某种基础表示,但多数情况下都没有关系,并且不会更改任何算术规则。

12
@JMD-请与主持人一起删除您的两个交叉发布之一,并在P.SE中放置一个。跨站点交叉发布的想法不那么普遍。该国防部可以代替您迁移问题。

10
@JMD-交叉发布仍然不是您应该执行的操作。如果需要,可以针对此类问题进行迁移。
奥德

2
@JMD不要交叉发布,非常适合一个以上站点的问题非常少见。例如,这一次,您的问题不在Stack Overflow上。但是,即使您的问题同时适用于这两个站点,在站点周围购物的问题通常还是不受欢迎。我们所有人都在这里度过自己的时间,您可能至少需要等待一段时间才能评估在交叉发布之前在Stack Overflow上获得的答案。
扬尼斯,2012年

Answers:


59

除了以10为基数以外,用代码写数字的通常原因是因为您有点纠结。

举一个C语言的例子(因为C语言对任何事物都有利,它对位纠缠也很有用),说一些低级格式在一个字节中编码一个2位和一个6位数字xx yyyyyy

main() {
    unsigned char codevalue = 0x94; // 10 010100
    printf("x=%d, y=%d\n", (codevalue & 0xc0) >> 6, (codevalue & 0x3f));
}

产生

x=2, y=20

在这种情况下,用十六进制写常数要比用十进制写常数要容易些,因为一个十六进制数字整齐地对应于四个位(半字节;一个“半字节”)和两个对应于一个字节:该数字0x3f包含所有位在低半字节中设置,在高半字节中设置两位。

您也可以用八进制写第二行:

printf("x=%d, y=%d\n", (codevalue & 0300) >> 6, (codevalue & 077));

这里,每个数字对应于一个三比特的块。有些人觉得更容易思考,尽管我认为这几天很少见。


另一个示例可能是“魔术数” 0xDEADBEEF的使用。看到这篇文章stackoverflow.com/questions/5907614/0xdeadbeef-vs-null
Etsitpab Nioliv

45

我使用不同基准的主要原因是当我关心位时。

它更容易阅读

int mask=0xFF;
byte bottom_byte = value & mask;

int mask=255;
byte bottom_byte = value & mask;

或更复杂的图像

int mask=0xFF00FF00;
int top_bytes_by_word = value & mask;

相比

int mask=4278255360; //can you say magic number!? 
int top_bytes_by_word = value & mask;

在此非常清楚十六进制示例的用意是什么,因为十六进制基本上只是二进制的一种更紧凑的形式...相比之下,base-10(我们使用的)与二进制的映射关系不佳。

0xFF = b11111111 = 255
0xFFFF = b1111111111111111 = 65536
0xF0F0 = b1111000011110000 = 61680

您还可以使用某些语言使用其他基础。除了二进制,十六进制和十进制之外,您几乎没有使用其他基数。一些奇数的人仍然使用八进制,但这是在理智的程序中看到的最深奥的东西。


2
八进制一点也不罕见,0八进制:)(看到Stack Exchange网络上的某个地方,现在找不到它)。
Gerrit 2012年

2
@Earlz:有很多手指的人。:-)
布赖恩·奥克利

3
26 x 2 + 10 =所有大写和小写字母以及所有数字。真的不是那么不寻常。我还看到使用Base 36,这只是相同的不区分大小写的版本。
Darrel Hoffman

3
@vasile:一小时内有60分钟,一分钟内有60秒,因为人们使用的是base-60系统,而不是相反。我希望您不要相信自然界中有东西会说一小时必须有60分钟!
Joren 2012年

1
是的,他们在星空读取它,并且它们以60为基,因为这是时间的度量。一年360天(= 6x60),以60为基数衡量时间并不是那么疯狂。
YTG

8

您可能知道,计算机基于二进制文件-这是基于2的。

在基数2和4、8和16(以及2的倍数)之间进行转换很容易,并且将这种转换保留在源代码中可以使处理数字变得更加容易。

对于汇编语言和C语言之类的低级语言,这可以直接转换为处理器操作(例如,用于除法和乘法的位移位),这意味着使用这些数字基最终会产生更快的代码。

此外,并非所有运算都是数字运算-您确实需要在位图上直接摆弄这些位图-使用以2为底的整数或整数倍可以简化运算。

如果您想了解更多信息,建议阅读Charles Petzold的Code


3
编译器没有该死的。虽然在列出的基数之间进行转换确实确实比较容易,但是针对基数10的简单(缓慢的)转换也不难,而且大多数对编译器构造有用的语言(您不使用汇编语言)都具有转换可在其标准库中获得,因此编译器实际上是免费的。

1
在C中使用十六进制不会转化为更快的程序。编译器不在乎您使用什么基础。
查尔斯·索尔维亚

5
无论程序以什么基础编写,编译器都会在编译时将其转换为二进制。组装说明相同。
Karl Bielefeldt 2012年

2
企业计算机实际上基于三元组:正确,错误和“找不到文件”
Martin Beckett 2012年


4

除了高度专业化的程序外,很少使用10、16或2以外的基数。

基数16(十六进制)非常有用,因为字节的整个范围(0-255)可以用两位数字(0x00-0xFF)表示,这可以使原始十六进制转储或二进制数据的使用变得更加容易。当使用带位运算符的位掩码时,十六进制也很有用,因为与字节对应的两位数字有助于提高可读性。

极少数情况下,基数2(二进制)也可以与按位运算一起使用,但是许多编程语言不支持基数2的文字,而且十六进制反而更加简洁易读。

由于UNIX文件许可权,有时也使用Base-8(八进制)。除此之外,在高度专业化的数学环境之外使用除10以外的基数是非常罕见的。


八进制通常用于指定字符值,有时用于转储二进制数据。
卡勒布(Caleb)2012年

3

使用其他基数的最常见的正当理由与转换为基数2的难易程度有关:将基数为8或基数为16的数字转换为二进制数而无需使用计算器,只需记住8或16的简短表就很容易了数字:

 0000 0     0001 1     0010 2     0011 3
 0100 4     0101 5     0110 6     0111 7

 1000 8     1001 9     1010 A     1011 B
 1100 C     1101 D     1110 E     1111 F

这带来了多种可能性:

  • 当数字表示有意义的二进制数的组成时,无需计算机即可确定各个组件。例如,如果一个24位的数表示在RGB颜色,它是微不足道的,以告诉0xFF00FF品红(红+蓝); 当你出现时,任务要困难得多16711935
  • 当数字表示位掩码时,将其记为紧凑的十六进制数而不是更长的二进制数更实用
  • 某些体系结构竭尽全力使二进制代码以八进制数打印时易于阅读。PDP-11是这样一种系统:最高有效位可以让您区分16位操作中的8位操作;最后两个八进制组将让您告诉操作中涉及的两个寄存器,依此类推。我知道有几个人可以在不使用反汇编程序的情况下从屏幕上读取PDP-11二进制代码,但是他们需要将机器代码打印在八进制系统中。

2

计算机(或更准确地说是编译器)实际上根本不在乎您在源代码中使用的数字基数。最常用的编程语言直接支持基数8(八进制),10(十进制)和16(十六进制)。有些还直接支持基数2(二进制)的数字。专门的语言也可能支持其他数字基础。(通过“直接支持”,我的意思是它们允许在该基数中输入数字,而无需在源代码本身中诉诸数学技巧,例如移位,乘法,除法等。例如,C直接以其支持基数16。0x数字前缀和常规十六进制数字集0123456789ABCDEF。现在,这些技巧可能有助于使数字更易于理解,但是只要您在没有数字的情况下也可以表达相同的数字,这样做(或不这样做)只是一种方便。)

最后,这是无关紧要的。假设您有如下声明:

int n = 10;

目的是创建一个整数变量,并使用十进制数字10对其进行初始化。计算机会看到什么?

i  n  t     n     =     1  0  ;
69 6e 74 20 6e 20 3d 20 31 30 3b (ASCII, hex)

编译器将对此进行标记化,并意识到您正在int使用name 声明类型的变量n,并为其分配一些初始值。但是那个值是多少?

对于计算机而言,忽略字节顺序和对齐问题,该变量的初始值输入为0x31 0x30。这是否意味着初始值为0x3130(以10为底的12592)?当然不是。语言解析器必须继续使用所使用的字符编码来读取文件,因此它先读取1 0后跟语句终止符。由于假定使用该语言的基数为10,因此(向后)读为“ 0个,1个十进制,结尾”。即,值为十进制。

如果我们以十六进制指定一个值,并且我们的语言用于0x指定以下值以十六进制表示,那么我们将得到以下内容:

i  n  t     n     =     0  x  1  0  ;
69 6e 74 20 6e 20 3d 20 30 78 31 30 3b (ASCII, hex)

编译器将看到0x(0x30 0x78)并将其识别为以16为底的前缀,因此将在其后寻找有效的以16为底的数字。直到语句终止符为为止10。这将转换为0“ 1”,1“ 16”,在基数10中等于16。或者在基数2中等于00010000。或者,您也可以代表它。

在这两种情况下,为了简单起见,编译器都忽略了优化,它分配了足够的存储空间来保存int类型变量的值,并将从源代码中读取的值放置到某种临时的保存变量中。然后(可能要晚得多)将结果二进制值写入目标代码文件。

如您所见,在源代码中编写数值的方式完全无关紧要。它可能对编译时间有很小的影响,但我可以想象(再次忽略操作系统的磁盘缓存之类的优化)诸如磁盘旋转盘周围的随机湍流,磁盘访问时间,数据总线冲突之类的事情。等等,效果要大得多。

底线:不用担心。在您选择的编程语言支持的基础上写数字,这对于如何使用和/或读取数字很有意义。您花了更多的时间来阅读此答案,这比通过巧妙地在源代码中使用哪个数字基数来节省编译时间要多得多。;)


1

为什么有人会用除10以外的底数来编程数字

以下是一些尚未出现的原因...

x00-某些操作系统和硬件设备的API期望参数为十六进制/二进制。当您为此类API编写代码时,使用数字与API期望的格式相同的数字更容易,而不是在不同的基数之间进行转换。例如,将消息字节的结尾发送到服务器或发送消息以关闭与通信通道的连接。

x01-您可能希望您的应用程序代表某些键盘上不可用的字符,例如版权符号(\ u00a9)。

x02-在不同的区域性设置中(在视觉上)保留一些常量/文字,特别是当源代码/文件在具有不同本地设置的开发人员之间移动时。

x03-使他们的代码看起来混乱和复杂-好是C#不支持八进制常量!


1

关键问题在于以合理的方式表示单个计算机大小。6502是8位处理器。4004是4位处理器。

当处理4或8位数字时,效果很好。4位数字是单个十六进制字符。8位数字(一个字节)是两个十六进制数字。具有2字大小幂的系统是当今常见的标准-16位,32位,64位。所有这些都很好地除以4以表示为十六进制。

八进制(基数8)用于单词大小为12、24或36的系统中。PDP8,IBM Mainframe和ICL 1900早已使用。使用八位字节而不是有限范围的十六进制更容易表示这些单词(是的,它们也分为4个)。

显然,使用基数为8的编号还可以节省成本。代表BCD中的12位,第一个数字只能是0-4,但是第二,第三和第四位可以是0-9。如果将其设置为十六进制,则一个具有3个十六进制字符,但是每个十六进制字符。生产仅具有0-7 的数码管比具有0-9(对于BCD具有附加逻辑)或十六进制的0-F 的数码管便宜。

今天仍然可以看到八进制的unix文件权限(755、644),其中所有者,组和世界每个都有3位代表权限。


在数学世界中,偶尔会用不同的基础做一些奇怪的事情。例如,来自euler计划396的较弱的Goodstein序列...或更简单的回文数。以N为底的数字具有一个属性,即N-1的倍数的数字总和为N-1的倍数。此外,如果N-1是一个完美的正方形,则sqrt(N-1)也存在此属性。这在某些数学问题中有一些应用。


1
八进制是因为PDP具有9 / 18bit字节,八进制数字表示3bit,所以如果您的字节可以被3整除,则很有意义
Martin Beckett 2012年

1
在某些16位系统(最著名的是PDP-11)上也使用了八进制,因为15(除符号位以外的位数)可以很好地划分为3。它在原始UNIX操作系统中得到了广泛使用(例如, “ od”是转储二进制文件的标准工具,其默认格式是16位八进制而不是8位十六进制),而不仅仅是获得权限。PDP-11指令集具有两个6位操作数字段也可能是相关的。
Random832

还使用了八进制,因为它可以在当时的技术上显示。Nexi管,有人吗?还是其他0-9显示器?AF显示需要一段时间才能显示。
杰里米·J·斯塔彻

1

在金融业中,存在有效地以36基础标识符方案。它使用数字0-9和字母BZ表示值0-35。它跳过元音以防止生成任何令人讨厌的名称。

但是,这并不完美。曾经有一段时间,一个不幸的公司拥有身份证B000BZ


1

原因1:因为电路级别上的所有数字均以base-2表示(电气开关处于打开或关闭状态)。原因2:由于比实际电路高一层,所以位被分组为字节,而字节则很容易用两个十六进制数字表示,而用3个十进制数字(和一些验证)来表示字节的所有可能值。字节。

因此,如果您在这些级别上工作(或在某些托管环境中近似),则使用二进制或十六进制比十进制更容易。您执行此操作的情况是多种多样的,但通常从不只需要基本算术的情况。


1

经常使用基数为16(十六进制)的数字的一个区域是指定颜色,尤其是在Web上使用HTML / CSS时。我们在数字显示器上使用的颜色是通过将3种“基本”颜色(RGB-红色,绿色,蓝色)的3个强度值组合在一起来指定的,这些颜色混合在一起以创建1600万种可显示颜色中的任何一种(使用24位颜色) )。

例如,十六进制的全强度绿色将是0x00ff0065280十进制。现在,想象一下尝试“手动”混合您的头部中具有相等的红色和蓝色(例如强度为一半)的颜色以创建漂亮的紫色:)用十六进制表示,就像0x800080用十进制值表示那样8388736。使用灰色阴影时,它变得更加容易-50%的灰度是0x808080(十六进制)和8421504(十进制),75%的灰度是0xC0C0C012632256,依此类推。

使用十六进制要直观得多,只要熟悉十六进制值,任何人都可以立即“猜测”该颜色。如果您需要多次使用相同的颜色(通常是这种情况),那么也容易出错。

检出任何网页(尤其是CSS)以获取疯狂的十六进制用法:D

注意:在CSS中,十六进制值是使用#前缀写的,例如:#00ff00绿色,有时也缩短为三位数,例如#0f0绿色。


0

对于某些算法,以2为底的意义比其他任何意义都重要。例如,您是否愿意编写一个遍历二叉树或十进制树的函数?

但是,更经常使用基数2,因为这是计算机几乎通用地表示其数字的方式。这意味着:

  • 在基数2中,许多操作效率更高:
    • 2的乘法,除法和模幂比一般除法快得多
    • 标志和较小的值可以作为较大数字的二进制数更有效地存储,检索和操作。
  • 读取,写入和操作数据文件和网络数据流的操作必须直接处理以二进制数字表示的事实。

此外,总有一种罕见的应用程序固有地需要一个奇数基,该奇数基既不能是2也不是10。


2
当然,我会使用10进制树。2您正在使用什么奇怪的字符?
CodesInChaos 2012年

0

老实说,这是偏爱,如果您出于某种原因拥有多指并且有11根手指,或者喜欢用脚趾数数,因此您喜欢以20为基数工作,那完全取决于您。但是要意识到,在一个普遍性主题上,如果我们得到一些在基数19中进行位操作的东西,那么我们大多数每天必须处理比特和字节的人就会被打勾。

BASE X的原因

以10为基数-所有事物的模型,因为我们有10个计数数字(脚既怪异又臭,所以我们不使用这些数字)。

基数2-计算机将其用于位(开/关),这与栅极/晶体管/电容器所传播的可读电压电平有关。

Base 8-旧的,当计算机不是超级庞大时(或当它们在空间方面明智时),这对某些东西或其他东西(我一点都不喜欢)有好处

Base 16-适合显示字节的上下半字节以进行位操作。这在嵌入式/ fpga /硬件世界中超级有用。

计算机中的正常基础

顺带一提,我可以确切地告诉您颜色在十六进制RGB值中的“开启”程度,因此可以在硬件中以单个int表示,然后可以将某些偏移返回给我轻松实现1种复杂的颜色= 1个数据点,非常适合内存有限的大型图像处理。将其与以10为基数的表示形式进行比较,可以将它们全部相加并存储在一个数字中,但是哪个数字是哪个数字,或者R是时间10000,G是100,B是它自己的空间,那么这是很多数学运算,乘法通常要花费比移位更多的周期,因此下一个数据片段已经在队列中,而最后一个数据片段正在处理之前,哎呀,现在不见了。

有时,最好以2、8或16为基数工作。在大多数机器中,乘以2只是一点点移位,而这些机器却超快,除以2。

进一步阐述一下位旋转的想法。在嵌入式环境中工作时,需要访问很多灯,开关或其他寄存器映射项的数组很多次。

在这种情况下,为每个开关分配整个char,byte或int既低效又愚蠢,一个开关或灯有2个位置-接通和断开-为什么我要分配最多256个位置或2 ^ 16的东西阵列中的每个灯都可以是1位,将8个或16个或32个或64个或128个(数据类型的宽度)适合在单个字/寄存器上。需要空间效率,这是值得欢迎的。

在编程中使用以2 ^ n为基数的东西来处理诸如RGB数据,大量信号数据(GPS,音频,ASCII等)之类的十六进制,二进制和八进制要简单得多,因为这就是在机器中的表示方式,并且可以更容易辨别正在呈现的内容以及如何对其进行操作。

使用奇怪的基地

除非您对此进行编码,否则没有效率。您希望以11为基数,必须为其设置数据类型,并使任何运算符重载以向用户处理其表示形式。我认为没有理由将拥有5个项目并且仅拥有5个项目的倍数的系统转换为5个项目数学。此外,您最好祈祷谁决定为基础271编写代码的人对其进行了很好的记录,或者您可以花更多的时间来理解它而不是创建基础271值得,因为所有项目都是271的倍数。



0

令我惊讶的是,所有其他答案都没有提到在计算备用基数时有两种非常常见的用法:

  1. 编码:例如,Base64编码非常普遍。编码只是将一系列字节解释为一个大的二进制数(以2为基数),并将该数字转换为以ASCII数字表示的Base64数。
  2. 压缩:通常希望以较大的基数表示二进制,十进制或十六进制数,以缩短表示形式。例如,像bit.ly这样的所有缩短器都在执行此操作。或者,您可以这样做以缩短在URL中使用的GUID。

    - 821F6321-881B-4492-8F84-942186DF059B (base-16 guid) 
    becomes
    - RRIDHW463YD8YXX7MIDI (base-36)
    - 3UFmaWDjj9lifYyuT0 (base-62)
    
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.