Bertanya-tanya apakah ada cara nontrivial untuk menemukan tanda bilangan ( fungsi signum )?
Mungkin solusi yang lebih pendek / lebih cepat / lebih elegan daripada yang sudah jelas
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
Jawaban singkat!
Gunakan ini dan Anda akan aman dan cepat (sumber: moz )
if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };
Anda mungkin ingin melihat kinerja dan biola perbandingan pemaksaan tipe
Waktu sudah lama berlalu. Lebih lanjut terutama karena alasan sejarah.
Hasil
Untuk saat ini kami memiliki solusi ini:
1. Jelas dan cepat
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
1.1. Modifikasi dari kbec - satu jenis lebih sedikit, lebih berkinerja, lebih pendek [tercepat]
function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }
peringatan: sign("0") -> 1
2. Elegan, pendek, tidak terlalu cepat [paling lambat]
function sign(x) { return x && x / Math.abs(x); }
hati-hati: sign(+-Infinity) -> NaN
,sign("0") -> NaN
Pada Infinity
nomor resmi di JS, solusi ini tampaknya tidak sepenuhnya benar.
3. Seni ... tapi sangat lambat [paling lambat]
function sign(x) { return (x > 0) - (x < 0); }
4. Menggunakan bit-shift
cepat, tapisign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Aman untuk mengetik [megafast]
! Sepertinya browser (terutama chrome v8) membuat beberapa optimasi ajaib dan solusi ini ternyata jauh lebih berkinerja daripada yang lain, bahkan daripada (1.1) meskipun berisi 2 operasi tambahan dan secara logis tidak pernah bisa lebih cepat.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
Alat
Perbaikan dipersilakan!
[Offtopic] Jawaban yang diterima
Andrey Tarantsov - +100 untuk seni, tapi sayangnya itu sekitar 5 kali lebih lambat dari pendekatan yang sudah jelas
Frédéric Hamidi - entah bagaimana jawaban yang paling disukai (untuk saat ini menulis) dan itu agak keren, tapi jelas bukan bagaimana hal-hal harus dilakukan, imho. Juga tidak menangani nomor Infinity dengan benar, yang juga merupakan angka, lho.
kbec - adalah perbaikan dari solusi yang sudah jelas. Tidak terlalu revolusioner, tetapi secara keseluruhan saya menganggap pendekatan ini sebagai yang terbaik. Pilih dia :)
sumber
0
adalah kasus khusustest everything
versi tersebut, Safe akan menolak untuk menguji nilai-nilai khusus, jadi akan lebih cepat! Coba jalankanonly integers
pengujian sebagai gantinya. Selain itu, JSPerf hanya melakukan tugasnya, bukan tentang menyukainya. :)typeof x === "number"
memberikan keajaiban pada kinerja. Tolong, buat lebih banyak berjalan, terutama FF, Opera dan IE untuk membuatnya jelas.Math.sign()
(0 === 0, tidak secepat "Aman") yang muncul di FF25 dan akan datang di chrome.Jawaban:
Versi solusi cepat yang lebih elegan:
sumber
var sign = (number)? ((number < 0)? -1 : 1 ) : 0
Math.sign(number)
Membagi bilangan dengan nilai absolutnya juga memberikan tandanya. Menggunakan operator logika AND yang hubung singkat memungkinkan kita untuk kasus khusus
0
sehingga kita tidak berakhir membaginya:sumber
var sign = number && number / Math.abs(number);
berjaganumber = 0
0
perlu menggunakan kasing khusus. Jawaban diperbarui sesuai. Terima kasih :)Fungsi yang Anda cari disebut signum , dan cara terbaik untuk mengimplementasikannya adalah:
sumber
Haruskah ini tidak mendukung nol yang bertanda tangan JavaScript (ECMAScript)? Tampaknya berfungsi saat mengembalikan x daripada 0 dalam fungsi "megafast":
Ini membuatnya kompatibel dengan draf ECMAScript's Math.sign ( MDN ):
sumber
Bagi orang yang tertarik dengan apa yang sedang terjadi dengan browser terbaru, di versi ES6 ada metode Math.sign asli . Anda dapat memeriksa dukungannya di sini .
Pada dasarnya itu kembali
-1
,1
,0
atauNaN
sumber
Superfast jika Anda tidak membutuhkan Infinity dan mengetahui bahwa nomor tersebut adalah bilangan bulat, ditemukan di sumber openjdk-7:
java.lang.Integer.signum()
sumber
Saya pikir saya akan menambahkan ini hanya untuk bersenang-senang:
0 dan NaN akan mengembalikan -1
berfungsi dengan baik pada +/- Infinity
sumber
Solusi yang berfungsi pada semua angka, serta
0
dan-0
, sertaInfinity
dan-Infinity
, adalah:Lihat pertanyaan " Apakah +0 dan -0 sama? " Untuk informasi lebih lanjut.
Peringatan: Tidak ada jawaban, termasuk sekarang standar
Math.sign
akan bekerja pada kasus0
vs-0
. Ini mungkin tidak menjadi masalah bagi Anda, tetapi dalam implementasi fisika tertentu itu mungkin penting.sumber
Anda dapat menggeser nomor tersebut dan memeriksa Bit Paling Signifikan (MSB). Jika MSB adalah 1 maka angkanya negatif. Jika 0 maka angkanya positif (atau 0).
sumber
var sign = number < 0 : 1 : 0
n & 0x80000000
seperti bitmask. Adapun konversi ke 0,1, -1:n && (n & 0x80000000 ? -1 : 1)
-5e32
dan itu rusak.ToInt32
. Jika Anda membaca di sana (bagian 9.5) ada modulus yang mempengaruhi nilai angka karena kisaran integer 32-bit lebih kecil dari kisaran tipe Nomor js. Jadi itu tidak akan berhasil untuk nilai-nilai itu, atau ketidakterbatasan. Saya masih suka jawabannya.Saya baru saja akan menanyakan pertanyaan yang sama, tetapi menemukan solusi sebelum saya selesai menulis, melihat Pertanyaan ini sudah ada, tetapi tidak melihat solusi ini.
(n >> 31) + (n > 0)
tampaknya akan lebih cepat dengan menambahkan terner sekalipun
(n >> 31) + (n>0?1:0)
sumber
Sangat mirip dengan jawaban Martijn ini
Saya merasa lebih mudah dibaca. Juga (atau, tergantung pada sudut pandang Anda, bagaimanapun), itu juga menyimpan hal-hal yang dapat diartikan sebagai angka; misalnya, kembali
-1
saat disajikan dengan'-5'
.sumber
Saya tidak melihat arti praktis mengembalikan -0 dan 0 dari
Math.sign
jadi versi saya adalah:sumber
Metode yang saya ketahui adalah sebagai berikut:
Tanda matematika (n)
var s = Math.sign(n)
Ini adalah fungsi asli, tetapi yang paling lambat dari semuanya karena overhead panggilan fungsi. Namun ia menangani 'NaN' di mana yang lain di bawah ini mungkin hanya menganggap 0 (yaitu, tanda Matematika ('abc') adalah NaN).
((n> 0) - (n <0))
var s = ((n>0) - (n<0));
Dalam hal ini hanya sisi kiri atau kanan yang dapat menjadi 1 berdasarkan tanda. Ini akan menghasilkan
1-0
(1),0-1
(-1), atau0-0
(0).Kecepatan yang satu ini tampaknya leher dan leher dengan yang berikutnya di bawah di Chrome.
(n >> 31) | (!! n)
var s = (n>>31)|(!!n);
Menggunakan "Pergeseran kanan yang menyebarkan tanda". Pada dasarnya menggeser 31 tetes semua bit kecuali tanda. Jika tanda diset, ini menghasilkan -1, jika tidak maka 0. Benar
|
tes positif dengan mengubah nilai menjadi boolean (0 atau 1 [BTW: string non-numerik, seperti!!'abc'
, menjadi 0 dalam kasus ini, dan bukan NaN]) lalu menggunakan operasi bitwise OR untuk menggabungkan bit.Ini tampaknya kinerja rata-rata terbaik di seluruh browser (paling tidak terbaik di Chrome dan Firefox), tetapi bukan yang tercepat di SEMUA browser tersebut. Untuk beberapa alasan, operator terner lebih cepat di IE.
n? n <0? -1: 1: 0
var s = n?n<0?-1:1:0;
Tercepat di IE karena alasan tertentu.
jsPerf
Pengujian dilakukan: https://jsperf.com/get-sign-from-value
sumber
Dua sen saya, dengan fungsi yang mengembalikan hasil yang sama seperti yang akan dilakukan Math.sign, yaitu tanda (-0) -> -0, tanda (-Infinity) -> -Infinity, tanda (null) -> 0 , tanda (tidak ditentukan) -> NaN, dll.
Jsperf tidak mengizinkan saya membuat pengujian atau revisi, maaf karena tidak dapat memberi Anda pengujian (saya telah mencoba jsbench.github.io, tetapi hasilnya tampak lebih mirip satu sama lain daripada dengan Jsperf ...)
Jika seseorang dapat menambahkannya ke revisi Jsperf, saya akan penasaran untuk melihat bagaimana perbandingannya dengan semua solusi yang diberikan sebelumnya ...
Terima kasih!
Jim.
EDIT :
Saya seharusnya menulis:
(
(+x && -1)
bukan(x && -1)
) untuk menanganisign('abc')
dengan benar (-> NaN)sumber
Math.sign tidak didukung di IE 11. Saya menggabungkan jawaban terbaik dengan jawaban Math.sign:
Sekarang, seseorang dapat menggunakan Math.sign secara langsung.
sumber