C语言 如何创建一个尾数后有值的浮点数?

zlhcx6iw  于 11个月前  发布在  其他
关注(0)|答案(4)|浏览(102)

使用C或C++从整数创建浮点数的最快方法是什么?
例如,我想从12345创建浮点数0.12345f。
对我来说,一个慢的方法是从整数创建一个字符串,然后传递给atof。但是,一定有更快的方法来解决它,通过移位?

8aqjt8rx

8aqjt8rx1#

你可以使用一个循环:

int ival = 12345;
float fval = ival;
while (fabs(fval) >= 1) fval /= 10;

字符串
一般来说,只有当你确定性能是一个真实的问题时,你才应该担心它,除非你需要每秒做数百万次,否则应该足够了。

ahy6op9u

ahy6op9u2#

实际上你要做的运算是x/10^d,其中x是你的数字,d是x中的位数。这使得它更容易一些。你所要做的就是数数。
数数的方法有很多种。最简单的方法是

double y = 1;
while (y <= x)
   y *= 10;

return (double)x / y;

字符串
但如果你想快点...
如果你的数字是32位整数,你可以使用这个技巧从位旋转黑客

unsigned int v; // non-zero 32-bit integer value to compute the log base 10 of 
int r;          // result goes here
int t;          // temporary

static unsigned int const PowersOf10[] = 
    {1, 10, 100, 1000, 10000, 100000,
     1000000, 10000000, 100000000, 1000000000};

t = (IntegerLogBase2(v) + 1) * 1233 >> 12; // (use a lg2 method from above)
r = t - (v < PowersOf10[t]);


当他们说“使用上面的lg 2方法”时,你可以使用他们在页面前面写的算法,比如

static const char LogTable256[256] = 
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
    -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
    LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
    LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};

unsigned int v; // 32-bit word to find the log of
unsigned r;     // r will be lg(v)
register unsigned int t, tt; // temporaries

if (tt = v >> 16)
{
  r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
}
else 
{
  r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
}


当然,这可能有些矫枉过正,但这恰恰说明了有多少种快速的方法可以做到这一点!

km0tfn4u

km0tfn4u3#

这将比“除以10直到数字缩放”的解决方案快一点,因为乘法比除法快。但我使用它的主要原因是因为它更准确:除以10会在每次除法时丢失精度,而乘以10则不会(直到你做23次,这比你需要处理一个长整数要多得多)。所以这里只有最后一个除法是不精确的:

double to_fraction(long mantissa) {
  double mag = fabs(mantissa), e = 10.;
  while (e < mag) e *= 10.;
  return mantissa / e;
}

字符串

zd287kbt

zd287kbt4#

最快的方法是使用math.h中的log10()pow()函数。

#include <math.h>

// An integer representation of a fractional value less than 1.
long integer_mantissa = 12345;

// Use `log10()` to count the decimal digits in the number, minus 1.
// Add back the 1 to get the total number of digits.
long decimal_places = ((long)log10(integer_mantissa) + 1);

// Get the scale factor used to shift the decimal point to the right
// by raising 10 to the negative `decimal_places` power.
double mantissa_scale = pow(10, -decimal_places);

// Multiply the integer by our scale factor to get the final value.
double fraction = integer_mantissa * mantissa_scale;

字符串
此方法不包含任何循环或分支指令,使其成为任何具有本机浮点操作的架构上最快的实现。无论底层浮点表示如何,这也都可以工作,使其完全可移植到任何编译器或平台。

相关问题