《高阶Perl》——第1章 递归与回调 1.1 十进制到二进制的转换

简介: 本节书摘来自华章计算机《高阶Perl》一书中的第1章,第1.1节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

第1章

递归与回调

本书将要介绍的第一个“高级的”技术是递归。递归(recursion)是一种解决问题的方法,它把问题简化成一个更简单的同类型问题。

不像本书中的大多数技术,递归已是众所周知并被广泛理解的。但考虑到它是后续几种技术的基础,因此我们需要很好地理解它的优点。

1.1 十进制到二进制的转换

在Perl 5.6.0之前,在Perl中没有生成一个二进制数的好方法。从5.6.0开始,可以用sprintf("%b", $num),但之前这是一个令人备受困扰的问题。

任何整数都可以写成2k+b的形式,其中k是一个更小的整数,b是0或者1。b是二进制展开式的最末一位。判断这个最末位是0或者1很容易,只要看输入数是偶数还是奇数。剩下的数是2k,其二进制展开式和k一样,但要左移一位。例如,37=2×18+1,这里k是18,b是1,所以37的二进制展开式(100101)只需在18的(10010)末位添1即可。

如何计算37的展开式呢?它是个奇数,所以末位必为1,剩余的展开式部分和18一样。如何计算18的展开式呢?18是偶数,所以末位为0,剩余的展开式部分和9一样。9的二进制展开式是什么呢?9是奇数,所以末位为1,剩余的展开式部分和4一样。以此类推,直到最后1的二进制展开式,那当然是1。

这种方法适用于任何数。可以按照下面的过程计算一个数n的二进制展开式。

1)如果n是1,它的二进制展开式是1,就可以省略剩余的过程。类似地,如果n是0,展开式就是0。
2)否则:计算k和b使得n=2k+b且b=0或者1。为此,只需以2除n,k是商,b是余数,如果n是偶数,b是0,如果n是奇数,b是1。
3)用同样的方法计算k的二进制展开式。结果记为E。
4)n的二进制展开式是Eb。

创建一个称为binary()的函数计算展开式。开始第1步:

### Code Library: binary
sub binary {
  binary my ($n) = @_;
  return $n if $n == 0 || $n == 1;

第2步如下:

  my $k = int($n/2);
  my $b = $n % 2;

第三步需要计算k的二进制展开式。要怎么做呢?这简单,因为有个计算二进制展开式的binary()函数,一旦写完这个函数就有了。可以以k作为binary()的参数调用它。

my $E = binary($k);

现在最后一步是字符串的合并:

  return $E . $b;
}

计算完成。例如,如果执行binary(37),就得到字符串10010。

这里本质的技巧是把问题简化成一个更简单的情形。假设要找到一个数n的二进制展开式,这个二进制展开式是一个更小的数k的二进制展开式和单独一位b的组合。然后解决同样问题的更简单情形,在函数binary()的定义中使用它本身。当以某个数作为参数执行binary()的时候,它需要为另一个更小的参数计算binary(),顺次为再小些的参数计算binary()。最后,参数变成1,binary()直接给出1的二进制表示即可。

最后一步称为递归的基本型(base case),是很重要的。没有它,函数可能永不终止。如果在binary()的定义中,遗漏了这行:

return $n if $n == 0 || $n == 1;

那么binary()将永远计算下去,并且对于任何参数都永远不产生一个结果。

相关文章
|
4月前
|
存储 C#
C# 逻辑位运符及运算原理 按位操作二进制
C# 逻辑位运符及运算原理 按位操作二进制
|
7月前
|
测试技术 C语言
分享两个C库源码中的移位函数
分享两个C库源码中的移位函数
91 0
|
9月前
|
C语言
C语言:写一个函数返回参数二进制中 1 的个数(三种思路)-1
思路一:使用 %2 和 /2 取出每一位并判断 总体思路: (一). 创建函数,参数要设置成无符号整数,设置计数器计算1的个数 (二). 使用 while循环 循环判断二进制每一位, 使用 %2 判断最低位是否为 1, 使用 /2 去掉判断了的最低位,下次循环开始判断新的最低位
 C语言:写一个函数返回参数二进制中 1 的个数(三种思路)-1
|
11月前
|
Python
Python 格雷码转换公式 i^i//2,简洁优美 pythonic
Python 格雷码转换公式 i^i//2,简洁优美 pythonic
79 0
十进制转二进制的方法 + 写代码实现[C/C++]
整数十进制转二进制转换方法 + 如何用代码实现为主要内容 方法1:除二取余法 十进制数除2得商取余法:对十进制进行除法运算,十进制除以2可以得到一个商和余数 方法2:按权相加法 ......
414 1
【程序填空】下面程序的功能是将一个整数字符串转换为一个整数,如”-1234”转换为-1234
【程序填空】下面程序的功能是将一个整数字符串转换为一个整数,如”-1234”转换为-1234
184 0
|
Python
Python自写函数内容实现十进制数转化为二、八、十六进制数
Python自写函数内容实现十进制数转化为二、八、十六进制数
256 0
运算符,位运算基础,字符串拼接,包机制
运算符,位运算基础,字符串拼接,包机制 运算符 优先级尽量使用() • 算术运算符 + - * / % ++ -- • 赋值运算符 = • 关系运算符 > < >= <= == != • 逻辑运算符 && || ! • 位运算符 & | ^ ~ >> << >>> • 条件运算符 ? : • 拓展赋值运算符 += -= *= /=
运算符,位运算基础,字符串拼接,包机制
|
PHP
PHP函数运用之怎么进行进制的转换
在上一篇文章《PHP函数运用之返回某个日期的前一天和后一天》中,我们介绍了利用strtotime() 函数获取给定日期前一天和后一天日期、前一月和后一月日期、一周和后一周的日期等方法,感兴趣的朋友可以学习了解一下~ 本文的重点是“进制转换”,介绍一下二进制数和十进制数的相互转换、十进制数和十六进制数的相互转换、十进制数和八进制数的相互转换。 二进制数和十进制数的相互转换 1、二进制数转十进制数 可以使用 bindec(二进制字符串) 函数,它可把二进制数转换为十进制数。
112 0
|
索引 Python
python将AD7606B原始补码数据数组转换成原码数据数组并进行处理为电压值
python将AD7606B原始补码数据数组转换成原码数据数组并进行处理为电压值
python将AD7606B原始补码数据数组转换成原码数据数组并进行处理为电压值