C 浮点加法/乘法/除法
我在做课本上的一些家庭作业,对某些算术运算的浮点舍入/精度有一些问题 如果我用这样的整型铸造双打:C 浮点加法/乘法/除法,c,floating-point,floating-accuracy,floating-point-conversion,C,Floating Point,Floating Accuracy,Floating Point Conversion,我在做课本上的一些家庭作业,对某些算术运算的浮点舍入/精度有一些问题 如果我用这样的整型铸造双打: int x = random(); double dx = (double) x; 假设变量y、z、dy和dz遵循相同的格式 那么,我们希望: (dx + dy) + dz == dx + (dy + dz) (dx * dy) * dz == dx * (dy * dz) 联想?我知道,如果我们有分数表示,那么它就不会有关联性,因为根据哪些操作数彼此相加/相乘,舍入会损失一些精度。然而,由
int x = random();
double dx = (double) x;
假设变量y、z、dy和dz遵循相同的格式
那么,我们希望:
(dx + dy) + dz == dx + (dy + dz)
(dx * dy) * dz == dx * (dy * dz)
联想?我知道,如果我们有分数表示,那么它就不会有关联性,因为根据哪些操作数彼此相加/相乘,舍入会损失一些精度。然而,由于这些都是从整数中浇铸出来的,我觉得精度不会有问题,而且这些可以是关联的
最后,我使用的教科书根本没有解释FP除法,所以我想知道这句话是不是真的,或者至少是浮点除法的一般工作原理:
dx / dx == dz / dz
我在网上查到了这一点,我在一些领域读到了类似3/3这样的操作可以产生0.999…9,但没有足够的信息来解释这是如何发生的,或者它是否会随其他部门的操作而变化 假设
int
最多为32位,并且double
遵循IEEE-754double
最多可以精确存储253个整数值
在添加的情况下:
(dx + dy) + dz == dx + (dy + dz)
==
的两边都有精确的值,因此它是关联的
而在乘法的情况下:
(dx * dy) * dz == dx * (dy * dz)
值可能超过253,因此不能保证它们相等。您应该了解,浮点数通常在内部表示为符号位、定点尾数(52位,其中隐含的前导一位)和二进制指数(11位表示IEEE双精度)。可以将指数视为给定值的数学单位的“量子” 如果总和都符合尾数,且指数不超过20==1,则加法应该是关联的。如果
random()
生成的是32位整数,则将适合使用(dx+dy)+dz这样的和,并且加法将是关联的
在乘法的情况下,很容易看出2个32位数字的乘积可能超过53位,因此指数可能需要超过1,尾数才能包含结果的大小,因此关联性失败
对于除法,在dx/dx
的特殊情况下,编译器可能会用常数1.0替换表达式(可能是在零检查之后)。一个好的编译器应该识别dx/dx,而不是实际发出除法指令。您可以准确地将最大为2^53+1的任何值表示为双精度。除此之外,您还会遇到舍入错误,即使对于整数类型也是如此。你可能还记得,从小学时代起,一个数字除以它本身就是1,所以比较“可能”是有效的。但是,一般情况下,不应使用“==”来比较浮点数,而是应获取绝对值,获取差值,检查差值是否小于某个threshold(dx*dy)*dz==dx*(dy*dz)
如果的精度是int
精度的两倍,这是一个问题-通常情况下(dx+dy)+dz==dx+(dy+dz)
不太可能是个问题,因为的精度比int
的精度+1高一倍dx/dx==dz/dz
明显的问题应该是dx==0
或dz==0
。指数还有一个内置的偏移量(我想是256),允许正指数和负指数,而不必为符号消耗一点。指数偏移量(通常称为偏差)是指数范围的一半。对于指数为11位的IEEE double,偏差为1023。对于IEEE single,它是127。只是澄清一下,所以双精度can存储的最大值是2^53的原因是52位尾数+隐含的前导1?要清楚:double
可以精确存储所有整数-pow(2,53)+pow(2,53)
--包括在内-就像54位有符号整数或int54\u t
。