学习编程需要掌握多少数学知识?要那些数学基础?

下面是我在reddit的子论坛 r/learnprogramming 看到的几个帖子:

· “要成为一个优秀的程序员需要学习多少数学?

· “我应该重新学习数学吗?

· “这可能是我提问过的最愚蠢的一个问题。成为一个优秀的程序员究竟需要学习多少数学?

数学和编程有一种容易让人误解的联系。许多人认为在开始学习编程之前必须对数学很在行或者数学分数很高。但一个人为了编程的话,需要学习多少数学呢?

实际上不需要很多。这篇文章中我会深入探讨编程中所需要的数学知识。你可能已经都知道了。

对于基本的编程,你需要知道下面的:

● 加减乘除 — 实际上,电脑会帮你作加减乘除运算。你仅需要知道什么时候运用它们。

● 模运算 — 模运算是用来计算余数,它的符号通常用%百分号来表示。所以23除以7等于3,余数是2。23 mod 7 = 2。

● 判断是奇数还是偶数的模运算 — 如果你想知道一个数是奇数还是偶数,用它mod 2来作模运算。如果结果是0,它就是偶数。如果结果是1,就是奇数。23 mod 2等于1,所以23是奇数,24 mod 2等于0,24是偶数。

● 对一个数作百分数运算,就是用这个数来乘以一个百分数。譬如你要得到279的54%,就是用0。54*279。这就意味着为什么1.0等于100%,0.0等于0%。

● 知道负数是什么。负数乘以负数等于正数。负数乘以正数等于负数。就这么简单。

● 知道笛卡尔坐标系统。在编程中,(0,0)代表屏幕左上角,Y坐标的正轴往下。

● 知道勾股定律,因为它是用来计算笛卡尔坐标中两点之间的距离的。勾股定律a^2 + b^2 = c^2。(x1, y1)和(x2, y2)两点之间的距离等于( (x1 – x2)^2 + (y1 – y2)^2 )。

● 知道十进制、二进制、十六进制。十进制就是我们通常用的十个数:0-9。通常认为这个十进制系统是人类发明的,因为我们有十个手指。

电脑采用二进制数据,只有两个数字:0和1。这是因为我们用电子元件来构建的电脑,让电脑只识别两种状态更便宜些(一种代表0,另一种代表1)。

数是一样的,但是在不同的进制系统里的表现形式不同,因为不同进制包含的数的个数不同。十六进制比十进制多六个数字,所以我们用A-F表示超过9的数。能够表现这些进制系统的最简单方法就是用一个计数器(odometer)。下面三种不同的计数器显示的是同一个数,但在不同的进制系统中的形式不同:

在新窗口中查看计数器页面

在新窗口中查看计数器页面

你甚至不需要知道怎么从一个进制系统转换成另一个系统。每种编程语言都有帮你转换的函数。

(提示一下,十六进制的使用是因为一个十六进制的数可以表示四个二进制的数。因为十六进制中的3和二进制中的0011对应,十六进制的A和二进制的1010对应,所以十六进制中的3A(十进制的58)可以写成二进制的00111010。十六进制在编程中的使用是因为它是对二进制的简化。没人喜欢写出的数全是0和1。)

就是这么多了。除了进制系统以外,你可以已经知道编程所需的数学知识了。虽然普遍认为编程需要学习许多数学,但实际上并不需要那么多。你可能为了编写一个程序,譬如说地震模拟器,而需要学习数学。其实你更需要学习地震的数学,而不是因为要编写地震模拟器而学习数学。

某些编程领域中更为高级的数学

有一些领域中需要更多的数学知识(但95%的软件中,你都不需要知道它们。)

● 3D游戏和3D绘图 — 3D通常需要涉及三角函数和线性代数(用矩阵来解决问题的数学)。当然,有许多3D图形库已经实现了这些数学编程,你不需要知道这些数学。

● 2D物理(譬如愤怒的小鸟)和3D物理(譬如许多流行的3D游戏) — 为了写涉及到物理的编程,你需要学习一些物理方程和公式(尤其是力学,如弹力,重力,球滚下斜坡等物理。)然而,已经有一些物理引擎和软件库帮你实现了,所以你也不需要知道游戏(如愤怒的小鸟)中的物理公式。

● 加密学 — 事实上我指的是RSA。你需要知道质数的有关知识,以及如何求最大公约数(其实是个非常简单的算法,还有许多编程语言中都有gcd()函数,帮你求解最大公约数)其他的编码大部分就是将数据按照某种步骤挪动。举个例子,下面的flash就是AES“Rijndael”编码的步骤。所有的步骤包含用一些数减去另一些数,将行向上移,将列数字打乱,再作简单的加法运算。

如果你要写你自己的加密算法(通常不需要你做,因为已经有许多很好的工具了,并且如果你不是加密学的专家的话,你的程序也许会很容易被破解。)如果你仅仅想加密一些数据的话,已经有许多加密和解密的软件库了。

所以就算是以上的情况,你也不需要真正的知道3D图像,物理或者加密的数学。你只需要学习运用软件库就行了。

编程需要学习什么?

你需要学习的是如何建模和设计算法。这意味着,如何将真实世界的运算或者数据处理抽象出来,写出代码,让计算机来帮你运算。例如,在游戏“龙与地下城”(Dungeons and Dragons)中,角色和怪兽都有许多不同的战斗统计值:

● 血点(Hit points)是一个人死前所能经受的伤害值。越高的血点就意味着可以经受更多的伤害。

● 防御等级(armor class)是对你的武器防御能力的量度。防御值越低,武器的防御能力越高。

● THAC0(读作“thay-co”,“To Hit Armor Class 0”),是对一个人进行有效攻击的能力的测量。THAC0值越低,攻击越准。

● 武器的攻击力用类似1d6+2来表示,它表示摇一个六面骰得到的值,然后再加2。2d4就是摇2个4面骰,然后将它们相加。(“龙与地下城”采用的是4,6,8,10,12和20面骰。)

dungeons and dragons

要看攻击者打防御者,让攻击者摇动一个20面骰。如果这个数字大于或等于攻击者的THAC0减去防御者的防御能力,那么这个攻击就成功,防御者将受到伤害。不然,防御者就阻击了这个攻击,并且不费血。

我们假设两个人物,Alice和Bob,她们具有以下值:

● Alice: HP 14, AC 5, THAC0 18, DAMAGE 1d6

● Bob: HP 12, AC 7, THAC0 16, DAMAGE 2d4

所以Alice有更多的血点和防御力(记住,AC越低越好)。但是Bob更可能成功击中对方(记住,THAC0越低越好),并造成更多的伤害。我们说Bob的攻击力更强是因为2d4可以造成2-8点伤害,而Alice的1d6只能造成1-6点伤害。(如果你懂统计学,你可以计算出Bob的期望伤害值是5,比Alice的3。5要高。)

你会打赌Alice或者Bob会赢得比赛对吗?很难讲谁会赢,他们看起来势均力敌。尽管可能你的统计学学得很好,但做这个计算将会十分头疼。编写“龙与地下城”的程序(模拟战斗过程),你甚至不需要知道统计学。仅仅需要运行几百次或者几千次战斗,看看谁赢得更多。

下面是用Python写的程序:(下载代码

import random, copy

NUM_FIGHTS = 1

VERBOSE = True

# Lower thac0 and lower ac values are better. Higher damage & hp values are better.

aliceTemplate = {'name': 'Alice', 'hp': 14, 'ac': 5, 'thac0': 18, 'dmgnum': 1, 'dmgsize':6, 'dmgmod': 0}

bobTemplate   = {'name': 'Bob',   'hp': 12, 'ac': 7, 'thac0': 16, 'dmgnum': 2, 'dmgsize':4, 'dmgmod': 0}

def display(s):

if VERBOSE:

print(s)

def attack(attacker, defender):

if random.randint(1, 20) >= attacker['thac0'] - defender['ac']:

damage = 0

for i in range(attacker['dmgnum']):

damage += random.randint(1, attacker['dmgsize'])

damage += attacker['dmgmod']

display('%s (%s hp) hits %s (%s hp) for %s points of damage. %s is reduced to %s hp.' % (attacker['name'], attacker['hp'], defender['name'], defender['hp'], damage, defender['name'], defender['hp'] - damage))

defender['hp'] -= damage

else:

display('%s misses %s.' % (attacker['name'], defender['name']))

aliceWins = 0

bobWins = 0

for i in range(NUM_FIGHTS):

display('======================')

display('Start of combat #%s' % (i+1))

alice = copy.deepcopy(aliceTemplate)

bob = copy.deepcopy(bobTemplate)

while True:

attack(alice, bob)

if bob['hp'] <= 0:

break

attack(bob, alice)

if alice['hp'] <= 0:

break

if alice['hp'] <= 0:

display('Alice has died.')

bobWins += 1

if bob['hp'] <= 0:

display('Bob has died.')

aliceWins += 1

print()

print('Alice won %s (%s%%) fights. Bob won %s (%s%%) fights.' % (aliceWins, round(aliceWins / NUM_FIGHTS * 100, 2), bobWins, round(bobWins / NUM_FIGHTS * 100, 2)))

当运行这个程序时,你会看到:

Start of combat #1

Alice misses Bob.

Bob (12 hp) hits Alice (14 hp) for 6 points of damage. Alice is reduced to 8 hp.

Alice misses Bob.

Bob misses Alice.

Alice misses Bob.

Bob misses Alice.

Alice misses Bob.

Bob misses Alice.

Alice (8 hp) hits Bob (12 hp) for 5 points of damage. Bob is reduced to 7 hp.

Bob misses Alice.

Alice misses Bob.

Bob misses Alice.

Alice misses Bob.

Bob (7 hp) hits Alice (8 hp) for 2 points of damage. Alice is reduced to 6 hp.

Alice (6 hp) hits Bob (7 hp) for 6 points of damage. Bob is reduced to 1 hp.

Bob misses Alice.

Alice (6 hp) hits Bob (1 hp) for 1 points of damage. Bob is reduced to 0 hp.

Bob has died.

Alice won 1 (100.0%) fights. Bob won 0 (0.0%) fights.

但是可能Alice正好在某一次战斗中很幸运。让我们关掉输出再重新运行程序(在屏幕输出比运行程序更耗时间),当战斗次数达到30,000次时(将NUM_FIGHTS改成30000,VERBOSE变量变成False):

1

Alice 赢得12909 (43.03%)次战斗. Bob赢得17091 (56.97%)战斗。

所以我们看到使用上面的数值,Bob稍稍占先。电脑进行了30,000次战斗模拟。如果我们用笔和纸还有骰来进行30000次战斗模拟的话,可能需要几个月来算出结果,而我的笔记本仅用了8秒。

那么如果Alice的血点从14增加到20呢。谁会赢呢?

1

Alice赢得19438 (64.79%)次战斗. Bob赢得10562 (35.21%)次战斗.

我们看到给Alice增加6点血点,结果倒过来了,Alice占先了。那么如果Alice的血点只是增加到16呢?

1

Alice赢得15176 (50.59%)次战斗啊. Bob赢得14824 (49.41%)次战斗.

所以仅仅增加2个血点,就已经足够扳回Bob更强攻击力的胜算。

来看这个程序,它只用了加减乘除来计算一个百分比。甚至在更复杂的程序中,需要表示magic spells,治愈部位,多次攻击,在战斗中切换武器等不同效果时,我们也不需要知道更多的数学了。

当然,去学更多的数学吧。可以让你成为更出色的程序员。但是为了学习编程需要多少数学?真的非常少。

更新:我想我应该在基本知识点中增加基本代数,但仅仅需要知道的如 如果X * 3 = 12,知道X等于4。

——————-

虽然大多数开发人员会告诉你,他们在工作中从来不需要数学,但是经过一番沉思后,我有了个想法:就是反马斯洛的锤子理论:当你有一把锤子,你会把一切看成是钉子。

本文仅为 Al Sweigart 一家之言,再推荐 Alan Skorkin 的这篇文章《数学是成就卓越开发人员的必备技能

——————-

原文:Al Sweigart  编译:伯乐在线 – 唐小娟

如何迅速成为Java高手

最近一直状态不好,今天索性就睡了一天。没有什么可以说的,转载专业方面基础知识给以广大喜欢折腾的同学,但是请注意。经验文章看多了,你不实践,照样没法成为高手。大家切记啊!

转载文章开始:如何迅速成为Java高手

Quicl也接到过很多学弟的咨询,可是由于自己不是高手啊,所以大家看看下面高手的经验:很多网友问我学习Java有没有什么捷径,我说“无他,唯手熟尔”。但是我却很愿意将自己学习的一些经验写出来,以便后来者少走弯路,帮助别人是最大的快乐嘛!我编程我当然快乐,我是Quicl、伪Geeker。喜欢程序设计,ACM。

Continue reading

夜半论考研与工作,CSDN达人指点迷津。

半夜有点“工作上的事情”需要上网查资料,习惯性的打开CSDN顺便看看业界最新资讯。程序人生是个很好的板块,我觉得里面的故事可以媲美《故事会》了,很是精彩,高中开始一直看这个,学到了很多不是特别正统但又很实用的知识。自己现在比其他同学少走弯路大概也就这个习惯所利吧。程序人生中的一个:“从事游戏开发,我要不要考研。”吸引了我的注意。

我一向是对这种问题所不屑的,从事游戏开发和考研冲突吗?作者是不是表述有问题吧。仔细一看,是我的理解有误,摘录原文如下:“

马上就大四开学了,之前一直是打算考本校的研究生的,我们学校计算机还行吧,北京前三。从事游戏开发一直是我的梦想,当初选择计算机专业就是因为热爱游戏。 Continue reading

软件的围城,谈高级语言的学习(一位架构师的忠告!)

软件开发中,语言这一关是从业人员必须要闯的一关。 首先要记住一点:学语言并不等于是学软件.从C到C++,到JAVA,c#,VB,语言的趋势是从原有的过程型到现代的面向对象了
过程型的语言如C,是按面向过程的思维,是人在处理事情的顺序思维体现即先算法后数据结构,缺点是如果事情过于复杂,这个过程的顺序处理中就藕合度就非常高,并且在重用性上也不利。
面向对象的优势在于在处理事情时先把事物对象封装,再将各个过程可以灵活的串起来,即先数据结构后算法的一种思维,这样可以形成一种低藕合度的的优势,并且可以达到高度的重用。
分析了这个背景,就看看现代高级语言的一些具体特点。
a.现代高级语言的数据结构(JAVA或C#):
类是一个最重要的数据结构,由于现代信息数据量的激增,在现在大容量内存中,类可以以动态,大容量(堆)的提供数据处理所要求的内存,所以在高级的语言中,类也就是这些语言中的生命基线了。
所以从以前几K或几M内存的软件编写方式到现在动则上G的内存中编写代码,却实有很大的出入,但有一点要注意的是,再大的内存也是有上限的,在编写代码还是要有很多注意的技巧。
接口,在JAVA或C#中,这也是一个很重要的结构了。如果把类看作是一个真正处理数据的载体,那么接口可以看作是这个载体的指挥官,具体一点是:接口专门作一些计划,类就负责完成这些计划。
所以接口能将业务的定义和业务的实现分开对待,就像人做事要先有计划,再去按这个计划作事一样,因此接口在高级的语言中跟类一样,都是非常重要的数据结构。
其他的就是类接口的成员了,以后有时间再说吧。。。呵呵
b.高级语言的算法
很多的计算机专业都学了数据结构和算法这一门课,一直把算法的概念定位在高深的,专一的处理过程。其实在你用JAVA或C#编写第一个方法的时候,算法就开始了。方法的设计或定义,方法的具体实
现等都是高级语言的算法设计体现,不要以为搞个像二叉树,图形计算的时候你就知道这是要用算法。平常的这些代码方法就是在用你的算法思路了。
对于语言和软件的具体学习,我有几点建议与大家共享:
起步:最好能有些计算原理,操作系统,数据结构,软件工程等方面的理解能力.
(以。NET的学习为列)
1.透过语言看本质.
任何语言的学习是不能脱离环境来单独用的!,所以学C#肯定是要结合.NET Framework(学java除了像eclpise开发工具的应用之外,也是要结构应用一些开源框架,如spring,hibernate)
从.NET Framework1.0,1.1,2.0,包括现在3.0,3.5的框架.框架都不外乎要做到:内存管理,安全管理,异常管理,编译环境管理,类库管理等.
a.内存管理:这是任何一个优秀语言和框架的招牌功夫,不要想像现在的内存条容量很大又如何的便宜,那些垃圾软件可以在半个小时内照样把你的内存空间吃得通光!
一个软件加载到内存中,占用的内存区可分二大部分.
第一部分:代码区(存放程序代码的空间,空间大小也是差不多固定下来的).
第二部分:数据区(存放程序代码加载的各种数据).
数据区可分为:全局/静态数据区,常量数据区,栈,堆,对于全局/静态数据区,常量数据区会在程序编译阶段就已分配好了固定的空间,这样,消耗内存容量的情况就关健看栈和堆
了.栈的空间大小在程序中是按固定大小分配的,这个固定大小哪倒底是多大?这是要由编译器决定的事啦,在VS.NET2003中栈的大小默认是1MB,当然我们可以通过编译选项来指定栈
的大小,但通常栈也不会太大.由于栈上的内存是系统自动分配,压栈和出栈都有相应的指令来进行操作,因此效率较高,并且栈的内存空间是连续的,不会产生内存碎片,所以内存的分配管理最后重任落在了
堆上,
堆的大小只受限于系统的有效虚拟内存大小,一般是用来分配一些占用内存较大的对象或数据,由于堆所占用的内存是由开发人员来动态分配和回收的,当NEW(C#用new,C++用
new,malloc)申请内存时,系统需要按一定的算法在堆空间(虚拟内存)中寻找合适的大小的空闲堆,并修改相应的维护堆空闲空间的链表,然后返回地址给程序,所以效率比栈要低,还易产生内存碎片,针对这
个重任,微软在.NET 框架中作了垃圾回收的管理(GC),在.NET中引用类型的都是用堆来分布内存的,当然CG是一种被动的回收机制,要想取得更好更高的性能,快速高效的利用内存,还得要利用成对编码的原
则:较晚的分配内存,最早的释放内存,在C++或C#中都提供了构造与析构的方式,但我们也可以提前执行GC,但效率始终没有C++高,呵呵,先天性的.
b.异常管理:很多人写代码时都是把代码一写上,编译一通过,跑一下,OK,就完成了,写代码最好是在写完一句或一个功能时,要看一下,如果有错误时程序是怎么处理的,把正确时的处理与异常时的
处理都作好了,你的代码肯定是OK,这样的代码才有容错机制.
c.其他的有时间再谈
2.读代码.
不管你以后要作一个普通的软件工程师或高级软件研发人员,要想写出好的代码,不多读好代码,那肯定是闭门造车,所以成就软件人生,第一关是多读好的代码,现在书市上那有这样的书呀,很少,
奇少!petshop,duwamish以及MSDN上的代码都是可以多读的,多读最好能练练手,自己写一写,看代码也有技巧,首先要把代码的类结构搞清楚,再去看具体实现!
3.调试.
写代码的第一关就是调试了,要想成为一个高手,除了多读好代码,多写,伴随着这个过程更多的是调试,所以调试技术最能衡量一个开发人员的重要指标,调试会让你更多的去理解软件是怎么运行
的,以后会如何处理这类型的问题,常用的调试估计大学都学过,在.NET中作项目,必须得学会应用程序的调试,脚本调试,window服务及Web服务的调试,数据库程序的调试.调试技术的书籍有一本书推
荐:<<.net 和windows应用程序调试>>,清华出版社的,也是Visual Studio.net产品组审校的
4.理解接口和抽像类.
这是.NET的核心之一了,大型的应用软件中,要设计成高可扩展性的应用程序,得依赖松散耦合的原则,高内聚低耦合,接口负责只作业务的定义,把定义和现实很好的剥离了,能够更好的满足这种原
则,所以在.NET的设计中不用接口是不敢想像的,在C#中是采用单类多接口的继承方式来进行实现,C++中是多类继承的方式,在petshop4.0中整个的技术架构就是用的接口,在.net Framework
(1.0,1.1,2.0,3.0)中也全部是采用接口的设计思想!
其实这一关也是学习JAVA和C++所共同的核心,当然C++是没有接口,只提供抽像类.
5.代码设计.
写出好的代码,得首先要有一个好的代码结构,学会用设计模式会有助于你取得一个更好的代码结构或一个好的框架,其实常用的设计模式不多,在.NET框架中接口和抽像类是你应用设计模式的基
础,也可以这么讲吧,其他的如:MVC基于BS的,抽像工厂,工厂方法,外观模式,适配器模式,命令模式,单件模式等
6.文档.一个好的产品或软件都是伴随着各种文档产生的,文档的好处不用多说,如要作好一个软件开发人员,熟练办公软件也是基本功!熟悉基本的软件文档内容写法是最好的.