10% + 10% = 0.11 ?是 bug 还是 feature ?微软开源的计算器项目告诉你答案!
点击蓝色“五分钟学算法”关注我哟
加个“星标”,天天中午 12:15,一起学算法
作者 | 守望先生
来源 | 编程珠玑
前言
近日,关于手机计算器10%+10%=0.11的事情火热,多个品牌的手机未能幸免,基本“阵亡”,同时还包括了windows10的自带标准计算器。你的手机阵亡了吗?
%10+10%按理应该等于0.2,为什么会出现这样的情况?
那么这是计算器的BUG?还是另有隐情?是程序员的不负责任,还是另有考虑?
真实情况
到底是怎么回事呢?实际上,这些计算器并不是为数学家和工程师准备的,但%的引入,却可以极大方便计算折扣,税率,小费等。比如一件100元的衣服,折扣20%:
100 - 20% 80实际上它计算的是
100 - (100*20%)早期计算器的按键比较少,没有括号,能显示的字符长度也有限,因此%在这种场景下能解决痛点,极大减少按键数量。
当然了国内我们通常见到的是打几折,不过国外的网站是这样的:
折扣通常都会用类似10% off这样的表达。针对这种表达的计算方式也逐渐成为了一种”标准“,所以在我们的很多计算器中都有。
所以10%+10%实际上计算的是:
10% + 10% * 10% = 0.11但是对于国内的用户来说,如果计算器没有括号你会怎么计算?你可能是会按照下面这样:
100 * 0.8 = 80毕竟是受过九年义务教育的优秀青年,小数还不会么?
同时你也可以看到在微软自带的计算器(win+r,输入calc回车即可打开)中,标准型计算器有%:
不过它计算10%+10%计算得出的值可能每次都不一样,我们稍后解释。
而科学型和程序员型中,压根没有%运算符,通常也不会用百分数直接计算,而是用小数。
那么在标准计算器或者说这些简单功能的计算器中%到底是什么作用呢?
从代码角度来看
作为一个程序员,自然要从代码的角度来看了。为此我在 github 上找到了微软开源的计算器项目,其地址为:
我找到关于%计算的部分,摘出了其中相关的代码:
case IDC_PERCENT: { // If the operator is multiply/divide, we evaluate this as "X [op] (Y%)" // Otherwise, we evaluate it as "X [op] (X * Y%)" if (m_nOpCode == IDC_MUL || m_nOpCode == IDC_DIV) { result = rat / 100; } else { result = rat * (m_lastVal / 100); } break; }注释中也已经解释了(论一个好注释的重要性),当操作符是乘法或者除法的时候,与%相关的直接除以100再和另外的数操作(即我们通常认识的算法),否则就按照上一次结果的百分比来计算。
结果 操作 0 初始值 0 输入10%,计算0 + 10% * 0 0 输入+10%,计算0 + 10 *0最终会得到0。只不过很多手机计算器中直接把第一个10%当成了0.1,这也就是我们看到一些手机计算器最终会得到0.11结果的原因。
但是如果你计算100 * 10%,它按照原始的方式计算,即计算得到10。
所以这是有意为之,而并非什么bug!程序员不背这个锅。
另外我们都知道,%常用于取模运算,它是一个二元运算符,例如:
所以当你在Linux的命令行输入bc,然后输入10+10%,你会看到下面的结果
$ bc 10+10% (standard_in) 3: syntax error 10%3 1没错,它会提示你语法错误,而不是帮你计算10的10%,因为这里的%并非计算百分数,而是用来取模的。所以在windows自带的程序员计算器和科学计算器中,有MOD,而没有%。
注:bc命令是Linux一个强大的计算器。
总结
%在某些场景方便计算,这不是bug,而是feature。
讨论
你觉得有必要使用这种计算方式吗?欢迎留言说出你的看法!
你的手机”阵亡“了吗?
有热门推荐👇
1.【程序员】全球最厉害的 14 位程序员
2.【GitHub】我在 GitHub 上看到了一个丧心病狂的开源项目!
3.【算法】动画:七分钟理解什么是KMP算法
4.【数据结构】十大经典排序算法动画与解析,看我就够了
- 开源还是商用?十大云运维监控工具测评告诉你答案
- 【PMP】PMP相关-做一个项目是自己从头开发还是开源项目二次开发?
- 微软BUG Bounty悬赏项目扩展至.NET Core和ASP.NET Core
- 微软开源项目MSBEE 解决.net2.0VS.net1.1 过渡中兼容问题
- 微软再次转变:为开源项目成立子公…
- 第一次怀疑是微软bug,还是我又错了?以前都是从自己身上找问题,这次想从微软身上找问题了
- 微软开源项目站点
- 战争结束:微软为 SAMBA 开源项目贡献代码
- Github上如何为开源项目提bug?
- 微软开源项目MSBEE 解决.net2.0VS.net1.1 过渡中兼容问题
- 微软开源项目MSBEE 解决.net2.0VS.net1.1 过渡中兼容问题
- 关于微软的开源项目的分享
- 我搞了一个开源的项目,网址http://akenxp.gro.clinux.org目前还是计划阶段,欢迎大家加盟。
- 微软开源项目MSBEE 解决.net2.0VS.net1.1 过渡中兼容问题
- 微软开源项目MSBEE 解决.net2.0VS.net1.1 过渡中兼容问题
- Apache POI是一个开源的Java读写Excel、WORD等微软OLE2组件文档的项目。目前POI已经有了Ruby版本
- 微软Codeplex最热门的25个开源项目
- 高分求救,微软屏传开源的项目,里面也有屏传的代码,是用C#实现的。
- 关于开源项目侧边栏字母搜索列表ListViewFilter的bug解决办法
- .NET微软技术 开源项目建设 - 我们开源就是要赚钱