目录

介绍

背景

银行家舍入

从零舍入一半

舍入一半以上

Math≠数学

总结

参考


关于.NET的Math.Round的意外行为

介绍

在开始之前,想象一下运行以下内容后“ a”和“ b”会有什么值:

a = Math.Round(1.5);
b = Math.Round(2.5);

如果你的答案是“ a = 2和b = 3”,你就像我一样,错了。正确的答案是两者a和b最终都是2。困惑吗?您可能想要坚持知道原因。

背景

大约一个星期前,我正在研究一些沿着x轴移动两个实体的代码。在库内部,它们的x值是double,但是public接口只允许以整数形式的米(这里应该是单位的意思)。我曾经使用Math.Round把这个double值转换成整数。

代码的要求之一是实体之间的距离绝不会超过一米。我使用舍入值来检查这个。

正如您现在可能已经猜到的那样,代码仍然失败。即使两个实体相距一米之外,具有相同的起始速度并且以相同的速度加速,使用相同的算法,整数值仍然偶尔返回相同的x值,因此代码保持失败。

起初,我认为这是使用double值导致的某种精度错误。但这没有多大意义,因为算法会导致两个值的精度损失相同。经过一些调试后,我终于发现它不是double而是Math.Round表现得与我预期的不同。

银行家舍入

在我弄清楚问题是在使用Math.Round之后,我很快发现了问题:在.NET中舍入的默认[ 1]实现是“舍入一半到偶数” [ 2]又名“银行家舍入”。这意味着中点值向最接近的偶数舍入。在我在介绍中提供的示例中,这意味着两个值都是向着舍入2,最接近的偶数。

那么为什么它在.NET中实现这样呢?这是一个错误吗?

好吧,首次实施时,Microsoft遵循IEEE 754标准。这是默认Math.Round实现的原因。[3](:目前的IEEE 754标准包含五个舍入规则[4])

另一个很好的理由是,银行家的舍入没有遭受负向或正向的偏倚,就像舍弃零的舍入方法对于最合理的分布一样。

从零舍入一半

但一切都不会丢失。

如果您希望1.5要舍入2,并且2.5要舍入3(像我期望的),该Math.Round方法具有的覆盖方法,让您使用了“从零舍入一半” [5]的方法来代替。

a = Math.Round(1.5, MidpointRounding.AwayFromZero);
b = Math.Round(2.5, MidpointRounding.AwayFromZero);

在上面的代码片段中,1.5舍入到2并2.5舍入到3。

舍入一半以上

然而有趣的是,在做了一些研究之后,它看起来像“从零舍入一半”,也不是数学中常用的方法。相反,“舍入一半以上” [6]方法通常在数学中使用[7]。对于正数,没有差异,但对于负数,中点值向+∞舍入而不是从0舍入。

这样一来,有相同数量的分数被四舍五入到零,而在“从零舍入一半”的方法中,两者0.5和-0.5没有舍入到零,使零成为所有其他数字的例外。

Math≠数学

事实证明,Math.Round方法甚至不支持数学中常用的实际舍入方法。

当我第一次发现这个时,我非常失望。毕竟,即使提供了很好的理由,库仍然会被Math调用。它确实似乎传达了某种意图。

但是写这篇文章确实让我思考:在研究之前,我甚至都没有意识到有这么多的舍入方法。每个都有自己的优点和缺点。每个都有自己的后果。如果我不知道所有这些方法,我当然不知道这些后果。所以也许别人为我做这件事并做出适当的“默认”决定并不是一件坏事。

毕竟,如果你的舍入的后果对你的代码至关重要,我希望你不做我曾经做过的假设,或者至少至少发现他们在一些好的老式测试中是错误的。

总结

即使这个主题不是真正的脑外科(或火箭科学),但我真的希望你能学到新的东西,或者至少享受阅读。

最后,我认为这是一个很好的提醒,即使我们每天使用的看似简单的事情都是多么复杂。这里也可能有一些关于假设的教训。;)

快乐的舍入!

参考

  1. https://docs.microsoft.com/en-us/dotnet/api/system.math.round?view=netframework-4.7.2#midpoint-values-and-rounding-conventions
  2. https://en.wikipedia.org/wiki/Rounding#Round_half_to_even
  3. http://stackoverflow.com/questions/311696/why-does-net-use-bankers-rounding-as-default/6562018#6562018
  4. https://en.wikipedia.org/wiki/IEEE_754#Rounding_rules
  5. https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero
  6. https://en.wikipedia.org/wiki/Rounding#Round_half_up
  7. https://www.mathsisfun.com/numbers/rounding-methods.html(不确定这个参考的可靠性,但我找不到很多关于数学中的舍入方法)

原文地址:https://www.codeproject.com/Tips/1272542/How-NETs-Math-Round-has-Nothing-to-do-with-Maths-A

.NET的Math.Round与数学无关。没关系!相关推荐

  1. JavaScipt中的Math.ceil() 、Math.floor() 、Math.round()

    1. Math.ceil()用作向上取整. 2. Math.floor()用作向下取整. 3. Math.round() 我们数学中常用到的四舍五入取整. 转载于:https://www.cnblog ...

  2. java的round函数加点差_【JAVA】Math.Round()函数常见问题“四舍5入”

    java.lang.Math.Round()使用时候,处理方式整理,方便以后查找   /**  * 测试函数 2014-01-10  */ public class TestMath {     pu ...

  3. JavaScript中带有示例的Math.round()方法

    JavaScript | Math.round()方法 (JavaScript | Math.round() Method) Math.round() is a function in math li ...

  4. JAVA的静态方法的运算_java. util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作。...

    java. util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作. /* public static double abs ( double num):获取绝对值 ...

  5. java的round函数怎么用_Java Math round()用法及代码示例

    java.lang.Math.round()是内置数学函数,它返回最接近参数的long.通过将1/2相加,将结果四舍五入为整数,再加上1/2后取结果的下限,并将结果强制转换为long类型. 如果参数为 ...

  6. php tofixed,详解js四舍五入tofixed和Math.round方法

    在javascript:里数值计算一直存在着很多的问题,今天我们就不一一探讨了.今天我们主要是解决在js四舍五入是怎么实现的.在JS里四舍五入还是比较麻烦的呢,没有php四舍五入那么简单,下面我们就来 ...

  7. Math.round(11.5)等于多少? Math.round(-11.5)等于多少?

    Math.round()运算规则+0.5向下取整 package com.study.JavaBase;import org.junit.Test;/*** @Description Math.rou ...

  8. WinCE的C#编程,对float型进行四舍五入保留两位小数,小数进行四舍五入操作,Math.Round的应用案例。...

    private  float ConvertFloat4Se5Ru(float flotValue) {              int iValue = (int)Math.Round(flotV ...

  9. Math.round(11.5)等于多少?Math.round(-11.5)等于多少?

    ceil的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.6)的结果为-11: floor的英文是地板,该方法就表示向下取整,Math. ...

最新文章

  1. 阿里开源新一代人机对话模型 ESIM,曾创下人机对话准确率新纪录
  2. Centos6.5安装python2.7与pip
  3. spring boot 的常用注解使用 总结
  4. 蒙版遮住全屏(包括导航栏)
  5. 字符驱动之按键(一:无脑轮询法)
  6. 第十二篇:实用的关联容器
  7. 修改显卡型号软件_马甲显卡又双叕来了 怎么选知道吗?
  8. 安装centos7步骤_Centos7下源码编译安装mysql5.7 详细步骤 小白也能安装
  9. #if defined和#if !defined的含义
  10. 计算机辅助教学研究现状,国内计算机辅助口译教学研究的现状与思考.docx
  11. C++ malloc new 的区别
  12. Qt5.2.1 + VS2012 环境配置
  13. 第一章概述-------第一节--1.7 计算机网络体系结构
  14. 学大数据可以从事什么工作?前景如何?
  15. oracle提示错误1033,ora-1033 制造问题和解决问题
  16. 华为Mate系列主要参数
  17. 微信小程序 语音录制功能和文件(ppt、word、excel、pdf、txt格式)上传
  18. Linux 内核源码中likely()和unlikely()
  19. 【一种利用插值验证的FL隐私保护框架】VFL: A Verifiable Federated Learning
  20. 2.Enable ADB integration' to be enabled.

热门文章

  1. python获取命令行参数_Python获取命令行参数的正确方法,案例详解
  2. PSD分层情人节海报模板,让人眼前一亮
  3. 圣诞节海报设计还没开始?感受下合适的节日感PSD模板
  4. 促销海报设计的套路你知道么? 看这里!
  5. UI设计实用素材|iPhone样机模型(展示你的应用程序、网站或用户界面的完美方式。
  6. conda 删除env_软件包与环境管理神器之conda
  7. Python使用pip自动升级所有第三方库
  8. 基于HTML5的贪吃蛇游戏的设计与实现
  9. 用QEMU构建嵌入式LINUX系统
  10. 【gSOAP】gSOAP生成服务代理和对象C语言代码示例