2020 trabajo suave de trabajo proyectos personales - la intersección de las estadísticas de la geometría plana

2020 trabajo suave de trabajo proyectos personales - la intersección de las estadísticas de la geometría plana

proyecto contenido
enlace de curso Primavera 2020 Computer Software Engineering Institute (Roger Ren Jian)
Los requisitos operativos proyecto de trabajo individual
Objetivos del curso La teoría del aprendizaje y el proceso de desarrollo de software del sistema, la experiencia de desarrollo de software acumulan a través de la práctica
Esta cosecha del blog Familiarizado con la sintaxis de C ++, herramientas conocidas VS, el proceso es simple práctica de proyectos de desarrollo de libros
clases de enseñanza 005
dirección del proyecto https://github.com/eitbar/IntersectProject.git

En primer lugar, el costo estimado de cada módulo en el tiempo de desarrollo del programa

PSP2.1 Etapas del Proceso de Software Personal Estimado de consumo de tiempo (minutos) Los que consumen mucho tiempo reales (minutos)
Planificación plan
· Estimación • Calcular la cantidad de tiempo esta tarea requiere 10 10
Desarrollo desarrollar
· Análisis · Análisis de Necesidades (incluyendo el aprendizaje de nuevas tecnologías) 60 60
· Diseño de especificaciones Generar documentos de diseño 40 100
· Revisión de diseño · Revisión de Diseño (y sus colegas revisaron los documentos de diseño) 10 50
· Codificación Estándar · Especificaciones de códigos (desarrollo de normas apropiadas para el desarrollo actual) 0 0
· Diseño · Diseño específico 60 60
· Codificación · Codificación específica 150 150
· Revisión de código · Revisión Código 10 20
· Prueba · Test (autoprueba, modificar el código, enviar modificaciones) 60 120
la presentación de informes informe
· Informe de prueba · Informe de prueba 30 30
· Medida del tamaño · Cargas de trabajo informáticas 10 10
· Postmortem y Plan de Mejora de Procesos · La retrospección, y proponer plan de mejora de procesos 60 120
total 580 730

Visto desde la mesa, la fase de diseño, las pruebas de fase y etapa del sumario y el tiempo estimado eran muy diferentes.

Creo que el diseño del algoritmo y la generación de código de resolución de problemas incluidos en los documentos de diseño y estudiantes para discutir cómo hacerlo clasificada como la revisión del diseño. Posteriormente sentir las dos partes no deben tomar tanto tiempo, demasiado sobre el rendimiento e indeciso, no dudando nada bueno, ya partir de los resultados finales, enredado desde hace mucho tiempo o simplemente utilizar "violenta", dos a tiempo parcial se trata de "desperdiciado" hacia fuera.

La fase de prueba se debe a que en el caso no están familiarizados con las pruebas de error de la unidad de pruebas lleva tiempo y la investigación para mejorar el rendimiento del método también lleva mucho tiempo.

En segundo lugar, la descripción de ideas para resolver problemas

Análisis de requerimientos

Requisitos funcionales: N determinado de líneas rectas, el número de puntos de interrogación en un plano en menos dos en una línea determinada. Introducir el tema de la garantía sólo un número finito de respuestas.

Requisitos de ensayo: El programa presentado por los parámetros de entrada y la correspondiente necesidad de apoyar el acuerdo.

las necesidades de desarrollo adicionales: dibujo de una ronda.

Con floja populares problema de lenguaje de descripción de que la línea recta en el plano N no se repetirá un número total de la intersección. Tenga en cuenta los siguientes puntos:

  • Una pluralidad de líneas puede intersectar en un punto.
  • Información está determinada por dos recta número entero puntos de coordenadas, las coordenadas de intersección pueden ser fraccionada.
  • los requisitos del proyecto de apoyo a los parámetros de línea de comandos, archivo de datos de leer, escribir la salida a un archivo.
  • El número total de intersección es de menos de 5.000.000, los medios de que puede haber un gran número de cálculos de punto duplicados.
  • N puede ser significativo.

Se requiere conocimiento: lineal y la representación circular. El método de cálculo de los requisitos de la línea de intersección y de línea. Cálculo círculo y el círculo para encontrar las intersecciones. El método para encontrar las intersecciones del círculo y la línea recta.

Ideas de resolución de problemas

El más directo una idea, N es el número de líneas de veintidós calculadas las coordenadas de intersección y se guarda, no se guarda el repetir las mismas coordenadas, las estadísticas finales coordenadas almacenadas es el tema de la respuesta. determinación del peso Hash utilizando, calculado suponiendo una complejidad constante de tiempo es O (k), entonces la complejidad de tiempo enfoque de O (N ^ 2 ^ * k), la complejidad espacial es O (N ^ 2 ^). Grupo estimar ligeramente O (10 ^ 8 ^) de 1 segundo palabras, y la adición calcula constante, entonces, cuando N es menor o igual a 1000, este enfoque se pueden obtener resultados dentro de los 60 segundos, necesidades puntuaciones de exactitud, pero teniendo en cuenta el rendimiento parte de las necesidades del proceso a ser mejorado.

Una reflexión más profunda, sin duda hay intersección entre las líneas paralelas, ya sea atravesada cuando se puede pasar por alto las líneas paralelas hacen? Podemos calcular la pendiente de cada línea a la recta de paquetes a la misma pendiente de la línea es un grupo, el mismo conjunto de líneas sin desplazamiento. Si los últimos divididos \ (m \) grupos \ (L_i \) líneas rectas, y por lo tanto reducir el total de \ (2 \ \ sum ^ L_i ) cálculos, en algunos casos, puede haber alguna mejora el rendimiento pero todavía no puede garantizar resultados seguros en menos de 60 años.

Piense otra vez, el algoritmo principal cuello de botella que se calcula el punto de repetición , puede reducir el punto de repetir que de alguna manera computacional? N líneas rectas se añaden secuencialmente a la totalidad de los dibujos, en el cálculo de la intersección, la intersección se registra el número de líneas rectas cruzan. Sin embargo, debido a que C ++ experiencia relativamente escasa, y no para estimar la complejidad del tiempo de calcular el punto de intersección con el tiempo la complejidad de las estructuras de datos de biblioteca de C ++ estándar, y por lo tanto dan por vencidos.

Por último, teniendo en cuenta las necesidades de desarrollo redonda, puede primera recta procesado por el método anterior, y luego tratar círculo de la violencia directa.

Pregunté a los problemas relacionados con la red, pero no conseguir un buen algoritmo, esperanza después del final del trabajo, de los profesores y otros estudiantes blogueo obtener nuevos conocimientos.

En tercer lugar, el proceso de diseño e implementación

En primer lugar, la necesidad de almacenar la geometría de entrada de información, es decir, con lineal, redondo, de la clase a calcular de antemano puede almacenarse después de la parte para ahorrar tiempo. Luego, en nuestro algoritmo, también tenemos que construir la intersección de la clase de geometría intersección.

Tres clases diseñadas específicamente para:

  • Intersección categorías:
    • Atributo: double: abscisa;
    • Atributo: double: ordenada;
  • rectas categorías:
    • Attribute: double,double,double: tres parámetros ecuaciones generalmente lineales ( \ (ax + by + C = 0 \) );
    • Attribute: double,double: pendiente (pendiente positiva cuando el infinito, que se define como INF), la intersección (el tiempo es infinito positivo, definido como INF);
    • Attribute: double,double: una línea recta a través de cualquier punto;
    • Método: Point: encontrar las intersecciones con otra línea
  • clases redondas:
    • Atributo: double,double: coordenadas del centro;
    • Atributo: double: radio;
    • Attribute: double,double,double: tres parámetros ecuación general de un círculo ( \ (^ X ^ 2 + Y 2 + DX + EY + F = 0 \) )
    • Método: std::vector<Point>: encontrar las intersecciones con otra línea
    • Método: std::vector<Point>: encontrar las intersecciones del círculo con otro

Utilice la intersección map, sety por lo que puede rápida consulta estructura de datos para el almacenamiento. Uso de matriz lineal, juego y otras estructuras de datos se puede almacenar en el orden de tejido. Circle puede ser atravesada utilizando cualquier estructura de datos almacenada.

La principal función de flujo de procesamiento de los parámetros de línea de comando de lectura, el simple análisis, los datos se leen y almacenan en una matriz u otra estructura de datos. El problema se divide entonces en una línea de intersección y la intersección de la línea recta, el círculo y otra geometría. Call solveLine()estadísticas de función y el número de intersección línea recta, a continuación, llamar solveCycle()al número de la intersección de las estadísticas círculo y funciones de línea. Por último, la salida a un archivo.

solveLine()Función principales procesos: en primer lugar, la pendiente de la línea recta de acuerdo con un paquete, el procesamiento predeterminado no se inicia antes de que cualquier geometría plana. Entonces añadieron secuencialmente al plano recto, cuando la solicitud de llamada con la función añadida de la intersección de línea de la línea recta, el plano de intersección de la línea se calcula en las líneas existentes, comprobar si una intersección existe, si no, las intersecciones almacenadas en la estructura de datos, y las estadísticas aumentar el número.

solveCycle()Función principal proceso es el siguiente: con el fin de añadir al círculo plano, círculo y llamando a la función de petición con la geometría otro punto de intersección de la informática y los gráficos de la intersección existente, la consulta intersección si se ha producido, si no, el punto de intersección en una estructura de datos y aumentar el número de estadísticas.

La intersección de la línea y las funciones de cálculo línea recta : determinar en primer lugar si en paralelo, si el paralelo de regreso un punto especial, de lo contrario, el cálculo de la intersección usando la fórmula de cálculo. Aquí es necesario configurar la unidad de pruebas , los resultados de las pruebas son correctas. Prueba paralelo caso, la pendiente es 0 , la pendiente de la ausencia del caso de líneas rectas de intersección entre sí.

Círculo de intersección con las funciones de cálculo línea recta : primera línea recta y el cálculo de la distancia entre centros, hay varias intersecciones se determina, si no hay intersección, regresó cola vacía; si una intersección tangencial se calcula para un pie de una perpendicular a la línea recta centro, y que comprende una vuelta cola de intersección; si dos puntos de intersección, para calcular una perpendicular pie a una línea recta como el centro, y luego en la dirección de la aceleración lineal vector una cierta longitud, para obtener dos puntos de intersección, y vuelven cola contiene dos intersecciones. Aquí es necesario configurar la unidad de pruebas , los resultados de las pruebas son correctas. círculo de prueba y una línea recta tangente a , intersección , con de encontrar las intersecciones del caso, en el que la necesidad comprende una línea recta con una pendiente de 0 , la pendiente de la ausencia de circunstancias especiales.

Circle interseca el círculo con la función de cálculo : primero a través del centro de los dos círculos se cruzan determinación de la distancia, si la cola es devuelto intersección vacía; si se corta la línea recta calculado por una ecuación general de un círculo, el círculo de intersección y luego contando el número de líneas rectas. Aquí es necesario configurar la unidad de prueba , el círculo de la prueba y el círculo endo , exo , se cruzan , fuera de , que contiene la situación para encontrar las intersecciones.

Además de la función esencial, que tenga que agregar función de comparación de punto flotante , la precisión se establece en 1e-8. La función toma dos parámetros, si el primer parámetro es mayor que un segundo, devuelve un número positivo, igual a 0 devoluciones, devuelve un número negativo inferior a. Aquí es necesario configurar la unidad de pruebas , prueba de comparación de punto flotante es correcta.

Si las estructuras de datos requeridas utilizadas para el tipo de servicio pesado, también necesario para preparar las correspondientes funciones sobrecargadas.

En cuarto lugar, la mejora del rendimiento.

La primera edición del Programa de Análisis de Rendimiento

En la primera edición se código completado modificado repetidamente insecto, y, a través del programa para análisis de rendimiento y después de una serie de pruebas de unidad de prueba.

Los datos de rendimiento se analiza usando: 7000 datos de la geometría generados al azar, en el que cada línea y el círculo 3500, el número final de intersecciones se calcula 22191950 intersecciones. módulo de generación de números aleatorios en el paquete al azar pitón.

VS2019 en perfilador de rendimiento, análisis de utilización de la CPU como sigue:

Como puede verse, las mayoría de las funciones que requieren mucho tiempo, funciones estadísticas deben ser el punto de intersección del círculo y el resto de la geometría, también es razonable. Haga clic en la página-informe detallado, análisis de solveCycle()resultados de la función son los siguientes:

Sorprendiendo que la proporción de tiempo de cálculo en comparación con la ronda directamente en el proceso de búsqueda de la intersección, a mapmodificar y consulta de estructura de datos el tiempo que tarda más. A través del acceso a la información se puede ver, la biblioteca estándar de C ++ mapprincipalmente a través de la implementación árbol rojo-negro, consultar y modificar el tiempo de complejidad son \ (O (\ log (el n-)) \) . Sin embargo, en esta cuestión, absolutamente no necesitamos utilizar su estructura secuencial y Pointtipo de contenido es relativamente simple. Después de algunas preguntas, me encontré con que C ++ tiene unordered_mapesta estructura de datos, su función es similar a la de Java hashmap, consultar y modificar los términos de rápido que map, por lo que decidí reemplazar la estructura de datos para el registro de la intersección unordered_map, y está Pointsobrecargado método hash.

El análisis preliminar de la rendimiento optimizado

La estructura de datos de la intersección de grabación reemplazado unordered_mapdespués de mí, el mismo programa de análisis de rendimiento de la operación utilizando los mismos datos, los siguientes resultados obtenidos:

Desde el momento puede ejecutar todo el programa, aporta una importante optimización de estructuras de datos sentirse reemplazado. Reducción de los originales 01 segundos a 1 minuto 24.5 segundos pena felices por un rato :)

Pero entonces me sentí un poco extraño, pensé que el cuello de botella procedimiento debe repetirse calcular la intersección, pero ¿por qué aquí se utiliza la estructura de datos en una intersección registro de ello?

pensamiento posterior optimización del rendimiento

A continuación, mediante el análisis de los datos con los resultados de las pruebas, descubrí que en realidad los datos de prueba es que los datos no coincide con la demanda , por lo que el análisis de rendimiento no ayuda a resolver el cuello de botella en el algoritmo.

Debido a que los datos que estoy usando un poco intersección solapamiento generado de forma aleatoria, la paga en general una gran cantidad de puntos, por lo que la complejidad del tiempo es en un montón en la intersección de la estructura de datos de mantenimiento. El título indica claramente, hay una serie de restricciones intersección , la demanda para el sujeto, de hecho, la optimización del rendimiento debe centrarse en la reducción de la repetición del punto de cálculo, cambiar la estructura de datos sólo se puede dar cuenta de una pequeña cabeza en la prueba real.

datos de prueba no razonables, que me ayude a llegar a un cuello de botella de rendimiento razonable, el análisis de rendimiento no ayuda a resolver el algoritmo de cuello de botella, donde los cambios en esta estructura de datos deben finalmente ayuda para mí no serán muchos.

Además de la forma de generar datos de prueba de una más razonable, hay un problema me deja un tanto perplejo. En el desarrollo de software real, la optimización del rendimiento debería ser una parte esencial, cuando el software que no se han formado cuando no hay datos de usuario, ¿cómo se sabe dónde está la optimización de rendimiento clave? Si el énfasis equivocado, por ejemplo, hago grandes esfuerzos para encontrar un enchufe para escribir la estructura de datos extremadamente rápido (Puedo enviar el papel para hacer un informe directamente a embarcarse en un pináculo de la vida), Se traduce en el uso real, otros simplemente no utilizan esta característica, o la función de esta velocidad en realidad no afectará a la experiencia del cliente, que no era en vano?

Cinco código de la llave Descripción

Creo que el código de la llave tiene tres partes.

  • solveLine(): Añadir a la intersección del plano y el cálculo en línea recta ignora línea paralela, esto debería ser la única diferencia con la violencia directa de mis amigos para encontrar las intersecciones, y de acuerdo con el menor número de intersecciones para inferir, líneas paralelas no debe ser mucho, rendimiento optimizado no vale la pena una mención. Tenga en cuenta el código y se muestra a continuación:

    int solveLine() {
      //ans为统计交点个数
      int ans = 0;
      //将直线按斜率排序,实现斜率分组功能
      sort(l, l + ln);
      //map查找用的迭代器
      umap::iterator iter;
      //依次遍历直线,当前待添加直线为i
      for (int i = 0; i < ln; i++) {
          //按顺序遍历已经添加到平面中的直线
          for (int j = 0; j < i; j++) {
              //如果遍历到平面中直线j与i的斜率相同,那么j~i之间的直线斜率都与i相同,不再计算i
              if (doublecompare(l[i].k, l[j].k) == 0) {
                  break;
              }
              //求直线i与j的交点
              Point tpoint = l[i].intersectWithLine(l[j]);
              //如果是新交点,加入umap中,并统计结果,否则不做处理
              iter = vis.find(tpoint);
              if (iter == vis.end()) {
                  ans += 1;
                  vis[tpoint] = 1;
              }
          }
      }
      return ans;
    }
  • std::vector<Point> Cycle::intersectWithLine(Line t): Buscando el círculo de intersección con la línea recta, y se almacena en vectorel retorno, un primer pedal ideas de orden, y después sigue la dirección del vector de aceleración, y las Notas de código:

    std::vector<Point> Cycle::intersectWithLine(Line t) {
      //交点vector
      std::vector<Point>ps;
      //先计算圆心到直线的距离
      double ld = abs(t.a * x + t.b * y + t.c) / sqrt(t.a * t.a + t.b * t.b);
      //相离
      if (doublecompare(ld, r) == 1) {
          return ps;
      }
      //相切
      else if (doublecompare(ld, r) == 0) {
          //斜率不存在,横坐标为直线横坐标,纵坐标为圆心纵坐标
          if (t.k == inf_k) {
              ps.push_back(Point(t.x1, y));
              return ps;
          }
          //斜率为0,横坐标为圆心横坐标,纵坐标为直线纵坐标
          if (t.k == 0) {
              ps.push_back(Point(x, t.y1));
              return ps;
          }
          //斜率正常
          //先算过圆心与直线t垂直的线y=-1/k*x+b2
          double b2 = x / t.k + y;
          //直线t斜截式中b1
          double b1 = t.b1;
          //两直线求交点,即垂足
          double xt = t.k * (b2 - b1) / (1 + t.k * t.k);
          double yt = t.k * xt + b1;
          //相切时,垂足即交点
          ps.push_back(Point(xt, yt));
          return ps;
      }
      //相交
      double ln = sqrt(r * r - ld * ld);
      //同理
      if (t.k == inf_k) {
          ps.push_back(Point(t.x1, y - ln));
          ps.push_back(Point(t.x1, y + ln));
          return ps;
      }
      if (t.k == 0) {
          ps.push_back(Point(x - ln, t.y1));
          ps.push_back(Point(x + ln, t.y1));
          return ps;
      }
      double b2 = x / t.k + y;
      double b1 = t.b1;
      double xt = t.k * (b2 - b1) / (1 + t.k * t.k);
      double yt = t.k * xt + b1;
      //求出垂足后,求直线方向向量
      double s1k2 = sqrt(1 + t.k * t.k);
      double nx = 1 / s1k2;
      double ny = t.k / s1k2;
      //加减方向向量与半弦长的乘积得到两个交点
      ps.push_back(Point(xt + ln * nx, yt + ln * ny));
      ps.push_back(Point(xt - ln * nx, yt - ln * ny));
      return ps;
    }
  • std::size_t operator()(const Point& c) const: Uso unordered_mapcuando Pointla clase especificada hashfunción, de la siguiente manera:

    class PointHash
    {
    public:
      std::size_t operator()(const Point& c) const
      {
          //直接利用库中hash函数,为防止32/64位操作系统的影响,默认size_t为32位,x,y各分16位
          return hash<double>()(c.x) + (hash<double>()(c.y) << 16);
      }
    };

En sexto lugar, para eliminar la advertencia de código

Se recomienda esta máquina para utilizar la regla VS2019, el número de errores y advertencias son cero!

Supongo que te gusta

Origin www.cnblogs.com/eitbar/p/12453042.html
Recomendado
Clasificación