求解浮点数最大公约数和最小公倍数(c语言)

       在推导GNSS组合模型过程中需要计算不同频点的最小公倍数或最大公约数,所以在此记录。同样也适用于其他浮点数的求解。最全GNSS 系统(GREJSCI)各个信号频率带宽一览表

设有两个浮点数x1,x2  且  z1 ∈ Z(整数),z2 ∈ Z(整数)

最大公因数y1:x1/y1 ∈Z(整数)    x2/y1  ∈Z(整数)

最小公倍数y2:x1 * z1 = y2,x2 * z2 = y2

          以GPS的第一频点L1(1575.42MHz)和第二频点L2(1227.60MHz),北斗的B2a频点(1176.450MHz)和B2b频点(1207.14MHz)为例,求取二者的最大公因数和最小公倍数,结果如下。

具体思路:

①先判断两个浮点数小数点后面位数的个数,取较大的为n,将两个浮点数扩大10^n,即将两个浮点数放大为整数。

②利用辗转相除法,计算两个整数的最大公因数,然后再根据最大公因数计算最小公倍数。

③将计算后的最大公因数计算最小公倍数再次除以10^n则得到最终结果。

出现问题及解决:

①直接定义double类型的变量来存储两个浮点数会有精度损失,导致后续求解结果不准确。比如输入GPS两个频点的值是1575.42和1227.60,但是存储在double类型的变量内为1575.420000000000001和1227.59999999999999,所以直接用数字去计算并不能得到我想要的结果,就决定将浮点数在字符数组内处理。


     首先将两个浮点数以字符串的形式赋值给定义好的字符数组,然后来到第一个函数judgements_num分别计算两个浮点数的小数个数。

        然后用if语句去判断哪个的个数大为n,将两个浮点数扩大相同的10^n倍,这一步在尝试多种方法后,还是需要在字符数据内进行操作。具体代码在最下面的main函数中,标注的很详细。

        这样就得到了无精度损失的扩大后的两个数字,但此时他们还存储在字符数组内,所以需要用到#include<stdlib>头文件下的atoi函数,将字符数组内的数字转为整形变量。这样就解决了浮点数化为整形的问题,只需要调用求最大公因数的函数common_divisor和求最小公倍数的函数multipile即可,这里参照了  求最大公约数的4种常用算法,这篇文章的博主介绍的非常详细。

 ② 此外还有一点需要注意,不同卫星系统的频点还会出现小数点后三位的情况,比如北斗的B1I信号频率为1561.098MHz,那么其与其他频点组合时两个浮点数就要扩大10^3,比如另一个频点为B1C(1575.42MHz),求二者的最小公倍数就要1561098*1575420=2459385011160,有13位数字,非常容易溢出。所以在求最小公倍数的时候全部以long long类型运算。两个整数相乘的结果一定正确吗?关于数据溢出问题。
 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<math.h>
#include <stdlib.h>
 
 
int judgements_num(char str[])     //求浮点数小数个数
{
    int i = 0;
    int count = 0;
    int len = 0;;
 
    // 去除末尾的 '0'
    len = strlen(str);
    while (str[len - 1] == '0')
    {
        str[--len] = '\0';
    }
 
    // 找到小数点并计算小数点后的位数
    for (i = 0; i < len; i++)
    {
        if (str[i] == '.')
        {
            count = len - i - 1;
            break;
        }
    }
 
    return count;
}
 
int common_divisor(int a, int b)           //求最大公约数
{
    int temp;                  
    if (a < b)                     //a<b 则交换 
    {
        temp = a; a = b; b = temp;
    }
    while (b != 0)
    {
        temp = a % b;              //a中大数除以b中小数循环取余,直到b及余数为0
        a = b;
        b = temp;
    }
    return a;                  //返回最大公约数到调用函数处
}
 
long long multipile(int a, int b,int max)         //求最小公倍数
{
 
    long long int num = 0;
    int temp;
    temp = max;          
    num = (long long)a * (long long)b;
    return(num/ temp);           //返回最小公倍数到主调函数处进行输出
}
 
 
int main()
{
    char str1[50];
    char str2[50];
    char str1_2[50];
    char str2_2[50];
    
    int num1 = 0;
    int num2 = 0;
 
   
    long max = 0;       
    long long min = 0;
    double new_max = 0;
    double new_min = 0;
    int a, b;
    int i, i1;
    int j, j1;
    int n1 = 0;
    int n2 = 0;
    int n = 0;
    int n0 = 0;
 
    printf("请输入第一个数字:");
    scanf("%s", str1);
    printf("请输入第二个数字:");
    scanf("%s", str2);
 
    n1 = judgements_num(str1);
    n2 = judgements_num(str2);
 
 
    if (n1 > n2)
        n = n1;
    else
        n = n2;
 
    if (strlen(str1) > strlen(str2))
        n0 = strlen(str1);
    else
        n0 = strlen(str2);
 
   //在字符数组扩大两个浮点数
    for (i = 0; i <n0;i++)
    {
        if (str1[i] == '.')
        {
            for (j = 0; j <n; j++)
            {
                if(/*str1[i+j+1]!='\0' &&*/ str1[i+j+1]<='9' && str1[i+j+1]>='0')
                    str1[i+j] = str1[i+j + 1];
                else
                {
                    str1[i+j] = '0';
                }
                str1[i + j + 1] = '\0';
            }
      
            break;
        }
    }
 
    for (i1 = 0; i1 < n0; i1++)
    {
        if (str2[i1] == '.')
        {
            for (j1 = 0; j1 <  n; j1++)
            {
                if(/*str2[i1+j1+1]!='\0' &&*/ str2[i1 + j1 + 1]<='9' && str2[i1 + j1 + 1]>='0')
                str2[j1+i1] = str2[j1+i1 + 1];
                else
                {
                    str2[j1+i1] = '0';
 
                }
                str2[j1 + i1 + 1] = '\0';                    
            }
            break;
        }
    }
    //printf("%d\n", strlen(str1));
    //printf("%d\n", strlen(str2));
 
 
    printf("两个浮点数分别放大10的%d次幂\n", n);
 
    //将字符数组内扩大后的浮点数转为整数变量
    num1= atoi(str1);
    num2= atoi(str2);
 
    printf("第一个数放大结果:%d\n", num1);
    printf("第二个数方法结果:%d\n", num2);
 
    max = common_divisor(num1,num2);
    min = multipile(num1, num2, max);
    printf("放大后的最大公因数:%ld\n", max);
    printf("放大后的最小公倍数:%lld\n", min);
 
 
 
    new_max = max /pow(10,n);
    new_min = min /pow(10,n);
 
    printf("两个浮点数的最大公因数为:%lf\n两个浮点数的最小公倍数为:%lf\n",new_max,new_min);
    printf("%lf * %ld = 最小公倍数\n", num1 / pow(10, n), min / num1);
    printf("%lf * %ld = 最小公倍数", num2 / pow(10, n), min / num2);
 
 
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

做完作业了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值