gpt4 book ai didi

c - c 中浮点的这种定点转换有什么问题?

转载 作者:行者123 更新时间:2023-12-04 07:57:04 25 4
gpt4 key购买 nike

我正在尝试将浮点转换为定点,因为硬件没有浮点加速。我似乎找不到变量 screen_X 的错误该值始终为 320.0。精度为 Q38,26(编辑有用位为 Q6.26,64 位变量用于 mul 和 div 兼容性)。

#define fixed_precision 26
#define CONV_F(A) (A*conv_fixed_precision)
#define CONV_DF(A) (A/(1<<fixed_precision))
#define MUL38_26(A, B)((long long)(A*B)>>fixed_precision)
#define DIV38_26(A, B)((long long)(A<<fixed_precision)/B)

// global variable
double conv_fixed_precision = (1 << fixed_precision);
浮点代码如下:
void draw_balls(VGA& vga) {
int i;
for (i = 0; i < NB_BALL; i++) {
if (R_Ball[i] == 0) continue; // the pearl has already been found
double screen_X = X_Ball[i];
double screen_Y = Y_Ball[i];

screen_X -= X_position;
screen_Y -= Y_position;
screen_X *= Scale;
screen_Y *= Scale;

double screen_Radius = R_Ball[i] * Scale;
if ((screen_X * screen_X + screen_Y * screen_Y <= screen_Radius * screen_Radius)) {
//La perle est trouvee
R_Ball[i] = 0;
int time = get_time();
printf("Found %i pearl(s) at time %i\n", ++found_pearl, time);
}

double tmp_X = screen_X;
double tmp_Y = screen_Y;
screen_X = (tmp_X * cosAngle - tmp_Y * sinAngle) * 240 + 320;
screen_Y = (tmp_X * sinAngle + tmp_Y * cosAngle) * 240 + 240;
screen_Radius *= 240;

if (screen_X + screen_Radius < 0) break;
if (screen_X - screen_Radius >= 640) break;
if (screen_Y + screen_Radius < 0) break;
if (screen_Y - screen_Radius >= 480) break;

drawBall3D(vga, screen_X, screen_Y, screen_Radius, i % 7);
}
#ifdef USE_OPEN_GL
glFlush();
#endif
和定点代码如下:
void draw_balls(VGA & vga) {
int i;

long long cosAngF = CONV_F(cosAngle);
long long sinAngF = CONV_F(sinAngle);
long long scaleF = CONV_F(Scale);
long long xPosF = CONV_F(X_position);
long long yPosF = CONV_F(Y_position);

for (i = 0; i < NB_BALL; i++) {
if (R_Ball[i] == 0) continue; // the pearl has already been found
long long screen_X = CONV_F(X_Ball[i]);
long long screen_Y = CONV_F(Y_Ball[i]);

screen_X -= xPosF;
screen_Y -= yPosF;
screen_X = MUL38_26(screen_X, scaleF);
screen_Y = MUL38_26(screen_Y, scaleF);

long long screen_Radius = CONV_F(R_Ball[i] * Scale);
if ((MUL38_26(screen_X, screen_X) + MUL38_26(screen_Y, screen_Y)) <= MUL38_26(screen_Radius, screen_Radius)) {
//La perle est trouvee
R_Ball[i] = 0;
int time = get_time();
printf("Found %i pearl(s) at time %i\n", ++found_pearl, time);
}

long long tmp_X = screen_X;
long long tmp_Y = screen_Y;
long long F240 = ((long long)240)<<fixed_precision;
long long F320 = ((long long)320) << fixed_precision;

screen_X = MUL38_26(MUL38_26(tmp_X, cosAngF) - MUL38_26(tmp_Y, sinAngF), F240) + F320;
screen_Y = MUL38_26(MUL38_26(tmp_X, sinAngF) + MUL38_26(tmp_Y, cosAngF), F240) + F240;
screen_Radius = MUL38_26(screen_Radius, F240);

long long F640 = ((long long)640) << fixed_precision;
long long F480 = ((long long)480) << fixed_precision;
if (screen_X + screen_Radius < 0) break;
if (screen_X - screen_Radius >= F640) break;
if (screen_Y + screen_Radius < 0) break;
if (screen_Y - screen_Radius >= F480) break;

drawBall3D(vga, screen_X>>fixed_precision, screen_Y >> fixed_precision, screen_Radius >> fixed_precision, i % 7);
}
#ifdef USE_OPEN_GL
glFlush();
#endif
#endif

}

最佳答案

  • \在您的 #defines错了\告诉你的编译器定义在下一行继续,但你的定义是单行,所以你的代码错误甚至无法编译。我敢打赌,您是在基于 GCC 的编译器上的某些 MCU 或 DSP 上执行此操作,这些编译器通常在出错时不会生成新的二进制文件,因此您很可能使用过去最后一次编译的旧版本进行编程(有时很难将其视为消息 build has stop 与编译控制台中的成功操作没有太大区别)。
  • 你有 38.26添加到 64 位并使用 long long
    问题是 long long 可以是任何东西,那么它在您的环境中有多少位?如果只是 64 位,那么你会遇到问题,因为:
    A<<fixed_precision
    需要 64+fixed_precision位来存储结果,所以如果你得到的更少,那么你扔掉 A 的 MSB 位会使你的结果无效(除法)
    这可以在 64 位上完成而不会降低精度。这里是我通常实现的定点数学:
    m = 1<<n
    Integer(a) = Real(x*m)
    Real(x) = Integer(a)/m
    x*m + y*m = (x+y)*m -> (a+b)
    x*m - y*m = (x-y)*m -> (a-b)
    x*m * y*m = (x*y)*m*m -> (a*b)>>n
    x*m / y*m = (x/y) + (x%y)/y -> (a/b)<<n + ((a%b)<<n)/b
    但是要注意乘法a*b仍然需要 128 位,所以使用 naive O(n^2)或 Karatsuba 乘法,如果您没有像乘法或 port this to 64bit 这样的 ALU 访问权限.另一种选择是剖析 a*b>>n分为除法( >>n )和模( &(n-1) )部分,就像我对除法所做的一样。但是我懒得把它等同起来,因为我可以访问 64b*64b=(64+64)b在我编码的所有平台上的操作。
  • 2'os 补码上的有符号算术右移需要 SAR
    如果您的号码已签名,则天真地使用 a>>n不可能,因为它很可能会破坏您的数字符号。要在 2'os 补码上除以 2 的幂,您需要 SAR(算术右移),因此您需要复制 MSB 位,以便进行 1 位移位,请执行以下操作:
    (a>>1)|(a&0x8000000000000000);
    要进行更多位移,您需要添加分支……例如 4,8,16 位:
    (a>> 4)|((a&0x8000000000000000)?0xF000000000000000:0);
    (a>> 8)|((a&0x8000000000000000)?0xFF00000000000000:0);
    (a>>16)|((a&0x8000000000000000)?0xFFF0000000000000:0);
    掩码可以存储在 LUT 中,或者您可以在循环中使用 1 位移位,但这会更慢。
  • 关于c - c 中浮点的这种定点转换有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66649479/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com