首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不动点表示法

不动点表示法
EN

Stack Overflow用户
提问于 2014-03-15 10:30:24
回答 3查看 1.4K关注 0票数 4

我正在寻找一个通常可以理解的表示法来定义一个不动点数表示。该表示法应该能够定义两个因子的幂(使用小数位)和一个通用因子(有时我被迫使用它,尽管效率较低)。还应该定义一个可选的偏移量。

我已经知道了一些可能的符号,但它们似乎都受限于特定的应用程序。

  • 例如,Simulink表示法完全符合我的需要,但它只在Simulink世界中才被知道。此外,fixdt()函数的重载用法也不是那么可读的。
  • TI定义了一个非常紧凑的Q格式,但是符号是隐式的,它不管理通用因素(即不是2的幂)。
  • 阿萨姆使用带有2次分子和分母多项式(方法)的6系数有理函数.很普通,但不那么友好。

还请参阅维基百科讨论。

问题只是关于表示法(不是表示法的效率,也不是定点操作)。因此,这是一个代码可读性、可维护性和可测试性问题。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-03-15 11:51:53

啊,是的。拥有良好的命名注解绝对关键的,不能用不动点算法引入bug。我使用Q表示法的显式版本,它通过将_Q<M>_<N>附加到变量的名称来处理M和N之间的任何除法。这也使得有可能将签名也包括在内。没有运行时性能的惩罚。示例:

代码语言:javascript
复制
uint8_t length_Q2_6;                // unsigned, 2 bit integer, 6 bit fraction
int32_t sensor_calibration_Q10_21;  // signed (1 bit), 10 bit integer, 21 bit fraction.

/*
 * Calculations with the bc program (with '-l' argument):
 *
 * sqrt(3)
 * 1.73205080756887729352
 *
 * obase=16
 * sqrt(3)
 * 1.BB67AE8584CAA73B0
 */
const uint32_t SQRT_3_Q7_25 = 1 << 25 | 0xBB67AE85U >> 7; /* Unsigned shift super important here! */

如果有人还没有完全理解为什么这样的注释是非常重要的,您能在下面的两个示例中发现是否存在错误吗?

示例1:

代码语言:javascript
复制
speed_fraction = fix32_udiv(25, speed_percent << 25, 100 << 25);
squared_speed  = fix32_umul(25, speed_fraction, speed_fraction);
tmp1 = fix32_umul(25, squared_speed, SQRT_3);
tmp2 = fix32_umul(12, tmp1 >> (25-12), motor_volt << 12);

示例2:

代码语言:javascript
复制
speed_fraction_Q7_25 = fix32_udiv(25, speed_percent << 25, 100 << 25);
squared_speed_Q7_25  = fix32_umul(25, speed_fraction_Q7_25, speed_fraction_Q7_25);
tmp1_Q7_25  = fix32_umul(25, squared_speed_Q7_25, SQRT_3_Q1_31);
tmp2_Q20_12 = fix32_umul(12, tmp1_Q7_25 >> (25-12), motor_volt << 12);

想象一下,如果一个文件包含#define SQRT_3 (1 << 25 | 0xBB67AE85U >> 7),另一个文件包含#define SQRT_3 (1 << 31 | 0xBB67AE85U >> 1),代码在这些文件之间移动。例如,这很有可能被忽略,并引入示例2中存在的bug,这个错误在这里是故意执行的,并且不可能被意外执行。

票数 2
EN

Stack Overflow用户

发布于 2014-03-15 11:07:50

实际上,Q格式是商业应用程序中最常用的表示形式:当您需要快速处理小数时,您的处理器没有浮点单元( FPU ),它不能本地使用浮点数和双数据类型--它必须为它们模拟非常昂贵的指令。

通常,您只使用Q格式来表示小数部分,虽然这不是必须的,但是表示的精度更高。下面是你需要考虑的问题:

  • 使用的位数(Q15使用16位数据类型,通常是短int)
  • 第一位是符号位(在16位中,数据值为15位)。
  • 其余的位用于存储数字的小数部分。
  • 由于您表示的是小数,所以值在[0,1]中的某个位置。
  • 您也可以选择对整数部分使用一些位,但是您将失去精度--例如,如果您想以q格式表示3.3,则需要1位的符号,2位的整数部分,剩下13位用于小数部分(假设您使用16位表示),这种格式称为2Q13。

示例:假设您希望以Q15格式表示0.3;应用三的规则:

代码语言:javascript
复制
      1 = 2^15 = 32768 = 0x8000
    0.3 = X
    -------------
    X = 0.3*32768 = 9830 = 0x666

这样做就失去了精确性,但至少现在的计算速度很快。

票数 2
EN

Stack Overflow用户

发布于 2014-03-15 10:57:25

在C中,不能像使用内置类型那样使用用户定义的类型。如果您想这样做,您需要使用C++。在该语言中,您可以为不动点类型定义类,重载所有算术运算符(+、-、*、/、%、+=、-=、*=、/=、%=、-、++、强制转换为其他类型),这样该类实例的使用就像内置类型一样。

在C中,您需要显式地执行您想做的事情。有两种基本的方法。

方法1:在用户代码中进行定点调整。

这是免费的,但是你需要记住做正确的调整。我认为,最简单的方法是将过去的点位数添加到变量名的末尾,因为类型系统不会对您有多大的好处,即使您使用的所有点位置都是typedef

代码语言:javascript
复制
int64_t a_7 = (int64_t)(7.3*(1<<7));    //a variable with 7 past point bits
int64_t b_5 = (int64_t)(3.78*(1<<5));   //a variable with 5 past point bits
int64_t sum_7 = a_7 + (b_5 << 2);    //to add those two variables, we need to adjust the point position in b
int64_t product_12 = a_7 * b_5;    //the product produces a number with 12 past point bits

当然,这是很多麻烦,但至少你可以很容易地在每个点检查点调整是否正确。

方法2:为不动点数字定义一个结构,并将算法封装在一组函数中。如下所示:

代码语言:javascript
复制
typedef struct FixedPoint {
    int64_t data;
    uint8_t pointPosition;
} FixedPoint;

FixedPoint fixed_add(FixedPoint a, FixedPoint b) {
    if(a.pointPosition >= b.PointPosition) {
        return (FixedPoint){
            .data = a.data + (b.data << a.pointPosition - b.pointPosition),
            .pointPosition = a.pointPosition
        };
    } else {
        return (FixedPoint){
            .data = (a.data << b.pointPosition - a.pointPosition) + b.data,
            .pointPosition = b.pointPosition
        };
    }
}

这种方法在使用上有点干净,但是它引入了大量的开销。这一间接费用包括:

  1. 函数调用。
  2. 复制用于参数和结果传递的结构,如果使用指针,则复制指针取消引用。
  3. 需要在运行时计算点调整。

这与没有模板的C++类的开销非常相似。使用模板会将一些决策移回编译时,而代价是失去灵活性。

这种基于对象的方法可能是最灵活的方法,它允许您以透明的方式添加对非二进制点位置的支持。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22422557

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档