返回顶部
首页 > 资讯 > 精选 >十进制浮点数的表示方法
  • 522
分享到

十进制浮点数的表示方法

2023-06-03 09:06:08 522人浏览 安东尼
摘要

使用十进制浮点数,可以避免二进制浮点数与我们习惯的十进制数之间的表示误差.这个在金融领域是非常重要的.但是计算机基本都只能对二进制浮点数进行计算,也就是IEEE754格式表示的浮点数.很多程序都会自己模拟十进制浮点数的计算.为了统一,IEE

使用十进制浮点数,可以避免二进制浮点数与我们习惯的十进制数之间的表示误差.这个在金融领域是非常重要的.但是计算机基本都只能对二进制浮点数进行计算,也就是IEEE754格式表示的浮点数.很多程序都会自己模拟十进制浮点数的计算.为了统一,IEEE754做了扩展,包括了十进制的浮点数.

IEEE 754-2008里面规定了十进制浮点数的一些规范.不过里面没有说具体的二进制表示方法.只是规定了32位,64位,128位的十进制浮点数的表示范围和有效位数. 因为具体一个浮点数的二进制里面每个位表示啥,都是每个机器自己决定的.不需要跟外界一致.只是在传输的时候要保证数据的精度和范围一致就行了.下表来自wikipedia,列出了每种浮点数的有效位数,指数的范围.

Name Common name Base DigitE min E max 
binary16 Half precisio210+1 -1415
binary32 Single precision 223+1 -126127
binary64 Double precision 252+1 -10221023
binary128 Quadruple precision 2112+1 -1638216383
decimal32 
107-9596
decimal64 
1016-383384
decimal128 
1034-6143

6144 

实际的系统中,十进制浮点数有两种表示方法,分别是Densely Packed Decimal(密集十进制数)和Binary Integer Decimal(二进制整数表示的十进制数).

DPD表示方便转换成十进制的浮点数字符串,但是需要专门的计算单元来做计算,软件模拟比较麻烦.

而BID表示更直观,转换到二进制会比较容易.很方便用二进制的整数运算单元来计算.

所以Power6上有了硬件的十进制浮点计算单元,就用DPD表示.而在x86 x64 cpu上没有十进制计算单元, 各种软件实现的十进制浮点库默认大都用BID方式表示.比如Intel就实现了一个开源的c 语言的十进制浮点数库。Http://software.intel.com/en-us/articles/intel-decimal-floating-point-math-library/

十进制浮点的意义,在于更符合人们的习惯,比如下面的例子

  1. #include<stdio.h>

  2.  int main()

  3.  {

  4.      double a = 7.;

  5.      double b = 0.00007;

  6.      printf("%d/n",a==b*100000);

  7.  }

 


正确的输出应该是1,但是实际的输出结果是0,在做相等比较的时候,还不得不考虑一下这个误差了。而某些时候误差会在计算过程中累计,变成比较明显的错误了。

如果用intel的十进制浮点库赖做这个计算,结果就会不同了。intel这个库明显还在试验阶段,用起来比较麻烦。

  1. int main()

  2.  {

  3.      Decimal64 a, b, c;

  4.      _IDEC_round my_rnd_mode = _IDEC_dflround;

  5.      _IDEC_flags my_fpsf = _IDEC_allflagsclear;

  6.      a = bid64_from_int32(7);

  7.     b = bid64_from_string("0.00007",my_rnd_mode, &my_fpsf);

  8.      c = bid64_mul(b,bid64_from_int32(100000),my_rnd_mode,&my_fpsf);

  9.     printf("%d/n",bid64_quiet_equal(a,c,&my_fpsf));

  10.      return 0;

  11.  }

 

使用和double位数相同的Decimal64,结果就是1了。这里显然不是精度的问题,而是十进制浮点数能丝毫不变的表示十进制的小数。

我们可以看到这里使用的是BID的表示方法。函数名前面都带个bid前缀。

接下来,我们来具体看看BID的表示方法,我们可以把刚才程序中的a和c按照十六进制输出

    printf("%llx/n%llx/n",a,c);

结果是

31c0000000000007
31200000000aae60

可见,两个相等的十进制浮点数的BID表示不一定是相同的。也就是说,一个数有多种表示方法。

a的表示里,最低位的16进制数就是7,而c的表示里,最低的5位15进制数aae60,其实就是十进制的700000。看来这后面的就是有效数字部分了。查一下BID的表示方法,还是比较复杂的,有6种情况。最高位是符号位,这里当然是0.符号位后面的两位是00,01,或10时,64位BID每个位的意义是这样的,s后面的2位和之后的8位是指数部分,之后53位T和t都是有效数字部分

s 00eeeeeeee TTTtttttttttttttttttttt tttttttttttttttttttttttttttttt
s 01eeeeeeee TTTtttttttttttttttttttt tttttttttttttttttttttttttttttt
s 10eeeeeeee TTTtttttttttttttttttttt tttttttttttttttttttttttttttttt
而如果符号位后面的两位是11,那么每一位的意义是
s 11 00eeeeeeee (100)Ttttttttttttttttttttt tttttttttttttttttttttttttttttt
s 11 01eeeeeeee (100)Ttttttttttttttttttttt tttttttttttttttttttttttttttttt
s 11 10eeeeeeee (100)Ttttttttttttttttttttt tttttttttttttttttttttttttttttt
这时,有效数字前面就加了隐含的100.
这个BID表示的数的值就是 (-1)^S *T*10^(E-398) ,其中T 是实际的有效数字(就是说如果有隐含的100需要加上后计算),E是指数,T,E都是2进制表示的
还是回到我们的例子
a的二进制数
0 0110001110 00000 00000000 00000000 00000000 00000000 00000000 00000111
指数部分就是0110001110,也就是398,所以a就是 7*10^(398-398) ,也就是7

而c的二进制是
0 0110001001 00000 00000000 00000000 00000000 00001010 10101110 01100000
指数部分是 0110001001,也就是393, 所以c的值是 700000*10^(393-398), 还是7.
这就能看明白为啥同样是7,二进制表示却不同。这也是十进制浮点和二进制浮点一个不同之处,十进制浮点没有规定一定要是哪一种表示。这也给相等比较带来了一点麻烦。

power6 里面内置了十进制浮点计算单元,而power6上面的编译器也就支持了内置的十进制浮点类型。前面已经说了,power上面的十进制浮点才用的是DPD表示方法。还是看个程序吧。下面这个程序在一个使用Power6的P520机器上,操作系统是AIX5.3 ML6, 用xlc 10.2编译。_Decimal64就是64位的十进制浮点。

  1. int main(int arGC, char **argv)

  2. {

  3. long i, count;

  4. double dfund, dinterest;

  5. _Decimal64 Dfund, Dinterest;

  6.  long long value;

  7.  uNIOn trans{

  8.   _Decimal64 dv;

  9.   int av[2];

  10.  } transTemp;

  11.  dfund = atof(argv[1]);

  12.  dinterest = atof(argv[2]);

  13.  Dfund = atodecimal(argv[1]);

  14.  Dinterest = atodecimal(argv[2]);

  15.  count = atoi(argv[3]);


  16.  transTemp.dv = Dinterest;

  17.  printf("value=%#x,%#x/n",transTemp.av[],transTemp.av[1]);

  18.  printf("double  fund=%20.10f interest=%40.30f/n",dfund,dinterest);

  19.  printf("Decimal fund=%20.10Df interest=%40.30Df/n",Dfund,Dinterest);

  20.  for(i=;i<count;i++) {

  21.          dfund=dfund*dinterest;

  22.          Dfund=Dfund*Dinterest;

  23.  }

  24.  printf("Print final funds/n");

  25.  printf("double  fund=%30.10f/n",dfund);

  26.  printf("Decimal fund=%30.10Df/n",Dfund);

  27. }

 

其中 atodecimal是自己写的一个帮助函数

  1. _Decimal64 atodecimal(char *s)

  2. {

  3. _Decimal64 top=, bot=, result;

  4. int negative=, i;

  5.         if( s[] == '-') {

  6.                 negative=1;

  7.                 s++;

  8.         }

  9.         if( s[] == '+') s++;

  10.          for(; isdigit(*s); s++) {

  11.                 top = top * 10;

  12.                 top = top + *s - '';

  13.         }

  14.         if(*s == '.') {

  15.                 s++;

  16.                 for(i=strlen(s)-1; isdigit(s[i]);i--) {

  17.                         bot = bot / 10;

  18.                         bot = bot + (_Decimal64)(s[i] - '')/(_Decimal64)10;

  19.                 }

  20.         }

  21.         result = top + bot;

  22.         if(negative)

  23.                 result = -result;

  24.         return result;

  25. }

 

这个程序用xlc 10.2编译时,跟上参数表示使用硬件十进制浮点。不过这样会导致编译出来的可执行文件在power5以前的cpu上无法运行。

运行的时候输入参数 ./dfp_hw 1 1.00000091 6000000

dfp_hw是程序的名字,1就是程序里面的 fund,1.00000091是interest,也就是利息,6000000是count,输出结果:

value=0x22180000,0x800001b
double  fund=        1.0000000000 interest=        1.000000910000000020616539586630
Decimal fund=        1.0000000000 interest=        1.000000910000000000000000000000
Print final funds
double  fund=                235.0968403429
Decimal fund=                235.0968403137

可以看到用double存储利息,再输出,就不再是1.00000091了,后面有一点误差。而用_Decimal64存储输入结果,再输出,是一点误差都没有。

然后把interest乘6000000次,也就是1.0000091的6000000次方,输出的结果误差就比较明显了。用windows自带的计算器可以验证,_Decimal64的结果是正确的。

现在来看看1.00000091的二进制表示。也就是0x22180000,0x800001b,注意这里这个power机器是大端的,所以前面以前是高4字节,后面是低4字节。连起来看,就是0x22180000 0800001b也就是

00100010 00011000 00000000 00000000 00001000 00000000 00000000 00011011

DPD表示方法也比较复杂,从高位开始看,第一位还是符号位0,DPD的规定如果符号位后面的两位是00,01,或者10,那么每一位的意义如下

s 00 mmm (00)eeeeeeee (mmm)[tttttttttt][tttttttttt][tttttttttt][tttttttttt][tttttttttt]
s 01 mmm (01)eeeeeeee (mmm)[tttttttttt][tttttttttt][tttttttttt][tttttttttt][tttttttttt]
s 10 mmm (10)eeeeeeee (mmm)[tttttttttt][tttttttttt][tttttttttt][tttttttttt][tttttttttt]
其中,e是指数,e的表示方法跟前面的BID方式很像。t和m是有效数字,其中,每10位t组成一个declet,表示一个3位的十进制数。m实际的位置是在第4位到第6位,但是它逻辑上的位置是在那些t前面,所以用()表示放到e的后面。

因为2的10次方是1024,刚好能表示10的3次方。但是表示起来还是需要点技巧的,declet表示三位十进制数的规则比较复杂,这也是这个表示方法叫Densely Packed Decimal(密集十进制数)的原因。下表是编码的方式。b9-b0代表10个二进制数,d2 d1 d0代表3个十进制数。

b9

b8

b7

b6

b5

b4

b3

b2

b1

b0

d2

d1

d0

编码值

数位的模式

a

b

c

d

e

f

g

h

i

0abc

0def

0ghi

(0–7) (0–7) (0–7)

3位小数字

a

b

c

d

e

f

1

i

0abc

0def

100i

(0–7) (0–7) (8–9)

两位小数字,一位大数字

a

b

c

d

e

f

1

1

i

0abc

100f

0dei

(0–7) (8–9) (0–7)

a

b

c

d

e

f

1

1

i

100c

0def

0abi

(8–9) (0–7) (0–7)

a

b

c

1

f

1

1

1

i

0abc

100f

100i

(0–7) (8–9) (8–9)

一位小数字,两位大数字

a

b

c

1

f

1

1

1

i

100c

0abf

100i

(8–9) (0–7) (8–9)

a

b

c

f

1

1

1

i

100c

100f

0abi

(8–9) (8–9) (0–7)

x

x

c

1

1

f

1

1

1

i

100c

100f

100i

(8–9) (8–9) (8–9)

三位大数字

就我们的例子来看一下,最低的10位是0000011011,看b3b2b1,这里是101,所以就是上表第3行的情况,三位数字就是 (0000)(1001)(0001)也就是091,然后看从低位数的第3个10位二进制数,也就是00100000000,这显然是第一种情况,也就是100,连起来就是100000091,指数部分是390,那么这个十进制的值就是 10^(390-398)*100000091 = 1.00000091.

通过这个简单的例子,就应该对DPD方式的十进制浮点表示方式有个大概的了解了。这个方式算起来比较麻烦,所以除非有硬件支持,软件模拟的方式都不会使用的,但是DPD转换成十进制浮点的字符串表示就会很方便。

 

--结束END--

本文标题: 十进制浮点数的表示方法

本文链接: https://lsjlt.com/news/233928.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 十进制浮点数的表示方法
    使用十进制浮点数,可以避免二进制浮点数与我们习惯的十进制数之间的表示误差.这个在金融领域是非常重要的.但是计算机基本都只能对二进制浮点数进行计算,也就是IEEE754格式表示的浮点数.很多程序都会自己模拟十进制浮点数的计算.为了统一,IEE...
    99+
    2023-06-03
  • C语言浮点数的二进制表示
    本篇内容介绍了“C语言浮点数的二进制表示”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!浮点数是属于有理数中某特定子集的数的数字表示,在计算机...
    99+
    2023-06-17
  • PHP如何将二进制数据转换为十六进制表示
    这篇文章将为大家详细讲解有关PHP如何将二进制数据转换为十六进制表示,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。PHP 将二进制数据转换为十六进制表示 引言 在某些情况下,需要将二进制数据转换为十六进制...
    99+
    2024-04-02
  • 负数的二进制表示方法是什么
    本篇内容介绍了“负数的二进制表示方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!原码:一个整数,按照绝对值大小转换成的二进制数,称为...
    99+
    2023-06-04
  • 浮点数的表示范围有多大
    浮点数的表示范围:1、对于单精度浮点数,其表示范围大约为±3.4 × 10^38,也可以用科学计数法表示为±3.4E+38;2、对于双精度浮点数,表示范围更广,大约为±1.8 × 10^308,或者用科学计数法表示为±1.8E+308。本教...
    99+
    2023-08-17
  • C#实现十六进制与十进制相互转换以及及不同进制表示
    目录前言C#中数字的进制表示形式十六进制转十进制代码实现十六进制转十进制C#内置方法16转10进制Convert.ToInt32()int.Parse()和int.TryParse十...
    99+
    2024-04-02
  • python十进制转二进制方法详解
      在 Python中,十进制数可以转换成二进制数。例如: 但是,十进制数不是直接转换成二进制,而是先转换成二进制数,再转换成十进制。接下来我们来看看具体的实现方法: 首先我们来看一个例子: 上面代码中,使用了循环遍历的方法。从这个例子中...
    99+
    2023-10-04
    numpy
  • 控制Python浮点数输出位数的操作方法
    目录技术背景常规控制方法取有效数字总结概要 在python的输出结果中,尤其是浮点数的输出,当我们需要写入文本文件时,最好是采用统一的输出格式,这样也能够增强结果的可读性。而对于浮点...
    99+
    2024-04-02
  • php如何将16进制转为浮点数
    本篇内容主要讲解“php如何将16进制转为浮点数”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“php如何将16进制转为浮点数”吧!php将16进制转为浮点数的方法:1、使用“hexdec(十六进...
    99+
    2023-06-30
  • python浮点数怎么转化为二进制
    要将Python浮点数转换为二进制,可以使用`float.hex()`方法获得浮点数的十六进制表示,然后再将十六进制字符串...
    99+
    2023-09-08
    python
  • C#的浮点常量怎么表示
    这篇文章主要介绍“C#的浮点常量怎么表示”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C#的浮点常量怎么表示”文章能帮助大家解决问题。浮点常量一个浮点常量是由整数部分、小数点、小数部分和指数部分组成...
    99+
    2023-06-17
  • php如何将二进制转为浮点型数
    这篇文章主要介绍“php如何将二进制转为浮点型数”,在日常操作中,相信很多人在php如何将二进制转为浮点型数问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”php如何将二进制转为浮点型数”的疑惑有所帮助!接下来...
    99+
    2023-06-30
  • C++实现十进制数转换为二进制数的数学算法
    一、十进制转换为二进制的数学算法 设目标十进制数为n,用短除法一直除以2,循环这个过程并记录余数,当商为0时结束循环,余数从后往前读就是转换为的二进制数 eg: 二、代码实现 1....
    99+
    2024-04-02
  • c语言双精度浮点数如何表示
    C语言中的双精度浮点数使用 double 数据类型表示,占用 8 个字节(64 位)。其内部的表示方式遵循 IEEE 754 浮点数...
    99+
    2023-09-29
    c语言
  • Python二进制转化为十进制数学算法详解
    目录PythonPython二进制Python十进制Python二进制转化为十进制数学算法在python中可以通过内置函数int()函数进行二进制转十进制;int()函数可以将一个指...
    99+
    2023-01-06
    Python二进制转化为十进制 Python进制转化 Python二进制转化
  • php十进制转八进制的算法是什么
    本文操作环境:Windows10系统、PHP7.1版、Dell G3电脑。php十进制转八进制的算法是什么decoct() 函数把十进制数转换为八进制数。如需把八进制转换为十进制,可以利用octdec() 函数。语法decoc&#...
    99+
    2021-10-01
    PHP
  • python如何表示2进制、8进制和16进制数字
    这篇文章主要介绍python如何表示2进制、8进制和16进制数字,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!表示2进制,8进制和16进制数字在2.6以上版本,以如下方式表示prin...
    99+
    2024-04-02
  • PHP中string转浮点数的方法详解
    PHP中string转浮点数的方法详解 在PHP编程中,经常会遇到将字符串转换为浮点数的需求,特别是在处理用户输入或者外部数据时。本文将详细介绍在PHP中进行字符串到浮点数的转换方法,...
    99+
    2024-04-02
  • 使用C#中的Convert.ToInt32()将十进制,八进制,十六进制字符串转换为整数
    可以使用Convert.ToInt32()方法将十进制、八进制和十六进制字符串转换为整数。示例代码如下:```csharpstrin...
    99+
    2023-09-13
    C#
  • 使用SHA-1算法生成UUID的十六进制表示 - 作为令牌使用
    本篇文章向大家介绍《使用SHA-1算法生成UUID的十六进制表示 - 作为令牌使用》,主要包括,具有一定的参考价值,需要的朋友可以参考一下。问题内容我正在编写一个 go oauth 应用程序,在其中...
    99+
    2024-04-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作