模拟定点除法/乘法

发布于 2024-10-17 20:32:54 字数 1152 浏览 1 评论 0原文

我正在编写一个定点类,但遇到了一些障碍...乘法、除法部分,我不知道如何模拟。我对部门操作员进行了非常粗暴的批评,但我确信这是错误的。到目前为止,情况是这样的:

class Fixed
{
    Fixed(short int _value, short int _part) : 
        value(long(_value + (_part >> 8))), part(long(_part & 0x0000FFFF)) {};

    ...

    inline Fixed operator -() const  // example of some of the bitwise it's doing
    {
        return Fixed(-value - 1, (~part)&0x0000FFFF);
    };

    ...

    inline Fixed operator / (const Fixed & arg) const // example of how I'm probably doing it wrong
    {
        long int tempInt = value<<8 | part;
        long int tempPart = tempInt;
        tempInt  /= arg.value<<8 | arg.part;
        tempPart %= arg.value<<8 | arg.part;
        return Fixed(tempInt, tempPart);
    };

    long int value, part; // members
};

我……不是一个很好的程序员,哈哈!

该类的 part 是 16 位宽(但表示为 32 位长,因为我想象它在修复之前需要为可能的溢出留出空间),value 也是如此 这是整数部分。当“部分”在其中一项操作中超过 0xFFFF 时,最高 16 位将添加到“值”中,然后该部分被屏蔽,因此仅保留最低 16 位。这是在 init 列表中完成的。

我不想问,但如果有人知道我在哪里可以找到类似的文档,甚至只是“技巧”或如何执行这两个操作符,我会非常高兴!当谈到数学时,我是个傻瓜,我知道以前有人不得不这样做/问过这个问题,但搜索谷歌一次并没有把我带到应许之地......

I'm writing a Fixedpoint class, but have ran into bit of a snag... The multiplication, division portions, I am not sure how to emulate. I took a very rough stab at the division operator but I am sure it's wrong. Here's what it looks like so far:

class Fixed
{
    Fixed(short int _value, short int _part) : 
        value(long(_value + (_part >> 8))), part(long(_part & 0x0000FFFF)) {};

    ...

    inline Fixed operator -() const  // example of some of the bitwise it's doing
    {
        return Fixed(-value - 1, (~part)&0x0000FFFF);
    };

    ...

    inline Fixed operator / (const Fixed & arg) const // example of how I'm probably doing it wrong
    {
        long int tempInt = value<<8 | part;
        long int tempPart = tempInt;
        tempInt  /= arg.value<<8 | arg.part;
        tempPart %= arg.value<<8 | arg.part;
        return Fixed(tempInt, tempPart);
    };

    long int value, part; // members
};

I... am not a very good programmer, haha!

The class's part is 16 bits wide (but expressed as a 32-bit long since I imagine it'd need the room for possible overflows before they're fixed) and the same goes for value which is the integer part. When the 'part' goes over 0xFFFF in one of it's operations, the highest 16 bits are added to 'value', and then the part is masked so only it's lowest 16 bits remain. That's done in the init list.

I hate to ask, but if anyone would know where I could find documentation for something like this, or even just the 'trick' or how to do those two operators, I would be very happy for it! I am a dimwit when it comes to math, and I know someone has had to do/ask this before, but searching google has for once not taken me to the promised land...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

时光是把杀猪刀 2024-10-24 20:32:54

正如 Jan 所说,使用单个整数。由于看起来您正在指定 16 位整数和小数部分,因此您可以使用普通的 32 位整数来完成此操作。

“技巧”是要意识到当你对数字进行操作时,数字的“格式”会发生什么。您的格式将被描述为 16.16。当您添加或减去时,格式保持不变。当你相乘时,你得到 32.32——所以你需要一个 64 位的临时值作为结果。然后进行>>16 移位以得到 48.16 格式,然后取底部 32 位以得到 16.16 的答案。

我对除法有点生疏——在 DSP 中,我在那里学习了这些东西,我们尽可能避免(昂贵的)除法!

As Jan says, use a single integer. Since it looks like you're specifying 16 bit integer and fractional parts, you could do this with a plain 32 bit integer.

The "trick" is to realise what happens to the "format" of the number when you do operations on it. Your format would be described as 16.16. When you add or subtract, the format stays the same. When you multiply, you get 32.32 -- So you need a 64 bit temporary value for the result. Then you do a >>16 shift to get down to 48.16 format, then take the bottom 32 bits to get your answer in 16.16.

I'm a little rusty on the division -- In DSP, where I learned this stuff, we avoided (expensive) division wherever possible!

假装爱人 2024-10-24 20:32:54

要启动并运行,首先实现(一元)inverse(x) = 1/x,然后将 a/b 实现为 a*inverse( b)。您可能希望将中间体表示为 32.32 格式。

To get things up and running, first implement the (unary) inverse(x) = 1/x, and then implement a/b as a*inverse(b). You'll probably want to represent the intermediates as a 32.32 format.

不乱于心 2024-10-24 20:32:54

我建议使用一个整数值而不是单独的整数部分和小数部分。加法和减法是直接对应的整数,您可以简单地使用 64 位支持,目前所有常见编译器都支持:

  • 乘法:

     运算符*(const 固定&其他) const {
         返回固定值(((int64_t)value * (int64_t)other.value)>>16);
     }
    

    1 表示为 1 << 16,所以你需要除以 1 << 16 最后进行补偿。

  • 部门:

     运算符/(const 固定&其他) const {
         返回固定(((int64_t)值<<16)/(int64_t)other.value);
     }
    

    1 表示为 1 << 16,所以你需要乘以1 << 16之前补偿。

64 位整数

  • 在 gcc 上,stdint.h(或 cstdint,将它们放置在 std:: 命名空间中)应该可用,因此你可以使用我上面提到的类型。否则,在 32 位目标上它是 long long,在 64 位目标上它是 long
  • 在 Windows 上,它始终是 long long__int64

I'd recommend using one integer value instead of separate whole and fractional part. Than addition and subtraction are the integeral counterparts directly and you can simply use 64-bit support, which all common compilers have these days:

  • Multiplication:

     operator*(const Fixed &other) const {
         return Fixed(((int64_t)value * (int64_t)other.value) >> 16);
     }
    

    1 is represented as 1 << 16, so you need to divide by 1 << 16 at the end to compensate.

  • Division:

     operator/(const Fixed &other) const {
         return Fixed(((int64_t)value << 16) / (int64_t)other.value);
     }
    

    1 is represented as 1 << 16, so you need to multiply by 1 << 16 before to compensate.

64-bit integers are

  • On gcc, stdint.h (or cstdint, which places them in std:: namespace) should be available, so you can use the types I mentioned above. Otherwise it's long long on 32-bit targets and long on 64-bit targets.
  • On Windows, it's always long long or __int64.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文