第 2 章家庭作业:2.82~2.91

第 2 章家庭作业:2.82~2.91

家庭作业 2.82(★)我们在一个 int 类型值为 32 位的机器上运行程序。这些值以补码形式表示,而且它们都是算术右移的。unsigned 类型的值也是 32 位的。

我们产生随机数 xy,并且把它们转换成无符号数,显示如下:

/* Create some arbitrary values */
int x = random();
int y = random();

/* Convert to unsigned */
unsigned ux = (unsigned) x;
unsigned uy = (unsigned) y;

对于下列每个 C 表达式,你要指出表达式是否总是为 1。如果它总是为 1,那么请描述其中的数学原理。否则,列举出一个使它为 0 的参数示例。

A. (x<y) == (-x>-y)

B. ((x+y)<<4)+y-x == 17*y+15*x

C. ~x+~y+1 == ~(x+y)

D. (ux-uy) == -(unsigned)(y-x)

E. ((x>>2)<<2) <= x

家庭作业 2.83(★★)一些数字的二进制表示是由形如 0.yyyyyy... 的无穷串组成的,其中 y 是一个 k 位的序列。例如,1/3 的二进制表示是 0.01010101...(y=01),而 1/5 的二进制表示是 0.001100110011...(y=0011)。

A. 设 Y = B2Uk(y),也就是说,这个数具有二进制表示 y。给出一个由 Y 和 k 组成的公式表示这个无穷串的值。

提示: 请考虑将二进制小数点右移 k 位的结果。

B. 对于下列的 y 值,串的数值是多少?

  1. 101

  2. 0110

  3. 010011

家庭作业 2.84(★)填写下列程序的返回值,这个程序测试它的第一个参数是否小于或者等于第二个参数。假定函数 f2u 返回一个无符号 32 位数字,其位表示与它的浮点参数相同。你可以假设两个参数都不是 NaN。两种 0,+0 和 -0 被认为是相等的。

int float_le(float x, float y) {
    unsigned ux = f2u(x);
    unsigned uy = f2u(y);

    /* Get the sign bits */
    unsigned sx = ux >> 31;
    unsigned sy = uy >> 31;

    /* Give an expression using only ux, uy, sx, and sy */
    return ____________________________________________;
}

家庭作业 2.85(★)给定一个浮点格式,有 k 位指数和 n 位小数,对于下列数,写出阶码 E、尾数 M、小数 f 和值 V 的公式。另外,请描述其位表示。

A. 数 7.0。

B. 能够被准确描述的最大奇整数。

C. 最小的规格化数的倒数。

家庭作业 2.86(★)与 Intel 兼容的处理器也支持“扩展精度”浮点格式,这种格式具有 80 位字长,被分成 1 个符号位、k=15 个阶码位、1 个单独的整数位和 n=63 个小数位。整数位是 IEEE 浮点表示中隐含位的显式副本。也就是说,对于规格化的值它等于 1,对于非规格化的值它等于 0。填写下表,给出用这种格式表示的一些“有趣的”数字的近似值。

描述 扩展精度:值 扩展精度:十进制
最小的正非规格化数
最小的正规格化数
最大的规格化数

将数据类型声明为 long double,就可以把这种格式用于为与 Intel 兼容的机器编译 C 程序。但是,它会强制编译器以传统的 8087 浮点指令为基础生成代码。由此产生的程序很可能会比数据类型为 floatdouble 的情况慢上许多。

家庭作业 2.87(★)2008 版 IEEE 浮点标准,即 IEEE 754-2008,包含了一种 16 位的“半精度”浮点格式。它最初是由计算机图形公司设计的,其存储的数据所需的动态范围要高于 16 位整数可获得的范围。这种格式具有 1 个符号位、5 个阶码位(k=5)和 10 个小数位(n=10)。阶码偏置量是 25-1-1=15。

对于每个给定的数,填写下表,其中,每一列具有如下指示说明:

Hex: 描述编码形式的 4 个十六进制数字。

M: 尾数的值。这应该是一个形如 x 或 x/y 的数,其中 x 是一个整数,而 y 是 2 的整数幂。例如:0、67/64 和 1/256。

E: 阶码的整数值。

V: 所表示的数字值。使用 x 或者 x × 2z 表示,其中 x 和 z 都是整数。

D: (可能近似的)数值,用 printf 的格式规范 %f 打印。

举一个例子,为了表示数 7/8,我们有 s=0、M=7/4 和 E=-1。因此这个数的阶码字段为 011102(十进制值 15-1=14),尾数字段为 11000000002,得到一个十六进制的表示 3B00。其数值为 0.875。

标记为“—”的条目不用填写。

描述 Hex M E V D
-0 -0 -0.0
最小的 > 2 的值
512 512 512.0
最大的非规格化数
-∞ -∞ -∞
十六进制表示为 3BB0 的数 3BB0

家庭作业 2.88(★★)考虑下面两个基于 IEEE 浮点格式的 9 位浮点表示。

  1. 格式 A
  • 有一个符号位。
  • 有 k=5 个阶码位。阶码偏置量是 15。
  • 有 n=3 个小数位。
  1. 格式 B
  • 有一个符号位。
  • 有 k=4 个阶码位。阶码偏置量是 7。
  • 有 n=4 个小数位。

下面给出了一些格式 A 表示的位模式,你的任务是把它们转换成最接近的格式 B 表示的值。

如果需要舍入,你要向 +∞ 舍入。另外,给出用格式 A 和格式 B 表示的位模式对应的值。要么是整数(例如 17),要么是小数(例如 17/64 或 17/26)。

格式 A:位 格式 A:值 格式 B:位 格式 B:值
1 01110 001 -9/16 1 0110 0010 -9/16
0 10110 101
1 00111 110
0 00000 101
1 11011 000
0 11000 100

家庭作业 2.89(★)我们在一个 int 类型为 32 位补码表示的机器上运行程序。float 类型的值使用 32 位 IEEE 格式,而 double 类型的值使用 64 位 IEEE 格式。

我们产生随机整数 xyz,并且把它们转换成 double 类型的值:

/* Create some arbitrary values */
int x = random();
int y = random();
int z = random();

/* Convert to double */
double dx = (double) x;
double dy = (double) y;
double dz = (double) z;

对于下列的每个 C 表达式,你要指出表达式是否总是为 1。如果它总是为 1,描述其中的数学原理。否则,列举出使它为 0 的参数的例子。请注意,不能使用 IA32 机器运行 GCC 来测试你的答案,因为对于 floatdouble,它使用的都是 80 位的扩展精度表示。

A. (float)x == (float)dx

B. dx-dy == (double)(x-y)

C. (dx+dy)+dz == dx+(dy+dz)

D. (dx*dy)*dz == dx*(dy*dz)

E. dx/dx == dz/dz

家庭作业 2.90(★)分配给你一个任务,编写一个 C 函数来计算 2x 的浮点表示。你意识到完成这个任务的最好方法是直接创建结果的 IEEE 单精度表示。当 x 太小时,你的程序将返回 0.0。当 x 太大时,它会返回 +∞。填写下列代码的空白部分,以计算出正确的结果。假设函数 u2f 返回的浮点值与它的无符号参数有相同的位表示。

float fpwr2(int x)
{
    /* Result exponent and fraction */
    unsigned exp, frac;
    unsigned u;

    if (x < __________) {
        /* Too small. Return 0.0 */
        exp = __________;
        frac = __________;
    } else if (x < __________) {
        /* Denormalized result */
        exp = __________;
        frac = __________;
    } else if (x < __________) {
        /* Normalized result. */
        exp = __________;
        frac = __________;
    } else {
        /* Too big. Return +oo */
        exp = __________;
        frac = __________;
    }

    /* Pack exp and frac into 32 bits */
    u = exp << 23 | frac;
    /* Return as float */
    return u2f(u);
}

家庭作业 2.91(★)大约公元前 250 年,希腊数学家阿基米德证明了 223/71 < π < 22/7。如果当时有一台计算机和标准库 <math.h>,他就能够确定 π 的单精度浮点近似值的十六进制表示为 0x40490FDB。当然,所有的这些都只是近似值,因为 π 不是有理数。

A. 这个浮点值表示的二进制小数是多少?

B. 22/7 的二进制小数表示是什么?提示: 参见家庭作业 2.83。

C. 这两个 π 的近似值从哪一位(相对于二进制小数点)开始不同的?