( Saya telah menguji pendekatan ini sebelumnya, dan saya ingat itu berhasil dengan benar, tetapi saya belum mengujinya secara khusus untuk pertanyaan ini. )
Sejauh yang saya tahu, keduanya dan dapat menderita pembatalan besar jika hampir paralel / tegak lurus — atan2 tidak dapat memberikan akurasi yang baik jika salah satu input dimatikan.∥v1×v2∥v1⋅v2
Mulailah dengan merumuskan kembali masalah sebagai menemukan sudut segitiga dengan panjang sisi,dan(Ini semua dihitung secara akurat dalam aritmatika floating point). Ada varian rumus Heron yang terkenal karena Kahan ( Area salah hitung dan Sudut Segitiga yang Seperti Jarum ), yang memungkinkan Anda menghitung luas dan sudut (antara dan ) dari sebuah segitiga yang ditentukan oleh panjang sisinya, dan melakukannya secara stabil secara numerik. Karena pengurangan subproblem ini juga akurat, pendekatan ini harus bekerja untuk input yang sewenang-wenang.a=|v1|b=|v2|c=|v1−v2|ab
Mengutip dari makalah itu (lihat hal.3), dengan asumsi ,
Semua kurung di sini ditempatkan dengan hati-hati, dan mereka peduli; jika Anda menemukan diri Anda mengambil akar kuadrat dari angka negatif, panjang sisi input bukan panjang sisi segitiga.a≥b
μ=⎧⎩⎨c−(a−b),b−(a−c),invalid triangle,if b≥c≥0,if c>b≥0,otherwise
angle=2arctan(((a−b)+c)μ(a+(b+c))((a−c)+b)−−−−−−−−−−−−−−−−−−−−√)
Ada penjelasan tentang bagaimana ini bekerja, termasuk contoh nilai yang gagal rumus lainnya, dalam makalah Kahan. Formula pertama Anda untuk adalah di halaman 4.αC′′
Alasan utama saya menyarankan rumus Kahan's Heron adalah karena itu membuat primitif yang sangat bagus — banyak pertanyaan geometri planar yang berpotensi rumit dapat direduksi menjadi menemukan area / sudut segitiga sembarang, jadi jika Anda dapat mengurangi masalah Anda menjadi itu, ada formula stabil yang bagus untuk itu, dan tidak perlu untuk membuat sesuatu sendiri.
Sunting Mengikuti komentar Stefano, saya membuat plot kesalahan relatif untuk , ( kode ). Dua baris tersebut adalah kesalahan relatif untuk dan , sepanjang sumbu horizontal. Tampaknya itu berfungsi.
v1=(1,0)v2=(cosθ,sinθ)θ=ϵθ=π/2−ϵϵ