使用 ref 和 out 传递数组

使用 ref 和 out 传递数组

在项目中利用到了自己封装的一个FFT算法,这个算法需要返回两个数组值,因此考虑到了使用ref和out来传递数组。

1.ref和out的区别

  1. 数组类型的 ref 参数必须由调用方明确赋值(传入的参数必须先被初始化)。 因此,不需要由被调用方明确赋值。 可以将数组类型的 ref 参数更改为调用的结果。 例如,可以为数组赋以 null 值,或将其初始化为另一个数组。在使用数组类型的 out 参数前必须先为其赋值;即必须由被调用方(必须在方法中对其完成初始化)为其赋值。
  2. out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。

2.实例

傅里叶变换的方法,返回两个数组,幅值和频率
//1.使用out参数

   public void TTFTrans(out double[] range_data, out double[] frequency_data)
        {
        //**必须在方法中对其完成初始化**
            range_data = new double[512];
            frequency_data = new double[512];
            double fs = 50;
            Complex[] real_data = new Complex[1024];
            Random r = new Random();
            //采样1024个数据
            for (int i = 0; i < 1024; i++)
            {
                real_data[i] = 15 * Math.Sin(Math.PI * 2 * 1 * (i / fs)) + 10 * Math.Sin(Math.PI * 2 * 5 * (i / fs)) + 5 * Math.Sin(Math.PI * 2 * 10 * (i / fs)) + r.Next(0, 20) * Math.Sin(Math.PI * 2 * r.Next(0, 10) * 20 * ((i) / fs));

            }
            Complex[] com = FFTT.fft_frequency(real_data);
            //计算所得到幅度值
            //对采样数组进行傅里叶变换
            double N = com.Length;

            for (int i = 0; i < com.Length / 2; i++)
            {
                double rr = (com[i].Real);
                double ri = (com[i].Imaginary);
                frequency_data[i] = i * (fs / N);
                range_data[i] = (Math.Sqrt((rr * rr) + (ri * ri))) / (N / 2);
            }


        }

FFTT.cs:

public static class FFTT
    {
        public static Complex[] fft_frequency(Complex[] sourceData)
        {
            int countN = sourceData.Length;
            //2的r次幂为N,求出r.r能代表fft算法的迭代次数  
            int r = Convert.ToInt32(Math.Log(countN, 2));


            //分别存储蝶形运算过程中左右两列的结果  
            Complex[] interVar1 = new Complex[countN];
            Complex[] interVar2 = new Complex[countN];
            interVar1 = (Complex[])sourceData.Clone();

            //w代表旋转因子  
            Complex[] w = new Complex[countN / 2];
            //为旋转因子赋值。(在蝶形运算中使用的旋转因子是已经确定的,提前求出以便调用)  
            //旋转因子公式 \  /\  /k __  
            //              \/  \/N  --  exp(-j*2πk/N)  
            //这里还用到了欧拉公式  
            for (int i = 0; i < countN / 2; i++)
            {
                double angle = -i * Math.PI * 2 / countN;
                w[i] = new Complex(Math.Cos(angle), Math.Sin(angle));
            }

            //蝶形运算  
            for (int i = 0; i < r; i++)
            {
                //i代表当前的迭代次数,r代表总共的迭代次数.  
                //i记录着迭代的重要信息.通过i可以算出当前迭代共有几个分组,每个分组的长度  

                //interval记录当前有几个组  
                // <<是左移操作符,左移一位相当于*2  
                //多使用位运算符可以人为提高算法速率^_^  
                int interval = 1 << i;

                //halfN记录当前循环每个组的长度N  
                int halfN = 1 << (r - i);

                //循环,依次对每个组进行蝶形运算  
                for (int j = 0; j < interval; j++)
                {
                    //j代表第j个组  

                    //gap=j*每组长度,代表着当前第j组的首元素的下标索引  
                    int gap = j * halfN;

                    //进行蝶形运算  
                    for (int k = 0; k < halfN / 2; k++)
                    {
                        interVar2[k + gap] = interVar1[k + gap] + interVar1[k + gap + halfN / 2];
                        interVar2[k + halfN / 2 + gap] = (interVar1[k + gap] - interVar1[k + gap + halfN / 2]) * w[k * interval];
                    }
                }

                //将结果拷贝到输入端,为下次迭代做好准备  
                interVar1 = (Complex[])interVar2.Clone();
            }

            //将输出码位倒置  
            for (uint j = 0; j < countN; j++)
            {
                //j代表自然顺序的数组元素的下标索引  

                //用rev记录j码位倒置后的结果  
                uint rev = 0;
                //num作为中间变量  
                uint num = j;

                //码位倒置(通过将j的最右端一位最先放入rev右端,然后左移,然后将j的次右端一位放入rev右端,然后左移...)  
                //由于2的r次幂=N,所以任何j可由r位二进制数组表示,循环r次即可  
                for (int i = 0; i < r; i++)
                {
                    rev <<= 1;
                    rev |= num & 1;
                    num >>= 1;
                }
                interVar2[rev] = interVar1[j];
            }
            return interVar2;

        }
    }

客户端调用:

  public MainWindow()
        {
            InitializeComponent();          
            ////声明double类型数组,用来接收傅里叶变换返回的幅值
            double[] range_data = null;//幅值
            //声明double类型数组,用来接收傅里叶变换返回的频率
            double[] frequency_data = null;//频率  
            //**传入参数不需要初始化**
            TTFTrans(out range_data, out frequency_data);
            for (int i = 0; i < range_data.Length; i++)
            {
                Console.WriteLine(range_data[i].ToString());
            }
        }

//2.使用ref参数

 public void TTFTrans(ref double[] range_data,ref double[] frequency_data)
        {
            double fs = 50;
            Complex[] real_data = new Complex[1024];
            Random r = new Random();
            //采样1024个点
            for (int i = 0; i < 1024; i++)
            {
                real_data[i] = 15 * Math.Sin(Math.PI * 2 * 1 * (i / fs)) + 10 * Math.Sin(Math.PI * 2 * 5 * (i / fs)) + 5 * Math.Sin(Math.PI * 2 * 10 * (i / fs)) + r.Next(0, 20) * Math.Sin(Math.PI * 2 * r.Next(0, 10) * 20 * ((i) / fs));

            }
            Complex[] com = FFTT.fft_frequency(real_data);
            //计算所得到幅度值
            //对采样数组进行傅里叶变换
            double N = com.Length;               
            for (int i = 0; i < com.Length / 2; i++)
            {
                double rr = (com[i].Real);
                double ri = (com[i].Imaginary);
                frequency_data[i] = i * (fs / N);
                range_data[i] = (Math.Sqrt((rr * rr) + (ri * ri))) / (N / 2);              
            }    
        }

客户端:

 public MainWindow()
        {
            InitializeComponent();
            //**使用ref传入的参数必须初始化**
            double[] range_data = new double[1024 / 2];//幅值
            double[] frequency_data = new double[1024/2];//频率  
            TTFTrans( ref range_data,ref  frequency_data);
            for (int i = 0; i < range_data.Length; i++)
            {
            Console.WriteLine(range_data[i].ToString());
            } 
        }

ref是有进有出,而out是只出不进

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值