专栏首页五分钟学算法10% + 10% = 0.11 ?是 bug 还是 feature ?微软开源的计算器项目告诉你答案!

10% + 10% = 0.11 ?是 bug 还是 feature ?微软开源的计算器项目告诉你答案!

作者 | 守望先生

来源 | 编程珠玑

前言

近日,关于手机计算器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 上找到了微软开源的计算器项目,其地址为: https://github.com/microsoft/calculator/

我找到关于%计算的部分,摘出了其中相关的代码:

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再和另外的数操作(即我们通常认识的算法),否则就按照上一次结果的百分比来计算。 所以,如果你计算10%+10%,它是下面的过程:

结果 操作
0    初始值
0    输入10%,计算0 + 10% * 0
0    输入+10%,计算0 + 10 *0

最终会得到0。只不过很多手机计算器中直接把第一个10%当成了0.1,这也就是我们看到一些手机计算器最终会得到0.11结果的原因。

但是如果你计算100 * 10%,它按照原始的方式计算,即计算得到10。

所以这是有意为之,而并非什么bug!程序员不背这个锅。

另外我们都知道,%常用于取模运算,它是一个二元运算符,例如: 10%3 = 1

所以当你在Linux的命令行输入bc,然后输入10+10%,你会看到下面的结果

$ bc
10+10%
(standard_in) 3: syntax error
10%3
1

没错,它会提示你语法错误,而不是帮你计算10的10%,因为这里的%并非计算百分数,而是用来取模的。所以在windows自带的程序员计算器和科学计算器中,有MOD,而没有%。

注:bc命令是Linux一个强大的计算器。

总结

%在某些场景方便计算,这不是bug,而是feature

本文分享自微信公众号 - 五分钟学算法(CXYxiaowu)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 法解种三的数文回:画动

    判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

    五分钟学算法
  • 好吧,又是两分钟看完一道投机取巧的算法题

    事实上,你在使用暴力破解法的过程中就能发现规律: 这 9 个数字中只有 2(它的倍数) 与 5 (它的倍数)相乘才有 0 出现。

    五分钟学算法
  • 每天一算:Evaluate Reverse Polish Notation

    我们会在每天早上8点30分准时推送一条LeetCode上的算法题目,并给出该题目的动画解析以及参考答案,每篇文章阅读时长为五分钟左右。

    五分钟学算法
  • 震惊!10%+10%=0.11?是bug还是feature?

    近日,关于手机计算器10%+10%=0.11的事情火热,多个品牌的手机未能幸免,基本“阵亡”,同时还包括了windows10的自带标准计算器。你的手机阵亡了吗?

    帅地
  • 10%+10%=0.11?是bug还是feature?

    近日,关于手机计算器10%+10%=0.11的事情火热,多个品牌的手机未能幸免,基本“阵亡”,同时还包括了windows10的自带标准计算器。你的手机阵亡了吗?

    编程珠玑
  • Swift 优雅的适配大小

    SwiftyFitsize在默认状况下所使用的参照宽度为iphone6的375 如果设计图所选用设备的宽度与默认值不同,可以在AppDelegate下初始化所...

    LinXunFeng
  • 使用Python列表实现向量运算

    在Python中,列表支持与整数的乘法运算,但表示的是列表元素的重复,并生成新列表,如: >>> [1,2,3]*3 [1, 2, 3, 1, 2, 3, 1...

    Python小屋屋主
  • Leetcode-Easy 806. Number of Lines To Write String

    给一个字符串S,从左到右将它们排列行,每行最大长度为100,,同时给定一个数组withds,widths[0]对应着 a的宽度, widths[1]对应着b的宽...

    致Great
  • 【收藏】黎活明给程序员的忠告

    展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告 走过的路,回忆起来是那么曲折,把自己的一些心得体会分享给程序员兄弟姐妹们,虽然时代...

    一个淡定的打工菜鸟
  • 自增自减表达式-c语言学习笔记

    Youngxj

扫码关注云+社区

领取腾讯云代金券