你知道Hello World程序的由来吗?

Hello World是一个最著名的程序。对每一位程序员来说,这个程序几乎是每一门编程语言中的第一个示例程序。实际上,这个程序的功能只是告知计算机显示Hello World这句话。传统意义上,程序员一般用这个程序测试一种新的系统或编程语言。对程序员来说,看到这两个单词显示在电脑屏幕上,往往表示他们的代码已经能够编译、装载以及正常运行了,这个输出结果就是为了证明这一点。

这个测试程序在一定程度上具有特殊的象征意义。在过去的几十年间,这个程序已经渐渐地演化成为了一个久负盛名的传统。几乎所有的程序员,无论是在你之前,或在你之后,当第一次实现与计算机成功沟通之后,在某种程度上,他们的肾上腺素就会急剧上升(激动不已)。以下就是这个著名程序的诞生故事。

Hello World究竟从何而来?


Hello, World最早是由 Brian Kernighan 创建的。1978年,Brian Kernighan写了一本名叫《C程序设计语言》的编程书,在程序员中广为流传。他在这本书中第一次引用的Hello World程序,源自他在1973年编写的一部讲授 B语言的编程教程:

main (){
extrn a,b,c;
putchar (a); putchar (b); putchar (c); putchar ('!*n');
}
a 'hell';
b 'o, w';
c 'orld';

但是非常不幸的是,当 Forbes India 杂志采访他的时候,他自己对这段传奇故事中一些记忆已经有点儿模糊了。当他被问及为什么选择『Hello, World!』时,他回答说,『我只记得,我好像看过一幅漫画,讲述一枚鸡蛋和一只小鸡的故事,在那副漫画中,小鸡说了一句‘Hello World’』。

鉴于Hello World这个计算机程序的广泛流行程度,这个起因看起来还是蛮合适的。

那个时候,无论是 Kernighan,还是他的同事 Dennis Ritchie - C语言之父,都无法想象C语言以及这本教程书将会在今天如此之流行。他们所做的工作只是贝尔实验室的一个研究项目,而在当时,贝尔实验室也只是美国电话电报公司(AT&T)的技术研究与开发机构而已。

尽管没人能够科学地解释为什么Hello World如此地流行,但是,Hello, World程序的确在计算机发展历史上成为了一个具有重要意义的里程碑。我们一起来回顾一下当时的历史环境。

襁褓中的变革

现在你可能很难想象,但是在Hello World连同Kernighan的编程书出版之前,计算机对于公众来说,几乎隐含着一种负面的意义。在1970年代,主机时代的计算机,不仅运行缓慢,体积庞大到足以占用整个一间屋子,而且还需要一位全职的科学家或者研究者来维护它。事实上,在1970年代后期之前,计算机科学家在编程的时候还要使用大量的打孔卡!



通常情况下,一般人认为计算机是一种不可触碰、复杂,而且极其昂贵的设施,它们仅仅适用于学术、政府或者国防。事实上,即使是那些专注计算机领域的工业巨头们也在努力克服这些障碍。当时谁也无法想到,事隔多年之后,也就是现在,如果我们暂时失去了我们的个人数字设备(如手机等),我们甚至会感到焦虑。

第一个著名的计算机应用的案例发生在1890年- 为了收集和统计超过六千万美国人口的相关数据。另一个案例出现在1940年,也就是二战期间,Bombes & Colossus 计算机被用于破解德国人的通讯密码。

在1950年,世界上迎来了第一代商用计算机,如 Zuse 3和UNIVAC,在当时主要应用于算术运算,但如果你想要买到这些设备,需要花费上百万美元。

从教育相关的角度来看,绝大多数早期的有关编程语言的图书,如FORTRAN或BASIC,常常都会从一点入手:计算机非常有用。这是算法工程师和研究者 John Mount 的一个重要观点。Mount认为,Hello World大范围流行开启了一个崭新的时代–计算机科学家不再需要说服社会和大众,计算的工具化特征已经所处可见。

例如,在1964年,一本名叫 My Computer Likes Me When I Speak Basic 的图书,在它的前言部分,就专门讲述了计算机编程语言的一般性用途。而且,书中的第一个例子的输出结果就是『MY HUMAN UNDERSTANDS ME』。之所以使用这个示例的原因,目的是为了帮助人们理解计算机这个新生事物,并且希望告诉人们:你可以和计算机进行交流。在此之后,也就是1956 年,动态编程语言开启了将计算机应用于现实世界的更多实例。

在C语言以及Hello World程序流行起来之前,计算机并没有得到大范围的应用和普及,计算机行业也没有开始真正的腾飞。

Hello World,编程时代的真正来临

引发Hello World广泛传播的一个最主要催化剂,是PDP-11型计算机的面世,PDP-11是一款在商业上极其成功的小型计算机。数字设备公司(DEC)以$10,000的单价,总共出售了六十万台。尽管如此,这种类型的计算机已经比当时价值几百万美元的大型机在价格上便宜了许多。另外,其中PDP-11 16-bit系列不要求使用打孔卡,你可以使用相应的编程语言直接与计算机进行沟通。在那个年代,这还是第一次。

有趣的是,为了加速社会的广泛接受度,数字设备公司并没有将其称为『计算机』。为了和以往那些大型主机相区别,数字设备公司改称其为『可编程的数据处理器』。当越来越多的机构开始采购越来越多的可编程计算机时,对于C语言编程书籍的需求也变得越来越旺盛了。

C 语言和UNIX操作系统首先在PDP-11这个机型上变得流行了起来。因此,在接下来的一段时间里,其他类型的商用计算机也开始支持这个C编程语言以及 UNIX,这种流行趋势最终促使成千上万的计算机相关工作者,开始阅读这本两百来页的《C程序设计语言》。当然,这其中自然包括了Hello World这个例子程序。

在八十年代以及九十年代,几乎每一位曾在桌面软件领域工作过的程序员,都曾拥有一本《C程序设计语言》。在当时,这本书大约售出了几百万本之多。

也许有很多不同的基本程序可供初学者动手尝试,但是截至目前为止,Hello World则是其中最为著名的一个。每一位程序员都曾记得他们的第一个Hello World程序,因为对他们来说,这就是一个重大事件。也许有些人还没有意识到这一点,但是,当一名新程序员清除完一些障碍顺利抵达Hello World时,他的内心体验到的不仅仅是一种成功的喜悦,更重要的是,他正在亲身经历一个跨越历史的时刻。

原文:the-history-of-hello-world

### Armijo准则在梯度下降法中的应用 #### 什么是Armijo准则? Armijo准则是线搜索方法的一种策略,用于确定每次迭代中步长 \( \alpha \) 的合适值。该准则的核心思想是在保证目标函数充分减少的同时,避免步长过小或过大。具体来说,它通过比较当前点的目标函数值和沿搜索方向移动后的目标函数值来调整步长。 设目标函数为 \( f(x) \),当前点为 \( x_k \),搜索方向为 \( d_k \),则新点可以表示为 \( x_{k+1} = x_k + \alpha d_k \)。为了找到合适的步长 \( \alpha \),Armijo准则定义如下: \[ f(x_k + \alpha d_k) \leq f(x_k) + c_1 \alpha \nabla f(x_k)^T d_k, \] 其中 \( c_1 \in (0, 1) \) 是一个小的常数,\( \nabla f(x_k) \) 表示目标函数在 \( x_k \) 处的梯度向量[^3]。 此不等式的含义是:当步长 \( \alpha \) 足够小时,目标函数的实际减少量应至少达到预测减少量的一个比例 \( c_1 \)[^3]。 --- #### 如何实现Armijo准则? 以下是基于梯度下降法实现Armijo准则的具体流程: 1. **初始化参数** 设定初始步长 \( \alpha_0 > 0 \),缩小因子 \( \beta \in (0, 1) \),以及常数 \( c_1 \in (0, 1) \)。 2. **计算搜索方向** 对于梯度下降法,搜索方向通常取负梯度方向,即 \( d_k = -\nabla f(x_k) \)。 3. **验证Armijo条件** 计算目标函数值并检查是否满足以下条件: \[ f(x_k + \alpha d_k) \leq f(x_k) + c_1 \alpha \nabla f(x_k)^T d_k. \] 如果上述条件成立,则接受当前步长 \( \alpha \);否则,令 \( \alpha := \beta \cdot \alpha \),继续测试直到条件被满足。 4. **更新位置** 当找到满足条件的步长后,更新当前位置为 \( x_{k+1} = x_k + \alpha d_k \)。 5. **终止条件** 判断是否满足收敛条件(如梯度范数小于某个阈值),如果不满足,则返回第2步继续迭代。 --- #### Python代码实现 下面是一个简单的Python代码示例,展示如何结合梯度下降法和Armijo准则进行优化: ```python import numpy as np def armijo_line_search(f, grad_f, x, d, alpha=1.0, beta=0.5, c1=1e-4): """ 使用Armijo准则执行线搜索 参数: f: 目标函数 grad_f: 梯度函数 x: 当前点 d: 搜索方向 alpha: 初始步长 beta: 缩小因子 c1: 控制系数 返回: 满足Armijo准则的步长alpha """ fx = f(x) grad_fx = grad_f(x) while f(x + alpha * d) > fx + c1 * alpha * np.dot(grad_fx, d): alpha *= beta return alpha def gradient_descent_armijo(f, grad_f, x_start, max_iter=1000, tol=1e-6): """ 带有Armijo准则的梯度下降法 参数: f: 目标函数 grad_f: 梯度函数 x_start: 初始点 max_iter: 最大迭代次数 tol: 收敛容忍度 返回: 近似最优解x_optimal """ x = x_start iter_count = 0 while np.linalg.norm(grad_f(x)) > tol and iter_count < max_iter: d = -grad_f(x) # 搜索方向为负梯度 alpha = armijo_line_search(f, grad_f, x, d) x = x + alpha * d iter_count += 1 return x # 测试例子 f = lambda x: x[0]**2 + x[1]**2 # 定义目标函数 grad_f = lambda x: np.array([2*x[0], 2*x[1]]) # 定义梯度函数 x_start = np.array([1.8, 1.7]) # 设置初始点 result = gradient_descent_armijo(f, grad_f, x_start) print("Optimal solution:", result) ``` --- #### 关键点解析 1. **步长的选择** 步长 \( \alpha \) 的大小直接影响到算法的收敛速度和稳定性。如果步长太小,可能会导致收敛缓慢;而步长太大可能导致错过最优解。因此,采用Armijo准则动态调整步长是一种有效的方法。 2. **搜索方向的影响** 在标准梯度下降法中,搜索方向始终为负梯度方向。然而,在其他更复杂的优化方法(如共轭梯度法)中,搜索方向可能是经过特殊设计的方向[^2]。 3. **实际应用场景** Armijo准则广泛应用于各种数值优化问题中,尤其是在高维空间下的非线性优化场景下表现尤为突出[^4]。 --- ###
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值