导航:首页 > 源码编译 > 浮点数近似方式编译选项

浮点数近似方式编译选项

发布时间:2022-04-30 06:59:49

① 浮点小数的表示方法

Java 语言支持两种基本的浮点类型: float 和 double ,以及与它们对应的包装类 Float 和 Double 。它们都依据 IEEE 754 标准,该标准为 32 位浮点和 64 位双精度浮点二进制小数定义了二进制标准。

IEEE 754 用科学记数法以底数为 2 的小数来表示浮点数。IEEE 浮点数用 1 位表示数字的符号,用 8 位来表示指数,用 23 位来表示尾数,即小数部分。作为有符号整数的指数可以有正负之分。小数部分用二进制(底数 2)小数来表示,这意味着最高位对应着值 ?(2 -1),第二位对应着 ?(2 -2),依此类推。对于双精度浮点数,用 11 位表示指数,52 位表示尾数。IEEE 浮点值的格式如图 1 所示。

图 1. IEEE 754 浮点数的格式

因为用科学记数法可以有多种方式来表示给定数字,所以要规范化浮点数,以便用底数为 2 并且小数点左边为 1 的小数来表示,按照需要调节指数就可以得到所需的数字。所以,例如,数 1.25 可以表示为尾数为 1.01,指数为 0: (-1) 0*1.01 2*2 0

数 10.0 可以表示为尾数为 1.01,指数为 3: (-1) 0*1.01 2*2 3

特殊数字

除了编码所允许的值的标准范围(对于 float ,从 1.4e-45 到 3.4028235e+38),还有一些表示无穷大、负无穷大、 -0 和 NaN(它代表“不是一个数字”)的特殊值。这些值的存在是为了在出现错误条件(譬如算术溢出,给负数开平方根,除以 0 等)下,可以用浮点值集合中的数字来表示所产生的结果。

这些特殊的数字有一些不寻常的特征。例如, 0 和 -0 是不同值,但在比较它们是否相等时,被认为是相等的。用一个非零数去除以无穷大的数,结果等于 0 。特殊数字 NaN 是无序的;使用 == 、 < 和 > 运算符将 NaN 与其它浮点值比较时,结果为 false 。如果 f 为 NaN,则即使 (f == f) 也会得到 false 。如果想将浮点值与 NaN 进行比较,则使用 Float.isNaN() 方法。表 1 显示了无穷大和 NaN 的一些属性。

表 1. 特殊浮点值的属性

表达式 结果
Math.sqrt(-1.0) -> NaN
0.0 / 0.0 -> NaN
1.0 / 0.0 -> 无穷大
-1.0 / 0.0 -> 负无穷大
NaN + 1.0 -> NaN
无穷大 + 1.0 -> 无穷大
无穷大 + 无穷大 -> 无穷大
NaN > 1.0 -> false
NaN == 1.0 -> false
NaN < 1.0 -> false
NaN == NaN -> false
0.0 == -0.01 -> true

基本浮点类型和包装类浮点有不同的比较行为

使事情更糟的是,在基本 float 类型和包装类 Float 之间,用于比较 NaN 和 -0 的规则是不同的。对于 float 值,比较两个 NaN 值是否相等将会得到 false ,而使用 Float.equals() 来比较两个 NaN Float 对象会得到 true 。造成这种现象的原因是,如果不这样的话,就不可能将 NaN Float 对象用作 HashMap 中的键。类似的,虽然 0 和 -0 在表示为浮点值时,被认为是相等的,但使用 Float.compareTo() 来比较作为 Float 对象的 0 和 -0 时,会显示 -0 小于 0 。

浮点中的危险

由于无穷大、NaN 和 0 的特殊行为,当应用浮点数时,可能看似无害的转换和优化实际上是不正确的。例如,虽然好象 0.0-f 很明显等于 -f ,但当 f 为 0 时,这是不正确的。还有其它类似的 gotcha,表 2 显示了其中一些 gotcha。

表 2. 无效的浮点假定

这个表达式…… 不一定等于…… 当……
0.0 - f -f f 为 0
f < g ! (f >= g) f 或 g 为 NaN
f == f true f 为 NaN
f + g - g f g 为无穷大或 NaN

舍入误差

浮点运算很少是精确的。虽然一些数字(譬如 0.5 )可以精确地表示为二进制(底数 2)小数(因为 0.5 等于 2 -1),但其它一些数字(譬如 0.1 )就不能精确的表示。因此,浮点运算可能导致舍入误差,产生的结果接近 ― 但不等于 ― 您可能希望的结果。例如,下面这个简单的计算将得到 2.600000000000001 ,而不是 2.6 :

double s=0;
for (int i=0; i<26; i++)
s += 0.1;
System.out.println(s);

类似的, .1*26 相乘所产生的结果不等于 .1 自身加 26 次所得到的结果。当将浮点数强制转换成整数时,产生的舍入误差甚至更严重,因为强制转换成整数类型会舍弃非整数部分,甚至对于那些“看上去似乎”应该得到整数值的计算,也存在此类问题。例如,下面这些语句:

double d = 29.0 * 0.01;
System.out.println(d);
System.out.println((int) (d * 100));

将得到以下输出:

0.29
28

这可能不是您起初所期望的。

浮点数比较指南

由于存在 NaN 的不寻常比较行为和在几乎所有浮点计算中都不可避免地会出现舍入误差,解释浮点值的比较运算符的结果比较麻烦。

最好完全避免使用浮点数比较。当然,这并不总是可能的,但您应该意识到要限制浮点数比较。如果必须比较浮点数来看它们是否相等,则应该将它们差的绝对值同一些预先选定的小正数进行比较,这样您所做的就是测试它们是否“足够接近”。(如果不知道基本的计算范围,可以使用测试“abs(a/b - 1) < epsilon”,这种方法比简单地比较两者之差要更准确)。甚至测试看一个值是比零大还是比零小也存在危险 ―“以为”会生成比零略大值的计算事实上可能由于积累的舍入误差会生成略微比零小的数字。

NaN 的无序性质使得在比较浮点数时更容易发生错误。当比较浮点数时,围绕无穷大和 NaN 问题,一种避免 gotcha 的经验法则是显式地测试值的有效性,而不是试图排除无效值。在清单 1 中,有两个可能的用于特性的 setter 的实现,该特性只能接受非负数值。第一个实现会接受 NaN,第二个不会。第二种形式比较好,因为它显式地检测了您认为有效的值的范围。

清单 1. 需要非负浮点值的较好办法和较差办法
// Trying to test by exclusion -- this doesn't catch NaN or infinity
public void setFoo(float foo) {
if (foo < 0)
throw new IllegalArgumentException(Float.toString(f));
this.foo = foo;
}
// Testing by inclusion -- this does catch NaN
public void setFoo(float foo) {
if (foo >= 0 && foo < Float.INFINITY)
this.foo = foo;
else
throw new IllegalArgumentException(Float.toString(f));
}

不要用浮点值表示精确值

一些非整数值(如几美元和几美分这样的小数)需要很精确。浮点数不是精确值,所以使用它们会导致舍入误差。因此,使用浮点数来试图表示象货币量这样的精确数量不是一个好的想法。使用浮点数来进行美元和美分计算会得到灾难性的后果。浮点数最好用来表示象测量值这类数值,这类值从一开始就不怎么精确。

用于较小数的 BigDecimal

从 JDK 1.3 起,Java 开发人员就有了另一种数值表示法来表示非整数: BigDecimal 。 BigDecimal 是标准的类,在编译器中不需要特殊支持,它可以表示任意精度的小数,并对它们进行计算。在内部,可以用任意精度任何范围的值和一个换算因子来表示 BigDecimal ,换算因子表示左移小数点多少位,从而得到所期望范围内的值。因此,用 BigDecimal 表示的数的形式为 unscaledValue*10 -scale 。

用于加、减、乘和除的方法给 BigDecimal 值提供了算术运算。由于 BigDecimal 对象是不可变的,这些方法中的每一个都会产生新的 BigDecimal 对象。因此,因为创建对象的开销, BigDecimal 不适合于大量的数学计算,但设计它的目的是用来精确地表示小数。如果您正在寻找一种能精确表示如货币量这样的数值,则 BigDecimal 可以很好地胜任该任务。

所有的 equals 方法都不能真正测试相等

如浮点类型一样, BigDecimal 也有一些令人奇怪的行为。尤其在使用 equals() 方法来检测数值之间是否相等时要小心。 equals() 方法认为,两个表示同一个数但换算值不同(例如, 100.00 和 100.000 )的 BigDecimal 值是不相等的。然而, compareTo() 方法会认为这两个数是相等的,所以在从数值上比较两个 BigDecimal 值时,应该使用 compareTo() 而不是 equals() 。

另外还有一些情形,任意精度的小数运算仍不能表示精确结果。例如, 1 除以 9 会产生无限循环的小数 .111111... 。出于这个原因,在进行除法运算时, BigDecimal 可以让您显式地控制舍入。 movePointLeft() 方法支持 10 的幂次方的精确除法。

使用 BigDecimal 作为互换类型

SQL-92 包括 DECIMAL 数据类型,它是用于表示定点小数的精确数字类型,它可以对小数进行基本的算术运算。一些 SQL 语言喜欢称此类型为 NUMERIC 类型,其它一些 SQL 语言则引入了 MONEY 数据类型,MONEY 数据类型被定义为小数点右侧带有两位的小数。

如果希望将数字存储到数据库中的 DECIMAL 字段,或从 DECIMAL 字段检索值,则如何确保精确地转换该数字?您可能不希望使用由 JDBC PreparedStatement 和 ResultSet 类所提供的 setFloat() 和 getFloat() 方法,因为浮点数与小数之间的转换可能会丧失精确性。相反,请使用 PreparedStatement 和 ResultSet 的 setBigDecimal() 及 getBigDecimal() 方法。

对于 BigDecimal ,有几个可用的构造函数。其中一个构造函数以双精度浮点数作为输入,另一个以整数和换算因子作为输入,还有一个以小数的 String 表示作为输入。要小心使用 BigDecimal(double) 构造函数,因为如果不了解它,会在计算过程中产生舍入误差。请使用基于整数或 String 的构造函数。

构造 BigDecimal 数

对于 BigDecimal ,有几个可用的构造函数。其中一个构造函数以双精度浮点数作为输入,另一个以整数和换算因子作为输入,还有一个以小数的 String 表示作为输入。要小心使用 BigDecimal(double) 构造函数,因为如果不了解它,会在计算过程中产生舍入误差。请使用基于整数或 String 的构造函数。

如果使用 BigDecimal(double) 构造函数不恰当,在传递给 JDBC setBigDecimal() 方法时,会造成似乎很奇怪的 JDBC 驱动程序中的异常。例如,考虑以下 JDBC 代码,该代码希望将数字 0.01 存储到小数字段:

PreparedStatement ps =
connection.prepareStatement("INSERT INTO Foo SET name=?, value=?");
ps.setString(1, "penny");
ps.setBigDecimal(2, new BigDecimal(0.01));
ps.executeUpdate();

在执行这段似乎无害的代码时会抛出一些令人迷惑不解的异常(这取决于具体的 JDBC 驱动程序),因为 0.01 的双精度近似值会导致大的换算值,这可能会使 JDBC 驱动程序或数据库感到迷惑。JDBC 驱动程序会产生异常,但可能不会说明代码实际上错在哪里,除非意识到二进制浮点数的局限性。相反,使用 BigDecimal("0.01") 或 BigDecimal(1, 2) 构造 BigDecimal 来避免这类问题,因为这两种方法都可以精确地表示小数。

② C语言float类型

C语言float类型是单精度浮点类型。

对于每一个浮点数,二进制编码的表示:(-1)^s * M * e。
s:是指的符号位,有两种取值,为0时,表示正浮点数。为1时表示负的浮点数。
M:是有效位数。
e:是指数。实际上这是一个偏置指数。

一般来说,float单精度浮点类型占32个二进制位,其中s符号位占1位,M有效数位占23位,e指数位占8位。

③ C语言中的浮点数的问题

在32位编译器中,按照IEEE754标准,单精度浮点数float固定占4个字节,其中符号位1位,阶码8位(表示范围-126~127),尾数23位(表示范围1.0000...000~1.111111...111)共32位。按照此标准,能表示的最大数字是2^127*2=3.4x10^38,即3.4E38。
你可以理解为计算机中的科学计数法,只不过是2的幂而不是10的幂,即±M*2^E。其中M为尾数,E为阶码

④ C语言学习,浮点型数据的问题

我们说的浮点数包括单精度浮点数和双精度浮点数。
这里,我先拿单精度浮点数来解释你的问题。

单精度数,是指计算机表达实数近似值的一种方式。VB中,Single(单精度浮点型)变量存储为 IEEE 32 位(4 个字节)浮点数值的形式,它的范围在负数的时候是从 -3.402823E38 到 -1.401298E-45,而在正数的时候是从 1.401298E-45 到 3.402823E38 。
单精度存储格式
符号位S(sign) - 1bit
0代表正号,1代表负号。

指数位E(exponent) - 8bit
E的取值范围为0-255(无符号整数),实际数值e=E-127。
有时E也称为“移码”,或不恰当的称为“阶码”(阶码实际应为e) 就是你所说的p。

尾数位M(mantissa) - 23bit
M也叫有效数字位(sinificand)、系数位(coefficient), 甚至被称作“小数”。
在一般情况下,m=(1.M)2,使得实际起作用范围为1≤尾数<2。
为了对溢出进行处理,以及扩展对接近0的极小数值的处理能力。

单精度浮点数实例:
对于内部存储数据(00111111 01100110 01100110 01100110)2:
符号位
(最左侧)S=0。这表示是个正数

指数
(左侧第2-9位)E=(01111110)2=(126)10,所以s=S-127=-1。

尾数
(最后的23位)M=(1100110 01100110 01100110)2,m=(1.M)2=(1.7999999523162841796875)10
该二进制小数转为10进制的计算方式为1 + (1/2+1/4) + (1/32+1/64) + (1/512+1/1024)……

实际值
N=1.7999999523162841796875*2-1=0.89999997615814208984375
(其实,这个数据是0.9的单精度浮点数的实际内部存储,可以看到有一定的误差)

单精度浮点数的表示范围及说明
表示范围
最大表示范围:单精度浮点数可以表示的范围为±3.40282 * 1038(1.1111...12*2127)
接近于0的最小值:单精度浮点数可以表示1.175 * 10-38(1.00...02*2-126)的数据而不损失精度。
当数值比以上值小的时候,将会由于尾数的有效位数减少而逐步丧失精度(IEEE 754的规定),或者有的系统则直接采用0值来简化处理过程。

精度
单精度浮点数的实际有效精度为24位二进制,这相当于 24*log102≈7.2 位10进制的精度,所以平时我们说“单精度浮点数具有7位精度”。(精度的理解:当从1.000...02变化为1.000...12时,变动范围为2-23,考虑到因为四舍五入而得到的1倍精度提高,所以单精度浮点数可以反映2-24的数值变化,即24位二进制精度)

误差
浮点数以有限的32bit长度来反映无限的实数集合,因此大多数情况下都是一个近似值。同时,对于浮点数的运算还同时伴有误差扩散现象。
特定精度下看似相等的两个浮点数可能并不相等,因为它们的最小有效位数不同。
由于浮点数可能无法精确近似于十进制数,如果使用十进制数,则使用浮点数的数学或比较运算可能不会产生相同的结果。
如果涉及浮点数,值可能不往返。值的往返是指,某个运算将原始浮点数转换为另一种格式,而反向运算又将转换后的格式转换回浮点数,且最终浮点数与原始浮点数相等。由于一个或多个最低有效位可能在转换中丢失或更改,往返可能会失败。

关于双精度型:
目前大多数高级语言(包括C)都按照IEEE-754标准来规定浮点数的存储格式,IEEE754规定,单精度浮点数用4字节存储,双精度浮点数用8字节存储,分为三个部分:符号位、阶和尾数。阶即指数,尾数即有效小数位数。单精度格式阶占8位,尾数占24位,符号位1位,双精度则为11为阶,53位尾数和1位符号位。

⑤ 浮点数问题

楼主的问题应该是浮点数在内存中的存储,浮点数有float和double两种。你耐心看看下面的解释就懂了。
任何数据在内存中都是以二进制的形式存储的,例如一个short型数据1156,其二进制表示形式为00000100 10000100。则在Intel CPU架构的系统中,存放方式为 10000100(低地址单元) 00000100(高地址单元),因为Intel CPU的架构是小端模式。但是对于浮点数在内存是如何存储的?目前所有的C/C++编译器都是采用IEEE所制定的标准浮点格式,即二进制科学表示法。
在二进制科学表示法中,S=M*2^N 主要由三部分构成:符号位+阶码(N)+尾数(M)。对于float型数据,其二进制有32位,其中符号位1位,阶码8位,尾数23位;对于double型数据,其二进制为64位,符号位1位,阶码11位,尾数52位。
31 30-23 22-0
float 符号位 阶码 尾数
63 62-52 51-0
double 符号位 阶码 尾数
符号位:0表示正,1表示负
阶码:这里阶码采用移码表示,对于float型数据其规定偏置量为127,阶码有正有负,对于8位二进制,则其表示范围为-128-127,double型规定为1023,其表示范围为-1024-1023。比如对于float型数据,若阶码的真实值为2,则加上127后为129,其阶码表示形式为10000010
尾数:有效数字位,即部分二进制位(小数点后面的二进制位),因为规定M的整数部分恒为1,所以这个1就不进行存储了。
下面举例说明:
float型数据125.5转换为标准浮点格式
125二进制表示形式为1111101,小数部分表示为二进制为 1,则125.5二进制表示为1111101.1,由于规定尾数的整数部分恒为1,则表示为1.1111011*2^6,阶码为6,加上127为133,则表示为10000101,而对于尾数将整数部分1去掉,为1111011,在其后面补0使其位数达到23位,则为11110110000000000000000
则其二进制表示形式为
0 10000101 11110110000000000000000,则在内存中存放方式为:
00000000 低地址
00000000
11111011
01000010 高地址
而反过来若要根据二进制形式求算浮点数如0 10000101 11110110000000000000000
由于符号为为0,则为正数。阶码为133-127=6,尾数为11110110000000000000000,则其真实尾数为1.1111011。所以其大小为
1.1111011*2^6,将小数点右移6位,得到1111101.1,而1111101的十进制为125,0.1的十进制为1*2^(-1)=0.5,所以其大小为125.5。
同理若将float型数据0.5转换为二进制形式
0.5的二进制形式为0.1,由于规定正数部分必须为1,将小数点右移1位,则为1.0*2^(-1),其阶码为-1+127=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进制表示形式为
0 01111110 00000000000000000000000
由上分析可知float型数据最大表示范围为1.11111111111111111111111*2^127=3.4*10^38
对于double型数据情况类似,只不过其阶码为11位,偏置量为1023,尾数为52位

⑥ 浮点数在计算机中是如何表示的

实型变量分为两类:

单精度型和双精度型,其类型说明符为float 单精度说明符,double 双精度说明符。在Turbo C中单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。

双精度型占8 个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。

⑦ 关于c语言中如何定义浮点数

需要准备的材料分别有:电脑、C语言编译器。

1、首先,打开C语言编译器,新建一个初始.cpp文件,例如:test.cpp。

⑧ 计算机组成原理——浮点数表示方法

就是在二进制中,一个数的小数点可以可以通过乘以2的幂次来改变位置,这是其原理 。

浮点数的组成:阶符+ 阶码 +数符+ 尾数

计算机中表示浮点数的字长通常为32位,其中7位作阶码,1位为阶符,23位尾数,1位作数符

例如用2个字节表示一个浮点数(32写起来麻烦,所以用2个字节就是16位来举例,呵呵希望谅解) (72.45x10^5)D先换成普通二进制数(11011101000110011001000)B

然后开始像十进制数的科学计数法那样写成约等于(0.1101110)Bx(2^23)D

之后再将后半部分的(2^23)D转换成(2^10111)B

于是整个数就变成了(0.1101110x2^10111)B

在计算机中表示成0001011101101110 其中第一个0是阶符表示指数是正的第九个0表示尾数是正的他们中间的就是阶码,后面的就是尾数。

⑨ 浮点数比较可以使用float compare方法吗

计算机内的浮点数是有一定的字长和精度的。
如果是2个float型的浮点数,你用 float compare方法当然可以。
如果有1个或2个是double型的浮点数,用 float compare方法 很可能因精度引起的误差而出错。
通常,最好根据具体情况,自己写 比较式 较好。 你可以假定 两数相减的绝对值 小于 某个误差值 就是相等,若是不相等时,再用 > 或 < 判断大小。

⑩ C语言中的浮点值是什么意思

就是常说的小数,浮点是意思就是数字中有个漂浮的点,这个点就是常说的小数点。

1、C语言中均支持两种浮点数,float和double。
其中double的精度,和表示范围比float要大。
另外,部分编译器支持更大精度的long double,但不是所有的编译器都支持。
以上为三种浮点数的类型。在定义的时候,需要以
TYPE var=init_value;
的方式定义,功能为定义一个名字为var,类型为TYPE的变量,并赋值初始值为init_value。
其中=init_value部分可以省略。
2、比如定义一个float类型的浮点变量为
float f;
定义一个类型为double的浮点型变量,并初始化值为1.234,写作
double d = 1.234;

阅读全文

与浮点数近似方式编译选项相关的资料

热点内容
算法期中试卷 浏览:939
php连接hbase 浏览:815
服务器的威胁性应该是什么等级 浏览:827
3d打印机的算法原理 浏览:481
腾讯云通信服务器 浏览:889
minecraft最可怕服务器地址 浏览:274
程序员选专业有必要吗 浏览:32
如何重装rpc服务器 浏览:637
程序员必备的app 浏览:167
电动汽车加密币 浏览:962
xp支持多少层文件夹 浏览:650
阿里云服务器防御指标 浏览:895
cc网络编程学习 浏览:460
单片机又叫微控制器对吗 浏览:662
安卓软件商店如何评分 浏览:657
linuxexecv 浏览:616
苹果照片视频文件夹 浏览:392
cdes加密解密算法 浏览:752
app发版如何让运营及时配活动 浏览:801
python结束界面 浏览:485