求解浮点数最大公约数和最小公倍数(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;
}

  • 24
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计的实现,以及它们在MATLAB环境的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

做完作业了

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

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

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

打赏作者

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

抵扣说明:

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

余额充值