一个浮点数跨平台产生的问题

一个浮点数跨平台产生的问题

感谢网友唐磊(微博@唐磊_name)投稿,本文原文在唐磊的博客上(原文地址),原文分析还不够好,而且可能对人有误导,所以,我对原文做了很多修改,并加了Linux下的内容。浮点数是一个很复杂的事情,希望这篇文章有助于大家了解浮点数与其相关的C/C++的编译选项。(注:我没有Windows 32位以及C#的环境,所以,对于Windows 32位的程序和C#的程序没有验证过)

背景就简单点儿说,最近一个项目C#编写,涉及浮点运算,来龙去脉省去,直接看如下代码。

float p3x = 80838.0f;
float p2y = -2499.0f;
double v321 = p3x * p2y;
Console.WriteLine(v321);

很简单吧,马上笔算下结果为-202014162,没问题,难道C#没有产生这样的结果?不可能吧,开启Visual Studio,copy代码试试,果然结果是-202014162。就这样完了么?显然没有!你把编译时的选项从AnyCPU改成x64试试~(服务器环境正是64位滴哦!!)结果居然边成了-202014160,对没错,就是-202014160。有点不相信,再跑两遍,仍然是-202014160。呃,想通了,因为浮点运算的误差,-202014160这个结果是合理的。

为什么合理呢?很正常,因为上面的p3x和p2y是两个float类型,虽然v321是double,但也是两个float类型计算完后再转成double的,float的精度本来也只有7位,所以,对于这个上亿的数,自然没有办法保证精度

但是为什么修改CPU的type会有不同的效果?嗯,我们再试试C/C++。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (9 人打了分,平均分: 4.44 )
Loading...
Java中的CopyOnWrite容器

Java中的CopyOnWrite容器

感谢 清英 同学的投稿

Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到。

什么是CopyOnWrite容器

CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (14 人打了分,平均分: 4.21 )
Loading...
如何用最有创造力的方式输出42

如何用最有创造力的方式输出42

酷壳似乎好长时间没有像《编程真难啊》或是《老手是这样教新手编程的》或是像《如何写出无法维护的代码》这样“严肃正经”的文章了,所以,赶在大家还没有向我扔臭鸡蛋前奉献一篇。这篇文章来自CodeGolf.StackExchange上的《Most creative way to display 42》—— 请以最有创造力的方式输出42。于是出现了下面的这些答案(注:精彩的总是留在最后面)

人生和宇宙终级问题的答案:42

这里,需要介绍一下为什么要输出42。这时因为42是我们人生,世界乃至整个宇宙的终级答案。这要从《银河系漫游指南》(英文名:The Hitchhiker’s Guide to the Galaxy)说起。这本书是著名英国科幻小说作家Douglas  Adams所著5本银河系漫游指南系列科幻喜剧系列小说中的第一本,改编自他本人为英国广播公司第四电台(BBC Radio 4)所写的广播剧剧本。该书1979年10月12日首次由麦克米伦出版公司(Pan Books)出版,次周成为英国图书销量榜冠军,前3个月内销售超过25万本。截至2005年,这本小说已被翻译成超过30种语言在全世界发行,并且被改编为电视剧、电影、舞台剧等多种艺术形式的作品。

这本小说中小说中充满尖锐的讽刺和隐喻,被西方科幻爱好者奉为“科幻圣经”。其中有两个关键词,一个是Don’t Panic,一个是42影响力很大,而其中关于42的故事简介是这样的:

百万年前,老鼠其实是一种超智慧生物,它们建造了一部超级电脑深思Deep Thought,它们问超级电脑,生命、宇宙以及任何事情的终极答案(Answer to Life, the Universe, and Everything)什么,经过了750万年的计算,深思告诉老鼠的后人答案是42,深思解释它只能计算出答案是什么,但答案的原因必须由另一部更高智能的电脑才能解释,而该部电脑就是地球。经过了800万年,就在结果要出来的五分钟前,地球却因为挡在预定兴建的星际间高速公路的路线,被Vogons给毁灭,电脑没有给出最后的结果。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (25 人打了分,平均分: 4.60 )
Loading...
由苹果的低级Bug想到的

由苹果的低级Bug想到的

2014年2月22日,在这个“这么二”的日子里,苹果公司推送了 iOS 7.0.6(版本号11B651)修复了 SSL 连接验证的一个 bug。官方网页在这里:http://support.apple.com/kb/HT6147,网页中如下描述:

Impact: An attacker with a privileged network position may capture or modify data in sessions protected by SSL/TLS

Description: Secure Transport failed to validate the authenticity of the connection. This issue was addressed by restoring missing validation steps.

也就是说,这个bug会引起中间人攻击,bug的描述中说,这个问题是因为miss了对连接认证的合法性检查的步骤。

这里多说一句,一旦网上发生任何的和SSL/TL相关的bug或安全问题,不管是做为用户,还是做为程序员的你,你一定要高度重视起来。因为这个网络通信的加密协议被广泛的应用在很多很多最最需要安全的地方,如果SSL/TLS有问题的话,意味着这个世界的计算机安全体系的崩溃。

Bug的代码原因

Adam Langley的《Apple’s SSL/TLS bug 》的博文暴出了这个bug的细节。(在苹果的开源网站上,通过查看苹果的和SSL/TLS有关的代码变更,我们可以在文件sslKeyExchange.c中找到下面的代码)

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (43 人打了分,平均分: 4.84 )
Loading...
可视化编程

可视化编程

本文来自《Visual Programming Languages – Snapshots》,作者Eric Hosick收集了一堆关于可视化编程的工具,好多我都听都没听说过,我一股脑的全转过来,给大家看看,算是开开眼界了。本文也是参考了Wikipedia的 Visual Programming Language 词条。

另外,在原文有很多评论,其中也有很多正文没有提到的,你可以前去围观一下。

SketchPad

Maybe the first. 1963.

图片来源, Wikipedia官方网站

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (16 人打了分,平均分: 4.75 )
Loading...
从“黑掉Github”学Web安全开发

从“黑掉Github”学Web安全开发

Egor Homakov(Twitter: @homakov 个人网站: EgorHomakov.com)是一个Web安全的布道士,他这两天把github给黑了,并给github报了5个安全方面的bug,他在他的这篇blog——《How I hacked Github again》(墙)说明了这5个安全bug以及他把github黑掉的思路。Egor的这篇文章讲得比较简单,很多地方一笔带过,所以,我在这里用我的语言给大家阐述一下黑掉Github的思路以及原文中所提到的那5个bug。希望这篇文章能让从事Web开发的同学们警惕。关于Web开发中的安全事项,大家可以看看这篇文章《Web开发中的你需要了解的东西

OAuth简介

首先,这个故事要从Github OAuth讲起。所以,我们需要先知道什么是OAuth。所谓OAuth就是说,第三方的应用可以通过你的授权而不用知道你的帐号密码能够访问你在某网站的你自己的数据或功能。像Google, Facebook, Twitter等网站都提供了OAuth服务,提供OAuth服务的网站一般都有很多开放的API,第三方应用会调用这些API来开发他们的应用以让用户拥有更多的功能,但是,当用户在使用这些第三方应用的时候,这些第三方的应用会来访问用户的帐户内的功能和数据,所以,当第三应用要干这些事的时候,我们不能让第三方应用弹出一个对话框来问用户要他的帐号密码,不然第三方的应用就把用户的密码给获取了,所以,OAuth协议会跳转到一个页面,让用户授权给这个第三方应用以某些权限,然后,这个权限授权的记录保存在Google/Facebook/Twitter上,并向第三方应用返回一个授权token,于是第三方的应用通过这个token来操作某用户帐号的功能和数据时,就畅通无阻了。下图简单地说明了Twitter的OAuth的授权过程。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (44 人打了分,平均分: 4.57 )
Loading...
一个“蝇量级” C 语言协程库

一个“蝇量级” C 语言协程库

(感谢网友 @我的上铺叫路遥 投稿)

协程(coroutine)顾名思义就是“协作的例程”(co-operative routines)。跟具有操作系统概念的线程不一样,协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程技巧。实际上协程的概念比线程还要早,按照 Knuth 的说法“子例程是协程的特例”,一个子例程就是一次子函数调用,那么实际上协程就是类函数一样的程序组件,你可以在一个线程里面轻松创建数十万个协程,就像数十万次函数调用一样。只不过子例程只有一个调用入口起始点,返回之后就结束了,而协程入口既可以是起始点,又可以从上一个返回点继续执行,也就是说协程之间可以通过 yield 方式转移执行权,对称(symmetric)、平级地调用对方,而不是像例程那样上下级调用关系。当然 Knuth 的“特例”指的是协程也可以模拟例程那样实现上下级调用关系,这就叫非对称协程(asymmetric coroutines)。

基于事件驱动模型

我们举一个例子来看看一种对称协程调用场景,大家最熟悉的“生产者-消费者”事件驱动模型,一个协程负责生产产品并将它们加入队列,另一个负责从队列中取出产品并使用它。为了提高效率,你想一次增加或删除多个产品。伪代码可以是这样的:

# producer coroutine
loop
while queue is not full
  create some new items
  add the items to queue
yield to consumer

# consumer coroutine
loop
while queue is not empty
  remove some items from queue
  use the items
yield to producer

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (29 人打了分,平均分: 4.72 )
Loading...
分布式系统的事务处理

分布式系统的事务处理

当我们在生产线上用一台服务器来提供数据服务的时候,我会遇到如下的两个问题:

1)一台服务器的性能不足以提供足够的能力服务于所有的网络请求。

2)我们总是害怕我们的这台服务器停机,造成服务不可用或是数据丢失。

于是我们不得不对我们的服务器进行扩展,加入更多的机器来分担性能上的问题,以及来解决单点故障问题。 通常,我们会通过两种手段来扩展我们的数据服务:

1)数据分区:就是把数据分块放在不同的服务器上(如:uid % 16,一致性哈希等)。

2)数据镜像:让所有的服务器都有相同的数据,提供相当的服务。

对于第一种情况,我们无法解决数据丢失的问题,单台服务器出问题时,会有部分数据丢失。所以,数据服务的高可用性只能通过第二种方法来完成——数据的冗余存储(一般工业界认为比较安全的备份数应该是3份,如:Hadoop和Dynamo)。 但是,加入更多的机器,会让我们的数据服务变得很复杂,尤其是跨服务器的事务处理,也就是跨服务器的数据一致性。这个是一个很难的问题。 让我们用最经典的Use Case:“A帐号向B帐号汇钱”来说明一下,熟悉RDBMS事务的都知道从帐号A到帐号B需要6个操作:

  1. 从A帐号中把余额读出来。
  2. 对A帐号做减法操作。
  3. 把结果写回A帐号中。
  4. 从B帐号中把余额读出来。
  5. 对B帐号做加法操作。
  6. 把结果写回B帐号中。

为了数据的一致性,这6件事,要么都成功做完,要么都不成功,而且这个操作的过程中,对A、B帐号的其它访问必需锁死,所谓锁死就是要排除其它的读写操作,不然会有脏数据的问题,这就是事务。那么,我们在加入了更多的机器后,这个事情会变得复杂起来:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (62 人打了分,平均分: 4.79 )
Loading...
函数式编程

函数式编程

当我们说起函数式编程来说,我们会看到如下函数式编程的长相:

  • 函数式编程的三大特性:
    • immutable data 不可变数据:像Clojure一样,默认上变量是不可变的,如果你要改变变量,你需要把变量copy出去修改。这样一来,可以让你的程序少很多Bug。因为,程序中的状态不好维护,在并发的时候更不好维护。(你可以试想一下如果你的程序有个复杂的状态,当以后别人改你代码的时候,是很容易出bug的,在并行中这样的问题就更多了)
    • first class functions:这个技术可以让你的函数就像变量一样来使用。也就是说,你的函数可以像变量一样被创建,修改,并当成变量一样传递,返回或是在函数中嵌套函数。这个有点像Javascript的Prototype(参看Javascript的面向对象编程
    • 尾递归优化:我们知道递归的害处,那就是如果递归很深的话,stack受不了,并会导致性能大幅度下降。所以,我们使用尾递归优化技术——每次递归时都会重用stack,这样一来能够提升性能,当然,这需要语言或编译器的支持。Python就不支持。
  • 函数式编程的几个技术
    • map & reduce :这个技术不用多说了,函数式编程最常见的技术就是对一个集合做Map和Reduce操作。这比起过程式的语言来说,在代码上要更容易阅读。(传统过程式的语言需要使用for/while循环,然后在各种变量中把数据倒过来倒过去的)这个很像C++中的STL中的foreach,find_if,count_if之流的函数的玩法。
    • pipeline:这个技术的意思是,把函数实例成一个一个的action,然后,把一组action放到一个数组或是列表中,然后把数据传给这个action list,数据就像一个pipeline一样顺序地被各个函数所操作,最终得到我们想要的结果。
    • recursing 递归 :递归最大的好处就简化代码,他可以把一个复杂的问题用很简单的代码描述出来。注意:递归的精髓是描述问题,而这正是函数式编程的精髓。
    • currying:把一个函数的多个参数分解成多个函数, 然后把函数多层封装起来,每层函数都返回一个函数去接收下一个参数这样,可以简化函数的多个参数。在C++中,这个很像STL中的bind_1st或是bind2nd。
    • higher order function 高阶函数:所谓高阶函数就是函数当参数,把传入的函数做一个封装,然后返回这个封装函数。现象上就是函数传进传出,就像面向对象对象满天飞一样。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (57 人打了分,平均分: 4.82 )
Loading...
X-Y Problem

X-Y Problem

X-Y Problem

对于X-Y Problem的意思如下:

1)有人想解决问题X
2)他觉得Y可能是解决X问题的方法
3)但是他不知道Y应该怎么做
4)于是他去问别人Y应该怎么做?

简而言之,没有去问怎么解决问题X,而是去问解决方案Y应该怎么去实现和操作。于是乎:

1)热心的人们帮助并告诉这个人Y应该怎么搞,但是大家都觉得Y这个方案有点怪异。
2)在经过大量地讨论和浪费了大量的时间后,热心的人终于明白了原始的问题X是怎么一回事。
3)于是大家都发现,Y根本就不是用来解决X的合适的方案。

X-Y Problem最大的严重的问题就是:在一个根本错误的方向上浪费他人大量的时间和精力

示例

举个两个例子:

Q) 我怎么用Shell取得一个字符串的后3位字符?
A1) 如果这个字符的变量是$foo,你可以这样来 echo ${foo:-3}
A2) 为什么你要取后3位?你想干什么?
Q) 其实我就想取文件的扩展名
A1) 我靠,原来你要干这事,那我的方法不对,文件的扩展名并不保证一定有3位啊。
A1) 如果你的文件必然有扩展名的话,你可以这来样来:echo ${foo##*.}

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (66 人打了分,平均分: 4.86 )
Loading...