You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中实现精准的FixedPoint定点数计算?

如何在C语言中实现精准的FixedPoint定点数计算?

我在C语言中使用struct来存储定点数的整数部分和小数部分。我猜测函数存在错误,可能未正确处理溢出,但不知道如何修改。

输入示例如下:

3.14123412345 + 0.23
5.6324 - 6.43252
8.112 * 1.31

我的输出结果为:

3.000000
-1.000000
0.000000

程序输出完全错误,数值的精度在存储或计算过程中丢失。

以下是我的初始代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#define maxn 110000
#define uint unsigned int
#define ull unsigned long long
typedef struct {
    int intgr;
    uint frac;
}PointFixedNum;
PointFixedNum a,b,ans;
char s1[maxn],s2[maxn],op;
double num1=0.0,num2=0.0;
void init(PointFixedNum *a,double num)
{
    a->intgr=(int)num;
    a->frac=(uint)((ull)(num-a->intgr)<<32);
}
void clear()
{
    a.frac=b.frac=ans.frac=0;
    a.frac=b.frac=ans.frac=0;
    num1=0.0;
    num2=0.0;
}
void read()
{
    scanf("%1100[^ ]",s1);
    scanf(" %c",&op);
    scanf("%1100s",s2);
    sscanf(s1,"%lf",&num1);
    sscanf(s2,"%lf",&num2);
}
PointFixedNum add(PointFixedNum a,PointFixedNum b)
{
    PointFixedNum c;
    ull sum=(ull)a.frac+b.frac;
    c.frac=(uint)(sum&((1ULL<<32)-1));
    c.intgr=a.intgr+b.intgr+(int)(sum>>32);
    return c;
}
PointFixedNum sub(PointFixedNum a,PointFixedNum b)
{
    PointFixedNum c;
    ull diff=(ull)a.frac-b.frac;
    c.frac=(uint)(diff&((1ULL<<32)-1));
    c.intgr=a.intgr-b.intgr-(int)(diff>>32);
}
PointFixedNum mul(PointFixedNum a,PointFixedNum b)
{
    PointFixedNum c;
    ull pro1=(ull)a.intgr*b.intgr;
    ull pro2=(ull)a.frac*b.frac;
    ull temp=(ull)((ull)pro1<<32)+(ull)pro2;
    c.intgr=(int)(temp>>32);
    c.frac=(uint)(temp&((1ULL<<32)-1));
}
void print(PointFixedNum a)
{
    double fraction=(double)a.frac/(1ULL<<32);
    double fin=(double)a.intgr+fraction;
    printf("%lf",fin);
}
int main()
{
    read();
    init(&a,num1);
    init(&b,num2);
    if(op=='+')
    {
        ans=add(a,b);
    }
    else if(op=='-')
    {
        ans=sub(a,b);
    }
    else if(op=='*')
    {
        ans=mul(a,b);
    }
    print(ans);
    return 0;
}

更新内容:

我根据评论和回答修复了程序中的部分bug,结果如下:

输入示例

3.14123412345 + 0.23
5.6324 - 6.43252
8.112 * 1.31

输出结果

3.37123412336
-0.80012000003
10.62671999843

目前各函数功能已实现,至少逻辑上无问题。当前仅存的问题是精度:加减运算在十位小数后会丢失精度。

如何提升精度?

有没有方法可以提升精度?或者十位小数后的精度损失是不可避免的?
如果确实不可避免,由于加减运算仅涉及位数最短的数,是否有办法在输出中保留未变化的部分?
示例:3.14123412345 + 0.23 = 3.37123412345,小数点后前两位(3.14)与0.23相加,但123412345部分未变化,能否直接在输出中保留这部分?

关于乘法运算

当输出结果的小数位数有限时,结果相当准确,有没有办法将输出的小数位数限制为与实际结果一致?
示例:8.112 * 1.31 = 10.62672,若能将输出小数位数限制为5位,结果就是正确的。

以下是我调整后的代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdint.h>
#define maxn 110000
#define int int32_t
#define uint uint32_t
#define ull uint64_t
typedef struct {
    int intgr;
    uint frac;
}PointFixedNum;
PointFixedNum a,b,ans;
const ull scale=(1ULL<<32);
char s1[maxn],s2[maxn],op;
double num1=0.0,num2=0.0;
void init(PointFixedNum *a,double num)
{
    a->intgr=(int)num;
    a->frac=(uint)((num-a->intgr)*scale);
}
/*void init(PointFixedNum *a, double num) {
  static const long long scale = 1LL << 32;

  // Round to get y
  long long y = llround(num*scale);

  // Now break y into 2 parts:
  a->intgr = y/scale;
  int32_t frac = y%scale;
  if (frac >= 0) {
    a->frac = frac;
  } else {
    a->frac = scale + frac;
    a->intgr--;
  }
}*/
// I check this version and the result is the same.
void clear()
{
    a.frac=b.frac=ans.frac=0;
    a.frac=b.frac=ans.frac=0;
    num1=0.0;
    num2=0.0;
}
void read()
{
    scanf(" %1100[^ ]",s1);
    scanf(" %c",&op);
    scanf("%1100s",s2);
    sscanf(s1,"%lf",&num1);
    sscanf(s2,"%lf",&num2);
}
PointFixedNum add(PointFixedNum a,PointFixedNum b)
{
    PointFixedNum c;
    ull sum=(ull)a.frac+b.frac;
    c.frac=(uint)(sum%scale);
    c.intgr=a.intgr+b.intgr+(int)(sum/scale);
    return c;
}
PointFixedNum sub(PointFixedNum a,PointFixedNum b)
{
    PointFixedNum c;
    ull diff=(ull)a.frac-b.frac;
    c.frac=(uint)(diff%scale);
    c.intgr=a.intgr-b.intgr-(int)(diff/scale);
    return c;
}
PointFixedNum mul(PointFixedNum a,PointFixedNum b)
{
    PointFixedNum c={0,0};
    //ull scale=1ULL<<32;
    ull pro1=(ull)a.intgr*b.intgr;
    ull pro2=(ull)a.intgr*b.frac;
    ull pro3=(ull)a.frac*b.intgr;
    ull pro4=(ull)a.frac*b.frac;

    ull carry=pro4%scale>=scale/2;

    ull sum=pro4/scale+pro3%scale+pro2%scale+carry;
    c.frac=sum%scale;
    carry=sum/scale;

    sum=pro1%scale+pro2/scale+pro3/scale+carry;
    c.intgr=sum%scale;

    carry=sum/scale;
    sum=pro1/scale+carry;

    return c;
}
void print(PointFixedNum a)
{
    double fraction=(double)a.frac/scale;
    double fin=(double)a.intgr+fraction;
    printf("%.11lf",fin);
}
int main()
{
    read();
    init(&a,num1);
    init(&b,num2);
    if(op=='+')
    {
        ans=add(a,b);
    }
    else if(op=='-')
    {
        ans=sub(a,b);
    }
    else if(op=='*')
    {
        ans=mul(a,b);
    }
    print(ans);
    return 0;
}

内容的提问来源于stack exchange,提问作者FriedrichC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 19:27:03