浮点数的误差问题

一直很奇怪C#的预定义数据类型中为什么加了一个decimal,有float和double不就够了吗?今天来挖一挖。

浮点型

Name

CTS Type

Description

Significant Figures

Range (approximate)

float

System.Single

32-bit single-precision floating point

7

±1.5 × 10−45 to ±3.4 × 1038

double

System.Double

64-bit double-precision floating point

15/16

±5.0 × 10 −324 to ±1.7 × 10308

如果我们在代码中写一个12.3,编译器会自动认为这个数是个double型。所以如果我们想指定12.3为float类型,那么你必须在数字后面加上F/f:
float f = 12.3F;

decimal类型

作为补充,decimal类型用来表示高精度的浮点数

Name

CTS Type

Description

Significant Figures

Range (approximate)

decimal

System.Decimal

128-bit high precision decimal notation

28

±1.0 × 10−28 to ±7.9 × 1028

从上表可以看出,decimal的有效位数很大,达到了28位,但是表示的数据范围却比float和double类型小。decimal类型并不是C#中的基础类型,所以使用的时候会对计算时的性能有影响。

对decimal、float、double运算结果出现误差的分析

我们知道将一个十进制数值转换为二进制数值,需要通过下面的计算方法:

1. 整数部分:连续用该整数除以2,取余数,然后商再除以2,直到商等于0为止。然后把得到的各个余数按相反的顺序排列。简称"除2取余法"。

2. 小数部分:十进制小数转换为二进制小数,采用"乘2取整,顺序排列"法。用2乘以十进制小数,将得到的整数部分取出,再用2乘余下的小数部分,然后再将积的整数部分取出,如此进行,直到积中的小数部分为0或者达到所要求的精度为止。然后把取出的整数部分按顺序排列起来,即先取出的整数部分作为二进制小数的高位,后取出的整数部分作为低位有效位。简称"乘2取整法"。

3. 含有小数的十进制数转换成二进制,整数、小数部分分别进行转换,然后相加。

例如:将十进制数值25.75转换为二进制数值,步骤如下:

25(整数部分)

25/2=12......1

12/2=6.......0

6/2=3......0

3/2=1......1

1/2=0......1

(25) 10=(11001) 2

0.75(小数部分)

0.75*2=1.5......1

0.5*2=1......1

(0.75) 10=(0.11) 2

(25.75) 10=(11001) 2+(0.11)2=(11001.11) 2

按照上述方法,我们将0.65及0.6转换为二进制代码:

(0.65)10 =(0.101001100110011001100110011001100110011......)2

(0.6) 10 =(0.10011001100110011001100110011001100110011......)2

后面的省略号表示已经算不完了,后面在无限重复 0011这段二进制数值。

文章开始部分,我们用的float类型,下面我们来看看float类型是否能存储上面转换出的二进制代码。

目前计算机上存储浮点数值是按照IEEE(电气和电子工程师协会)754浮点存储格式标准来存储的。

IEEE单精度浮点格式共32位,包含三个构成字段:23位小数f,8位偏置指数e,1位符号s。将这些字段连续存放在一个32位字里,并对其进行编码。其中0:22位包含23位的小数f; 23:30位包含8位指数e;第31位包含符号s。如下图所示:

也就是说上面将0.65及0.5转换出的二进制代码,我们只能存储23位,即使数据类型为double,也只能存储52位,这样大家便能看出问题出现的原因了。

截取的二进制代码已无法正确表示0.65及0.5,根据这个二进制代码肯定无法正确得到结果0.05。

对decimal、float、double错误的认识

引用自:http://topic.youkuaiyun.com/t/20050514/20/4007155.html中Ivony的评论

在精确计算中使用浮点数是非常危险的,尽管C#在浮点数运算时采取了很多措施使得浮点数运算的结果看起来是非常正常的。但实际上如果不清楚浮点数的特性而贸然使用的话,将造成非常严重的隐患。

考虑下面的语句:
double dd = 10000000000000000000000d;
dd += 1;
Console.WriteLine ( "{0:G50}", dd );
输出是什么?谁知道?
输出是:1000000000000000000000000
这就是浮点数精度损失的问题,最重要的是,在精度损失的时候,不会报告任何的错误,也不会有任何的异常产生。
浮点数的精度损失可能在很多地方出现,例如d * g / g不一定等于d,d / g * g也不一定等于d。
还有两个非常危险的错误认识!!
1
、decimal不是浮点型、decimal不存在精度损失。下面有段程序大家可以去看看结果是什么。记住!所有的浮点型变量都存在精度损失的问题,而decimal是一个不折不扣的浮点型,不论它精度有多高,精度损失依然存在decimal dd = 10000000000000000000000000000m;
dd += 0.1m;
Console.WriteLine ( "{0:G50}", dd );

2、decimal所能储存的数比double大,从double到decimal的类型转换不会出现任何问题。微软在decimal的帮助上真的要好好反省了。实际上只有从整形到decimal的转换才是扩大转换,decimal的精度比double大,但所能储存的最大数却比double要小。



计算机中的二进制的小数同十进制一样,比如10.125可以写成1.125*10的一次方,二进制写成1010.001,1.010001*2的三次方,都可以写成谁乘以进制的指数次,所以,在IEEE规则中规定浮点数的构成是符号位S+指数位E+尾数M,这个位数的组合构成浮点数。

JAVA遵守IEEE754规则:

float占4个字节,32位,表示为SEEEEEEEEMMMMMMMMMMMMMMMMMM,1位符号位,8位指数位,23位尾数位。当然如果指数值在1-254之间时,为1.M,否则就是0.M,指数又叫阶码,阶码采用移码表示,取值E-127.所以公式可总结为:小于0的小数:(-1)的S次*2的(1-127)次*(0.M),大于0的小数:(-1)的S次*2的(E-127)*(1.M).

5.0的在JAVA中的计算机二进制流表示为:

S=0,

5.0=101=1.01*2的2次

E-127=2 E=129=10000001

M=1.01

组合在一起就是 0 10000001 01000000000000000000000

再转成十进制:(-1)的0次 * 2的(129-127)次*(1.01)=101=5.0

输出float的二进制流,Java中的方法Float.floatToIntBits()

-5.0的表示:

Java二进制流:1 10000001 01000000000000000000000,其他省略。

0.1的表示:

0.1约等于0.0001100110011001100110011001=1.100110011001100110011001*2的-4次

S=0

E-127=-4 E=123=01111011

M=10011001100110011001100

组合在一起在JAVA中二进制流就是0 01111011 100110011001100110011001100

在转换成10进制为0.100000001490116119384765625

误差为0.000000001490116119384765625 如果26个float的0.1相加,结果为2.5999997 如果定义26个double的0.1相加,结果为2.600000000000001.

所以可以得出:

1.浮点数强制转换成整数时,舍入误差严重加重,强制转换时会舍弃非整数部分。

double d=29*0.01;//d=0.29

d=((int)d*100);//d=28

2.科学计数表示法中二进制位数越多,精度就越高。64位double就比32位的float精度高。对精度要求非常高的场合可以用BigDecimal类,能表示任意精度的数。

3.指数E为255时表示特殊数字。


Neo4j 智能供应链应用源代码简析 本文简析Neo4j智能供应链应用的源代码,让你也可以快速开发自己的供应链应用。 阅读详情

相关推荐

基于STM32的多路火灾报警系统设计

本文设计了一款基于STM32的多路火灾报警系统,利用多个传感器组合(如烟雾传感器、温度传感器等)进行数据采集与处理,精确判断火灾情况,并及时发出报警信号,保障生命与财产安全。本系统设计了一款基于STM32的多路火灾报警系统,通过结合烟雾传感器和温度传感器,提升了火灾检测的准确性和可靠性。未来,系统可以进一步集成更多传感器,如气体传感器、湿度传感器等,进一步提升火灾报警系统的智能化水平。本系统采用STM32F103单片机作为核心处理单元,结合烟雾传感器、温度传感器和报警模块,实现多通道火灾报警功能。

stm32d1219的博客 2034

浮点数比较当中的精度误差问题及解决

在使用浮点型数据时,通常需要考虑到浮点数的误差问题,介绍了浮点数比较时的误差原因以及解决办法。

m0_59555392的博客 1671

不到200块!手把手教你用ZYNQ7010和AD9363攒一台自己的开源SDR硬件(附BOM清单)

本文详细介绍了如何用不到200元的预算,基于ZYNQ7010 FPGA和AD9363射频芯片打造一台功能完备的开源SDR硬件平台。从核心组件选型、PCB设计到焊接调试,提供全流程实战指南,特别适合预算有限的硬件爱好者和创客群体探索无线通信世界。

weixin_26854829的博客 484

float转换为int误差问题

使用C语言编程序,有时需要把一种数值(如float类型的数值)转换成另一种类型(如int类型)的数值使用,这时,我们就要用到类型强制转换运算符,如(int)、(float)等。但是在VC++中,当把一个float类型的数值转换成int类型时,有时会出现比较大的误差。我在工作过程中就碰到过,当我把一个值为1140.00的float型变量ftemp使用如下方法转换成int类型,   itemp=(i

limingmcu的专栏 1万+

告别龟速!实测Copernicus Dataspace下载Sentinel-2数据的3个提速技巧(附Workspace批量操作)

本文分享了在Copernicus Dataspace平台高效下载Sentinel-2遥感数据的3个实用技巧,包括网络传输层优化、浏览器与API调优以及Workspace批量操作。通过这些方法,用户可将下载速度提升300%以上,特别适合科研人员和团队处理大规模数据需求。

weixin_30706691的博客 180

金融领域强化学习在多资产类别动态交易执行中的应用

在金融市场中,多资产类别的交易执行面临着诸多挑战,如市场的不确定性、资产间的复杂相关性等。传统的交易策略往往难以适应动态变化的市场环境。本研究的目的在于探索如何运用强化学习技术,实现多资产类别在动态市场环境下的高效交易执行。具体范围涵盖了从强化学习的基本原理到在多资产交易场景中的实际应用,包括核心算法的实现、数学模型的构建以及项目实战等方面。本文首先介绍研究背景,包括目的、预期读者和文档结构。接着阐述核心概念,包括强化学习和多资产类别动态交易执行的原理及其联系。

AI 领航者的博客 632

关于浮点数的精度丢失问题的思考

浮点数精度丢失的原因、浮点数的存储、float与double的范围和精度和解决方法

yanqiu12138的博客 3824

视网膜血管分割数据集(DRIVE数据集,STARE数据集,REFUGE数据集,CHASE_DB1数据集,DiaRetDB1数据集)

在医学图像处理领域,视网膜图像分析对于眼部疾病的早期诊断与治疗具有举足轻重的意义。随着人工智能技术的蓬勃发展,尤其是深度学习算法在图像分割任务中的广泛应用,高质量的视网膜图像数据集成为推动该领域研究进展的关键要素。这些数据集不仅是训练和优化算法模型的基石,更是衡量算法性能优劣的重要依据。本文聚焦于视网膜图像分割领域,详细介绍 DRIVE、STARE、REFUGE、CHASE_DB1 以及 DiaRetDB1 这几个具有代表性的数据集。

weixin_43518285的博客 2273

浮点数的误差

浮点数的误差 print(0.1 + 0.1 + 0.1 == 0.3) 输出: False 浮点数的误差问题与语言无关,本质上是二进制的存储问题造成的。 任何数据在计算机中都是以机器码存储的。 十进制的数字在计算机中是以二进制的数字存储的。 十进制的浮点数在计算机中也是以二进制的小数存储,以二进制运算。 那么, 在十进制转化为二进制存储的时候,引起截断误差。 在二进制...

cluster1893的博客 6982

第3章 zynq MII转GMII的配置和EMIO UART0的配置

本文介绍了在Vivado工程中实现MII转GMII接口适配的过程,同时配置EMIO UART0接口。主要内容包括:修改PS IP核添加UART0接口,使用concat IP核进行信号整合,调整GMII信号引脚连接,添加约束文件定义引脚映射,并最终生成bit流文件。通过详细的操作截图和TCL约束代码,展示了从硬件配置到生成可编程文件的完整流程,为Zynq平台开发提供了实用参考。

qq_36517072的博客 903

IEEE LaTeX模板中algorithm排版避坑指南:如何优雅地嵌入算法描述?

本文详细解析了在IEEE LaTeX模板中优雅排版algorithm的实用技巧,包括基础配置、高级自定义及常见问题解决方案。通过嵌套环境与[H]参数的应用,帮助研究者克服IEEEtran模板对算法排版的限制,实现专业且美观的算法呈现。

weixin_28340315的博客 410

浮点型变量的误差问题

剑指Offer面试小提示: 由于计算机表示小数(包括float和double型小数)都有误差,我们不能直接用等号(==)判断两个小数是否相等。如果两个小数的差的绝对值很小,比如小于0.0000001,就可以认为它们相等。 要明白这个提示,首先我们需要弄清楚这两种类型的变量,在计算机当中是如何存储的? float类型在机器中存储为4个字节,double类型存储为8个字节。虽然存储字节数不同,但却都可分成三个部分: 符号位 指数部分 尾数部分 如图所示,float类型具有1位符号位,8位指数位和23位尾.

柔水终成雕刀 1082

【即插即用模块】Transformer篇 | AAAI 2026 | Circulant Attention:全新ViT自注意力范式,复杂度从O(N²) 降至O(NlogN)!

本文提出了一种基于频域优化的循环注意力模块(Circulant Attention),通过离散傅里叶变换(DFT)将传统自注意力中的矩阵乘法转化为频域元素乘法,显著降低了计算复杂度。该模块采用复数线性层适配频域特征,并引入门控调制机制增强表达能力,在保持全局依赖捕捉能力的同时,将复杂度从O(N²)降至O(NlogN)。实验表明,该模块在多种视觉任务中均能提升模型性能,且计算效率更高。适用于需要高效全局注意力的视觉Transformer架构,可作为传统自注意力的替代方案。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 153

[Python]关于浮点数计算时的误差问题及其解决方法

而内存只会划分有限的空间来保存一个小数,所以当我们想要保存这个0.2的数字时,只会截取二进制数字中的一部分来保存,而当我们重新通过被截取的二进制数字来计算对应的十进制数字,就会产生误差。浮点数一个普遍的问题就是在计算机的世界中,浮点数并不能准确地表示十进制。并且,即便是最简单的数学运算,也会带来不可控制的后果。然后再将小数部分乘以2,将得到的整数部分作为二进制表示的第2位;,这导致了在计算过程中精度的丢失。,有的有限十进制小数只能使用无限的二进制小数表示。出现这种问题的原因是,计算机中保存数字的寄存器是。

Persona_LXY的博客 2486

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

【python】浮点数计算时的误差问题

python浮点数计算的问题 python不建议直接将两个浮点数进行精确的计算,因为python中的浮点数计算存在一个误差问题,例如: 出现这种问题的原因是,计算机中保存数字的寄存器是使用二进制来保存数字的,有的有限十进制小数只能使用无限的二进制小数表示。 首先看一下将十进制小数转换为二进制的过程为: 将小数乘以2,取出整数部分作为二进制表示的第1位;然后再将小数部分乘以2,将得到的整数部分作...

AXIMI的博客 1万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

浮点数的误差问题 1(C语言)

先来看一段程序: int main() { double n=0.01; double tmp=0; for(int i=0;i<40000000;i++) { tmp+=n; } printf("%f",tmp); return 0; } 从这段程序中可以明显看出编译结果产生了误差,所以浮点数的计算中是存在误差的。 #include<stdio.h> i...

weixin_44018317的博客 2649

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

008_浮点数误差问题

一、浮点数   a):float类型又被称作单精度类型,尾数可以精确到7位有效数字,在很多情况下,float类型的精度很难满足需求。   b):double表示这种类型的数值精度是float类型的两倍,又被称作双精度,绝大部分应用程序都采用double类型。 二、浮点数的表述范围    类型 占用存储空间 表数范围 floa...

dianmo9374的博客 287

关于浮点数的运算误差问题

项目中遇到的问题, #include "stdio.h" #include "stdlib.h" void test(double fRx, double space, unsigned int n) { double fRx_max = fRx + space * (double)n; double delta = 0; for(; fRx<=fRx_max; fRx+=spa

春播秋忙 1977

Java浮点数float和double精确计算的精度误差问题总结

1、float整数计算误差 案例:会员积分字段采用float类型,导致计算会员积分时,7位整数的数据计算结果出现误差。 原因:超出float精度范围,无法精确计算。 float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。 float:2^23 = 8388608,一共七位,这意味

喵星人 5万+

关于误差分析以及浮点数的精度问题

浮点,简单的讲就是实数的意思。浮点数就是可以近似表示某个任意的实数。 浮点精度分为: 16位:一半(二进制16) 32位:单(binary32),十进制32 64位:Double(binary64),decimal64 128位:四(binary128),DECIMAL128 256位:八进制(binary256) 扩展精度格式(40位或80位) ...

aby_byy的博客 561

整数进制、浮点数误差问题

整数进制、浮点数误差问题 整数进制问题 二进制以0b开头 八进制以0开头 十六进制以0x开头 表示二进制的十,八进制的十,十六进制的十代码如下: public static void main(String[] args) { //整数拓展:进制 二进制0b 八进制0 十六进制0x int i=10; int i1=0b10; int i2=010; int i3=0x10; System.out.println

weixin_45959563的博客 249

java浮点数误差_Java浮点数float和double精确计算的精度误差问题总结

1、float整数计算误差案例:会员积分字段采用float类型,导致计算会员积分时,7位整数的数据计算结果出现误差。原因:超出float精度范围,无法精确计算。float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。float:2^23 = 8388608,一共七位,这意味着最多能有7位有...

weixin_29414105的博客 758

为什么通过程序运算的浮点数结果有时会产生误差_浮点数加法引发的问题:浮点数的二进制表示...

1、问题:之前有同学问过这样一个问题:echo|awk '{print 3.99 -1.19 -2.80}'4.44089e-16类似的问题还有在 java 或者 javascript 中:23.53 + 5.88 + 17.64 = 47.0523.53 + 17.64 + 5.88 = 47.050000000000004为什么结果不是 0 或者不相等呢?如果你不能立马回答出原因,那说明你对浮...

weixin_34169322的博客 896

java浮点数误差_Java浮点数float和double精确计算的精度误差问题总结(source)

1、float整数计算误差案例:会员积分字段采用float类型,导致计算会员积分时,7位整数的数据计算结果出现误差。原因:超出float精度范围,无法精确计算。float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。float:2^23 = 8388608,一共七位,这意味着最多能有7位有...

weixin_33968957的博客 799

Java浮点数float,bigdecimal和double精确计算的精度误差问题总结

(转)Java浮点数float,bigdecimal和double精确计算的精度误差问题总结 1、float整数计算误差 案例:会员积分字段采用float类型,导致计算会员积分时,7位整数的数据计算结果出现误差。 原因:超出float精度范围,无法精确计算。 float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着...

agnsm00804的专栏 285

几何算法库中的浮点数误差问题

这个歧义的消除,就需要算法都统一到距离误差下,但统一到距离误差下往往会使算法变慢,所以,折中的方案是两个角度误差,一大一小,小于小的绝对重合,大于大的绝对不重合,两者之间的转为距离误差的算法。不夸张的说,因为这个问题的存在,几乎所有图形算法都不能完全按书上的实现,哪怕是最简单的判断点内外的射线法,在接近重合以及几何体不完美的情况下也会出错,都需要特殊处理(这个几何体不完美指的是几何体经过若干运算后,本身就带了误差,这个是必然会出现的)。所以,浮点数误差问题的根本解就是歧义检测与歧义处理。

weixin_45387973的博客 241
上一篇: 微软Silverlight 5开发书籍汇总
下一篇: 自定义数据类型,操作符重载实例
devgis
博客等级 码龄16年 52粉丝 60原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值