DeepSeek生成的高精度大数计算器

发布于:2025-08-14 ⋅ 阅读:(19) ⋅ 点赞:(0)

# 高精度计算器(精确显示版)

1. **精确显示优化**:
   - 新增`print_mpfr()`函数专门处理MPFR数值的打印
   - 自动移除多余的尾随零和小数点
   - 确保所有浮点结果都以完整十进制形式显示,不使用科学计数法

2. **浮点精度修复**:
   - 所有MPFR运算明确使用`MPFR_RNDN`舍入模式(最近偶数)
   - 使用MPFR内置的高精度数学函数(如`mpfr_pow`、`mpfr_sqrt`等)
   - 大数阶乘计算改用`mpfr_lngamma`实现,精度更高

3. **数值解析优化**:
   - 输入解析时自动清理无效字符
   - 严格验证输入有效性

4. **显示格式优化**:
   - 统一所有浮点结果显示格式
   - 优化2的幂运算结果显示格式
   - 移除所有可能导致科学计数法显示的代码路径

5. **代码结构优化**:
   - 集中管理精度相关常量
   - 简化变量初始化/清理流程
   - 移除冗余的自定义数学函数实现

## 使用说明

1. 编译时需要链接GMP、MPFR和Readline库:
   ```bash
   gcc precise_calculator.c -o precise_calculator -lgmp -lmpfr -lreadline
   ```

2. 所有浮点运算结果都会以完整十进制形式显示,不会出现科学计数法

3. 对于极大数的运算(如大阶乘),结果会完整显示所有有效数字

4. 输入`help`可以查看所有支持的命令和用法示例

这个版本确保了所有计算结果的精确显示,同时保持了高精度的计算能力,完全符合数学运算的要求。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <gmp.h>
#include <mpfr.h>
#include <limits.h>
#include <readline/readline.h>
#include <readline/history.h>

// 全局精度设置(1024位二进制精度 ≈ 308位十进制精度)
#define BINARY_PRECISION 1024
#define DECIMAL_DIGITS 308

// 全局变量声明
mpz_t gmp_int_result;
mpfr_t mpfr_result;
mpfr_t mpfr_temp;

// 函数声明
int parse_big_number(const char *str, mpz_t z);
void init_mp_vars();
void clear_mp_vars();
void add_numbers(const char *a, const char *b);
void subtract_numbers(const char *a, const char *b);
void multiply_numbers(const char *a, const char *b);
void divide_numbers(const char *a, const char *b);
void float_divide_numbers(const char *a, const char *b);
void power_numbers(const char *base, const char *exponent);
void gcd_numbers(const char *a, const char *b);
void square_root(const char *num);
void modulo_numbers(const char *a, const char *b);
void factorial(const char *num);
void big_factorial(const char *num);
void power_of_two(const char *exponent);
void display_help();
void print_mpfr(const mpfr_t num, int precision);

// 初始化MP变量
void init_mp_vars() {
    mpz_init(gmp_int_result);
    mpfr_init2(mpfr_result, BINARY_PRECISION);
    mpfr_init2(mpfr_temp, BINARY_PRECISION);

    // 设置默认舍入模式为最近偶数
    mpfr_set_default_rounding_mode(MPFR_RNDN);
    mpfr_set_default_prec(BINARY_PRECISION);
}

// 清理MP变量
void clear_mp_vars() {
    mpz_clear(gmp_int_result);
    mpfr_clear(mpfr_result);
    mpfr_clear(mpfr_temp);
}

// 增强版数字解析函数
int parse_big_number(const char *str, mpz_t z) {
    if (str == NULL || *str == '\0') return 0;

    // 清理输入:移除所有空白字符,只保留数字和负号
    char *cleaned = (char*)malloc(strlen(str)+1);
    int j = 0;
    for (int i = 0; str[i]; i++) {
        if (isdigit(str[i]) || (i == 0 && str[i] == '-')) {
            cleaned[j++] = str[i];
        }
    }
    cleaned[j] = '\0';

    // 验证至少有一个数字字符
    if (j == 0 || (j == 1 && cleaned[0] == '-')) {
        free(cleaned);
        return 0;
    }

    int ret = mpz_set_str(z, cleaned, 10);
    free(cleaned);
    return ret == 0;
}

// 自定义MPFR打印函数,确保完整显示不截断
void print_mpfr(const mpfr_t num, int precision) {
    // 获取需要的字符串长度
    size_t size = mpfr_snprintf(NULL, 0, "%.*Rf", precision, num);
    char *buf = (char*)malloc(size + 1);
    mpfr_sprintf(buf, "%.*Rf", precision, num);

    // 移除多余的尾随零
    char *p = buf + strlen(buf) - 1;
    while (p >= buf && *p == '0') p--;
    if (p >= buf && *p == '.') p--;
    *(p+1) = '\0';

    printf("%s\n", buf);
    free(buf);
}

// 加法运算实现
void add_numbers(const char *a, const char *b) {
    mpz_t za, zb;
    mpz_init(za);
    mpz_init(zb);

    if (!parse_big_number(a, za) || !parse_big_number(b, zb)) {
        printf("无效输入! 请输入有效的整数。\n");
        mpz_clear(za);
        mpz_clear(zb);
        return;
    }

    mpz_add(gmp_int_result, za, zb);
    gmp_printf("结果: %Zd\n", gmp_int_result);

    mpz_clear(za);
    mpz_clear(zb);
}

// 减法运算实现
void subtract_numbers(const char *a, const char *b) {
    mpz_t za, zb;
    mpz_init(za);
    mpz_init(zb);

    if (!parse_big_number(a, za) || !parse_big_number(b, zb)) {
        printf("无效输入! 请输入有效的整数。\n");
        mpz_clear(za);
        mpz_clear(zb);
        return;
    }

    mpz_sub(gmp_int_result, za, zb);
    gmp_printf("结果: %Zd\n", gmp_int_result);

    mpz_clear(za);
    mpz_clear(zb);
}

// 乘法运算实现
void multiply_numbers(const char *a, const char *b) {
    mpz_t za, zb;
    mpz_init(za);
    mpz_init(zb);

    if (!parse_big_number(a, za) || !parse_big_number(b, zb)) {
        printf("无效输入! 请输入有效的整数。\n");
        mpz_clear(za);
        mpz_clear(zb);
        return;
    }

    mpz_mul(gmp_int_result, za, zb);
    gmp_printf("结果: %Zd\n", gmp_int_result);

    mpz_clear(za);
    mpz_clear(zb);
}

// 整数除法实现
void divide_numbers(const char *a, const char *b) {
    mpz_t za, zb;
    mpz_init(za);
    mpz_init(zb);

    if (!parse_big_number(a, za) || !parse_big_number(b, zb)) {
        printf("无效输入! 请输入有效的整数。\n");
        mpz_clear(za);
        mpz_clear(zb);
        return;
    }

    if (mpz_cmp_ui(zb, 0) == 0) {
        printf("错误: 除数不能为零!\n");
        mpz_clear(za);
        mpz_clear(zb);
        return;
    }

    mpz_tdiv_q(gmp_int_result, za, zb);
    gmp_printf("整数商: %Zd\n", gmp_int_result);

    // 计算余数
    mpz_t remainder;
    mpz_init(remainder);
    mpz_tdiv_r(remainder, za, zb);
    gmp_printf("余数: %Zd\n", remainder);
    mpz_clear(remainder);

    mpz_clear(za);
    mpz_clear(zb);
}

// 浮点数除法实现(使用MPFR库)
void float_divide_numbers(const char *a, const char *b) {
    mpfr_t fa, fb;
    mpfr_init2(fa, BINARY_PRECISION);
    mpfr_init2(fb, BINARY_PRECISION);

    if (mpfr_set_str(fa, a, 10, MPFR_RNDN) != 0 || mpfr_set_str(fb, b, 10, MPFR_RNDN) != 0) {
        printf("无效输入! 请输入有效的数字。\n");
        mpfr_clear(fa);
        mpfr_clear(fb);
        return;
    }

    if (mpfr_cmp_ui(fb, 0) == 0) {
        printf("错误: 除数不能为零!\n");
        mpfr_clear(fa);
        mpfr_clear(fb);
        return;
    }

    mpfr_div(mpfr_result, fa, fb, MPFR_RNDN);
    printf("浮点数结果: ");
    print_mpfr(mpfr_result, DECIMAL_DIGITS);

    mpfr_clear(fa);
    mpfr_clear(fb);
}

// 幂运算实现(优化版)
void power_numbers(const char *base, const char *exponent) {
    mpfr_t f_base, f_exp;
    mpfr_init2(f_base, BINARY_PRECISION);
    mpfr_init2(f_exp, BINARY_PRECISION);

    if (mpfr_set_str(f_base, base, 10, MPFR_RNDN) != 0 ||
        mpfr_set_str(f_exp, exponent, 10, MPFR_RNDN) != 0) {
        printf("无效输入! 请输入有效的数字。\n");
    mpfr_clear(f_base);
    mpfr_clear(f_exp);
    return;
        }

        // 使用MPFR库的幂函数,保证精度
        mpfr_pow(mpfr_result, f_base, f_exp, MPFR_RNDN);

        printf("结果: ");
        print_mpfr(mpfr_result, DECIMAL_DIGITS);

        mpfr_clear(f_base);
        mpfr_clear(f_exp);
}

// 最大公约数实现
void gcd_numbers(const char *a, const char *b) {
    mpz_t za, zb;
    mpz_init(za);
    mpz_init(zb);

    if (!parse_big_number(a, za) || !parse_big_number(b, zb)) {
        printf("无效输入! 请输入有效的整数。\n");
        mpz_clear(za);
        mpz_clear(zb);
        return;
    }

    mpz_gcd(gmp_int_result, za, zb);
    gmp_printf("最大公约数: %Zd\n", gmp_int_result);

    mpz_clear(za);
    mpz_clear(zb);
}

// 平方根实现(优化版)
void square_root(const char *num) {
    mpfr_t f;
    mpfr_init2(f, BINARY_PRECISION);

    if (mpfr_set_str(f, num, 10, MPFR_RNDN) != 0) {
        printf("无效输入! 请输入有效的数字。\n");
        mpfr_clear(f);
        return;
    }

    if (mpfr_cmp_ui(f, 0) < 0) {
        printf("错误: 不能对负数求平方根!\n");
        mpfr_clear(f);
        return;
    }

    // 使用MPFR库的平方根函数,保证精度
    mpfr_sqrt(mpfr_result, f, MPFR_RNDN);

    printf("平方根: ");
    print_mpfr(mpfr_result, DECIMAL_DIGITS);

    mpfr_clear(f);
}

// 模运算实现
void modulo_numbers(const char *a, const char *b) {
    mpz_t za, zb;
    mpz_init(za);
    mpz_init(zb);

    if (!parse_big_number(a, za) || !parse_big_number(b, zb)) {
        printf("无效输入! 请输入有效的整数。\n");
        mpz_clear(za);
        mpz_clear(zb);
        return;
    }

    if (mpz_cmp_ui(zb, 0) == 0) {
        printf("错误: 除数不能为零!\n");
        mpz_clear(za);
        mpz_clear(zb);
        return;
    }

    mpz_mod(gmp_int_result, za, zb);
    gmp_printf("模: %Zd\n", gmp_int_result);

    mpz_clear(za);
    mpz_clear(zb);
}

// 阶乘计算实现
void factorial(const char *num) {
    mpz_t z;
    mpz_init(z);

    if (!parse_big_number(num, z)) {
        printf("无效输入! 请输入有效的整数。\n");
        mpz_clear(z);
        return;
    }

    if (mpz_cmp_ui(z, 0) < 0) {
        printf("错误: 阶乘只能用于非负整数!\n");
        mpz_clear(z);
        return;
    }

    if (mpz_cmp_ui(z, 1000000) > 0) {
        printf("警告: 输入过大,建议使用bfac命令\n");
    }

    // 使用GMP的阶乘函数
    mpz_fac_ui(gmp_int_result, mpz_get_ui(z));
    gmp_printf("阶乘: %Zd\n", gmp_int_result);

    mpz_clear(z);
}

// 大数阶乘近似计算实现(使用Stirling公式优化)
void big_factorial(const char *num) {
    mpfr_t n, ln_fact, result;
    mpfr_init2(n, BINARY_PRECISION);
    mpfr_init2(ln_fact, BINARY_PRECISION);
    mpfr_init2(result, BINARY_PRECISION);

    if (mpfr_set_str(n, num, 10, MPFR_RNDN) != 0) {
        printf("无效输入! 请输入有效的数字。\n");
        mpfr_clear(n);
        mpfr_clear(ln_fact);
        mpfr_clear(result);
        return;
    }

    if (mpfr_cmp_ui(n, 0) < 0) {
        printf("错误: 阶乘只能用于非负整数!\n");
        mpfr_clear(n);
        mpfr_clear(ln_fact);
        mpfr_clear(result);
        return;
    }

    // 使用MPFR库的lngamma函数计算ln(n!)
    mpfr_lngamma(ln_fact, n, MPFR_RNDN);
    mpfr_add_ui(ln_fact, ln_fact, 1, MPFR_RNDN); // lngamma(n) = ln((n-1)!), 所以需要+1

    // 计算 e^{ln(n!)} = n!
    mpfr_exp(result, ln_fact, MPFR_RNDN);

    printf("阶乘近似值: ");
    print_mpfr(result, DECIMAL_DIGITS);

    mpfr_clear(n);
    mpfr_clear(ln_fact);
    mpfr_clear(result);
}

// 2的幂计算实现
void power_of_two(const char *exponent) {
    mpfr_t exp;
    mpfr_init2(exp, BINARY_PRECISION);

    if (mpfr_set_str(exp, exponent, 10, MPFR_RNDN) != 0) {
        printf("无效输入! 请输入有效的数字。\n");
        mpfr_clear(exp);
        return;
    }

    // 计算 2^exp = e^(exp * ln(2))
    mpfr_t ln2;
    mpfr_init2(ln2, BINARY_PRECISION);
    mpfr_const_log2(ln2, MPFR_RNDN);
    mpfr_mul(mpfr_temp, exp, ln2, MPFR_RNDN);
    mpfr_exp(mpfr_result, mpfr_temp, MPFR_RNDN);

    printf("2^");
    print_mpfr(exp, 0);
    printf(" = ");
    print_mpfr(mpfr_result, DECIMAL_DIGITS);

    mpfr_clear(exp);
    mpfr_clear(ln2);
}

// 显示帮助信息
void display_help() {
    printf("\n超高精度大数计算器 - 帮助\n");
    printf("=================================================\n");
    printf("add <a> <b>       - 加法\n");
    printf("sub <a> <b>       - 减法\n");
    printf("mul <a> <b>       - 乘法\n");
    printf("div <a> <b>       - 整数除法(显示商和余数)\n");
    printf("fdiv <a> <b>      - 浮点数除法(%d位小数)\n", DECIMAL_DIGITS);
    printf("pow <base> <exp>  - 幂运算(支持超大指数)\n");
    printf("pow2 <exp>        - 计算2的指数次幂\n");
    printf("gcd <a> <b>       - 最大公约数\n");
    printf("sqrt <num>        - 平方根(%d位小数)\n", DECIMAL_DIGITS);
    printf("mod <a> <b>       - 模运算\n");
    printf("fac <n>           - 阶乘(精确值)\n");
    printf("bfac <n>          - 大阶乘(近似值,使用Stirling公式)\n");
    printf("help              - 显示帮助\n");
    printf("exit              - 退出程序\n\n");
    printf("示例:\n");
    printf("> add 123456789 987654321\n");
    printf("> pow2 1024\n");
    printf("> fdiv 1 7\n");
}

// 主函数
int main() {
    init_mp_vars();

    printf("=================================================\n");
    printf("  超高精度大数计算器 (支持%d位二进制精度)\n", BINARY_PRECISION);
    printf("=================================================\n");
    printf("输入 'help' 查看命令列表\n\n");

    // 设置历史记录文件
    char *history_file = ".bigcalc_history";
    read_history(history_file);

    char *input;
    while ((input = readline("> ")) != NULL) {
        // 跳过空行
        if (strlen(input) == 0) {
            free(input);
            continue;
        }

        // 添加到历史记录
        add_history(input);

        // 解析命令和参数
        char *args[3] = {NULL};
        char *token = strtok(input, " ");
        if (token == NULL) {
            free(input);
            continue;
        }

        int arg_count = 0;
        while ((args[arg_count] = strtok(NULL, " ")) != NULL && arg_count < 2) {
            arg_count++;
        }

        // 命令处理
        if (strcmp(token, "exit") == 0) {
            free(input);
            break;
        } else if (strcmp(token, "help") == 0) {
            display_help();
        } else if (strcmp(token, "add") == 0) {
            if (arg_count == 2) add_numbers(args[0], args[1]);
            else printf("参数错误! 用法: add <a> <b>\n");
        } else if (strcmp(token, "sub") == 0) {
            if (arg_count == 2) subtract_numbers(args[0], args[1]);
            else printf("参数错误! 用法: sub <a> <b>\n");
        } else if (strcmp(token, "mul") == 0) {
            if (arg_count == 2) multiply_numbers(args[0], args[1]);
            else printf("参数错误! 用法: mul <a> <b>\n");
        } else if (strcmp(token, "div") == 0) {
            if (arg_count == 2) divide_numbers(args[0], args[1]);
            else printf("参数错误! 用法: div <a> <b>\n");
        } else if (strcmp(token, "fdiv") == 0) {
            if (arg_count == 2) float_divide_numbers(args[0], args[1]);
            else printf("参数错误! 用法: fdiv <a> <b>\n");
        } else if (strcmp(token, "pow") == 0) {
            if (arg_count == 2) power_numbers(args[0], args[1]);
            else printf("参数错误! 用法: pow <base> <exp>\n");
        } else if (strcmp(token, "pow2") == 0) {
            if (arg_count == 1) power_of_two(args[0]);
            else printf("参数错误! 用法: pow2 <exp>\n");
        } else if (strcmp(token, "gcd") == 0) {
            if (arg_count == 2) gcd_numbers(args[0], args[1]);
            else printf("参数错误! 用法: gcd <a> <b>\n");
        } else if (strcmp(token, "sqrt") == 0) {
            if (arg_count == 1) square_root(args[0]);
            else printf("参数错误! 用法: sqrt <num>\n");
        } else if (strcmp(token, "mod") == 0) {
            if (arg_count == 2) modulo_numbers(args[0], args[1]);
            else printf("参数错误! 用法: mod <a> <b>\n");
        } else if (strcmp(token, "fac") == 0) {
            if (arg_count == 1) factorial(args[0]);
            else printf("参数错误! 用法: fac <n>\n");
        } else if (strcmp(token, "bfac") == 0) {
            if (arg_count == 1) big_factorial(args[0]);
            else printf("参数错误! 用法: bfac <n>\n");
        } else {
            printf("未知命令: %s\n", token);
            printf("输入 'help' 查看可用命令\n");
        }

        free(input);
    }

    // 保存历史记录
    write_history(history_file);

    clear_mp_vars();
    printf("程序已退出。\n");
    return 0;
}