在开发嵌入式系统时,尤其是处理大数时,会遇到取值范围的问题。51单片机通常没有内建大整数支持,因此我们需要采用不同的方法来解决这一问题

00 两种可行方法分别是:

  1. 使用数组存储每一位数据并进行进位运算:通过将大数按位拆分成数组,然后实现逐位加法、进位等操作。
  2. 使用符号变量进行计算:将数值分成低位和高位,分别用符号变量进行计算。

01:使用数组存储数据大小并处理进位

在这种方法中,我们将数值拆分成若干个位数(数组中的元素),并通过数组存储每一位数字,手动处理进位。

假设我们要处理的数值是存款金额 principal 和最终计算的利息,数值可能非常大,需要使用一个数组来按位存储。每个数组元素存储一个数字(从0到9),并手动实现加法和进位。

代码实现:
cs 复制代码
#include <reg52.h>
#include <math.h>
#include <stdio.h>

#define MAX_DIGITS 20  // 数字的最大位数

// 复利计算函数,采用逐位运算
void multiply_by_factor(int* number, double factor) {
    double carry = 0;  // 用于存储进位
    for (int i = 0; i < MAX_DIGITS; i++) {
        double digit_value = number[i] * factor + carry;
        number[i] = (int)digit_value % 10;  // 当前位
        carry = digit_value / 10;  // 进位
    }
}

// 打印数组中的大数
void print_large_number(int* number) {
    int i = MAX_DIGITS - 1;
    while (i >= 0 && number[i] == 0) {
        i--;  // 去掉前导零
    }
    if (i == -1) {
        uart_send_char('0');  // 如果数组全是0,则显示0
    } else {
        while (i >= 0) {
            uart_send_char(number[i] + '0');
            i--;
        }
    }
}

// 使用字符数组存储和计算复利
void calculate_large_interest(double principal, double rate, int years) {
    int large_number[MAX_DIGITS] = {0};  // 数字存储数组
    int i;
    
    // 将存款金额(principal)转换为数组形式
    for (i = MAX_DIGITS - 1; i >= 0; i--) {
        large_number[i] = (int)principal % 10;  // 存储个位数
        principal /= 10;  // 除以10,获得下一个位
    }

    // 计算复利
    double factor = 1 + rate / 100;
    for (i = 0; i < years; i++) {
        multiply_by_factor(large_number, factor);
    }

    // 打印结果
    print_large_number(large_number);
}

void main() {
    double principal = 1000.00;  // 假设存款金额为1000元
    double rate = 3.5;           // 假设年利率为3.5%
    int years = 5;               // 假设存款年数为5年

    uart_init();  // 初始化串口

    // 计算并打印复利结果
    calculate_large_interest(principal, rate, years);
}
  • large_number[MAX_DIGITS] :用于存储存款金额的每一位数字,MAX_DIGITS 定义了存储的最大位数。
  • multiply_by_factor():该函数逐位计算大数与利率的乘积,并处理每一位的进位。通过逐位相乘并累加进位来实现复利计算。
  • print_large_number():将存储的大数数组打印到串口。
  • calculate_large_interest() :这是主计算函数,首先将本金 principal 转换为大数数组,然后逐年计算复利。

02:使用符号变量(高位和低位分别存储)

这种方法相对简单,通过将数值拆分为低位和高位两部分来计算。符号变量可以帮助处理较大范围的数值。虽然不如数组方法灵活,但可以应对一些场景。

代码实现:

cs 复制代码
#include <reg52.h>
#include <stdio.h>
#include <math.h>

#define MAX_INT 0xFFFF  // 假设使用16位符号变量

// 定义一个结构体用于存储大数
typedef struct {
    unsigned int low;   // 低位
    unsigned int high;  // 高位
} BigNumber;

// 将两个整数合并成一个大数
BigNumber multiply_big_number(BigNumber num, double factor) {
    double result_low = num.low * factor;
    double result_high = num.high * factor;

    // 处理低位进位
    unsigned int new_low = (unsigned int)result_low;
    unsigned int carry = (unsigned int)(result_low / MAX_INT);

    // 处理高位和进位
    unsigned int new_high = (unsigned int)(result_high + carry);
    
    BigNumber result = { new_low, new_high };
    return result;
}

// 打印大数
void print_big_number(BigNumber num) {
    uart_send_char((num.high >> 8) & 0xFF);  // 打印高位字节
    uart_send_char(num.high & 0xFF);
    uart_send_char((num.low >> 8) & 0xFF);   // 打印低位字节
    uart_send_char(num.low & 0xFF);
}

void calculate_large_interest(double principal, double rate, int years) {
    // 初始化大数
    BigNumber principal_big = { (unsigned int)(principal), 0 };
    
    // 计算复利
    BigNumber result = principal_big;
    double factor = 1 + rate / 100;
    for (int i = 0; i < years; i++) {
        result = multiply_big_number(result, factor);
    }

    // 打印结果
    print_big_number(result);
}

void main() {
    double principal = 1000.00;  // 假设存款金额为1000元
    double rate = 3.5;           // 假设年利率为3.5%
    int years = 5;               // 假设存款年数为5年

    uart_init();  // 初始化串口

    // 计算并打印复利结果
    calculate_large_interest(principal, rate, years);
}

解释:

  • BigNumber 结构体:用于存储一个大数的低位和高位。
  • multiply_big_number():将大数与利率相乘,并处理低位和高位的进位。
  • print_big_number():将大数通过串口输出,打印低位和高位。
  • calculate_large_interest():计算复利的主函数,初始化本金的高低位数据,逐年进行复利计算。

其他需要注意的问题:

2. 51内存大小限制

需减少数组大小和double的使用

同时注意char 类型数组需要以'\0'结尾

3.复利年数过多时,使用数组单个计算理论可行,但程序疑似跑飞

4.无法使用#include <math.h>

pow((1 + rate / 100), years)

总结:

  1. 方案1(数组存储和逐位计算):适用于处理更大范围的数值,灵活性更高,可以根据需要扩展位数。
  2. 方案2(符号变量存储):相对简单,通过高低位分离来处理较大的数值,但计算灵活性较差。

两种方法各有优劣,选择哪一种方法取决于系统资源和所需的计算精度。如果存储空间和计算能力有限,使用符号变量(方案2)可能更为高效。如果需要处理更大范围的数值或更高精度,使用数组存储和逐位计算(方案1)会更适合

相关推荐
小菜鸟学代码··5 小时前
STM32文件详解
stm32·单片机·嵌入式硬件
马浩同学6 小时前
【GD32】从零开始学GD32单片机 | DAC数模转换器 + 三角波输出例程
c语言·单片机·嵌入式硬件·mcu
最后一个bug9 小时前
STM32MP1linux根文件系统目录作用
linux·c语言·arm开发·单片机·嵌入式硬件
wenchm10 小时前
细说STM32F407单片机IIC总线基础知识
stm32·单片机·嵌入式硬件
嵌入式lover10 小时前
STM32项目之环境空气质量检测系统软件设计
stm32·单片机·嵌入式硬件
kenwblack11 小时前
STM32 SPI读取SD卡
stm32·单片机
兰_博11 小时前
51单片机驱动1602液晶显示
单片机·嵌入式硬件·51单片机
深圳市青牛科技实业有限公司 小芋圆12 小时前
开关电源特点、分类、工作方式
前端·科技·单片机·物联网·分类·数据挖掘·新能源
我qq不是4515165212 小时前
单片机优先级
单片机·嵌入式硬件