【问题标题】:Floating Point Addition / Multiplication / Division浮点加法/乘法/除法
【发布时间】:2015-05-07 02:24:53
【问题描述】:

我正在做一些课本上的家庭作业,并且对某些算术运算的浮点舍入/精度有一些问题。

如果我像这样从 int 中转换了双精度数:

int x = random();
double dx = (double) x; 

假设变量 yzdydz 遵循相同的格式。

然后会像这样的操作:

(dx + dy) + dz == dx + (dy + dz)
(dx * dy) * dz == dx * (dy * dz)

具有关联性?我知道如果我们有小数表示,那么它就不会是关联的,因为根据哪些操作数相互相加/相乘,四舍五入会丢失一些精度。但是,由于这些是从整数铸造的,我觉得精度不会成为问题,而且这些可以是关联的?

最后,我使用的教科书根本没有解释 FP 除法,所以我想知道这个说法是否正确,或者至少只是浮点除法的一般工作原理:

dx / dx == dz / dz

我在网上查到了这个,我在某些方面读到,比如像 3/3 这样的运算可以产生 .999...9,但是没有足够的信息来解释这是如何发生的,或者它是否会随着其他除法运算而变化.

【问题讨论】:

  • 一个好的编译器应该能够识别 dx/dx 而不是真正发出除法指令。
  • 您可以将 2^53 + 1 以内的任何值精确地表示为双精度值。除此之外,您会遇到舍入错误,即使对于整数类型也是如此。 stackoverflow.com/a/1848762/141172
  • 你可能记得,从你上小学的时候起,一个数字除以自身就是 1,所以比较“可能”有效。但是,一般来说,浮点数不应该使用'=='来比较,获取绝对值,获取差异,检查差异是否小于某个阈值
  • (dx * dy) * dz == dx * (dy * dz) 如果double 的精度 int 精度的两倍,则会出现问题——这种情况经常发生。 (dx + dy) + dz == dx + (dy + dz) 不太可能成为问题,因为 double 精度肯定超过 int 精度 + 1。dx / dx == dz / dz 明显的问题应该是 dx==0dz==0
  • dx * dydy * dz 大于2^53 时,可能存在精度问题。 double dx = (double)(INT_MAX); double dy = (double)(INT_MAX - 0x111111); double dz = (double)(INT_MAX - 0xabcd);(dx * dy) * dz == dx * (dy * dz) 是假的。

标签: c floating-point floating-accuracy floating-point-conversion


【解决方案1】:

假设int 最多为 32 位,并且double 遵循 IEEE-754。 double 最多可以精确存储 253 个整数值。


在加法的情况下:

(dx + dy) + dz == dx + (dy + dz)

== 的两边都有自己的精确值,所以它是关联的。


而在乘法的情况下:

(dx * dy) * dz == dx * (dy * dz)

有可能超过253,所以不保证相等。

【讨论】:

  • 只是澄清一下,所以 double 可以存储的最大值是 2^53 的原因是因为 52 位尾数 + 隐含的前导 1?
  • 要明确:double 可以完全存储所有整数 -pow(2,53) ... +pow(2,53) --inclusive - 就像 54 位有符号整数或 int54_t
【解决方案2】:

您应该了解,浮点数通常在内部表示为符号位、定点尾数(52 位,IEEE 64-bit doubles 隐含前导一位)和二进制指数(IEEE 双精度为 11 位)。您可以将指数视为给定值的数学单位的“量子”。

如果总和都符合尾数且指数不超过 20 == 1,则加法应该是关联的。如果 random() 生成 32 位整数,则和如 @ 987654323@ 将适合,并且添加将是关联的。

在乘法的情况下,很容易看出 2 个 32 位数字的乘积可能远远超过 53 位,因此指数可能需要超过 1 才能使尾数包含结果的大小,所以关联失败。

对于除法,在 dx / dx 的特殊情况下,编译器可以用常量 1.0 替换表达式(可能在零检查之后)。

【讨论】:

  • 指数也有一个内置的偏移量(我想是 256),以允许正指数和负指数,而不必为符号消耗一点点
  • 指数偏移(通常称为偏差)是指数范围的一半。对于具有 11 位指数的 IEEE 双精度,偏差为 1023。对于 IEEE 单精度,偏差为 127。
猜你喜欢
  • 2011-05-06
  • 1970-01-01
  • 2016-01-14
  • 2023-03-25
  • 2014-02-14
  • 2013-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多