You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何精确输出与输入一致的浮点数?(C语言项目问题)

解决精确输出输入一致浮点数的方案

核心问题分析

直接用double存储浮点数后再反向解析输出会出现精度误差——因为二进制浮点数无法精确表示所有十进制小数(比如0.1),存储后的值是近似值,拆分输出时会多出尾数位。必须保留输入的原始字符串形式,同时将字符串手动转换为double用于计算,输出时直接打印原始字符串才能保证和输入完全一致。

实现步骤

1. 手动实现字符串转double函数(替代atof)

因为不能使用atof,我们自己解析字符串的整数和小数部分,转换为double类型:

double str_to_double(const char *str) {
    double result = 0.0;
    double decimal_part = 0.0;
    int sign = 1;
    int i = 0;
    double divisor = 10.0;

    // 处理正负号
    if (str[i] == '-') {
        sign = -1;
        i++;
    } else if (str[i] == '+') {
        i++;
    }

    // 处理整数部分
    while (str[i] != '\0' && str[i] != '.') {
        result = result * 10 + (str[i] - '0');
        i++;
    }

    // 处理小数部分
    if (str[i] == '.') {
        i++;
        while (str[i] != '\0') {
            decimal_part += (str[i] - '0') / divisor;
            divisor *= 10;
            i++;
        }
    }

    return sign * (result + decimal_part);
}

2. 读取输入:保存原始字符串+转换为double

针对你补充的lect_id+多分数的输入格式(比如A 1.11111 2.023 3.043),我们逐个字符读取,保存每个分数的原始字符串,同时转换为数值用于计算:

#include <stdio.h>
#include <string.h>

#define MAX_LECTURES 100   // 最大课程数
#define MAX_SCORES 50      // 每门课最大分数数量
#define MAX_STR_LEN 30     // 单个分数字符串最大长度

double str_to_double(const char *str) {
    // 上述函数实现
    double result = 0.0;
    double decimal_part = 0.0;
    int sign = 1;
    int i = 0;
    double divisor = 10.0;

    if (str[i] == '-') {
        sign = -1;
        i++;
    } else if (str[i] == '+') {
        i++;
    }

    while (str[i] != '\0' && str[i] != '.') {
        result = result * 10 + (str[i] - '0');
        i++;
    }

    if (str[i] == '.') {
        i++;
        while (str[i] != '\0') {
            decimal_part += (str[i] - '0') / divisor;
            divisor *= 10;
            i++;
        }
    }

    return sign * (result + decimal_part);
}

int main() {
    char lect_ids[MAX_LECTURES];
    char score_strings[MAX_LECTURES][MAX_SCORES][MAX_STR_LEN];
    double score_values[MAX_LECTURES][MAX_SCORES];
    int score_counts[MAX_LECTURES] = {0};
    int lecture_count = 0;
    char c;
    int str_idx = 0;
    int current_score_idx = 0;

    // 逐字符读取输入
    while ((c = getchar()) != EOF && lecture_count < MAX_LECTURES) {
        // 跳过前导空格/换行
        if ((c == ' ' || c == '\n') && str_idx == 0) {
            continue;
        }

        // 读取课程ID(每行第一个非空格字符)
        if (score_counts[lecture_count] == 0 && str_idx == 0) {
            lect_ids[lecture_count] = c;
            // 跳过ID后的空格
            while ((c = getchar()) != EOF && c == ' ');
            ungetc(c, stdin); // 把第一个分数的字符放回输入流
            str_idx = 0;
            continue;
        }

        // 遇到换行:结束当前课程的分数读取
        if (c == '\n') {
            if (str_idx > 0) {
                score_strings[lecture_count][current_score_idx][str_idx] = '\0';
                score_values[lecture_count][current_score_idx] = str_to_double(score_strings[lecture_count][current_score_idx]);
                score_counts[lecture_count]++;
            }
            lecture_count++;
            current_score_idx = 0;
            str_idx = 0;
            continue;
        }

        // 遇到空格:结束当前分数的读取
        if (c == ' ') {
            if (str_idx > 0) {
                score_strings[lecture_count][current_score_idx][str_idx] = '\0';
                score_values[lecture_count][current_score_idx] = str_to_double(score_strings[lecture_count][current_score_idx]);
                score_counts[lecture_count]++;
                current_score_idx++;
                str_idx = 0;
            }
            continue;
        }

        // 保存当前分数的字符
        if (str_idx < MAX_STR_LEN - 1) {
            score_strings[lecture_count][current_score_idx][str_idx] = c;
            str_idx++;
        }
    }

    // 处理最后一门课的最后一个分数
    if (str_idx > 0 && lecture_count < MAX_LECTURES) {
        score_strings[lecture_count][current_score_idx][str_idx] = '\0';
        score_values[lecture_count][current_score_idx] = str_to_double(score_strings[lecture_count][current_score_idx]);
        score_counts[lecture_count]++;
        lecture_count++;
    }

    // 输出原始格式的分数
    printf("输出结果:\n");
    for (int i = 0; i < lecture_count; i++) {
        printf("%c ", lect_ids[i]);
        for (int j = 0; j < score_counts[i]; j++) {
            if (j > 0) printf(" ");
            printf("%s", score_strings[i][j]);
        }
        printf("\n");
    }

    // 计算并输出平均分
    printf("\n平均分:\n");
    for (int i = 0; i < lecture_count; i++) {
        if (score_counts[i] == 0) {
            printf("%c: 无有效分数\n", lect_ids[i]);
            continue;
        }
        double sum = 0.0;
        for (int j = 0; j < score_counts[i]; j++) {
            sum += score_values[i][j];
        }
        printf("%c: %.6f\n", lect_ids[i], sum / score_counts[i]);
    }

    return 0;
}

为什么之前的方法失败

  1. 浮点数精度问题:直接用double存储后拆分输出,因为二进制浮点数的近似性,会导致小数部分出现多余尾数位。
  2. 输入读取逻辑混乱:嵌套的scanf会打乱输入流的读取指针,导致读取到错误的字符,引发段错误或读取结果异常。

内容的提问来源于stack exchange,提问作者acd123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:40:53