Kapan seharusnya fungsi trigonometri, dengan argumen derajat, mengembalikan -0.0?

10

Dalam menciptakan fungsi trigonometri my_sind(d), my_cosd(d), my_tand(d), yang digunakan argumen gelar daripada satu radian dan memberikan jawaban yang tepat pada kelipatan 90, saya melihat bahwa hasilnya kadang-kadang -0.0bukan 0.0.

my_sind( 0.0) -->  0.0
my_sind(-0.0) --> -0.0

my_sind(180.0) --> -0.0
my_sind(360.0) -->  0.0

sin()dan tan()biasanya mengembalikan hasil tanda nol yang sama untuk input tanda nol yang diberikan. Masuk akal bahwa my_sin()harus cocok sin()dengan input tersebut.

my_sind( 0.0) alike sin( 0.0) -->  0.0
my_sind(-0.0) alike sin(-0.0) --> -0.0

Pertanyaannya adalah : untuk apa seluruh nomor non_zero_nharus / mungkin hasilnya pernah kembali -0.0untuk my_sind(180*non_zero_n), my_cosd(180*n + 180), my_tand(180*non_zero_n)?

Kode ini cukup mudah sehingga hanya f(-0.0)menghasilkan -0.0dan dilakukan dengan itu. Sederhana bertanya-tanya apakah ada alasan untuk membuat pengembalian lain untuk yang lain ( tidak nol ) dan pentingnya mengasuransikan tanda itu.f(x)-0.0x


Catatan: Ini bukan pertanyaan mengapa 0.0vs -0.0terjadi. Ini bukan mengapa cos(machine_pi/4)tidak kembali 0.0. Ini juga bukan pertanyaan tentang bagaimana mengendalikan generasi 0.0atau -0.0. Saya melihatnya sebagai pertanyaan desain.

chux - Pasang kembali Monica
sumber

Jawaban:

4

Prinsip desain "kejutan terkecil" menunjukkan bahwa kita melihat fungsi yang telah ditetapkan sebelumnya untuk panduan. Dalam hal ini, fungsionalitas yang didirikan terdekat disediakan oleh sinpidan cospifungsi yang diperkenalkan dalam IEEE Std 754-2008 (Standar IEEE untuk Aritmatika Floating-Point), bagian 9. Fungsi-fungsi ini bukan bagian dari standar ISO C dan ISO C ++ saat ini, tetapi telah dimasukkan ke dalam perpustakaan matematika dari berbagai platform pemrograman, misalnya CUDA.

Fungsi-fungsi ini menghitung sin (πx) dan cos (πx), di mana multiplikasi dengan π terjadi secara implisit di dalam fungsi. tanpitidak didefinisikan, tetapi dapat, berdasarkan kesetaraan matematika, diasumsikan untuk menyediakan fungsionalitas sesuai dengan tanpi(x) = sinpi(x) / cospi(x).

Kita sekarang dapat menentukan sind(x) = sinpi(x/180), cosd(x) = cospi(x/180), tand(x) = tanpi(x/180)secara intuitif. Bagian 9.1.2 dari IEEE-754 menjabarkan penanganan argumen khusus untuk sinpidan cospi. Khususnya:

sinPi (+ n) adalah +0 dan sinPi (−n) adalah −0 untuk bilangan bulat positif n. Ini menyiratkan, dalam mode pembulatan yang sesuai, bahwa sinPi (−x) dan −sinPi (x) adalah angka yang sama (atau keduanya NaN) untuk semua x. cosPi (n + ½) adalah +0 untuk sembarang bilangan bulat ketika n + ½ mewakili.

Standar IEEE 754-2008 tidak memberikan alasan untuk persyaratan yang dikutip, namun, konsep awal dari bagian yang relevan menyatakan:

Jika nilai fungsi adalah nol, tanda 0 ini paling baik ditentukan dengan mempertimbangkan perpanjangan fungsi tanda dari fungsi matematika.

Pembacaan dari 754 Kelompok Kerja Arsip Surat dapat menghasilkan wawasan tambahan, saya belum punya waktu untuk menggali melalui itu. Menerapkan sind(),, cosd()dan tand()seperti dijelaskan di atas, kita sampai pada tabel contoh kasus ini:

SIND
 angle value 
  -540 -0
  -360 -0
  -180 -0
     0  0
   180  0
   360  0
   540  0

COSD
 angle value
  -630  0
  -450  0
  -270  0
   -90  0
    90  0
   270  0
   450  0

TAND
 angle value
  -540  0
  -360 -0
  -180  0
     0  0
   180 -0
   360  0
   540 -0
njuffa
sumber
5

sin () dan tan () biasanya mengembalikan hasil tanda nol yang sama untuk input nol tanda yang diberikan

Secara umum ini bisa benar karena:

  • Kecepatan / akurasi . Untuk ganda yang cukup kecil, jawaban terbaik sin(x)adalah x. Yaitu, untuk angka yang lebih kecil dari sekitar 1.49e-8, dobel paling dekat dengan sinus x sebenarnya x itu sendiri (lihat kode sumber glibc untuk sin () ).

  • Penanganan kasus khusus .

    Beberapa operasi aritmatika yang luar biasa dipengaruhi oleh tanda nol; misalnya "1/(+0) = +inf"tetapi "1/(-0) = -inf". Untuk mempertahankan kegunaannya, bit tanda harus merambat melalui operasi aritmatika tertentu sesuai dengan aturan yang berasal dari pertimbangan kontinuitas.

    Implementasi fungsi transendental elementer seperti sin (z) dan tan (z) dan invers dan analog hiperboliknya, meskipun tidak ditentukan oleh standar IEEE, diharapkan mengikuti aturan yang sama. Implementasi sin(z) diharapkan mereproduksi tanda z serta nilainya diz = ±O .

    ( Pemotongan Cabang untuk Fungsi Dasar yang Kompleks atau Banyak yang Dikisahkan Tentang Nothing's Sign Bit oleh W. Kahan)

    Nol yang ditandatangani secara negatif menggemakan konsep analisis matematika mendekati 0 dari bawah sebagai batas satu sisi (pertimbangkan 1 / sin(x): tanda nol membuat perbedaan besar).

EDIT

Mempertimbangkan poin kedua saya akan menulis my_sindsehingga:

my_sind(-0.0) is -0.0
my_sind(0.0) is 0.0

Standar C terbaru (F.10.1.6 sindan F.10.1.7 tan, implementasi dengan nol yang ditandatangani), menetapkan bahwa jika argumennya dikembalikan±0 , ia tidak dimodifikasi .

EDIT 2

Untuk nilai-nilai lain saya pikir ini masalah perkiraan. Diberikan M_PI<π:

0 = sin(π) < sin(M_PI)  1.2246467991473532e-16  +0.0
0 = sin(-π) > sin(-M_PI)  -1.2246467991473532e-16  -0.0
0 = sin(2*π) > sin(2*M_PI)  -2.4492935982947064e-16
0 = sin(-2*π) < sin(-2*M_PI)  2.4492935982947064e-16

Jadi jika my_sindmemberikan jawaban yang tepat pada kelipatan 180 ° dapat kembali +0.0atau -0.0(saya tidak melihat alasan yang jelas untuk lebih memilih satu daripada yang lain).

Jika my_sindmenggunakan beberapa perkiraan (misalnya degree * M_PI / 180.0rumus konversi), ia harus mempertimbangkan cara mendekati nilai kritis.

manlio
sumber
Apa yang Anda pikirkan sind(180), sind(-180), sind(360), sind(-360),...?
chux - Reinstate Monica
Terima kasih atas pembaruannya. Mungkin posting saya tidak jelas. Pertanyaan utamanya adalah apakah sebaiknya my_trig(x)kembali -0.0ketika |x|bukan 0.0?
chux - Reinstate Monica
Terima kasih untuk "Jadi jika my_sind memberikan jawaban yang tepat pada kelipatan 180 ° dapat mengembalikan +0.0 atau -0.0 (saya tidak melihat alasan yang jelas untuk memilih satu daripada yang lain)." Ini adalah titik diskusi terdekat sejauh ini. Saya berpikir bahwa "prinsip paling tidak heran" mendorong untuk selalu kembali +0.0, tetapi mencari untuk melihat apakah ada alasan kuat untuk kembali -0.0dalam beberapa situasi (selain x == +/-0.0).
chux - Reinstate Monica
@ chux: Saya pikir untuk kelipatan 180.0, kita benar-benar harus memeriksa nilai-nilai presisi mesin relatif mengingat nilai-nilai itu. Artinya, kenaikan / penurunan terkecil yang memberikan nilai keterwakilan yang berbeda dalam format numerik itu. Kemudian, bandingkan nilai itu dengan nilai sebenarnya untuk melihat apakah nilai itu akan jatuh pada sisi positif atau negatif.
rwong
@ mulailah Terima kasih atas idenya. Kelipatan 90,0 derajat , yang membalas sind(double degrees) dan cosd(double degrees)nilai dapat dikembalikan: -1.0, +0.0, +1.0. Posting ini adalah tentang harus -0.0pernah dikembalikan (selain dari sind (-0.0)). Catatan: sind()tidak tidak menggunakan sederhana sin(x/360*M_PI)pendekatan.
chux
3

Perpustakaan tidak mencoba membedakan +0 dari -0. IEEE 754 khawatir sedikit tentang perbedaan ini ... Saya menemukan fungsi [dalam math.h] cukup sulit untuk menulis tanpa khawatir tentang tanda tidak ada. - PJ Plauger, The Standard C Library , 1992, halaman 128.

Secara formal, fungsi trigonometri harus mengembalikan tanda nol sesuai dengan standar C ... yang membuat perilaku tidak terdefinisi.

Dalam menghadapi perilaku yang tidak terdefinisi, prinsip paling tidak heran menyarankan duplikasi perilaku dari fungsi yang sesuai math.h. Ini bau dibenarkan, sementara menyimpang dari perilaku fungsi yang sesuai dalam math.hbau seperti cara untuk memperkenalkan bug ke dalam persis kode yang tergantung pada tanda nol.

ben rudgers
sumber
Fungsi trigonometri di dalam math.htidak mengembalikan 0,0 ketika diberikan argumen seperti +/- pi / 2 atau +/- pi karena fungsi-fungsi ini hanya dapat mengambil nilai yang diwakili dekat +/- pi / 2, dll. Nilai "dekat" ini mengembalikan hasil di dekat 0,0. Karena fungsi trigonometri std library ( sin cos tan) tidak mengembalikan 0,0 (atau -0,0) untuk input apa pun (kecuali +/- 0,0), tetapi my_sind (), my_cosd (), my_tand () dapat mengembalikan 0,0 (atau -0,0) ada tidak ada perilaku 0,0 untuk digandakan.
chux - Reinstate Monica
@ chux Premis yang sin(-0.0)harus kembali -0adalah tersangka. Ini memperlakukan detail implementasi standar IEEE sebagai prinsip trigonometri. Meskipun ada prinsip matematika umum nol sebagai batas dua interval yang terkandung dalam implementasi IEEE, itu terjadi pada tingkat abstraksi yang tidak dalam trigonometri umum [karenanya variabilitas dalam fungsi trigonometri Anda kembali]. Yang terbaik yang bisa terjadi adalah Anda dapat mendefinisikan konvensi yang sewenang-wenang, tetapi akan berbeda dari math.hketidakseimbangan atas tanda nol.
ben rudgers
Catatan: Saya tidak menyarankan sin(-0.0)harus kembali -0.0, tapi itu my_sind(x)harus sesuai sin(x)saat xini +/-0.0. TKI: ikuti latihan sebelumnya. Lebih jauh pertanyaan itu sendiri adalah lebih lanjut tentang apa yang harus dilakukan kapan x != 0.0, harus my_sind(x)kembali -0.0seperti pada my_sind(180), dll? Mungkin jawaban / komentar Anda membahas hal itu - tetapi saya belum melihatnya.
chux - Reinstate Monica
@ chux Jika perilaku tidak terdefinisi, maka itu tidak terdefinisi. Seperti itulah C. Plauger tidak khawatir tentang +0versus -0ketika dia menulis math.hdua puluh tahun yang lalu. Tidak jelas bagi saya masalah apa yang membuat Anda khawatir tentang perbedaan yang diselesaikan.
ben rudgers
1
Mudah-mudahan Anda melihat bahwa untuk diterapkan dengan baik sin(rad)untuk nilai rad>0dan presisi apa pun tidak akan pernah menghasilkan 0.0karena pi tidak rasional. [Ref] (www.csee.umbc.edu/~phatak/645/supl/Ng-ArgReduction.pdf) Namun my_sind(deg)menghasilkan yang tepat 0.0(salah + atau -) setiap kelipatan 180.0karena nilai 0,0 adalah hasil matematika yang benar. "Prinsip tercengang" menyarankan pengembalian 0,0 dalam kasus ini. Pertanyaan saya apakah harus -0.0dikembalikan dalam kasus ini?
chux - Reinstate Monica