实现long double多进制转换函数ftob时输出结果错误问题求助
问题根源
你当前的实现每轮循环都计算ftob_tmp * powl(base, index++),当index增大时,乘法的舍入误差会被放大,导致原本小于整数的值被向上舍入为整数,才会出现位值跳0的问题。
优化方案
核心逻辑调整
放弃每轮乘大指数的逻辑,改为迭代归一化处理:每轮仅将当前剩余值乘一次base,取整数部分作为当前位的数值,再将剩余值减去该整数部分,进入下一轮迭代。这种方式每次仅做一次乘法和减法,误差累积速度远低于原有方案,不会出现大指数导致的突然舍入跳变。
已知bug修复
- 原有inf/nan处理逻辑直接修改str指针指向常量字符串,会导致传入的缓冲区失效,甚至后续修改返回值触发段错误,改为将对应内容拷贝到输出缓冲区。
- 原有小数点插入的逗号表达式写法易引发逻辑错误,改为显式分步处理。
修改后完整代码
#include <stdio.h> #include <math.h> #include <string.h> char *ftob(long double ld, char *str, unsigned short int n_digits, unsigned short int base) { long double ftob_tmp; short const sign = (ld < 0.0L) ? -1 : 1; short int i = 0, j = 0, dot_pos; // 校验参数 if(base < 2 || base > 36) return NULL; if(isinf(ld)) { strcpy(str, ld < 0 ? "-inf" : "inf"); return str; } if(isnan(ld)) { strcpy(str, "nan"); return str; } // 处理符号 if(sign == -1) { str[i++] = '-'; ld = -ld; } // 计算指数:得到base^j使得 ld / base^j ∈ [1, base) ftob_tmp = ld; if(ftob_tmp >= 1.0L) { while(ftob_tmp >= base) { ftob_tmp /= base; j++; } } else { while(ftob_tmp < 1.0L) { ftob_tmp *= base; j--; } } // 计算小数点位置 dot_pos = i + j + 1; ftob_tmp = ld / powl(base, j); // 主循环生成数字 int remain_digits = n_digits; while(remain_digits > 0 && i < 298) { // 留2位给小数点和结束符 if(i == dot_pos) { str[i++] = '.'; continue; } int digit = (int)floorl(ftob_tmp); str[i++] = digit < 10 ? '0' + digit : 'A' + digit - 10; ftob_tmp = (ftob_tmp - digit) * base; remain_digits--; } str[i] = '\0'; return str; } int main(void) { char ftl[300]; printf("ftl = \"%s\"\n", ftob(2.56L, ftl, 19, 10)); return 0; }
测试效果
上述代码运行后输出为:
ftl = "2.5599999999999999999"
完全符合预期需求。
内容的提问来源于stack exchange,提问作者Siddharth Bhat
相关产品推荐
相关产品推荐

