乘分配

当小学学会了乘法分配。详细乘法分配:并与多个两个数相乘的,他们能够把这个数字乘以,然后加入。由于一个恒定。乘法分配律也能够使用表达式的定义“(a+b)×c = a×c+b×c”的形式给出。乘法分配律的反用“a×c+b×c = (a+b)×c”相同成立。比如“10.2×(3+7) = 10.2×3+10.2×7 = 102”(反用形式为“10.2×3+10.2×7 = 10.2×(3+7) = 102”)。

计算机世界中的乘法分配律

为了一窥计算机世界中的乘法分配律,本文给出下面实例进行探究。

本例中先将整数24(纪念儿时玩过的名为“24点”的游戏)切割成四个整数的和,此部分操作在GetNumberList()方法中实现,切割后的四个整数保存进结构体变量中。整数24的全部切割结果则保存进List<Number>类型的集合numList中。

接着遍历集合numList。每次遍历中先取出24的四个切割数分别与5相乘再相加(相当于乘法分配律中的a×c+b×c部分)得到结果result1,再将计算的结果result1与24 * 5(相当于乘法分配律中的(a+b)×c部分)的结果result进行比較,相等则输出true,否则输出false。

using System;
using System.Collections.Generic;
namespace NoticeDetailExp1
{
class Program
{
static void Main(string[] args)
{
List<Number> numList = new List<Number>();
numList = GetNumberList();
int result = 24 * 5;
int result1;
foreach (Number n in numList)
{
result1 = n.Num1 * 5
+ n.Num2 * 5
+ n.Num3 * 5
+ n.Num4 * 5;
}
Console.WriteLine("n.Num1={0}, n.Num1={1}, n.Num1={2}, n.Num1={3}:result1 == result? {4}", n.Num1, n.Num2, n.Num3, n.Num4, result1 == result);
}
private static List<Number> GetNumberList()
{
List<Number> numList = new List<Number>();
for(int i=0; i<=24; i++)
for(int j=0; j<=24; j++)
for(int k=0; k<=24; k++)
for(int l=0; l<=24; l++)
if (i + j + k + l == 24)
{
Number num = new Number();
num.Num1 = i;
num.Num2 = j;
num.Num3 = k;
num.Num4 = l;
numList.Add(num);
}
return numList;
}
}
public struct Number
{
public int Num1 { get; set; }
public int Num2 { get; set; }
public int Num3 { get; set; }
public int Num4 { get; set; }
}
}

执行程序,得到下图所看到的结果。

大家从图中能看出什么呢?

【DD(不是“小弟弟”的缩写,至于是什么。你猜):我从图中能够看出。显示结果不全。

作者:呵呵。DD真是观察仔细入微。

结果是不全。可是本人通过拖动滚动栏已经确认全部返回结果都是true】

从结果了解到对于整型数据来说,乘法分配律全然适用。

那么将样例中的整型数据换成Double型数据,结果又会如何呢?

改动实例中的部分代码,其它代码保持不变,以下仅给出改动部分的代码。

//将整数5改动成Double型数183.70833333333334
//将result。result1的类型由int改动成double
double result = 24 * 183.70833333333334;
double result1;
foreach (Number n in numList)
{
//将整数5改动成Double型数183.70833333333334
result1 = n.Num1 * 183.70833333333334
+ n.Num2 * 183.70833333333334
+ n.Num3 * 183.70833333333334
+ n.Num4 * 183.70833333333334;
Console.WriteLine("n.Num1={0}, n.Num1={1}, n.Num1={2}, n.Num1={3}:result1 == result? {4}", n.Num1, n.Num2, n.Num3, n.Num4, result1 == result);
}

运行改动后的代码,得到下图所看到的的结果。

当然,这里给出的结果也是不全的,只是对说明问题没有不论什么影响。

从图中能够看出,将整型数据换成Double型数据后,返回的结果中出现了相当数量的false,也就是说result与result1不再是绝对地相等了。我们能够通过Debug程序看看当中究竟发生了什么。 以下以图中显示的返回结果为false的第一条数据为例。看看此时的result1的值是多少,为4409.0000000000009。而result的值为4409.0,非常显然将两者进行相等比較。自然会返回false,尽管两者仅相差0.0000000000009,不相等就是不相等。

那么,0.0000000000009的差距是如何产生的呢。

我们知道计算机在计算表达式“result1 = n.Num1 * 183.70833333333334  + n.Num2 * 183.70833333333334 + n.Num3 * 183.70833333333334 + n.Num4 * 183.70833333333334;”的值时。事实上会将运算分解成多步。用代码来表示其运算过程的话,应该与下面代码所看到的的运算过程类似。

double multi1 = n.Num1 * 183.70833333333334;
double multi2 = n.Num2 * 183.70833333333334;
double multi3 = n.Num3 * 183.70833333333334;
double multi4 = n.Num4 * 183.70833333333334;
result1 = multi1 + multi2 + multi3 + multi4;

而我们知道,浮点运算是不准确的,由于:计算机在处理浮点数的时候,会先把浮点数(float , double)转换成整数再转换成二进制,然后进行操作,假设有取余,会有不同的取余方式。

再加上运算完毕后,将二进制转换成上层的浮点数时,又会有一些取舍。这样一来,就会使终于的计算结果存在一定的误差。

再回到我们的问题,计算“double result = 24 * 183.70833333333334”会进行一次浮点运算。而计算“result1 = n.Num1 * 183.70833333333334+ n.Num2 * 183.70833333333334+ n.Num3 * 183.70833333333334+ n.Num4 * 183.70833333333334”时至少会进行5次浮点运算或者很多其它(这里有点拿不准)。每一次浮点运算都有可能伴随着误差的发生。所以导致终于看到的结果会随机性地产生一些偏差。

所以,在计算机的世界中。乘法分配律将不再适用。当然假设你对这一点点的损失无动于衷的话,你也能够觉得在计算机世界中乘法分配律相对地适应于浮点运算。

只是。这个问题隐藏的也太深了点吧。



非正确使用浮点型数据导致项目BUG了

在开发过程中要是没有考虑到前文所述的问题,往往会导致一些奇葩的BUG。

以前在项目代码中就看到了与实例代码相差无几的一段代码,代码中相同使用if (result1 == result)来进行条件推断,满足此条件后再进行其它一些操作,项目上线后非常长一段时间都相安无事,突然有一天这段代码产生BUG了,至于BUG原因,就算我不说大家也清楚。

后来花了非常大力气才搞清楚了问题的所在。问题弄清楚后。也才有了本文的产生。

所以本文作者想告诉大家:无论怎么说,开发中。在使用浮点型数据时,我们必须清楚浮点运算的特点,以免产生本文所述的类似的问题。

版权声明:本文博主原创文章,博客,未经同意不得转载。

非正确使用浮点数据由项目产生BUG讨论的问题的更多相关文章

  1. 对非正确使用浮点型数据而导致项目BUG的问题探讨

    乘法分配律 在上小学的时候就已经学习过乘法分配律,乘法分配律的详细内容是:两个数的和与一个数相乘.能够先把他们分别与这个数相乘,再相加.得数不变.乘法分配律的定义还能够用表达式"(a+b)× ...

  2. 计算机保研,maybe this is all you need(普通双非学子上岸浙大工程师数据科学项目)

    写在前面 9.28接收了拟录取通知,也终究是尘埃落定了,我人生的又一个阶段也终于结束.面对最终录取结果,或多或少会有所遗憾,但也还是基本达到了预期的目标了. 作为在今年严峻的保研形势下幸存的我,一直想 ...

  3. 以正确的方式开源 Python 项目

    以正确的方式开源 Python 项目 大多数Python开发者至少都写过一个像工具.脚本.库或框架等对其他人也有用的工具.我写这篇文章的目的是让现有Python代码的开源过程尽可能清 晰和无痛.我不是 ...

  4. 以正确的方式开源 Python 项目(转)

    大多数Python开发者至少都写过一个像工具.脚本.库或框架等对其他人也有用的工具.我写这篇文章的目的是让现有Python代码的开源过程尽可能清晰和无痛.我不是简单的指——“创建一个GitHub库,提 ...

  5. 浮点数据有损压缩算法 附完整C代码

    在几年前的时候在做修图APP算法的时候, 曾经一度想过对3D Lut 预设数据进行压缩, 主要用于提升用户体验. 关于3d lut算法开源的资源也挺多的,就不多做科普了. 有兴趣的朋友,可以去查阅下f ...

  6. 在javaScript中把非数值类型的数据自动转换为数值类型的两种方式

    一.使用Number()函数. 二.使用parseInt()/parseFloat()函数. 详情: 一.使用Number()函数将非数值类型的数据自动的转化为数组类型 Number()函数可以将任何 ...

  7. 全网最详细的IDEA里如何正确新建普通的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(类似eclipse里同一个workspace下【一个子项目】并存)(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 如果是在Myeclipse里,则是File -> new -> ...

  8. 全网最详细的Eclipse里如何正确新建普通的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 如果是在Myeclipse里,则是File -> new -> ...

  9. 全网最详细的MyEclipse里如何正确新建普通的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 如果是在eclipse里,则是File -> new ->  ...

随机推荐

  1. ANSI Common Lisp 中文翻譯版 — ANSI Common Lisp 中文版

    ANSI Common Lisp 中文翻譯版 — ANSI Common Lisp 中文版 ANSI Common Lisp 中文翻譯版¶

  2. FreeNAS 9.1.1 发布,网络存储系统 - 开源中国社区

    FreeNAS 9.1.1 发布,网络存储系统 - 开源中国社区 FreeNAS 9.1.1 发布,网络存储系统

  3. ajaxterm不好还是gateone好

    http://pkgs.org/centos-5-rhel-5/epel-i386/Ajaxterm-0.10-8.el5.noarch.rpm.html Web SSH 客户端Ajaxterm安装 ...

  4. Hadoop大数据面试--Hadoop篇

    本篇大部分内容參考网上,当中性能部分參考:http://blog.cloudera.com/blog/2009/12/7-tips-for-improving-mapreduce-performanc ...

  5. POJ 2826 An Easy Problem?! 好的标题

    受该两块木板以形成槽的效果.Q槽可容纳雨水多,注意雨爆跌,思想是非常easy,分类讨论是有点差. 1.假定两条线段不相交或平行,然后再装0: 2.有一个平行x轴.连衣裙0. 3.若上面覆盖以下的,装0 ...

  6. 【VBA研究】查找目录以下全部文件的名称

    作者:iamlaosong 目录里面保存有面单扫描的图像文件,文件名称为邮件号码.如今想收集这些邮件号码,由于量非常大,不可能一个一个的截取,仅仅能通过程序实现.假定,当前工作表B列里放的是存放这些图 ...

  7. 国内国外MD5在线解密站点

    -http://www.cmd5.com/english.aspx (457,354,352,282) - http://www.md5crack.com - http://www.hashcheck ...

  8. 158个JAVA免豆精品资料汇总

    附件完整版下载地址: http://down.51cto.com/data/431561 附件部分预览~ java中国移动收费系统[源代码] http://down.51cto.com/data/70 ...

  9. HDOJ 5276 YJC tricks time multimap

    multimap的使用 YJC tricks time Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/262144 K ...

  10. iPhone 6 首发无大陆,DevStore要去香港吗?

    iPhone 6 正式公布,微博已经被刷屏.iPhone 6 的各种信息都已经明了,先不说什么配置,什么设计,就说一点--iPhone6 首发地方是没有中国大陆的.这让我想起来最近參加的源代码大赛,这 ...