【第06天】给定一个两个坐标(x1,y1)和(x2,y2),求两点距离与斜率 | 浮点数精度问题

发布时间:2023-07-07 16:00

本文已收录于专栏
《Java入门一百例》

学习指引

  • 序、专栏前言
  • 一、什么是浮点数?
  • 二、float类型
  • 三、double类型
  • 四、浮点数的精度问题
  • 五、【例题1】
    • 2、解题思路
    • 3、模板代码
    • 4 、代码解析
  • 六、【例题2】
    • 2、解题思路
    • 3、模板代码
      • 1、方法1
      • 2、方法2
      • 3、方法3
    • 4 、代码解析
  • 六、推荐专栏
  • 七、课后习题

序、专栏前言

   本专栏开启,目的在于帮助大家更好的掌握学习Java,特别是一些Java学习者难以在网上找到系统地算法学习资料帮助自身入门算法,同时对于专栏内的内容有任何疑问都可在文章末尾添加我的微信给你进行一对一的讲解。
   但最最主要的还是需要独立思考,对于本专栏的所有内容,能够进行完全掌握,自己完完全全将代码写过一遍,对于算法入门肯定是没有问题的。
   算法的学习肯定不能缺少总结,这里我推荐大家可以到高校算法社区将学过的知识进行打卡,以此来进行巩固以及复习。
  学好算法的唯一途径那一定是题海战略,大量练习的堆积才能练就一身本领。专栏的任何题目我将会从【题目描述】【解题思路】【模板代码】【代码解析】等四板块进行讲解。

一、什么是浮点数?

  我们都知道,平时我们使用的数字不仅有整数还有小数。编程语言中肯定也有小数类型供我们使用,我们通常称之为——浮点数。八大数据类型中,有两种类似是属于浮点数类型,一个是float另一个是更加常用的double类型。

二、float类型

  float是单精度浮点数,内存占4个字节,有效的小数位是6~7位。它的使用一般比较少,在Java中默认的浮点数类型为double,就像整数类型默认为int一样,如果直接声明float a=1.0将会产生异常,产生了类型不匹配,这时我们要在浮点数后加一个F,显示地声明我们这是浮点数类型,类似float a=1.0F

三、double类型

  double是双精度浮点数,内存占8个字节,有效的小数位可以达到15位左右。double的精度更高,但内存消耗是float的两倍,且运算速度较慢。但浮点数我们更多考虑的是精度,所以我们更加需要使用一个高精度的数据类型,一般都使用double类型。

四、浮点数的精度问题

  说了这么多,那到底什么是浮点数的精度问题呢?其实,计算机的存储机制,是无法直接存储浮点数类型的。浮点数的麻烦就在于——你眼睛看到的不一定和计算机存储的是一样的。

double a=6.6/3;
System.out.println(a);//2.1999999999999997

  对上面的程序很多人就会觉得,a的值肯定是2.2啊。但当你打印出来时发现却是一个无限接近 2.2 2.2 2.2的小数2.1999999999999997。这说明什么?说明6.63肯定有一个有问题!!3是一个整数类型肯定是没问题的,那就说明6.6有问题。
  计算机存储的小数都是近似值的,比如我们看到的是6.6,但计算机在存储这个值的时候,要考虑精度,所以它底层可能存储的是6.60000002。这就导致得到的答案就是很接近与我们理想中的答案。
  所以浮点数的比较我们不能直接使用==。通常是选定一个误差区间,也可以叫做精度,当实际答案与理想答案的绝对值小于误差区间,我们就可以说明两数相等。类似下图,m就作为一个精度判断。

public class Main {
    static double m=0.0000001;
    public static void main(String[] args) {
        double a=6.6/3;
        System.out.println(a-2.2<=m);//true
    }
}

五、【例题1】

  给定两个坐标 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( x 2 , y 2 ) (x_2,y_2) x2,y2,请你求出两点的距离,答案保留 6 6 6 位小数。

2、解题思路

  首先要明确知道,坐标系中两点距离公式如何求——勾股定理
   在 一 个 直 角 三 角 形 中 , 两 条 直 角 边 的 平 方 之 和 等 于 斜 边 的 平 方 。 在一个直角三角形中,两条直角边的平方之和等于斜边的平方。
       \"【第06天】给定一个两个坐标(x1,y1)和(x2,y2),求两点距离与斜率
  如何可知,需要求的是斜边的距离,所以利用勾股定理可以得:
( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 = l 2 ( l 为 所 求 斜 边 ) (x_2-x_1)^2+(y_2-y_1)^2=l^2(l为所求斜边) x2x1)2+(y2y1)2=l2(l)
  化简可得:
l = ( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 l= \\sqrt{(x_2-x_1)^2+(y_2-y_1)^2} l=x2x1)2+(y2y1)2

3、模板代码

import java.util.*;
public class Main{
    static double m=0.0000001;
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int x1=sc.nextInt();
        int y1=sc.nextInt();
        int x2=sc.nextInt();
        int y2=sc.nextInt();
        int dx=x2-x1,dy=y2-y1;
        double ans=Math.sqrt(dx*dx+dy*dy);
        System.out.printf(\"%.6f\",ans);
    }
}

4 、代码解析

  • ( 1 ) (1) (1)为了简化式子,求出横坐标与纵坐标的差值dxdy。然后直接代入勾股定理内进行计算即可。
  • ( 2 ) (2) (2)Math.sqrtMath自带的开平方的函数,我们直接使用即可。
  • ( 3 ) (3) (3)Java中的System.out输出流,也有类似C语言的printf格式化输出函数,涉及浮点数类型的题目一般都出输出格式有要求,所以我们需要使用printf进行格式化输出。

六、【例题2】

  给定三个坐标 A ( x 1 , y 1 ) A(x_1,y_1) A(x1,y1) B ( x 2 , y 2 ) B(x_2,y_2) Bx2,y2以及 C ( x 3 , y 3 ) C(x_3,y_3) C(x3,y3),请你判断 A , B A,B A,B两点相连的直线与 B C BC BC两点相连的直线斜率是否相等,如果相等则输出YES,否则输出NO。(题目保证 x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3互不相等)

2、解题思路

  既然是判断斜率,那首先肯定要知道斜率公式:
k = ( y 2 − y 1 ) ( x 2 − x 1 ) k=\\frac{(y2-y1)}{(x2-x1)} k=(x2x1)(y2y1)
  如果是要满足两条直线斜率相等,那就要保证k相等,可知需要满足:
( y 3 − y 2 ) ( x 3 − x 2 ) = ( y 2 − y 1 ) ( x 2 − x 1 ) \\frac{(y3-y2)}{(x3-x2)}=\\frac{(y2-y1)}{(x2-x1)} (x3x2)(y3y2)=(x2x1)(y2y1)

3、模板代码

1、方法1

import java.util.*;
public class Main{
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int x1=sc.nextInt();
        int y1=sc.nextInt();
        int x2=sc.nextInt();
        int y2=sc.nextInt();
        int x3=sc.nextInt();
        int y3=sc.nextInt();
        double k1=(x2-x1)/(y2-y1);
        double k2=(x3-x2)/(y3-y2);
        System.out.println(k1==k2);
    }
}

2、方法2

import java.util.*;
public class Main{
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int x1=sc.nextInt();
        int y1=sc.nextInt();
        int x2=sc.nextInt();
        int y2=sc.nextInt();
        int x3=sc.nextInt();
        int y3=sc.nextInt();
        long a1=(y3-y2)*(x2-x1);
        long a2=(y2-y1)*(x3-x2);
        System.out.println(a1==a2);
    }
}

3、方法3

import java.util.*;
public class Main{
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int x1=sc.nextInt();
        int y1=sc.nextInt();
        int x2=sc.nextInt();
        int y2=sc.nextInt();
        int x3=sc.nextInt();
        int y3=sc.nextInt();
        String a=test(y2-y1,x2-x1);
        String b=test(y3-y2,x3-x2);
        System.out.println(a.equals(b));
    }
    static int gcd(int a,int b){
        return b==0?a:gcd(b,a%b);
    }
    static String test(int a,int b){
        int g=gcd(a,b);
        a/=g;
        b/=g;
        if (b<0){
            a=-a;
            b=-b;
        }
        return a+\"/\"+b;
    }
}

4 、代码解析

  • ( 1 ) (1) (1)方法1就是普通计算斜率的方法,但是要注意的是,求出来的值是一个浮点数,在坐标范围较大时候,就会产生误差。比如坐标范围达到1e9的程度,就很容易出错,且没有很好的解决办法。所以在斜率问题不太推荐大家这样写。

  • ( 2 ) (2) (2)两个整数相乘肯定是得到一个整数,而整数相除就可能得到浮点数。所以我们秉承着能乘绝不相除的原则,对原式进行化简得:
    ( y 3 − y 2 ) ( x 2 − x 1 ) = ( y 2 − y 1 ) ( x 3 − x 2 ) (y3-y2)(x2-x1)=(y2-y1)(x3-x2) (y3y2)(x2x1)=(y2y1)(x3x2)
    这样判断就不会产生浮点数的精度烦恼,但有可能爆int,所以大家看好数据范围,该开long一定要开。

  • ( 3 ) (3) (3)方法3是才用字符串的形式表达斜率,但首先需要将分子分母进行通分,然后如果分母是负数需要把负号移到分子上。这是我常用的一种方法,没有上述两种烦恼推荐大家在 2 , 3 2,3 2,3中选择一种使用。

六、推荐专栏

《零基础学算法100天》

七、课后习题

序号 题目链接 难度评级
1 表示一个折线图的最少线段数 3
学习有疑问?
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号