在不使用modf()的情况下获取float的小数部分

kni*_*666 24 c c++ math bit-manipulation

我正在为没有数学库的平台开发,所以我需要构建自己的工具.我目前得到分数的方法是将浮点数转换为固定点(乘以(浮点)0xFFFF,转换为int),只得到下部(掩码为0xFFFF)并再次将其转换回浮点数.

然而,不精确是杀了我.我正在使用我的Frac()和InvFrac()函数来绘制抗锯齿线.使用modf我得到一个非常流畅的线条.使用我自己的方法,由于精度损失,像素开始跳跃.

这是我的代码:

const float fp_amount = (float)(0xFFFF);
const float fp_amount_inv = 1.f / fp_amount;

inline float Frac(float a_X)
{
    return ((int)(a_X * fp_amount) & 0xFFFF) * fp_amount_inv;
}

inline float Frac(float a_X)
{
    return (0xFFFF - (int)(a_X * fp_amount) & 0xFFFF) * fp_amount_inv;
}
Run Code Online (Sandbox Code Playgroud)

提前致谢!

Dan*_*ham 44

如果我正确理解你的问题,你只想要小数点后的部分吗?你实际上不需要它(整数分子和分母)?

所以我们有一些数字,比方说3.14159,我们希望最终得到0.14159.假设存储了我们的号码float f;,我们可以这样做:

f = f-(long)f;
Run Code Online (Sandbox Code Playgroud)

如果我们插入我们的号码,其工作方式如下:

0.14159 = 3.14159 - 3;
Run Code Online (Sandbox Code Playgroud)

这样做是删除浮点数的整数部分,只留下小数部分.将float转换为long时,会丢弃小数部分.然后当你从原始浮点数中减去它时,你只剩下小数部分.由于float类型的大小(大多数系统上为8个字节),我们需要在这里使用很长的时间.一个整数(在许多系统上只有4个字节)不一定足以覆盖与a相同的数字范围float,但long应该是.

  • 当`f`为负时,这是错误的.(你要添加两个负数.)你根本不需要`if`:`f = f - (int)f`.如果`f`是负数,它将减去一个舍入为零的负int. (9认同)
  • 此外,您假设float的整数部分适合int. (6认同)
  • if ... then ... else ...在数学函数中经常使用这个?我的缓存,它哭了! (5认同)

AVB*_*AVB 8

正如我怀疑,modf不使用任何算术本身 -这是所有班次和面具,看看这里.你不能在你的平台上使用相同的想法吗?


Bil*_*nch 5

我建议您看一下如何在今天使用的系统上实现modf。查看uClibc的版本。

http://git.uclibc.org/uClibc/tree/libm/s_modf.c

(出于法律原因,它似乎是BSD许可的,但是您显然要仔细检查)

这里定义一些宏。


Mar*_*som 5

你的常量有一个错误。您基本上是尝试将数字左移 16 位,屏蔽除低位之外的所有内容,然后再次右移 16 位。移位与乘以 2 的幂相同,但您没有使用 2 的幂 - 您使用的是 0xFFFF,它相差 1。用 0x10000 替换它将使公式按预期工作。