任务内容:
任务思路:
1.从键盘读入一个整数作为深度点的编号,同时作为我们索引二维数组的行数,不同参数同时也对应不同的列数,有行有列就能提取出要参与计算的参数,再代入写好的方法,就能获得我们想要得到的储层参数。
2.实现一个循环,从第一个深度点开始一直遍历到最后,将每一个深度点能算出的对应储层参数放到一个一维数组里,再写出对应的极值函数和平均值函数,求出这组储层参数当中的最大值、最小值和平均值。
任务执行:
1.单深度点处理成果条的查看
这一点内容在上次的任务中就已经顺带完成了,也是我们的最后一部分:
首先,通过简单的Scanner获得用户想要读取的行标,然后制作一个简单的菜单窗口进行交互:
System.out.println("请输入想要读取第几行数据:");
Scanner sc = new Scanner(System.in);
int row = sc.nextInt();
System.out.println("please choose ->>");
System.out.println("********0. 孔隙度 ********");
System.out.println("********1. 泥质含量 ********");
System.out.println("********2.含油饱和度********");
System.out.println("********3.all output*******");
Scanner num = new Scanner(System.in);
int n = num.nextInt();
然后通过switch语句对应我们菜单中的内容,跟任务思路中写到的一样,我们的row是从键盘读取的行标,而不同的列标对应不同的参数,我们输出的时候可以直接代入我们写好的“porosity,shale,oil”方法当中进行运算。
switch (n){
case 0:
System.out.println("孔隙度为:");
System.out.println(porosity(tm[row][2]));
break;
case 1:
System.out.println("泥质含量为:");
System.out.println(shale(tm[row][3]));
break;
case 2:
System.out.println("含油饱和度为:");
System.out.println(oil(tm[row][4], porosity(tm[row][2])));
break;
case 3:
System.out.println("孔隙度为:");
System.out.println(porosity(tm[row][2]));
System.out.println("泥质含量为:");
System.out.println(shale(tm[row][3]));
System.out.println("含油饱和度为:");
System.out.println(oil(tm[row][4], porosity(tm[row][2])));
break;
default:
System.out.println("输入有误");
break;
}
2.储层参数极值和平均值的统计
1.为孔隙度、泥质含量和含油饱和度三个计算出来的储层参数各创建一个空的一维数组便于我们存放数据:
//孔隙度全部计算结果
double []Porosity = new double[tm.length];
for (int i = 0; i < tm.length; i++) {
Porosity[i] = judge_por(porosity(tm[i][2]));
}
//泥质含量全部计算结果
double []Shale = new double[tm.length];
for (int i = 0; i < tm.length; i++) {
Shale[i] = judge_so(shale(tm[i][3]));
}
//含油饱和度全部计算结果
double []Oil = new double[tm.length];
for (int i = 0; i < tm.length; i++) {
Oil[i] = judge_so(oil(tm[i][4],porosity(tm[i][2])));
}
2.构建极值方法和平均值方法:
//求最大值
public static double data_max(double arr []) {
double data_max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (Double.isNaN(arr[i])) {
continue;
}else if(arr[i] > data_max) {
data_max = arr[i];
}
}
return data_max;
}
//求最小值
public static double data_min(double arr[]){
double data_min = arr[0];
for (int i = 0; i < arr.length; i++) {
if (Double.isNaN(arr[i])) {
continue;
}else if(arr[i] < data_min) {
data_min = arr[i];
}
}
return data_min;
}
//求平均值
public static double aver(double arr[]) {
double average;
double sum = 0;
for (int i = 0; i < arr.length; i++) {
sum +=arr[i];
}
average = sum/arr.length;
return average;
}
3.代入各项参数数据,输出:
System.out.println("孔隙度:");
System.out.println("最大值:" + data_max(Porosity));
System.out.println("最小值:" + data_min(Porosity));
System.out.println("平均值:" + aver(Porosity));
System.out.println("泥质含量:");
System.out.println("最大值:" + data_max(Shale));
System.out.println("最小值:" + data_min(Shale));
System.out.println("平均值:" + aver(Shale));
System.out.println("含油饱和度:");
System.out.println("最大值:" + data_max(Oil));
System.out.println("最小值:" + data_min(Oil));
System.out.println("平均值:" + aver(Oil));
欸?今天的任务好像很简单嗷,是不是到这里就结束了?——
**哦付阔而斯诺特!**其实今天遇到的问题是最多的,还牵连到很多前两次写好的程序,删删改改之后才有了现在这么清晰的思路,让我们一起来看看遇到的问题:
遇到的问题
- 计算出现空值
如果我们将没有计算极值和平均值的原始一维数组(也就是我们的Porosity,Oil,Shale)整个输出出来的话,我们会发现里面存在一些负数,其实稍微理解一下~孔隙度、含油饱和度、泥质含量这些参数,它的负值基本是没有意义的,而且我们在运算的时候会发现计算含油饱和度时,有一个开根号的过程,负数开平方根肯定是没有意义的啊!那么Java在遇到无意义计算的时候会怎样?——返回空值对不对?所以就导致含油饱和度的极值在一开始其实返回的是NAN值
- 负数的处理
其实在文件要求里也有明确的规定数据的范围,我们需要对此进行有效的处理~所以就有了接下来的操作:
解决问题
1.我们写一个judge判断方法,对我们得到的储层参数数据的一维数组进行处理:
//判断函数
public static double judge_por(double num) {
if(num < 0) {
num = 0.005;
}else if (num > 0.4) {
num = 0.4;
}else if(Double.isNaN(num)) {
num = 0.0;
}
else
num =num;
return num;
}
public static double judge_so(double num) {
if(num < 0 || Double.isNaN(num)) {
num = 0.0;
}else if (num > 1) {
num = 1;
}else
num =num;
return num;
}
这里有一个语句:Double.isNaN(num)
,拓展开了说一下Java中的NAN:
关于NAN
1.NaN表示非数值,例如:0.0/0结果为NAN,负数的平方根结果也为NAN。
2.所有非数值的值都认为是不相同的,所有我们在检测NAN时使用 "=="是检测不到的。
if(x == Double.Nan) //这样是检测不到的
所有的浮点数值计算都遵循IEEE754规范,下面是用于表示溢出和出错情况的三个特殊的浮点数值。
1.正无穷大,负无穷大;
2.NaN(不是一个数字) 例如:计算0/0或者负数的平方根为NaN
常量Double.POSITIVE_INFINITY , Double.NEGATIVE_INFINITY 和 Double.NaN(与相应的Float类型的常量一样)分别表示这三个特殊的值, 但在实际应用中很少使用。特别要说明的是,不能这样检测一个特定的值是否等于Double.NaN,例如:
if(x == Double.NaN) //is never true
而对于所有“非数值”的值都认为是不同的。但是我们依然可以使用Double.isNaN方法。
浮点数值不适用用于禁止出现舍入误差的金融计算中。例如:
System.out.println(2.0 - 1.2)
将打印出0.799999999999,而不是0.8。其主要原因是数值采用二进制系统表示,而在二进制系统中无法精确表示1/10.这就好像十进制无法精确低表示1/3.
进行完上述操作处理之后,就基本上可以完成储层参数极值和平均值的统计了!
小结
本次的任务虽然不难,但数组空值的问题困扰了我很久,我也是看了很多文章才稍微弄懂一点对于nan值的处理。大家其实不难发现,不同的编程语言对于 NAN的处理难度也不一样,比如说python在处理NAN值得时候,一句drop.na()就可以去掉所有空值所在的行。
所以,走一步学一步,还要回头看一步,知识才能积累的起来!一起加油吧。
今天的内容就到这里啦,希望对你有一丢丢的帮助就好~