如果使用BC进行转换,是否了解“ ibase”和“ obase”?


22

我经常使用bc实用程序将十六进制转换为十进制,反之亦然。然而,它始终是有点试验和错误是如何ibaseobase应配置。例如,在这里我要将十六进制值C0转换为十进制:

$ echo "ibase=F;obase=A;C0" | bc
180
$ echo "ibase=F;obase=10;C0" | bc
C0
$ echo "ibase=16;obase=A;C0" | bc
192

这里的逻辑是什么?obaseA在我的第三示例)需要在相同的碱,将其转化(该值C0在我的例子)和ibase16在我的第三示例)必须在我转换到基座?


1
对于十六进制计算(以十六进制输入和输出),我必须在ibase之前设置obase!
Paschalis

Answers:


36

您实际上想说的是:

$ echo "ibase=16; C0" | bc
192

十六进制到十进制,以及:

$ echo "obase=16; 192" | bc
C0

十进制到十六进制。

你并不需要给双方ibaseobase涉及十进制数任何转换,因为这些设置默认为10。

对于二进制到十六进制的转换,您确实需要给出两者。在这种情况下,如果您obase先给出答案,我发现最容易理解的事情是:

$ echo "obase=16; ibase=2; 11000000" | bc
C0

如果您ibase先给出,则它将更改以下obase设置的解释,因此命令必须为:

$ echo "ibase=2; obase=10000; 11000000" | bc
C0

这是因为按此顺序将obase值解释为二进制数,因此您需要给出10000 2 = 16才能获得十六进制的输出。笨拙的


现在,让我们弄清楚为什么您的三个示例会如此表现。

  1. echo "ibase=F;obase=A;C0" | bc

    180

    根据POSIX,这将输入基数设置为15,将输出基数设置为10,因为单位值以十六进制表示。这要求bc告诉您在基数A₁₅= 10中C0₁₅是什么,它正确地回答了180₁₀,尽管这当然不是您要问的问题。

  2. echo "ibase=F;obase=10;C0" | bc

    C0

    这是基数为15的空转换。

    为什么?首先,因为F正如上一个示例中指出的那样,因为一位数字是用十六进制解释的。但是现在您将其设置为以15为底,下面的输出基本设置将以这种方式解释,并且10₁₅= 15,因此您将C0₁₅转换为C0₁₅为空。

    没错,输出不是您假设的十六进制,而是以15为基数!

    您可以尝试转换F0而不是来向自己证明这一点C0。由于F基数15中没有数字,bc因此将其钳位到E0,并E0作为输出。

  3. echo "ibase=16; obase=A; C0"

    192

    这是您的三个示例中仅有的可能具有实际用途的其中一个。

    它将输入基础首先更改为十六进制,因此您不再需要深入研究POSIX规范就可以理解为什么A将其解释为十六进制,在这种情况下为10。唯一的问题是将输出基数设置为A₁₆= 10是多余的,因为这是默认值。


7

设置ibase意味着您需要以obase相同的基础进行设置。解释您的示例将显示以下内容:

echo "ibase=F;obase=A;C0" | bc

您设置bc为考虑输入数字,如基数15中用“ ibase = F”表示。“ obase = A”将输出数字设置为以10为底,这是默认值。

bc 将C0读取为以15为底的数字:C =12。12* 15 = 180。


echo "ibase=F;obase=10;C0" | bc

在此示例中,将输入设置为以15为底,然后将输出设置为10(以15为底),因此输出以15为底。C0以15为底的输入是C0以15为底的输出。


echo "ibase=16;obase=A;C0" | bc

将输入设置为基数16,将输出设置为基数10(基数16中的A为基数10中的10)。

转换为10的C0为:12 * 16 = 192


我的个人规则是先设置obase,以便我可以使用10为底。然后再设置ibase,也可以使用10为底。

请注意,bc确实存在一个具有讽刺意味的例外:ibase=A并且obase=A始终将输入和输出设置为以10为底。在bc手册页中:

Single digit numbers always have the value of the digit 
regardless of the value of ibase.

此行为体现在以下规范中bc:从2004 OpenGroup bc规范中

When either ibase or obase is assigned a single digit value from 
the list in 'Lexical Conventions in bc', the value shall be assumed
in hexadecimal. (For example, ibase=A sets to base ten, regardless 
of the current ibase value.) Otherwise, the behavior is undefined 
when digits greater than or equal to the value of ibase appear in
the input.

这就是为什么该ibase=F设置将您的输入基准更改为15的原因,以及为什么我建议始终使用10为基准来设置基准。因此请避免混淆自己。


@StéphaneChazelas-我想起了1989年左右在SysVr3机器上工作的“ ibase = A”。我敢打赌,它可以追溯到Single Unix Spec。我无法快速搜索较早的参考资料。
Bruce Ediger 2015年

我认为这是因为与旧规范有关的链接更多,因为它们存在的时间更长。apache / mysql / bugzilla ...文档也会发生类似的情况,其中google首先为您提供较旧版本的文档,而不是最新版本。
斯特凡Chazelas

5

GNU bc将所有数字解释为对该数字有效的当前输入基数。当您在当前输入之外使用数字时,将其解释为基数中可用的最高数字(十进制为9)多位数的数字,或者用作单数数字时的常规值(A十进制== 10)。

GNU bc手册

不管ibase的值如何,一位数字始终具有该数字的值。(即A =10。)对于多位数字,请将bc所有大于或等于ibase的输入数字更改为ibase -1 的值。这使数字FFF始终是输入基数的最大3位数字。

但是,您应该知道POSIX标准仅在ibase和的分配中定义了此行为obase,在任何其他上下文中都没有定义。

根据BC上SUS规范

如果从bc的词汇约定中的列表中为ibaseobase分配了一位数字值,则该值应假定为十六进制。(例如,不管当前的ibase值是多少,ibase = A都设置为以10为底。)否则,当输入中出现大于或等于ibase值的数字时,该行为是不确定的。无论IBASEobase的应有的初始值10。

您缺少的关键因素是F实际上不是16,而是实际上是15,因此,当您设置ibase = F时,会将输入基数设置为15。

因此,要将ibase从未知状态可移植地设置为十六进制,您需要使用两个语句:ibase=A; ibase=16。但是,在程序开始时,您可以依靠它为小数,只需使用即可ibase=16


+1:可爱的把戏ibase=A; ibase=16
沃伦·杨


我一直认为标题中的6和7是版本。我从来没有见过什么不同-问题1-5是什么?
Random832

@ Random832:SUS和POSIX 是不同的东西
沃伦·杨

@WarrenYoung SUS不合并POSIX吗?该段没有扩展标签,并且该文档始终声明“ POSIX.1-2008的此部分内容”。
8

0

始终建议设置ibaseobase使用一个单一的数字,而不是诸如的数字16,因为根据bc手册页,

无论ibase的值如何,一位数字始终具有该数字的值。

这意味着无论值是多少,A,B,...,F始终10,11,...,15分别具有值ibase。您也可以使用F+1指定数字16。例如,你最好写

echo "ibase=F+1; obase=A; C0" | bc

而不是写echo "ibase=16; obase=A; C0" | bc来指定输入基为16,输出基为10。或者,例如,如果你想同时ibaseobase是16,你最好使用

ibase=F+1; obase=F+1

而不是使用 ibase=16; obase=10。同样,如果您要在以14为底的数字中输入数字,并以16为底的数字输出,请使用

ibase=E; obase=F+1

尽管浴槽形式具有相同的结果,但前者不太容易出错,而后者可能导致更多的混乱和错误。

当您在的执行环境中bc,或者要在文件中写入计算结果,然后将该文件bc作为参数传递时,两种形式之间的区别尤其明显。在这种情况下,你可能需要更改的值ibase,并obase数次,并且使用后一种形式,可导致严重的混乱和错误。(体验一下)

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.