浮点数精度丢失的"bug"不停的被种语言的开发人员或者数据库开发人员发现,或许有些人已经听说了其中的原因,但是仍然无法把握其出现的规律。解决问题的最好办法是让错误原因重现,而能让错误随时重现,说明该错误已经在你掌控之中,从而可以在真正的开发中去避免。
我们看两个场景:
一个是c#代码,他没有按照预期的输出0.1,而是0.10000000149011612
Console.WriteLine(Convert.ToDouble(
0.1f
));
一个是SQL代码,他和c#代码出现了同样的错误
declare
@f
float
(
23
)
declare
@s
float
(
53
)
set
@f
=
0.1
set
@s
=
@f
select
@s
这个错误出于什么原因,最权威的解释就是ieee754浮点数标准,可以参考msdn:
http://msdn.microsoft.com/zh-cn/library/0b34tf65(VS.80).aspx
如果你觉得他的描述过于枯燥,或者还无法与上面的错误示例结合起来的话,可以参考我的一些理解
我们用的很多十进制数是无法转为精确的二进制数的,包括0.1,0.2,0.11这样简单的小数对于IEEE浮点数格式来说是个无限循环小数,0.25,0.5,0.375这样的小数才能转为精确的二进制小数。
举个例子,比如十进制0.1和十进制0.375 这两个数,我们来手工转一下,思路很简单,同小学生学科学记数法一样。
0.375=0.375 * 2^2 *2^(-2)=1.5*2^(-2) //整数位在1-2之间,我们以前十进制也是这样做的!!
0.5=0.5*2*2^(-1)
0.375=2^-(2)+2^(-1 + -2)=0.011 //他是个有限小数
如果用分数表达可能更明了点
0.375=1/4+1/8 = 0.01+0.001=0.011
---------
0.1=1.6*(1/16)
=1/16+0.6/16
=1/16+1.2/32
=1/16+1/32+0.2/32
=1/16+1/32+1.6/2^8
=1/2^4+1/2^5+1/2^8+0.6/2^8
...显然和第二步的步骤一样了回到了0.6,他是个无限循环小数
0.1=0.00011001 00011001 00011001 00011001 ...无论机器尾数多长都不会精确的何况只有23或52位
然后我们再看以下一段代码测试的例子:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication19
{
class Program
{
static void Main(string[] args)
{
//无限循环小数的0.1,在数据类型转换时出现精度丢失。
Console.WriteLine(Convert.ToDouble(0.1f));
//有限小数的0.375不会出现。
Console.WriteLine(Convert.ToDouble(0.375f));
//实际情况当中的两个精度不同的数据在做运算时就会出现问题。
//那为什么相同精度的情况下不会出现精度丢失问题,这个是优化过的。
//还是0.1为例,他的内存数据
byte[] b = System.BitConverter.GetBytes(0.1f);
foreach (byte bb in b)
{
Console.Write("{0} ",bb);
}
Console.WriteLine("\r\n");
//可以看到第一个205是进位过的,其他的都是204,这个就像是3/2转为0.66667的意思一样。
b[0] -= 1;
float f = BitConverter.ToSingle(b, 0);
//f的实际值为0.099999994f,但是默认输出的时候把最后一个4给舍掉了
Console.WriteLine(f);
//因此系统是无法识别0.099999994f到0.1之间的精度的。
//设断点一次察看下面的浮点数,就知道了,到了0.099999998f它就自动进位为0.1了。
float f1 = 0.099999994f;
float f2 = 0.099999995f;
float f3 = 0.099999996f;
float f4 = 0.099999997f;
float f5 = 0.099999998f;
float f6 = 0.099999999f;
Console.WriteLine("f1:{0}\r\nf2:{1}\r\nf3:{2}\r\nf4:{3}\r\nf5:{4}\r\nf6:{5}",f1,f2,f3,f4,f5,f6);
//用BitConverter.GetBytes检查上面的6个浮点数,你会发现f1到f4是一样的,而f5、f6和0.1是一样的。
Console.Read();
}
}
}
分享到:
相关推荐
本文将围绕“浮点数与IEEE754的转换”这一主题进行深入探讨,旨在帮助读者理解浮点数的基本概念、IEEE754标准以及如何在实际编程中实现浮点数与IEEE754格式之间的转换。 ### 浮点数基本概念 浮点数是一种用于表示...
与之相比,IEEE 754是国际广泛采用的浮点数标准,它定义了32位单精度(float)和64位双精度(double)浮点数格式。 对于32位IEEE 754单精度浮点数到VC33的转换,首先我们需要解析IEEE 754格式的数值。32位单精度...
IEEE754是计算机科学中用于表示浮点数的标准,由国际电气和电子工程师协会(IEEE)于1985年制定,并在后续版本中进行了更新。这一标准对浮点数的存储格式、精度、运算规则以及异常处理等进行了明确规定,旨在确保...
这两个函数的核心逻辑是通过解析输入的十六进制字符串或字节数组中的每个字节,从而获取符号位、指数位和尾数位的信息,并根据IEEE754的标准公式重新计算出浮点数的实际值。 #### 七、总结 通过上述内容的学习,...
IEEE754 浮点数计算器 。。。。。。。。。。。。。。。。。。。。。。。
IEEE754字节转单精度/双精度浮点数
IEEE 754浮点数标准是计算机中表示浮点数的一种标准,最初由美国电气和电子工程师协会(IEEE)在1985年发布,并且成为了国际上广泛采纳的浮点数计算标准。该标准定义了浮点数的二进制表示、运算规则、异常处理以及舍...
IEEE754是一种国际标准,定义了如何用二进制表示浮点数,以确保不同系统间的一致性和兼容性。VB.Net(Visual Basic .NET)是一种常用的编程语言,它支持这种转换以便于开发者在程序中处理浮点数。 在VB.Net中,进行...
IEEE754标准是计算机科学领域中用于表示浮点数的一种广泛采用的国际标准,由电气和电子工程师协会(IEEE)制定。这个标准为单精度和双精度浮点数提供了统一的编码方式,使得不同计算机系统之间能够准确无误地交换...
IEEE 754 是一种广泛应用于计算机科学中的浮点数表示标准,由电气和电子工程师协会(IEEE)制定。它定义了如何在二进制系统中存储和操作浮点数,包括单精度(32位)和双精度(64位)格式。双精度浮点型是IEEE 754...
IEEE 754 单精度浮点数转换工具,支持十进制与单精度浮点数/双精度浮点数之间的互相转换
在计算机科学中,IEEE754标准是用于表示浮点数的一种国际标准,它定义了浮点数的存储格式,使得不同计算机系统之间可以一致地表示和交换浮点数值。这个标准广泛应用于各种编程语言和硬件平台,包括处理器、GPU以及...
学习计算机组成原理时实现的IEEE754标准的浮点数的机器数转换器,只要填入十进制浮点数值,便可以求出单精度的IEEE754标准的机器数表示方法,反之,给出IEEE754的机器数,可以求出其对应的十进制浮点数值
### IEEE浮点数标准IEEE754概述 IEEE 754标准是国际电子与电气工程师学会(IEEE...总之,IEEE754标准不仅是理解现代计算机系统中浮点数表示和运算的基础,也是实现高性能计算、科学计算等领域应用不可或缺的技术基石。
IEEE 754 是一个国际标准,由电气和电子工程师协会(IEEE)制定,用于规范浮点数的存储格式。这个标准确保了不同计算机系统之间浮点数的兼容性,使得数据在不同平台间可以准确地交换和计算。 浮点数的表示通常分为...
IEEE754 浮点数格式定义了单精度(32 位)和双精度(64 位)两种浮点数类型。本例中关注的是 32 位浮点数的转换,其结构如下: - **符号位(S)**:1 位,最高位表示符号,0 表示正数,1 表示负数。 - **指数部分...
本篇文章将深入探讨IEEE754标准下的浮点数表示法以及如何在C++(以示例语言)中实现浮点数与整数之间的相互转换。首先,我们来理解一下IEEE754浮点数标准。 IEEE754是国际电工委员会(IEEE)制定的一种浮点数二进制...
在计算机科学中,IEEE754标准是用于表示浮点数的一种广泛采用的格式,旨在确保不同计算机系统间的兼容性和精确度。这个标准定义了浮点数的存储布局、表示方法以及相关的运算,包括加法、减法、乘法和除法等。本文将...
IEEE754 浮点数格式是计算机中浮点数表示的标准格式,由于不同机器所选的基值、尾数位长度和阶码位长度不同,因此对浮点数表示有较大差别,为了解决这个问题,美国 IEEE(电子及电子工程师协会)提出了 IEEE 754 ...