|
发表于 2020-12-17 07:57:07
|
显示全部楼层
再改一下,这个可以控制误差,有效位数轻松上到6~7位。每个数字的迭代次数不同,简单的也许一次就够了,复杂的二三次也很可能。- float myln(float f) {
- if(f < 0) // 没有意义的东西
- return -0.0 / 0.0;
- else if(f == 0) // 负无穷大
- return -1.0 / 0.0;
-
- // 分段计算:指数段(E)、尾数段(M)。符号位(S)已经排除掉了
- // float的内存排布:SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
- int pow = (*(int*)&f >> 23) - 127; // 指数段
- *(int*)&f = *(int*)&f & 0x7FFFFF | 0x3F800000; // 尾数段,就在半开半闭区间[1, 2)范围内
-
- // 麦克劳林级数,计算的是ln(1+x) = x - x^2/2 + x^3/3 - x^4/4 ... ,所以f先减去1
- int region = f >= 1.5 ? 1 : 0;
- if(region)
- f /= 2;
- f -= 1;
- int i = 1; // 级数计算次数
- float ff = f, y = 0;
- do {
- y += ff / i;
- ff *= -f;
- i ++;
- printf(" ... i=%d, ff=%f\n", i, ff); // PC机上调试看迭代的次数
- } while((ff > 1e-5) || (ff < -1e-5)); // 误差控制
-
- if(region)
- y += 0.6931471805599453;
-
- return pow * 0.6931471805599453 + y;
- }
复制代码 |
|