`

代码之谜(零)- 其实,你不懂代码

阅读更多

前世今生

---------2012年9月28日 13时32分 新增-------

最近看本文评论,争议很多,我先说说这篇文章的前世今生吧。

我原文标题是『代码之谜 - 开篇/前言/序』,副标题是『其实,你不懂代码』,本来打算用“其实,代码中的运算符不等价于数学符号”。原文我写于2010年底,当时写在 evernote 中,用了”群“、”域“、”集合“、”关系“的概念解释了计算机中用二进制表示的离散的数和现实中连续的数之间的关系和区别。

前几天群里有人问道,遂打算写一个系列,用比较「贫」的语言把他们讲述出来。

原文首发在我的博客: http://justjavac.com/codepuzzle/2012/09/25/codepuzzle-introduction.html, 因为我也不能保证我的博客空间总是稳定的,所以,将这篇文章发布到了iteye,还可以顺便看看热心网友的评论。

----------正文分割线-------------

答应了群里的兄弟们要更新博客,结果回家又是洗衣服做饭的,转眼已经10点多了。

趁洗衣机正在转的功夫,打开 Evernote 找到了以前的几段 javascript 代码,本着人性本贱(咳,咳,该死的输入法,更正「人性本荐」)的精神, 给大家共享一下,不定期更新,算是我「代码之谜」系列的开篇吧。

我喜欢读一些让人震惊的书,比如『哥德尔、艾舍尔、巴赫书:集异璧之大成』,比如『从一到无穷大』,读完后张大嘴巴,「哇噻,太不可思议了,太令我震惊了」。 本系列博客的目的之一就是让每个阅读过的人在思维方式上有所改变,变得更理性,更加会思考,会学习。

本系列说来话长,从10年开始构思,当时写在 evernote 里面,名字叫『理性,像数学家一样思考』,废话少说,言归正传,贴代码吧

第一段代码:

 

function foo1(a){
    return a + '01';
}

foo1(01) 

 

第二段代码:

 

function foo2(a){
    return a + '010';
}

foo2(010); 

 

第三段代码: (注: 这不是 javascript 的问题,而且所有语言的问题,归根结底是 IEEE 标准中二进制浮点运算的问题,关于浮点数的详细问题请阅读 代码之谜 - 浮点数,「为什么没有链接呢,呵呵,因为我还没有写,正在整理中」。)

console.log(0.2 + 0.4);

第四段代码就相对来说简单多了: 参考我一些发布的这篇为什么 ++[[]][+[]]+[+[]] = 10?

[4,[3,2]][1][0];     // 3

 

-----------------------分割线-----------------------------

2012年9月25日 22时25分 更新

还是忍不住,睡前想唠叨几句。

也许很多人第一次接触编程时,对 i = i + 1 都感到百撕不得骑姐(咳,我就说了嘛,必须得换一个输入法了,更正「百思不得其解」)。

“i加上1怎么可能和i相等呢?”

后来慢慢知道了,不,确切的说,是慢慢地接受了,接受了=是赋值(前提是你学的不是pascal,我的入门语言就是它),因为你可能根本没有思考,只是被动接受

再后来,我们学了 if, 开始写分支代码:

if (a >3) { 
    // do something        
}

if (a < 5) {
    // do  something
}

 

但是当我们写出 if (3 < a < 5) 时,居然报错了,又是百撕不… 后来被教导了,这么写是错的,应该if (a>3 && a<5)。 于是我们又开始接受了,认为这么写是理所当然的,而且以后的代码都是这么写的。

 

直到有一天,你看了 python 的入门手册,尼玛,居然逆天的出现了 ‘if 3 < a < 5:’,当时绝对又震惊了,“怎么可以这么写?”。 难道你忘了,N年前你就是这么写的,而且当时你不也认为 3 < a < 5 是理所当然的吗(任何一个高中生都会同意这种写法), 为什么你现在又开始觉得 3 < a < 5 是种逆天写法呢,因为你在这几年的编程生涯中,已经被动接受了太多太多的东西,而且使你根本就不曾思考过, 这也是我写「代码之谜」系列的初衷。

当你被告知了,在编程中=是赋值的意思(其实他们没有告诉你,只是大部分语言这样,还有很多语言不是这样,比如pascal中:=是赋值,比如basic/VB中=即是赋值也是判断), 但是=如果不是相等的话,那肯定有表示相等的,对,就是==,或者===。

不管是==还是=,「相等」到底是什么意思呢?=或者==或者===,即使以后会出现====,到底和数学的「相等」有多少出入呢?

知道我们遇到了传说中的NaN(很多人认为NaN既然表示Not A Number,那么他就是语言定义的一个东东,根本不存在,这是错误的,NaN是在IEEE浮点数规范中明确定义的,包括本系列后面 后提到的+0和-0问题),它不等于任何值,而且,它居然不等于它自己。

一个数居然不等于它自己,其实确切的说,是 NaN == NaN 居然返回 false, 甚至 NaN === NaN 也返回 false。是 NaN 的问题,还是==或者===的问题,抑或这根本就是相等这个概念的问题。

在集合论中,相等的三要素,不管是==还是===,都无法满足,所以说,===根本就不是相等(如果你读过数学的「群伦」就更明白了)。

相等(等价)的三要素

  1. 自反省: A等于A
  2. 对称性: 如果A等于B,那么B等于A
  3. 传递性: 如果A等于B,而且B等于C,那么A等于C

当我们看到这几条定理时,我们从来没有怀疑过。 脱离了数学,我们进入了编程领域,当我们遇到了NaN, 我们知道了,在IEEE的数字表示规范里面,「自反省」是不被满足的,那么传递性和对称性呢? 如果你找到了反例,可以留言。

也许你说,相等/等于/全等/等价这些比较特殊,其它的应该都会满足吧。 我只能告诉你(说通俗一点),以前的所有定理、公理都只适用于一个领域,当它进入另一个领域我们就不能把它当作理所当然的,也许它没有问题,比如 1+2=3,但也许这只是一个巧合, 上面我就提到了 0.2+0.4 就不等于 0.6。

计算机和现实最大的不同(也是问题的根源)就是,世界是连续的,而计算机是非连续的,是离散的。 以前我们学校图书馆有很多「计算机数学」或者「离散数学」之类的书,我现在都不明白,里面写的那些数学,是设计计算机的工程师读呢,还是使用计算机的程序员读呢?里面的内容简直就是大杂烩嘛。 什么是离散数学呢?我的理解,不连续的数学都是离散数学。比如量子论里面用到的数学,就是离散数学。

其它算数定律或者定义有不满足的吗?

再举一例,上小学刚学乘法运算的时候老师就告诉我们,3x4就是4个3相加,下面这个例子再次颠覆你的想法。

console.log(0.1 * 10);
console.log(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1);

 

写完睡觉,如果大家有什么更好的例子,欢迎补充。

112
12
分享到:
评论
16 楼 clxy 2013-06-12  
所以我认为高级语言的方向就是尽量/彻底清除这些反人类的东东,掩盖掉机器内部细节,无限接近自然语言。

而现在那些一个个冒出来的“新”语言,竟是些打着高效快速简洁什么的旗号,纠结于面向函数,面向对象,面向并发,面向XX...要我说,最需要的是“面向人类”的计算机语言。

这个系列拜读了。赞!
15 楼 sk0sk 2013-04-21  
2进制不能完全等于10进制表示的浮点数,只能无限接近。
14 楼 zljwade 2013-01-18  
从零开始,还真是程序员的风格
13 楼 在世界的中心呼喚愛 2012-12-10  
有意思。这编主题应该是想表示多思考。
不过,每天忙忙碌碌的为着生活奔波,很少会停下来思考。比如我。
12 楼 justjavac 2012-11-19  
mfkvfn 写道
还有1.0/0.0不会出错,而是正无穷大。

我后面的文章会提到这个问题。
11 楼 mfkvfn 2012-11-19  
还有1.0/0.0不会出错,而是正无穷大。
10 楼 justjavac 2012-09-27  
mzy0316 写道
引用
但是当我们写出 if (3 < a < 5) 时,居然报错了,又是百撕不… 后来被教导了,这么写是错的,应该if (a>3 && a<5)。


这是因为表达式3<a,返回一个布尔值,而一个boolean < 5这样的表达式是不被支持的.
这只是因为默认情况下有些语言没有实现这样的方式
在c++里面,重载运算符.就能实现这样的表达式.当然也没什么意义.

引用
console.log(0.1 * 10); 
console.log(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1);

二进制浮点数的问题,这不能怪罪于我们以前学过的数学理论知识.
计算机运算都是人设计出来的.也是当时设计出来的遗留问题.可以说这其实与数学理论不违背的.现在有很多种实现小数精确计算的方法了.比如java的大数类

python 就支持 3 < a < 5 书写形式。
严格的说,计算机浮点数和我们的小数是不同的,他们不属于同一个“群”,或者说他们不属于同一个“域”。
我在随后的『浮点数』篇再详细写。
9 楼 lcfred 2012-09-26  
很有启发,不过有些观点不是很赞同,比如=只是赋值的一种表现形式,C语系(本人习惯上将C、C++、Java等语法相似的语言统称C语系语言)程序上的x=x+1恰巧和数学方程x=x+1形式一样,而前者有意义,后者无解
8 楼 mzy0316 2012-09-26  
引用
但是当我们写出 if (3 < a < 5) 时,居然报错了,又是百撕不… 后来被教导了,这么写是错的,应该if (a>3 && a<5)。


这是因为表达式3<a,返回一个布尔值,而一个boolean < 5这样的表达式是不被支持的.
这只是因为默认情况下有些语言没有实现这样的方式
在c++里面,重载运算符.就能实现这样的表达式.当然也没什么意义.

引用
console.log(0.1 * 10); 
console.log(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1);

二进制浮点数的问题,这不能怪罪于我们以前学过的数学理论知识.
计算机运算都是人设计出来的.也是当时设计出来的遗留问题.可以说这其实与数学理论不违背的.现在有很多种实现小数精确计算的方法了.比如java的大数类
7 楼 jessige_27 2012-09-26  
曾经也喜欢研究这些东西的 开始 现在 淡了
6 楼 utopialxw 2012-09-26  
期待后续~
5 楼 tobylxy 2012-09-26  
有趣
4 楼 justjavac 2012-09-26  
chinaagan 写道
命令式语言里x = x + 1,当然在函数式语言里可能行不通的。

当我们第一次看到这段代码时肯定有疑问, x=x+1,在数学中根本就无解嘛,即使是数学函数我们也是写成 y=x+1。

后来我们就认为x=x+1是理所当然的了,不再去疑问,不再去思考。

就如 @chinaagan 所说,直到我们遇到函数式语言,我们才又开始第二次思考,它不是理所当然的。只是在命令式语言里面通常是这样的。

看看这篇文章: 『如何避免产生赋值语句』 http://justjavac.com/javascript/2012/04/05/how-to-avoid-the-assignment-statement.html
3 楼 chinaagan 2012-09-26  
命令式语言里x = x + 1,当然在函数式语言里可能行不通的。
2 楼 zengjz88 2012-09-26  
有意思..
1 楼 chinaagan 2012-09-26  
形式化技术

相关推荐

    2--[秒懂百科,Python第2课].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码

    2--[秒懂百科,Python第2课].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码2--[秒懂百科,Python第2课].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码2--[秒懂百科,Python第2课].zip源码...

    2--[秒懂百科,Python第1课].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码

    2--[秒懂百科,Python第1课].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码2--[秒懂百科,Python第1课].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码2--[秒懂百科,Python第1课].zip源码...

    零基础Python快速入门--课件与代码

    小白零基础Python入门--课件与代码;帮助入门学者快速学习Python.

    明日科技《C#示例源代码》(9-12)

    注意:本源代码共有20章节,分五部分上传,名称分别为:明日科技《C#示例源代码》(1-4)、明日科技《C#示例源代码》(1-4)、明日科技《C#示例源代码》(5-8)、明日科技《C#示例源代码》(9-12)、明日科技《C#...

    ISO-14229-1 UDS 代码生成

    基于ISO-14229-1 Road vehicles — Unified diagnostic services (UDS) 代码生成工具。未经过本人同意不能用于商业目的买卖,代码中有本人联系方式,可技术讨论。

    超实用Excel VBA工具箱0-零基础学代码其实很简单

    超实用Excel VBA工具箱0-零基础学代码其实很简单

    ucos-ii全部源代码

    ucos-ii全部源代码 ucos-ii全部源代码 ucos-ii全部源代码ucos-ii全部源代码ucos-ii全部源代码ucos-ii全部源代码 ucos-ii全部源代码ucos-ii全部源代码ucos-ii全部源代码ucos-ii全部源代码

    基于Gitlab的代码审查流程(Code-Review)方案

    与之相对应,GitHub使用Pull Request来完成同样的过程。两种机制的核心都是通过同行审查来确保代码质量和项目的一致性。 Phabricator是一个功能完备的Web软件开发协作平台,除了源码审查和托管功能,还包含了BUG...

    MODBUS-RTU协议主机和从机代码STM32单片机F103实现

    MODBUS-RTU协议主机和从机代码STM32 含功能码03 05 06 10 ...我的代码是最容易看懂的 很多人想要很多功能号 实现原理就是用if判断数据帧有点区别,所以学会一条功能号,其它自然会了 4位595数码管模块显示

    蜗牛代码生成器-Mysql版

    《蜗牛代码生成器-Mysql版》是一款专为Mysql数据库设计的高效代码生成工具,旨在帮助开发者快速生成C#代码,极大地节省了编写数据库交互代码的时间和精力。这款工具的核心价值在于自动化处理繁琐的数据库操作,使得...

    基于Ssm和Vue的卡车零部件销售平台源码 卡车零部件销售平台代码(程序,中文注释)

    卡车零部件销售平台-卡车零部件销售平台-卡车零部件销售平台-卡车零部件销售平台-卡车零部件销售平台-卡车零部件销售平台-卡车零部件销售平台-卡车零部件销售平台-卡车零部件销售平台-卡车零部件销售平台-卡车零部件...

    迫零波束成形,MMSE波束成形代码

    迫零波束成形,MMSE波束成形以及非线性波束成形仿真代码

    SAEJ2012诊断故障代码定义(ISO 15031-6).pdf

    SAE J2012是美国汽车工程师学会(Society of Automotive Engineers, SAE)制定的一套诊断故障代码标准,与国际标准化组织(ISO)发布的ISO 15031-6标准等效。此标准被广泛应用于汽车行业中,用于定义和统一各类汽车故障...

    ORB_SLAM3源码(附带详细注释)

    在ORB_SLAM3的源代码中,你可以看到这些模块的实现细节,包括特征提取、匹配、卡尔曼滤波器的使用(用于平滑姿态估计)、BA(Bundle Adjustment,束调整)优化等技术。注释详细解释了每部分代码的功能,这有助于学习...

    典型的多目标优化算法matlab代码---PlatEMO(你所需要多目标优化代码都有)

    在多目标优化领域,Matlab是一种常用的编程工具,因为它提供了丰富的数学函数库和直观的编程环境,...如果你是这个领域的研究者或学生,通过学习和使用PlatEMO,你可以更深入地理解和掌握多目标优化算法的原理和应用。

    MS5837-30BA水深传感器中文手册与STM32代码

    中文翻译里面加上了我的解读,附上了关键部分的代码,写的非常详细。同时提供了stm32解析水深数据的例程。想学习MS5837的看着一份资料绝对够了。 如果本资源下载需要积分了那就是系统擅自改的,我已经改回很多次了,...

    多目标优化免费NSGA-II代码+详细解释(详见文章)

    多目标优化免费NSGA-II代码+详细解释(详见文章)该函数基于求解多目标最优解的进化算法,即目标的帕累托前沿。最初只输入种群大小和回采标准,或算法自动停止的总代数。您将被要求输入目标函数的数量、决策变量的...

    数学建模matlab常用算法代码整理集合.rar

    小波特征提取算法代码,小波异常值提取代码,隐马尔可夫预测代码,元胞自动机代码演示案例,智能算法之粒子群优化算法代码,智能算法之模拟退火算法代码,智能算法之遗传算法代码,主成分分析代码,主成分分析降维...

    字体及封闭图形G代码自动生成VC源码

    在压缩包内的文件“draw05_29_02”可能是该项目的源代码文件之一,很可能包含了实现这些功能的关键函数和算法。为了进一步理解和使用这个项目,需要具备C++编程基础,以及对数控加工和G代码的了解。通过阅读和分析源...

Global site tag (gtag.js) - Google Analytics