Cálculos de trigonometría rápida
Su tarea es crear un programa que pueda calcular el seno, el coseno y la tangente de un ángulo en grados.
Reglas
- No hay funciones de trigonometría incorporadas (ni siquiera secante, cosecante y cotangente si su idioma las tiene).
- Puede usar tablas de búsqueda, pero su tamaño total no debe exceder los 3000 miembros (para las tres operaciones juntas). Por favor, haga que lea las tablas de un archivo (por ejemplo
trig.lookup
) para que no confundan el código. - Sin acceso a internet.
- Debe redondear correctamente su salida como se explica a continuación. No use piso o techo.
- Puede usar cualquier método para calcular los valores, por ejemplo , fracciones continuas , siempre que sea correcto para 7 cifras significativas.
- Su código debe poder cronometrarse. Excluya las operaciones de E / S de archivo de su tiempo, así que solo cronometre las funciones que hacen el trigonometraje y cualquier redondeo.
- Debo poder ejecutar tu código. Publique un enlace a un compilador / intérprete disponible gratuitamente y brinde las instrucciones necesarias para compilar / ejecutar el código (por ejemplo, qué opciones pasar a GCC).
- Se aplican lagunas estándar .
Formato de entrada
- Lea desde un archivo llamado a
trig.in
menos que su idioma no admita E / S de archivo. - Los ángulos están entre 0 y 360 inclusive.
- La entrada consistirá en ángulos de diez cifras significativas en dígitos decimales, separados por nuevas líneas. Por ejemplo:
90.00000000
74.54390000
175.5000000
Formato de salida
- Para cada ángulo suministrado, debe generar su seno, coseno y tangente a 7 figuras significativas, separadas por espacios, en una sola línea. Utilice "notación científica", por ejemplo,
1.745329E-5
paratan 0.001
o1.000000E+0
parasin 90
. - Denote infinito o NaN por
n
, por ejemplo, la salida para90.00000000
debería ser1.000000 0.000000 n
. - Si la entrada es de tres ángulos separados por nuevas líneas, su salida debe constar de tres líneas, cada una de las cuales contiene el seno, el coseno y la tangente.
- No puede enviar nada más.
- Salida a un archivo llamado a
trig.out
menos que su idioma no admita E / S de archivo.
Puntuación
- más rápido de código . El desafío es escribir un programa que calcule estos tres valores lo más rápido posible. El tiempo más rápido gana.
- Todos recibirán la misma entrada de prueba de muchos ángulos.
- Los tiempos se registrarán en mi máquina.
- Su puntaje es el promedio de tres ejecuciones en la misma entrada (obviamente no puede guardar nada entre ejecuciones).
- Tiempo de compilación no incluido. Este desafío es más sobre el método utilizado que el lenguaje. (Si alguien pudiera señalarme cómo excluiría el tiempo de compilación para lenguajes como Java, estaría muy agradecido)
- Mi máquina es una instalación de Ubuntu 14.04. Las estadísticas del procesador están en Pastebin (obtenidas mediante la ejecución
cat /proc/cpuinfo
). - Editaré tu tiempo en tu respuesta cuando lo haya probado.
math
fastest-code
trigonometry
Geobits
fuente
fuente
sin
,cos
ytan
está en una nueva línea. ¿Necesito cambiarlo para generar las respuestas en una sola línea?Respuestas:
Fortran 90
Empleo el CORDIC método con una matriz de pre-tabulados de 60 valores arctan (véase el artículo Wiki para más detalles sobre por qué es necesario).
Este código requiere un archivo,
trig.in
con todos los valores en las nuevas líneas que se almacenarán en la misma carpeta que el ejecutable de Fortran. Compilar esto es,donde
file
está el nombre de archivo que le dé (probablementeSinCosTan.f90
sería más fácil, aunque no es necesario que coincida con el nombre del programa y el nombre del archivo). Si tiene el compilador Intel, le recomiendo usarya
-xHost
que (que no existe para gfortran) proporciona optimizaciones de mayor nivel disponibles para su procesador.Mis pruebas me dieron unos 10 microsegundos por cálculo al probar 1000 ángulos aleatorios usando gfortran 4.4 (4.7 o 4.8 está disponible en los repositorios de Ubuntu) y alrededor de 9.5 microsegundos usando ifort 12.1. Probar solo 10 ángulos aleatorios dará como resultado un tiempo indeterminable usando las rutinas de Fortran, ya que la rutina de tiempo es precisa al milisegundo y las matemáticas simples dicen que debería tomar 0.100 milisegundos para ejecutar los 10 números.
EDITAR Aparentemente estaba cronometrando IO que (a) hizo que el cronometraje fuera más largo de lo necesario y (b) es contrario a la viñeta # 6. He actualizado el código para reflejar esto. También descubrí que usar un
kind=8
número entero con la subrutina intrínsecasystem_clock
da una precisión de microsegundos.Con este código actualizado, ahora estoy calculando cada conjunto de valores de las funciones trigonométricas en aproximadamente 0.3 microsegundos (los dígitos significativos al final varían de ejecución a ejecución, pero constantemente se cierne cerca de 0.31 us), una reducción significativa del anterior iteración que cronometró IO.
fuente
Python 2.7.xo Java (elija)
Se puede descargar un intérprete gratuito de Python desde aquí .
Se puede descargar un intérprete gratuito de Java desde aquí .
El programa puede recibir información de un archivo llamado
trig.in
ubicado en el mismo directorio que el archivo del programa. La entrada está separada por nuevas líneas.Originalmente hice esto en Python porque, bueno, me encanta Python. Pero, dado que quiero tratar de ganar también, lo reescribí en Java después ...
Versión de Python: obtuve alrededor de 21 µs por ejecución en mi computadora. Obtuve unos 32 µs cuando lo ejecuté en IDEone .
Versión de Java: obtengo alrededor de 0.4 µs por ejecución en mi computadora y 1.8 µs en IDEone .
Especificaciones de la computadora:
Prueba:
sin
,cos
ytan
todos los ángulos de entrada.La entrada de prueba utilizada para ambos es la siguiente:
Acerca del Código:
La premisa de este programa era estimar
sin
ycos
usar sus polinomios de Taylor con 14 términos, que fue lo que calculé que era necesario para tener una estimación de error de menos de 1e-8. Sin embargo, descubrí que era más rápido de calcularsin
quecos
, así que decidí calcularcos
usandocos=sqrt(1-sin^2)
Versión de Python:
Versión de Java:
fuente
cos
cálculo es excesivo, solo lo haríasin(x+90degrees)
sin
como una función y como una variable. Pensé que sería más rápido no tener que pasarle algo porsin()
segunda vez, pero compararé los dos para ver si ese es realmente el caso. ¿Le pareció que lacopySign()
función es más lenta que sumar cosas como en misin()
función?Octava (o Matlab) y C
Un proceso de construcción un poco complicado, pero un enfoque novedoso y los resultados fueron alentadores.
El enfoque consiste en generar polinomios cuadráticos aproximados para cada grado. Entonces grado = [0, 1), grado = [1, 2), ..., grado = [359, 360) tendrán cada uno un polinomio diferente.
Octave - parte de construcción
Octave está disponible públicamente: Google
download octave
.Esto determina el mejor polinomio cuadrático para cada grado.
Guardar como
build-fast-trig.m
:C - parte de construcción
Esto convierte los dobles en formato de texto a formato binario nativo en su sistema.
Guardar como
build-fast-trig.c
:Compilar:
Generando el archivo de coeficientes
Correr:
Ahora tenemos
qcoeffs.dat
como archivo de datos para usar para el programa real.C - parte de activación rápida
Guardar como
fast-trig.c
:Compilar:
Correr:
Leerá
trig.in
, guardarátrig.out
e imprimirá para consolar el tiempo transcurrido con una precisión de milisegundos.Dependiendo de los métodos de prueba utilizados, puede fallar en ciertas entradas, por ejemplo:
La salida correcta debería ser
0.000000e+00 1.000000e+00 0.000000e+00
. Si los resultados se validan usando cadenas, la entrada fallará, si se validan usando un error absoluto, por ejemplofabs(actual - result) < 1e-06
, la entrada pasará.El error absoluto máximo para
sin
ycos
fue ≤ 3e-07. Porquetan
, dado que el resultado no se limita a ± 1 y puede dividir un número relativamente grande por un número relativamente pequeño, el error absoluto podría ser mayor. De -1 ≤ tan (x) ≤ +1, el error absoluto máximo fue ≤ 4e-07. Para tan (x)> 1 y tan (x) <-1, el error relativo máximo , por ejemplo,fabs((actual - result) / actual)
fue generalmente <1e-06 hasta llegar al área de (90 ± 5) o (270 ± 5) grados, luego el El error empeora.En las pruebas, el tiempo promedio por entrada individual fue (1.053 ± 0.007) µs, que en mi máquina fue aproximadamente 0.070 µs más rápido que el nativo
sin
ycos
,tan
al definirse de la misma manera.fuente
Cobra
Compilarlo con
cobra filename -turbo
Pruebas: AMD FX6300 @ 5.1GHz
La prueba 360 * 10000 utilizada por la respuesta C se ejecuta en 365 ms (frente a 190 ms)
La prueba de 4 entradas utilizada por las respuestas de Python y Java se ejecuta en 0,32 µs (frente a 30 µs, 3 µs)
La prueba de 1000 ángulos aleatorios utilizada por la respuesta de Fortran se ejecuta a 100 ns por ángulo (frente a 10 µs)
fuente
C
Aquí está mi intento. Funciona así:
Construya una tabla de todos los valores de sin (x) de 0 a 450 grados. De manera equivalente, todos estos valores son cos (x) de -90 a 360 grados. Con 2926 elementos, hay suficiente espacio para un valor cada 1 / 6.5 grados. La unidad del programa es, por lo tanto, 1 / 6.5 grados, y hay 585 unidades en un cuarto de vuelta.
Convierta los grados de entrada en unidades del programa (multiplique por
6.5==110.1 binary.
) Encuentre los valores más cercanos para sen y cos de la tabla. luego convierta la parte restante de la entrada (dx) en radianes.aplicamos la fórmula
sin(x+dx) == sin x +(d(sin x)/dx)*dx.
nota que(d(sin x)/dx)==cos x,
pero solo si usamos radianes.desafortunadamente, eso no es lo suficientemente preciso por sí solo, por lo que se requiere otro término, basado en la siguiente derivada.
d2(sin x)/dx2 == -sin x.
Esto debe multiplicarse pordx*dx/2
(no estoy seguro de dónde proviene el factor 2, pero funciona).Siga el procedimiento análogo para
cos x
, luego calculetan x == sin x / cos x
.Código
Hay alrededor de 17 operaciones de punto flotante aquí. Eso se puede mejorar un poco. El programa contiene la creación de tablas y resultados de prueba utilizando las funciones trigonométricas nativas, pero el algoritmo no. Agregaré el tiempo y la edición para cumplir con los requisitos de E / S más adelante (con suerte este fin de semana). Coincide con la salida de la función nativa, excepto por valores muy pequeños de sen x y cos x, que deberían mejorarse mejor que la salida de la función nativa con Algunos ajustes.
fuente