double精度缺失解决方案.docx

上传人:b****5 文档编号:5170992 上传时间:2022-12-13 格式:DOCX 页数:6 大小:19.02KB
下载 相关 举报
double精度缺失解决方案.docx_第1页
第1页 / 共6页
double精度缺失解决方案.docx_第2页
第2页 / 共6页
double精度缺失解决方案.docx_第3页
第3页 / 共6页
double精度缺失解决方案.docx_第4页
第4页 / 共6页
double精度缺失解决方案.docx_第5页
第5页 / 共6页
点击查看更多>>
下载资源
资源描述

double精度缺失解决方案.docx

《double精度缺失解决方案.docx》由会员分享,可在线阅读,更多相关《double精度缺失解决方案.docx(6页珍藏版)》请在冰豆网上搜索。

double精度缺失解决方案.docx

double精度缺失解决方案

double精度缺失解决方案

  篇一:

Java中解决浮点型数据精度不准的问题

  Java中如何解决double和float精度不准的问题我们知道浮点数是无法在计算机中准确表示的,例如在计算机中只是表示成了一个近似值,因此,对付点数的运算时结果具有不可预知性。

  在进行数字运算时,如果有double或float类型的浮点数参与计算,偶尔会出现计算不准确的情况。

如以下示例代码:

[java]viewplaincopyprint?

  1.packageex;

  2.

  3.publicclassBigDeciTest{

  4.publicstaticvoidmain(String[]args){

  (+);

  ();

  (*100);

  (/100);

  9.

  10.}

  11.

  12.}

  上述代码执行结果如下:

  [plain]viewplaincopyprint?

  1.

  2.

  3.

  4.

  在大多数情况下,使用double和float计算的结果是准确的,但是在一些精度要求很高的系统中,这种问题是非常严重的。

  在《EffectiveJava》中提到一个原则,那就是float和double只能用来作科学计算或者是工程计算,但在商业计算中我们要用,通过使用BigDecimal类我们可以解决上述问题,实例代码如下:

  [java]viewplaincopyprint?

  1.packageex;

  2.

  3.import*;

  4.

  5.publicclassBigDecimalDemo{

  6.publicstaticvoidmain(String[]args){

  ((,));

  ((,));

  ((,100));

  ((,100));

  11.}

  12.}

  13.

  14.classArithUtil{

  15.privatestaticfinalintDEF_DIV_SCALE=10;

  16.

  17.privateArithUtil(){}

  18.

  19.publicstaticdoubleadd(doubled1,doubled2){

  b1=newBigDecimal((d1));

  b2=newBigDecimal((d2));

  (b2).doubleValue();

  23.

  24.}

  25.

  26.publicstaticdoublesub(doubled1,doubled2){

  b1=newBigDecimal((d1));

  b2=newBigDecimal((d2));

  (b2).doubleValue();

  30.

  31.}

  32.

  33.publicstaticdoublemul(doubled1,doubled2){

  b1=newBigDecimal((d1));

  b2=newBigDecimal((d2));

  (b2).doubleValue();

  37.

  38.}

  39.

  40.publicstaticdoublediv(doubled1,doubled2){

  41.

  div(d1,d2,DEF_DIV_SCALE);

  43.

  44.}

  45.

  46.publicstaticdoublediv(doubled1,doubled2,intscale){

  (scale  48.thrownewIllegalArgumentException("Thescalemustbeaposit

  iveintegerorzero");

  49.}

  b1=newBigDecimal((d1));

  b2=newBigDecimal((d2));

  (b2,scale,_HALF_UP).doubleValue()

  ;

  53.

  54.}

  55.

  56.}

  运行结果如下:

  [plain]viewplaincopyprint?

  1.

  2.

  3.

  4.

  详细,请参考API文档。

  篇二:

C#浮点数精度丢失问题

  C#浮点数精度丢失问题

  C#中的浮点数,分单精度(float)和双精度(double):

  float是的别名,介于-和+之间的32位数字,符合二进制浮点算法的IEC60559:

1989(IEEE754)标准;

  double是的别名,介于-和+之间的64位数字,符合二进制浮点算法的IEC60559:

1989(IEEE754)标准;

  我们知道,计算机只认识0和1,所以数值都是以二进制的方式储存在内存中的。

(对于人脑和计算机哪个聪明,个人更倾向于选择人脑,计算机只是计算得快,而且不厌其烦而已!

  所以要知道数值在内存中是如何储存的,需先将数值转为二进制(这里指在范围内的数值)。

  根据IEEE754标准,任意一个二进制浮点数V均可表示为:

V=(-1^s)*M*(2^e)。

其中s∈{0,1};M∈[1,2);e表示偏移指数。

  以(10)为例,先转成二进制的数值为:

(2)(截取16位小数),采用科学记数法等于*(2^17)(整数位是1),即(10)=(-1^0)**(2^17)。

  整数部分可采用"除2取余法",小数部分可采用"乘2取整法"。

  从结果可以看出,小数部分转为二进制后,小数位数超过16位(我已经手算到小数点后32位都还没算完,其实这个位数是无穷尽的)。

  由于无法得到完全正确的数值,这里就引申出浮点数精度丢失的问题:

/*程序段1*/

  floatnum_a=;

  floatnum_b=num_a/2;

  (num_a);

  (num_b);

  这段程序代码,我们预想中正确的结果应该是:

和。

但结果居然是!

原因下面将讲到...

  这里介绍另一种转小数部分的方法,有兴趣可以看下:

  假如结果要求精确到N位小数,那么只需要将小数部分乘以2的N次方(例如N=16,*(2^16),得到)。

  取整数部分(12451),按整数的方法转为二进制,得到11000010100011,不足N位在高位用0补足。

  结果精确到16位后,用二进制表示为。

  可以看出,若是小数部分乘以2的N次方后,可以得到一个整数,那么这个小数可以用二进制精确表示,否则则不可以。

  (原理很简单,根据二进制小数位转十进制的方法,反推回去就可以得到这个结果)

  在内存中,float和double的储存格式是一致的,只是占用的空间大小不同。

  float总共占用32位:

  从左往右,第1位是符号位,占1位;第2-9位是指数位,占8位;第10-32位是尾数位,占23位。

  double总共占用64位,从左往右第1位也是符号位,占1位;第2-12位是指数位,占11位;第13-64位是尾数位,占52位。

  其中,符号位(即上文的s,下同),0代表正数,1代表负数。

  对于float,8位指数位的值范围为0-255(10),由于指数(即上文的e,下同)可正可负,而指数位的值是一个无符号整数。

根据标准规定,储存时采用偏移值(偏移值为127)的方法,储存值为指数+127。

例如01110011

(2)表示指数-12(10)((-12)+127=115),10001011

(2)表示指数12(10)(12+127=139)。

  {

  另外,IEEE754规定(同样适用于double):

  当指数全为0时,如果尾数全为0,表示±0(正负取决于符号位),如果尾数不全为0,计算时指数等于-126,尾数不加上第一位的1,而是还原为的小数,表示更接近0的小数;

  当指数全为1时,如果尾数全为0,表示±无穷大(正负取决于符号位),如果尾数不全为0,表示这不是一个数(NaN)。

  }

  同样的,对于double,11位指数位,储存时采用的偏移值为1023。

  尾数位,由于所有数值均可以转换成*(2^N)(此处暂时忽略精度问题),所以尾数部分只保存小数部分(最高位的1不存入内存,提高1个位的精度)。

  以float为例,二进制为*(2^17);数值为正数,符号位是0;

  指数是17,保存为144(17+127=144),即10010000(共8位,不足8位在高位用0补足);

  小数位是10000100011110111001100(截取23位);

  最终得到:

01001000010000100011110111001100,按字节倒序顺序,转为十六进制就是:

CC3D4248

  floatf_num=;

  varf_bytes=(f_num);

  ("float:

");

  ((f_bytes));

  (("",f_(i=>(i,2).PadLeft(8,'0'))));

  同样的格式,double最终得到:

0100000100001000010001111011100110000101000111101011100001010010(最后两位结果为什么是10而不是01,请参考浮点数的舍入),按字节倒序顺序,转为十六进制就是:

52B81E85B9470841

  doubled_num=;

  vard_bytes=(d_num);

  ("double:

");

  ((d_bytes));

  (("",d_(i=>(来自:

小龙文档网:

double精度缺失解决方案)ring(i,2).PadLeft(8,'0'))));

  回到精度丢失的问题,由于小数位无法算尽,内存用截取精度的方式储存了转换后的二进制,这导致保存的结果并非是完全正确的数值。

  看回程序段1的例子,

  num_a在内存中其实是保存为:

01001000010000100011110111001100,换算成十进制就是:

  num_b在内存中其实是保存为:

01000111110000100011110111001100,换算成十进制就是:

  先看num_b,由于num_a在内存中储存的值已经是不正确的,那么再利用其进行计算,得到的结果%也会是不正确的。

所以num_b的结果并不是我们想要的。

  然后为什么会变成,而会变成呢?

我们知道,内存中确实是储存了和这两个值,那么就只有可能是在输出的时候做了变动。

其实这是微软做的小把戏,我们有句俗话说"以毒攻毒",大概就这个意思,既然储存的已经是不正确的数值,那么在输出的时候,会智能地猜测判断原先正确的数值是什么,然后输出猜测的那个值,说不定就真的猜中了呢!

  篇三:

float与double的范围和精度=

  float与double的范围和精度

  1.范围

  float和double的范围是由指数的位数来决定的。

  float的指数位有8位,而double的指数位有11位,分布如下:

float:

  1bit(符号位)8bits(指数位)23bits(尾数位)

  double:

  1bit(符号位)11bits(指数位)52bits(尾数位)

  于是,float的指数范围为-127~+128,而double的指数范围为-1023~+1024,并且指数位是按补码的形式来划分的。

  其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。

  float的范围为-2^128~+2^128,也即-+38~++38;double的范围为-2^1024~+2^1024,也即-+308~++308。

  2.精度

  float和double的精度是由尾数的位数来决定的。

浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。

  float:

2^23=8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效

  数字;

  double:

2^52=4503599627370496,一共16位,同理,double的精度为15~16位。

  中Number类型

  在Oracle中Number类型可以用来存储0,正负定点或者浮点数,可表示的数据范围在

  *10(-130)——..9*10(125){38个9后边带88个0}

  的数字,当Oracle中的数学表达式的值>=*10(126)时,Oracle就会报错。

  Number的数据声明如下:

  表示作用说明

  Number(p,s)声明一个定点数p(precision)为精度,s(scale)表示小数点右边的数字个数,精度最大值为38,

  Number(p)声明一个整数相当于Number(p,0)Number声明一个浮点数其精度为38,要注意的是scale的值没有应用,也就是说scale的指不能简单的理解为0,或者其他的数。

  定点数的精度(p)和刻度(s)遵循以下规则:

  ?

当一个数的整数部分的长度>p-s时,Oracle就会报错?

当一个数的小数部分的长度>s时,Oracle就会舍入。

?

当s(scale)为负数时,Oracle就对小数点左边的s个数字

  进行舍入。

  ?

当s>p时,p表示小数点后第s位向左最多可以有多少位数字,如果大于p则Oracle报错,小数点后s位向右的数字被舍入

  4.验证

  createorreplacefunctionfunc_test(p_typenumber)returnnumber

  is

  /*

  功能:

基于警度图数据同步

  */

  l_cntnumber;

  begin

  selectp_typeintol_cntfromdual;

  returnl_cnt;

  endfunc_test;

  /

  showerr;

  5.结论

  number的总长度是40位,其中可能包括:

小数点,负号位。

select

  to_char(func_test(-

  1234567891234))fromdual;

  -//包括小数点及负号位共40位

  select

  to_char(func_test())fromdual;

  //4位整数+小数点+35位小数=40位

  select

  to_char(func_test())fromdual;

  //3位整数+小数点+36位小数=40位

  select

  to_char(func_test(1234567891234567891234567891234567891234))fromdual;

  1234567891234567891234567891234567891234//40位整数

  select

  to_char(func_test(12345678912345678912345678912345678912345))fromdual;

  +40//41

  位时精度发生丢失

  ×10^40即12345678912345678912345678912345678900000

  

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 艺术

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1