为什么我们将归一化的分数乘以0.5以获得IEEE 754表示的有效位数?

孤独的学习者

对Beej的网络编程指南7.4节中pack754()定义功能有疑问

此函数将浮点数f转换为其IEEE 754表示形式,其中bits表示位数的位数总数,并且expbits是仅用于表示指数的位数。

我只关心单精度浮点数,因此对于此问题,bits将其指定为,32并将expbits其指定为8这意味着使用23位来存储有效数(因为一位是符号位)。

我的问题是关于这一行代码。

    significand = fnorm * ((1LL<<significandbits) + 0.5f);

+ 0.5f该代码的作用是什么

这是使用此功能的完整代码。

#include <stdio.h>
#include <stdint.h> // defines uintN_t types
#include <inttypes.h> // defines PRIx macros

uint64_t pack754(long double f, unsigned bits, unsigned expbits)
{
    long double fnorm;
    int shift;
    long long sign, exp, significand;
    unsigned significandbits = bits - expbits - 1; // -1 for sign bit

    if (f == 0.0) return 0; // get this special case out of the way

    // check sign and begin normalization
    if (f < 0) { sign = 1; fnorm = -f; }
    else { sign = 0; fnorm = f; }

    // get the normalized form of f and track the exponent
    shift = 0;
    while(fnorm >= 2.0) { fnorm /= 2.0; shift++; }
    while(fnorm < 1.0) { fnorm *= 2.0; shift--; }
    fnorm = fnorm - 1.0;

    // calculate the binary form (non-float) of the significand data
    significand = fnorm * ((1LL<<significandbits) + 0.5f);

    // get the biased exponent
    exp = shift + ((1<<(expbits-1)) - 1); // shift + bias

    // return the final answer
    return (sign<<(bits-1)) | (exp<<(bits-expbits-1)) | significand;
}

int main(void)
{
    float f = 3.1415926;
    uint32_t fi;

    printf("float f: %.7f\n", f);

    fi = pack754(f, 32, 8);
    printf("float encoded: 0x%08" PRIx32 "\n", fi);

    return 0;
}

什么用途+ 0.5f担任这一代码?

chux-恢复莫妮卡

该代码是不正确的舍入尝试。

long double fnorm;
long long significand;
unsigned significandbits
...
significand = fnorm * ((1LL<<significandbits) + 0.5f);  // bad code

错误的第一个线索是fof 0.5f,它表示在例程中使用float进行指定是荒谬的介绍数学在该函数中没有应用。floatlong double ffnormfloat

但是添加0.5f并不意味着代码仅限于floatin中的数学(1LL<<significandbits) + 0.5f看看FLT_EVAL_METHOD哪一个可能允许更高精度的中间结果,并且在测试中欺骗了代码作者。

舍入尝试确实有意义,因为参数是实际的long double,并且目标表示形式更窄。添加0.5是一种常见的方法-但此处未完成添加国际海事组织,缺乏作者在此发表的评论,0.5f暗示其意图是“显而易见的”-不是微妙的,尽管不正确。

至于评论,移动0.5是呼之欲出的四舍五入正确的,但是可能会误导致一些以为加入与做float数学,(这是long double数学添加long double产品float原因0.5f晋升为long double第一)。

// closer to rounding but may mislead
significand = fnorm * (1LL<<significandbits) + 0.5f;

// better
significand = fnorm * (1LL<<significandbits) + 0.5L; // or 0.5l or simply 0.5

舍入时,不调用首选舍入<math.h>例程,例如rintl(), roundl(), nearbyintl(), llrintl(),添加显式类型0.5仍然是舍入的较弱尝试。它很弱,因为在许多情况下它舍入不正确。+0.5技巧依赖于精确的和

考虑

long double product = fnorm * (1LL<<significandbits);
long long significand = product + 0.5;  // double rounding?

product + 0.5本身可能会在截断/赋值之前经过舍入long long-实际上是两次舍入

最好在标准库函数集中使用正确的工具。

significand = llrintl(fnorm * (1ULL<<significandbits));

此舍入仍然存在significand一个极端情况,即现在太大了,significand , exp需要调整。正如@Nayuki所指出的那样,代码也有其他缺点。此外,它在上失败-0.0

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

MIPS:除法算法(除以IEEE-754格式的有效位数)对后4-5位(LSB)给出错误的答案

signif 没有给我正确的 R 中有效位数

格式化答案以更正C中的有效位数

ToString抽象操作:最低有效位数未唯一确定

为什么我们需要IEEE 754余数?

在Python中,为什么最低(最小)浮点值的有效位数与最大数字不同?

我在ggscatter中使用stat_regline_equation。有没有办法指定系数的有效位数?

谁还记得根据有效位数将 4 字节整数打包为 1 到 4 字节数组的算法?

是否可以强制某个浮点数的指数或有效位数与另一个浮点数匹配(Python)?

计算有效位数

MySQL 8:我应该能够编写一个有效的IEEE 754浮点数并读回确切的值吗?

将有效位数翻倍至3

在Python中如何找到最低有效位数

如何确定R中数据的有效位数?

确定数据帧中的有效位数

移位最高有效位数为1

获得std :: set的中间(中位数)的有效方法?

为什么我们需要再次拟合模型才能获得分数?

当我们有几个组时,基于控件的样本归一化

我们如何才能有效地计算Elixir中整数的位数?

R中数字值的双精度(64位)表示形式(符号,指数,有效位数)

查找有效位数与r中小数点后的位数

变成我们需要使用装饰器转换 TypeScript 类以获得有效的 Vue 组件?

我们应该在有角度的应用程序中对状态进行归一化吗?

为什么 'n = 5 是有效的语法?[Scala]

如何在Java中递增固定有效位数?

否定number_format()结果会更改有效位数吗?

通过分离有效位数和指数来近似log2(float)

如何获取NetCDF文件中存储的数据的有效位数?