项不会计算为接受 0 个参数的函数_.NET Core计算行星位置(2)——数据导入

先来随便找两个数据表头进行冷静分析,对于这种大型文本文件,推荐使用EmEditor打开,打开很大的文件也不会像记事本一样无响应很长时间。

fa50e8802086f9c4360b48874659e807.png

29ed7d4de37f38c6229392b5b5203d79.png

第一张是水星的表头,每个文件里大概有二三十个这样的表头,VSOP2013是每个表头的固定字符,后面的四个数字分别是

ip = 行星序号

iv= 变量序号

it=指数迭代序号

nt = 此表中的项数

后面的文字是注释

每一行的数据是22个参数,第一个参数是项(Term)的编号,随后17个大部分为0的数字是iphi的项数。最后四项是两个科学计数法表示的双精度浮点数。第一项是小数部分,第二项是指数部分。

再看看F程序里是怎么读取这些表单的,F程序的主函数是一个演示函数,迭代出几个时间片段,输入到主函数VSOP2013 (tdj,ibody,nfile,ifile,r,ierr)里,读取数据的相关代码在VSOP2013的函数内。

if 

这一段意义不大,大概意思就是在每一步出错了就返回一个错误值,21世纪20年代的先进语言用不着这样写调试。

         nn=0
         do iv=1,6
         do it=0,20
            limit(iv,it)=0
         enddo
         enddo

总共有6个变量,每个变量最多21个迭代,这个二维数组储存每个表的项数,但是我随手翻了翻数据只看到最多10个迭代。看到后面才明白这个东西是干什么用的

        do 
            read (ifile,1001,iostat=nerr) ip,iv,it,nt
            if (nerr.eq.-1) exit
            if (nerr.ne.0.or.ibody.ne.ip) return
            limit(iv,it)=nt
            do n=1,nt
               nn=nn+1
               read  (ifile,1002,iostat=nerr) (iphi(i,nn),i=1,17),sa,ca
               if (nerr.ne.0) return
               sa(21:21)='D'
               ca(21:21)='D'
               read (sa,'(d24.16)') ss(nn)
               read (ca,'(d24.16)') cc(nn)
               if (iv.eq.2.and.it.eq.1.and.n.eq.1) then
                  limit(iv,it)=nt-1
                  nn=nn-1
               endif
            enddo
         enddo

这一段代码综合来说,是用代号为1001的格式读取第一行,得到四个表单参数,然后把相应表单的项数放进limit[ , ],再迭代nt次,以1002格式读取每一项的内容,得到了这一项的iphi[],sa ca,sa和ca是字符串,要再转化成双精度数字,赋值给ss和nn。再通过不断重复增加nn的值,把整个文件的所有项数压进iphi[i,nn] ,ss[nn] ,cc[nn]三个数列中。在计算的过程中,通过提取limit[ , ]里每个表的项数,截取这个nn长度的数列中的一部分进行计算,我看完以后码畜流泪,这是什么窒息操作啊……这要是照抄进.NET我怕是要被围观群众一人一口吐沫淹死了。是对可读性的亵渎,也是对性能的浪费。所以得重头开始思考如何建立一个合理的数据结构,能够在读取数据的时候使用多线程同步写入,加快读取速度,而且要方便计算函数使用,尽可能减少使用的索引变量。

经过思考和实验,结合表头的四个表单变量,可以用struct构建起一个结构清晰的数据表,层层递进。struct的基本单元是一张表单中的所有项。Rank是项序号,iphi是17个int参数,ss和cc分别是浮点参数。每一个Planet包括了相应数据文件里的所有项目,在计算的时候可以分别提取出每一个Variable,发送给计算函数,在计算函数中再通过两层嵌套的for循环对每个次方中的每一项进行积分。

public 

数据表的格式让我不得不去模拟古代计算机的读取方式。本来我想用split()处理,但是发现了有一些特例的存在,让我只能回归淳朴。在iphi的序列中,每三位一个整形,也就会出现负的两位参数会和前一位的参数连在一起,无法用split()分开,为了保证对元数据无篡改,我开始研究Fortran的编码格式。

21b9fab9b27db432c9f058f63f0e56fb.png
1001  

1001是表头的格式,1002是项的格式。在查阅字典以后看明白了。9个空格,跟着3个3位长度的整形,加一个7位长度的整形。那么用一个扫描指针结合substring,截取出来相应的片段再转化成数字保存下来就可以了。于是我开始写读取表头的祖传代码。这里减掉两个1的原因是在Fortran程序里,行星和变量的索引都是从1开始的,但是在现代编程中,默认第一项的索引都是0,在这里减1就彻底统一了以后的使用规范。

private 

而对于1002格式的解析,可谓是真·祖传屎山代码,估计过一个星期我自己都不敢乱动了。在粪坑里艰苦奋战了一段时间,完成了private Term ReadTerm(string line)这个方法,具体代码就不放了,没人会想再看一遍的,每一次调用,输入一行数据,返回一个Term结构,里面包含了计算所需的整形和浮点数。再通过表头参数将项目赛进数据表的大树,最后返回一个Planet[] Solarsystem,里面包括了9颗行星所有所需的计算数据。最后进行性能优化采用了Parallel.For,在我五年前的小破本上完成数据初始化只要三四秒的样子。我一路艰苦奋战,不是为了别的,只是为了算出那火星在何方,那是我,遥远的家。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值