Go: matematika/bit: perpustakaan memutar bit bilangan bulat

Dibuat pada 11 Jan 2017  ·  168Komentar  ·  Sumber: golang/go

Diskusi sebelumnya di https://github.com/golang/go/issues/17373 dan https://github.com/golang/go/issues/10757.

Abstrak

Proposal ini memperkenalkan satu set API untuk memutar bit bilangan bulat.

Latar belakang

Proposal ini memperkenalkan satu set API untuk memutar bit bilangan bulat. Untuk proposal ini kami tertarik pada fungsi-fungsi berikut:

  • ctz - hitung angka nol yang tertinggal.
  • clz - hitung angka nol di depan; log_2.
  • popcnt - menghitung populasi; jarak hamming; paritas bilangan bulat.
  • bswap - membalik urutan byte.

Fungsi-fungsi ini dipilih dengan survei:

Kami membatasi diri pada empat fungsi ini karena memutar-mutar lainnya
trik sangat sederhana untuk diterapkan menggunakan perpustakaan yang diusulkan,
atau konstruksi Go yang sudah tersedia.

Kami menemukan implementasi untuk subset dari fungsi memutar-mutar yang dipilih
dalam banyak paket termasuk runtime, compiler dan tools:

| paket | clz | ctz | popcnt | bswap |
| --- | --- | --- | --- | --- |
| matematika/besar | X | X | | |
| waktu proses/internal/sistem | X | X | | X |
| alat/wadah/intset | X | | X | |
| cmd/kompilasi/internal/ssa | X | | X | |
| code.google.com/p/intmath | X | X | | |
| github.com/hideo55/go-popcount | | | X (asm) | |
| github.com/RoaringBitmap/roaring | | X | X (asm) | |
| github.com/tHinqa/bitset | X | X | X | |
| github.com/willf/bitset | X | | X (asm) | |
| gopl.io/ch2/popcount | | | X | |
| bawaan GCC | X | X | X | X |

Banyak paket lain mengimplementasikan subset dari fungsi-fungsi ini:

Demikian pula penyedia perangkat keras telah mengakui pentingnya
fungsi tersebut dan termasuk dukungan tingkat alat berat.
Tanpa dukungan perangkat keras, operasi ini sangat mahal.

| lengkungan | clz | ctz | popcnt | bswap |
| --- | --- | --- | --- | --- |
| AMD64 | X | X | X | X |
| LENGAN | X | X | ? | X|
| ARM64 | X | X | ? | X|
| S390X | X | X | ? | X|

Semua fungsi bit twiddling, kecuali popcnt, sudah diimplementasikan oleh runtime/internal/sys dan menerima dukungan khusus dari kompiler untuk "membantu mendapatkan performa terbaik". Namun, dukungan kompiler terbatas pada paket runtime dan pengguna Golang lainnya harus mengimplementasikan kembali varian yang lebih lambat dari fungsi ini.

Usul

Kami memperkenalkan perpustakaan std baru math/bits dengan API eksternal berikut, untuk menyediakan implementasi kompiler / perangkat keras yang dioptimalkan dari fungsi clz, ctz, popcnt dan bswap.

package bits

// SwapBytes16 reverses the order of bytes in a 16-bit integer.
func SwapBytes16(uint16) uint16
// SwapBytes32 reverses the order of bytes in a 32-bit integer.
func SwapBytes32(uint32) uint32
// SwapBytes64 reverses the order of bytes in a 64-bit integer.
func SwapBytes64(uint64) uint64

// TrailingZeros32 counts the number of trailing zeros in a 32-bit integer, and if all are zero, then 32.
func TrailingZeros32(uint32) uint
// TrailingZeros64 counts the number of trailing zeros in a 64-bit integer, and if all are zero, then 64.
func TrailingZeros64(uint64) uint

// LeadingZeros32 counts the number of trailing zeros in a 32-bit integer, and if all are zero, then 32.
func LeadingZeros32(uint32) uint
// LeadingZeros64 counts the number of trailing zeros in a 64-bit integer, and if all are zero, then 64.
func LeadingZeros64(uint64) uint

// Ones32 counts the number of bits set in a 32-bit integer.
func Ones32(uint32) uint
// Ones64 counts the number of bits set in a 64-bit integer.
func Ones64(uint64) uint

Alasan

Alternatif untuk proposal ini adalah:

  • Fungsi memutar-mutar bit diimplementasikan di perpustakaan eksternal yang tidak didukung oleh kompiler. Pendekatan ini berhasil dan merupakan keadaan saat ini. Runtime menggunakan metode yang didukung kompiler, sementara pengguna Golang terus menggunakan implementasi yang lebih lambat.
  • Pustaka eksternal didukung oleh kompiler. Mengingat bahwa kami mengharapkan perpustakaan ini untuk menggantikan runtime/internal/sys, itu berarti perpustakaan ini harus dikunci dengan kompiler dan hidup di perpustakaan standar.

Kesesuaian

Proposal ini tidak mengubah atau merusak API stdlib yang ada dan sesuai dengan pedoman yang kompatibel.

Penerapan

SwapBytes, TrailingZeros dan LeadingZeros sudah diimplementasikan. Satu-satunya fungsi yang hilang adalah Ones yang dapat diimplementasikan mirip dengan fungsi lainnya. Jika proposal ini diterima, proposal ini dapat diimplementasikan tepat waktu untuk Go1.9.

Masalah terbuka (jika berlaku)

Nama-nama sulit, gudang sepeda ada di komentar.

Harap sarankan fungsi tambahan untuk dimasukkan dalam komentar. Idealnya, harap sertakan di mana fungsi tersebut digunakan di stdlib (misalnya matematika/besar), alat atau paket populer.

Sejauh ini fungsi-fungsi berikut telah diusulkan dan sedang dipertimbangkan:

  • Putar Kiri / Putar Kanan

    • Kelebihan: &63 tidak perlu lagi mengkompilasi rotasi dengan argumen non-const ke satu instruksi pada x86, x86-64..

    • Cons: sangat pendek/sederhana untuk diterapkan dan sebaris.

    • Digunakan: crypto/ menggunakan putaran konstan yang ditangani dengan benar oleh kompiler.

  • ReverseBits

    • Kelebihan: ?

    • Kontra: ?

    • Digunakan: ?

  • Tambah/Sub dengan membawa kembali

    • Pro: Mahal sebaliknya

    • Kontra: ?

    • Digunakan: matematika/besar

Sejarah

14.Jan: Mengklarifikasi output TrailingZeros dan LeadingZeros ketika argumennya 0.
14.Jan: Metode yang diganti namanya: CountTrailingZeros -> TrailingZeros, CountLeadingZeros -> LeadingZeros, CountOnes -> Ones.
13.Jan: Nama arsitektur tetap.
11.Jan: Proposal awal dibuka untuk umum.

FrozenDueToAge Proposal-Accepted

Komentar yang paling membantu

Orang yang menulis kode ingin memutar ke kiri atau ke kanan. Mereka tidak ingin memutar ke kiri atau ke kanan, tergantung. Jika kami hanya menyediakan rotate-left, maka siapa pun yang ingin memutar ke kanan harus menulis ekspresi untuk mengubah rotasi kanan mereka menjadi rotasi kiri. Ini adalah jenis ekspresi yang dapat dilakukan komputer secara sepele tetapi pemrogram akan membuat kesalahan. Mengapa membuat programmer menulisnya sendiri?

Semua 168 komentar

@brtzsnr mungkin Anda harus mengirimkan dokumen ini ke repo proposal sebagaimana diuraikan dalam langkah-langkah proses proposal ?

Karena sudah turun harga mengikuti template, seharusnya mudah untuk menyalin-menempel ke CL membuat file design/18616-bit-twiddling.md (atau apa pun).

@cespare dari https://github.com/golang/proposal "jika penulis ingin menulis dokumen desain, maka mereka dapat menulisnya". Ini dimulai sebagai dokumen desain, jika ada perasaan kuat bahwa saya harus mengirimkan ini, saya baik-baik saja.

Saya akan baik-baik saja dengan ini, itu adalah fungsi yang cukup umum digunakan di banyak perpustakaan algoritmik dan matematika/bit sepertinya tempat yang tepat.

(Untuk satu, matematika/besar juga mengimplementasikan nlz (== clz).)

Mungkin ada beberapa penumpahan sepeda tentang nama-nama itu. Saya lebih suka fungsi mengatakan apa yang mereka kembalikan daripada apa yang mereka lakukan; yang pada gilirannya dapat menyebabkan nama yang lebih pendek. Contohnya:

bits.TrailingZeros64(x) daripada bits.CountTrailingZeros64(x)

Dan seterusnya.

Proposal tampaknya cukup jelas dan minimal - dokumen desain tampaknya berlebihan. Saya pikir CL akan lebih tepat saat ini.

(Itu adalah CL dengan API dan implementasi dasar - untuk tujuan diskusi menggantikan dokumen desain. Kami masih perlu memutuskan apakah proposal ini harus diterima atau tidak.)

@brtzsnr telah menulis dokumen desain: ada dalam deskripsi masalah dan mengikuti template . Saya berasumsi bahwa ada beberapa nilai memiliki semua dokumen ini di satu lokasi.

Lengkungan terakhir yang tercantum dalam tabel dukungan perangkat keras adalah "BSWAP" -- salah ketik?

Terima kasih telah menulis ini.

String doc untuk ctz dan clz harus menentukan hasilnya ketika melewati 0.

Saya juga lebih suka (misalnya) TrailingZeros32 daripada CountTrailingZeros32. Saya juga akan senang dengan Ctz32. Ini ringkas, akrab bagi kebanyakan orang, dan mudah di-google untuk sisanya.

Terima kasih atas proposalnya.
Saya hanya ingin menambahkan bahwa kami mungkin juga ingin fokus pada penggunaan, daripada hanya fokus pada instruksi. Misalnya, @dr2chase pernah ditemukan ada beberapa fungsi log2 di compiler/assembler. Itu dekat dengan CLZ tetapi tidak sama. Fungsi seperti ini mungkin juga ada dalam paket bit twiddling. Dan mungkin juga menyertakan fungsi berguna yang tidak terkait dengan instruksi ini.

Bagaimana kalau kami menyediakan paket untuk semua bit twiddling primitif yang didefinisikan oleh
Kesenangan Hacker?

Saat mendesain paket, kita tidak perlu mempertimbangkan apakah fungsinya
dapat diinternalisasikan atau tidak. Optimalisasi bisa terjadi nanti. Itu adalah,
jangan biarkan implementasi level rendah mengontrol paket level atas
antarmuka. Kami menginginkan antarmuka paket yang bagus, meskipun beberapa di antaranya tidak dapat
dipetakan ke instruksi tunggal.

@minux , untungnya, setiap fungsi memutar-mutar bit yang saya butuhkan sejauh ini persis seperti yang ada dalam proposal ini.

Mengikuti Hacker's Delight memiliki keuntungan bahwa kita tidak perlu membuang waktu untuk berdebat tentang nama.

Saya ingin menambahkan yang berikut ini:

ReverseBits (untuk uint32 dan uint64)
RotateLeft/Right (dapat diperluas inline dengan dua shift, tetapi compiler
tidak dapat selalu melakukan transformasi karena masalah rentang shift)

Mungkin juga dua hasil berupa penambahan dan pengurangan? Misalnya

func AddUint32(x, y, carryin uint32) (carryout, sum uint32) // carryin must
menjadi 0 atau 1.
Dan juga untuk uint64.

Dan SqrtInt.

Banyak saran saya tidak dapat diimplementasikan dalam satu instruksi, tapi
itulah intinya: kami ingin paket twiddling yang bagus, bukan sekadar
paket intrik. Jangan biarkan perangkat keras membatasi paket tingkat tinggi
antarmuka.

Terkait, berfungsi untuk memeriksa apakah add/multiply akan meluap.

Poin data terkait: ada berbagai masalah yang telah diajukan untuk cgo yang lebih cepat. Dalam salah satu contoh tersebut (proposal #16051), fakta bahwa implementasi cepat dari bsr/ctz/etc. mungkin terjadi disebut-sebut sebagai semoga memotong set kasus penggunaan di mana orang yang menulis go tergoda untuk menggunakan cgo.

@clements berkomentar pada 1 Juli 2016:

@eloff , ada beberapa diskusi (meskipun tidak ada proposal konkret untuk pengetahuan saya) untuk menambahkan fungsi untuk hal-hal seperti popcount dan bsr yang akan dikompilasi sebagai intrinsik jika didukung (seperti math.Sqrt hari ini). Dengan 1.7 kami mencoba ini di runtime, yang sekarang memiliki ctz intrinsik yang tersedia di amd64 SSA. Jelas itu tidak menyelesaikan masalah keseluruhan, tetapi itu akan menghilangkan satu alasan lagi untuk menggunakan cgo dalam konteks overhead yang rendah.

Banyak orang (termasuk saya sendiri) tertarik untuk pergi karena kinerjanya, jadi hal-hal seperti proposal saat ini untuk sedikit memutar-mutar akan membantu. (Dan ya, cgo juga sekarang lebih cepat di 1.8, yang bagus juga).

RotateLeft/Right (dapat diperluas inline dengan dua shift, tetapi compiler
tidak dapat selalu melakukan transformasi karena masalah rentang shift)

@minux Bisakah Anda menjelaskan apa masalahnya?

@brtzsnr : Saya pikir apa yang dimaksud Minux adalah ketika Anda menulis (x << k) | (x >> (64-k)) , Anda tahu Anda menggunakan 0 <= k < 64 , tetapi kompiler tidak dapat membaca pikiran Anda, dan itu tidak jelas diturunkan dari kode. Jika kita memiliki fungsi

func leftRot(x uint64, k uint) uint64 {
   k &= 63
   return (x << k) | (x >> (64-k))
}

Kemudian kita dapat memastikan (melalui &63) bahwa kompiler mengetahui bahwa rentang k dibatasi.
Jadi jika kompiler tidak dapat membuktikan bahwa input dibatasi, maka kita memerlukan AND tambahan. Itu lebih baik daripada tidak menghasilkan rakitan putar sama sekali.

Pada Jumat, 13 Januari 2017 pukul 22:37, Keith Randall [email protected]
menulis:

@brtzsnr https://github.com/brtzsnr : Saya pikir apa yang dimaksud Minux
adalah bahwa ketika Anda menulis (x << k) | (x >> (64-k)), Anda tahu Anda menggunakan 0
<= k <64, tetapi kompiler tidak dapat membaca pikiran Anda, dan itu tidak jelas
diturunkan dari kode. Jika kita memiliki fungsi

func leftRot(x uint64, k uint) uint64 {
k &= 63
kembali (x << k) | (x >> (64-k))
}

Kemudian kita dapat memastikan (melalui &63) bahwa kompiler mengetahui bahwa jangkauannya
dari k dibatasi.
Jadi jika kompiler tidak dapat membuktikan bahwa input dibatasi, maka kita memerlukan tambahan
DAN. Itu lebih baik daripada tidak menghasilkan rakitan putar sama sekali.

Benar. Jika kita mendefinisikan fungsi RotateLeft dan RotateRight, kita dapat secara formal
tentukan fungsi putar k bit kiri/kanan (tidak peduli apa k itu). Ini adalah
mirip dengan bagaimana operasi shift kami didefinisikan. Dan definisi ini juga
memetakan ke instruksi rotasi aktual dengan baik (tidak seperti shift, di mana lebih banyak
definisi intuitif membutuhkan perbandingan pada arsitektur tertentu).

Bagaimana dengan fungsi byte dan bit shuffling (dan unshuffling) yang digunakan oleh library kompresi blosc ? Slide (pengocokan dimulai dari slide 17). Fungsi-fungsi ini dapat dipercepat SSE2/AVX2.

Pada Jumat, 13 Januari 2017 pukul 23:24, opennota [email protected] menulis:

Bagaimana dengan fungsi pengocokan byte dan bit yang digunakan oleh blosc?
https://github.com/Blosc/c-blosc perpustakaan kompresi? Slide
http://www.slideshare.net/PyData/blosc-py-data-2014 (pengocokan
dimulai dari slide 17). Fungsi-fungsi ini dapat dipercepat SSE2/AVX2.

SIMD adalah masalah yang lebih besar dan di luar cakupan paket ini. Dia

17373.

Fungsi yang diusulkan saat ini memiliki implementasi asli Go yang jauh lebih besar dan secara tidak proporsional lebih mahal daripada optimal. Di sisi lain, rotate mudah untuk menulis sebaris dengan cara yang dapat dikenali oleh kompiler.

@minux dan juga semua orang: Apakah Anda tahu di mana rotasi kiri/kanan digunakan dengan jumlah bit yang diputar tidak konstan? crypto/sha256 menggunakan rotate misalnya, tetapi dengan jumlah bit yang konstan.

rotate mudah untuk menulis sebaris dengan cara yang dapat dikenali oleh kompiler.

Sangat mudah bagi mereka yang akrab dengan internal kompiler. Menempatkannya dalam paket matematika/bit membuatnya mudah bagi semua orang.

Tahukah Anda di mana rotasi kiri/kanan digunakan dengan jumlah bit yang diputar tidak konstan?

Berikut ini contoh dari #9337:

https://play.golang.org/p/rmDG7MR5F9

Dalam setiap pemanggilan, ini adalah jumlah bit yang diputar secara konstan setiap kali, tetapi fungsi itu sendiri saat ini tidak digarisbawahi, sehingga ia mengkompilasi tanpa instruksi rotasi apa pun. Fungsi perpustakaan matematika/bit pasti akan membantu di sini.

Pada Sat, Jan 14, 2017 at 05:05, Alexandru Moşoi [email protected]
menulis:

Fungsi yang diusulkan saat ini memiliki implementasi asli Go yang jauh lebih besar
dan secara tidak proporsional lebih mahal daripada optimal. Di sisi lain putar
mudah untuk menulis sebaris dengan cara yang dapat dikenali oleh kompiler.

Seperti yang saya tekankan berkali-kali dalam masalah ini, ini bukan cara yang benar untuk
merancang paket Go. Ini mengikat terlalu banyak ke perangkat keras yang mendasarinya. Apa yang kita
inginkan adalah paket memutar-mutar sedikit yang baik yang umumnya berguna. Apakah
fungsi dapat diperluas menjadi satu instruksi tidak relevan selama
karena antarmuka API terkenal dan umumnya berguna.

@minux https://github.com/minux dan juga semua orang: Tahukah Anda
di mana rotasi kiri/kanan digunakan dengan jumlah bit yang tidak konstan?
crypto/sha256 menggunakan rotate misalnya, tetapi dengan jumlah bit yang konstan.

Bahkan jika dalam masalah sebenarnya jumlah bit rotasi konstan,
compiler mungkin tidak dapat melihat itu. Misalnya ketika hitungan shift disimpan
dalam array, atau sembunyikan di penghitung loop atau bahkan pemanggil yang tidak sebaris
fungsi.

Salah satu contoh sederhana menggunakan jumlah variabel putar adalah hal yang menarik
implementasi popcount:
// https://play.golang.org/p/ctNRXsBt0z

func RotateRight(x, k uint32) uint32
func Popcount(x uint32) int {
    var v uint32
    for i := v - v; i < 32; i++ {
        v += RotateRight(x, i)
    }
    return int(-int32(v))
}

@josharian Contoh terlihat seperti keputusan inliner yang buruk jika rot tidak inline. Apakah Anda mencoba menulis fungsi sebagai func rot(x, n) alih-alih rot = func(x, n) ?

@minux : saya setuju dengan anda. Saya tidak mencoba mengikat API ke set instruksi tertentu; dukungan perangkat keras adalah bonus yang bagus. Fokus utama saya adalah menemukan penggunaan dalam kode nyata (bukan kode mainan) untuk memahami konteksnya, apa tanda tangan terbaik dan betapa pentingnya menyediakan fungsi favorit semua orang. Janji kompatibilitas akan menggigit kita nanti jika kita tidak melakukannya dengan benar sekarang.

Misalnya: Apa yang harus menjadi tanda tangan add dengan carry return? Add(x, y uint64) (c, s uint64) ? Melihat math/big kita mungkin membutuhkan Add(x, y uintptr) (c, s uintptr) juga.

Contohnya terlihat seperti keputusan inliner yang buruk jika rot tidak digariskan.

Ya. Ini adalah bagian dari bug yang mengeluh tentang inlining. :)

Apakah Anda mencoba menulis fungsi sebagai func rot(x, n) alih-alih rot = func(x, n)?

Itu bukan kode saya--dan itu bagian dari intinya. Lagi pula, itu adalah kode yang masuk akal.

Akan lebih baik untuk menjamin (dalam dokumentasi paket?) bahwa fungsi rotate dan byte-swap adalah operasi waktu-konstan sehingga dapat digunakan dengan aman dalam algoritme kripto. Mungkin sesuatu untuk dipikirkan untuk fungsi lain juga.

Pada Kam, 19 Jan 2017 jam 11:50, Michael Munday [email protected]
menulis:

Akan lebih baik untuk menjamin (dalam dokumentasi paket?)
fungsi rotate dan byte-swap adalah operasi waktu-konstan sehingga mereka
dapat digunakan dengan aman dalam algoritma kripto. Mungkin sesuatu untuk dipikirkan
untuk fungsi lain juga.

implementasi sepele byte swap adalah waktu yang konstan, tetapi jika yang mendasarinya
arsitektur tidak memberikan instruksi pergeseran variabel, itu akan sulit
untuk menjamin implementasi rotasi waktu yang konstan. Mungkin Go tidak akan pernah lari
pada arsitektur tersebut sekalipun.

Yang mengatakan, ada juga kemungkinan yang tidak dapat diabaikan bahwa yang mendasarinya
mikroarsitektur menggunakan shifter multi-siklus, dan kami tidak dapat menjamin
rotasi waktu yang konstan pada implementasi tersebut.

Jika waktu konstan yang ketat diperlukan, mungkin satu-satunya cara adalah menulis perakitan
(dan bahkan dalam kasus itu, itu membuat asumsi kuat bahwa semua yang digunakan
instruksi itu sendiri adalah waktu konstan, yang secara implisit tergantung pada
arsitektur mikro.)

Sementara saya memahami perlunya jaminan seperti itu, tetapi sebenarnya di luar
kendali kita.

Saya cenderung setuju dengan @minux. Jika Anda menginginkan primitif kripto waktu konstan, mereka harus hidup dalam kripto/halus. crypto/halus dapat dengan mudah dialihkan ke matematika/bit pada platform di mana implementasi tersebut telah diverifikasi. Mereka dapat melakukan sesuatu yang lain jika implementasi waktu yang lebih lambat tetapi konstan diperlukan.

Ini sepertinya layak dilakukan. Berangkat ke @griesemer dan @randall77 ke dokter hewan. Langkah selanjutnya tampak seperti dokumen desain yang diperiksa ke tempat biasa (saya memang melihat sketsa di atas).

Sekarang proposal ini dapat diteruskan, kita harus menyetujui detail API. Pertanyaan yang saya lihat saat ini:

  • fungsi mana yang harus disertakan?
  • tipe mana yang harus ditangani ( uint64 , uint32 saja, atau uint64 , uint32 , uint16 , uint8 , atau uintptr )?
  • detail tanda tangan (misalnya TrailingZeroesxx(x uintxx) uint , dengan xx = 64, 32, dll., vs TrailingZeroes(x uint64, size uint) uint mana ukurannya adalah salah satu dari 64, 32, dll. - yang terakhir akan mengarah ke API yang lebih kecil dan mungkin masih cukup cepat dep. pada implementasi)
  • beberapa nama sepeda shedding (saya suka terminologi "Hacker's Delight" tetapi mengejanya mungkin lebih tepat)
  • apakah ada tempat yang lebih baik daripada matematika/bit untuk paket ini.

@brtzsnr Apakah Anda ingin terus mempelopori upaya ini? Saya baik-baik saja jika Anda ingin mengambil desain awal Anda dan mengulanginya dalam edisi ini atau jika Anda lebih suka menyiapkan dokumen desain khusus. Atau, saya dapat mengambil ini dan mendorongnya ke depan. Saya suka melihat ini masuk selama fase 1.9.

Saya lebih suka nama xx yang dieja, secara pribadi: bits.TrailingZeroes(uint64(x), 32) lebih rumit dan kurang mudah dibaca daripada bits.TrailingZeroes32(x), imo, dan skema penamaan itu akan bekerja dengan ukuran variabel platform uintptr lebih mudah (xx = Ptr?).

Itu juga akan membuatnya lebih jelas jika Anda, katakanlah, tidak menyertakan uint8 dalam rilis pertama tetapi menambahkannya nanti—tiba-tiba akan ada banyak fungsi xx = 8 baru alih-alih sekumpulan komentar dokumen yang diperbarui yang menambahkan 8 ke daftar ukuran yang valid dengan catatan di dokumen rilis yang mudah dilewatkan.

Jika nama yang dieja digunakan, saya pikir istilah kesenangan Peretas harus dimasukkan dalam deskripsi sebagai "juga dikenal sebagai" sehingga pencarian (di halaman atau melalui mesin pencari) menemukan nama kanonik dengan mudah jika Anda mencari ejaan yang salah .

Saya pikir matematika/bit adalah tempat yang bagus—ini matematika dengan bit.

Saya harus mencatat bahwa SwapBytes{16,32,64} lebih konsisten dengan fungsi di sync/atomic daripada SwapBytes(..., bitSize uint) .

Meskipun paket strconv menggunakan pola ParseInt(..., bitSize int) , ada lebih banyak hubungan antara bits dan atomic , daripada dengan strconv .

Tiga alasan saya tidak suka SwapBytes(uint64, size uint):

  1. orang mungkin menggunakannya dalam kasus di mana ukuran tidak mengkompilasi konstanta waktu (pada
    setidaknya ke kompiler saat ini),
  2. itu memerlukan banyak konversi tipe. Pertama yang mengonversi uint32 ke
    uint64, dan kemudian mengubahnya kembali.
  3. kita harus memesan nama generik SwapBytes untuk generik masa depan
    versi fungsi (ketika Go mendapat dukungan generik).

@griesemer Robert, tolong ambil alih proposalnya. Saya akan punya waktu untuk mendorong proposal ini ke depan dalam satu bulan, tetapi kemajuan tidak boleh terhenti sampai saat itu.

Sepertinya ada preferensi yang jelas untuk tanda tangan formulir:

func fffNN(x uintNN) uint

yang membuka NN mana yang harus didukung. Mari kita fokus pada NN=64 untuk tujuan diskusi lanjutan. Akan mudah untuk menambahkan jenis yang tersisa sesuai kebutuhan (termasuk. uintptr).

Yang membawa kita langsung kembali ke proposal asli oleh @brtzsnr dan fungsi-fungsi berikut (dan variasinya masing-masing untuk jenis yang berbeda), ditambah apa yang disarankan orang sementara itu:

// LeadingZeros64 returns the number of leading zero bits in x.
// The result is 64 if x == 0.
func LeadingZeros64(x uint64) uint

// TrailingZeros64 returns the number of trailing zero bits in x.
// The result is 64 if x == 0.
func TrailingZeros64(x uint64) uint

// Ones64 returns the number of bits set in x.
func Ones64(x uint64) uint

// RotateLeft64 returns the value of x rotated left by n%64 bits.
func RotateLeft64(x uint64, n uint) uint64

// RotateRight64 returns the value of x rotated right by n%64 bits.
func RotateRight64(x uint64, n uint) uint64

Kami mungkin memiliki satu set fungsi Swap juga. Secara pribadi saya skeptis tentang ini: 1) Saya tidak pernah membutuhkan SwapBits, dan sebagian besar penggunaan SwapBytes adalah karena kode yang sadar-endian padahal seharusnya tidak. Komentar?

// SwapBits64 reverses the order of the bits in x.
func SwapBits64(x uint64) uint64

// SwapBytes64 reverses the order of the bytes in x.
func SwapBytes64(x uint64) uint64

Maka mungkin ada satu set operasi bilangan bulat. Mereka hanya akan ada dalam paket ini karena beberapa dari mereka (misalnya Log2) mungkin dekat dengan fungsi lain dalam paket ini. Fungsi-fungsi ini bisa berada di tempat lain. Mungkin nama paket bits perlu disesuaikan. Komentar?

// Log2 returns the integer binary logarithm of x.
// The result is the integer n for which 2^n <= x < 2^(n+1).
// If x == 0, the result is -1.
func Log2(x uint64) int

// Sqrt returns the integer square root of x.
// The result is the value n such that n^2 <= x < (n+1)^2.
func Sqrt(x uint64) uint64

Akhirnya, @minux menyarankan operasi seperti AddUint32 dll. Saya akan mengabaikannya untuk saat ini karena saya pikir mereka lebih sulit untuk ditentukan dengan benar (dan ada lebih banyak variasi). Kita bisa menghubungi mereka nanti. Mari kita mencapai beberapa konsensus di atas.

Pertanyaan:

  • Adakah pendapat tentang nama fungsi?
  • Adakah pendapat tentang operasi bilangan bulat?
  • Ada pendapat tentang nama/lokasi paket?

Saya lebih suka nama fungsi yang panjang. Go menghindari menyingkat dalam nama fungsi. Komentar dapat menyebutkan nama panggilan mereka ("nlz", "ntz", dll) untuk orang yang mencari paket seperti itu.

@griesemer , Anda tampaknya memiliki kesalahan ketik dalam pesan Anda. Komentar tidak cocok dengan tanda tangan fungsi.

Saya menggunakan SwapBits dalam aplikasi kompresi. Yang mengatakan, apakah arsitektur utama menyediakan kemampuan untuk melakukan pembalikan bit secara efisien? Saya berencana hanya melakukan dalam kode saya sendiri:

v := bits.SwapBytes64(v)
v = (v&0xaaaaaaaaaaaaaaaa)>>1 | (v&0x5555555555555555)<<1
v = (v&0xcccccccccccccccc)>>2 | (v&0x3333333333333333)<<2
v = (v&0xf0f0f0f0f0f0f0f0)>>4 | (v&0x0f0f0f0f0f0f0f0f)<<4

@bradfitz , @dsnet : Tanda tangan yang diperbarui (kesalahan ketik tetap). Juga pertanyaan yang diperbarui (orang lebih suka nama pintasan yang eksplisit).

Kecuali ada dukungan asli untuk bit-swapping, saya akan memilih untuk tidak menggunakan SwapBits . Ini bisa menjadi sedikit ambigu dengan nama saja apakah bit hanya ditukar dalam setiap byte, atau di seluruh uint64.

Mengapa mengecualikan sesuatu hanya berdasarkan ketersediaan instruksi? Terbalik sedikit
memiliki kegunaan penting dalam FFT.

Untuk menjawab pertanyaan Anda tentang ketersediaan instruksi bit terbalik: arm has
instruksi RBIT.

@griesemer Sejauh jenis tanda tangan fungsi seperti

func Ones64(x uint64) uint
func RotateLeft64(x uint64, n uint) uint64

Apakah RotateLeftN dll membutuhkan uints karena itu diperlukan untuk memudahkan intrinisasi (bila memungkinkan) atau hanya karena itu domainnya? Jika tidak ada kebutuhan teknis yang kuat, ada preseden yang lebih kuat untuk mengambil int, bahkan jika nilai negatif tidak masuk akal. Jika ada kebutuhan teknis yang kuat, haruskah mereka uintN untuk N yang sesuai untuk keteraturan?

Terlepas dari OnesN dan sejenisnya harus mengembalikan int kecuali jika operasi ini dapat dikomposisikan dengan operasi bit lain dalam hal ini mereka harus mengembalikan uintN untuk N yang sesuai.

@jimmyfrasche Karena itu domainnya. CPU tidak peduli. Apakah sesuatu adalah int atau uint tidak relevan untuk sebagian besar operasi kecuali perbandingan. Yang mengatakan, jika kita menjadikannya int, kita harus menjelaskan bahwa itu tidak pernah negatif (hasil), atau tidak boleh negatif (argumen), atau menentukan apa yang seharusnya dilakukan ketika negatif (argumen untuk rotasi). Kami mungkin bisa lolos hanya dengan satu Putar dalam kasus itu yang akan menyenangkan.

Saya tidak yakin bahwa menggunakan int membuat segalanya lebih mudah. Jika dirancang dengan benar, uints akan mengalir ke uints (itulah yang terjadi dalam matematika/besar) dan tidak diperlukan konversi. Tetapi bahkan jika konversi diperlukan, itu akan gratis dalam hal biaya CPU (meskipun tidak dalam hal keterbacaan).

Tapi saya senang mendengar/melihat argumen yang meyakinkan sebaliknya.

Jumlah bit putar harus uint (tanpa ukuran khusus) agar sesuai dengan
pergeseran operator bahasa.

Alasan untuk tidak menggunakan int adalah karena akan ada ambiguitas apakah
RotateRight -2 bit sama dengan RotateLeft 2 bit.

@minux Tidak ada ambiguitas ketika Rotate(x, n) didefinisikan untuk memutar x sebesar n mod 64 bit: Putar ke kiri sebesar 10 bit sama dengan memutar ke kanan sebesar 64-10 = 54 bit, atau (jika kita mengizinkan argumen int) sebesar -10 bit (dengan asumsi nilai positif berarti putar ke kiri). -10 mod 64 = 54. Kemungkinan besar kita mendapatkan efeknya secara gratis bahkan dengan instruksi CPU. Misalnya, instruksi 32bit x86 ROL/ROR sudah hanya melihat 5 bit terbawah dari register CL, secara efektif menjalankan mod 32 untuk rotasi 32 bit.

Satu-satunya argumen nyata adalah keteraturan dengan sisa stdlib. Ada banyak tempat di mana uint sangat masuk akal tetapi int digunakan sebagai gantinya.

Karena matematika/besar adalah pengecualian penting, saya tidak punya masalah dengan ini menjadi yang lain, tetapi itu adalah sesuatu yang perlu dipertimbangkan.

Saya berasumsi @minux berarti ambiguitas bagi seseorang yang membaca/

Haruskah bits.SwapBits benar-benar diberi nama dengan akhiran bit ketika nama paket sudah disebut bit? Bagaimana dengan bit.Swap?

Ide lain adalah bits.SwapN(v uint64, n int) daripada bits.SwapBytes di mana n mewakili jumlah bit untuk dikelompokkan untuk swap. Ketika n=1 bit dibalik, ketika n=8, byte ditukar. Salah satu manfaatnya adalah bits.SwapBytes tidak lagi harus ada, meskipun saya belum pernah melihat kebutuhan untuk nilai n lainnya, mungkin orang lain akan tidak setuju.

Seperti yang ditentukan di atas , LeadingZeros64 , TrailingZeros64 , Ones64 all LGTM.

Satu Rotate64 dengan jumlah rotasi yang ditandatangani menarik. Sebagian besar rotasi akan dengan jumlah yang konstan juga, jadi (jika/ketika ini menjadi intrinsik) tidak akan ada biaya runtime untuk tidak memiliki fungsi Kanan/Kiri yang terpisah.

Saya tidak memiliki pendapat yang kuat tentang bit/byte shuffling/swapping/reversing. Untuk membalikkan bit, bits.Reverse64 sepertinya nama yang lebih baik. Dan mungkin bits.ReverseBytes64 ? Saya menemukan Swap64 agak tidak jelas. Saya melihat daya tarik meminta Swap64 mengambil ukuran grup, tetapi apa perilakunya ketika ukuran grup tidak membagi 64 secara merata? Jika satu-satunya ukuran grup yang penting adalah 1 dan 8 , akan lebih mudah untuk memberi mereka fungsi terpisah. Saya juga bertanya-tanya apakah semacam manipulasi bidang bit umum mungkin lebih baik, mungkin melihat instruksi arm64 dan amd64 BMI2 untuk inspirasi.

Saya tidak yakin bahwa fungsi matematika bilangan bulat termasuk dalam paket ini. Mereka tampak lebih seperti termasuk dalam matematika paket, di mana mereka dapat menggunakan fungsi bit dalam implementasinya. Terkait, mengapa tidak func Sqrt(x uint64) uint32 (alih-alih mengembalikan uint64 )?

Meskipun AddUint32 dan teman-teman itu rumit, saya harap kita akhirnya mengunjungi mereka kembali. Selain itu, MulUint64 akan menyediakan akses ke HMUL, yang bahkan disediakan oleh RISC-V ISA super-minimalis sebagai instruksi. Tapi ya, mari kita masuk dulu; kami selalu dapat memperluas nanti.

bits tampaknya jelas seperti nama paket yang tepat. Saya tergoda untuk mengatakan jalur impor seharusnya hanya bits , bukan math/bits , tetapi saya tidak merasa kuat.

bit tampaknya jelas seperti nama paket yang tepat. Saya tergoda untuk mengatakan jalur impor seharusnya hanya bit, bukan matematika/bit, tetapi saya tidak merasa kuat.

IMO, jika itu hanya bits , (tanpa membaca dokumen paket) saya berharap itu agak mirip dengan paket bytes . Artinya, selain fungsi untuk beroperasi pada bit, saya berharap menemukan Reader dan Writer untuk membaca dan menulis bit ke/dari aliran byte. Membuatnya math/bits membuatnya lebih jelas itu hanya satu set fungsi stateless.

(Saya tidak mengusulkan agar kami menambahkan Pembaca/Penulis untuk aliran bit)

Rotate64 tunggal dengan jumlah rotasi yang ditandatangani menarik. Sebagian besar rotasi akan dengan jumlah yang konstan juga, jadi (jika/ketika ini menjadi intrinsik) tidak akan ada biaya runtime untuk tidak memiliki fungsi Kanan/Kiri yang terpisah.

Saya dapat melihat betapa nyamannya memiliki API paket yang sedikit lebih kecil dengan menggabungkan rotate left/right menjadi satu Rotate , tetapi kemudian ada juga masalah mendokumentasikan secara efektif parameter n ke menunjukkan bahwa:

  • negatif n menghasilkan rotasi ke kiri
  • nol n menghasilkan perubahan
  • positif n menghasilkan rotasi kanan

Bagi saya, tambahan mental dan dokumentasi overhead tampaknya tidak membenarkan menggabungkan keduanya menjadi satu Rotate . Memiliki RotateLeft dan RotateRight eksplisit di mana n adalah uint terasa lebih intuitif bagi saya.

@mdlayher Perlu diingat bahwa untuk n-bit kata yang diputar sebanyak k bit ke kiri sama dengan memutar nk bit ke kanan. Bahkan jika Anda memisahkan ini dalam dua fungsi, Anda masih perlu memahami bahwa memutar dengan k bit ke kiri selalu berarti memutar dengan (k mod n) bit (jika Anda memutar lebih dari n bit, Anda mulai lagi). Setelah Anda melakukannya, Anda bisa mengatakan bahwa fungsi putar selalu berputar sebanyak k mod n bit dan selesai. Tidak perlu menjelaskan nilai negatif atau fungsi kedua. Ini hanya berhasil. Ini sebenarnya lebih sederhana.

Selain itu, perangkat keras (misalnya pada x86) bahkan melakukan ini untuk Anda secara otomatis, bahkan untuk k yang tidak konstan.

@griesemer , kelemahan dari Rotate adalah ia tidak mengatakan arah mana yang positif. Apakah Rotate32(1, 1) sama dengan 2 atau 0x80000000? Misalnya, jika saya membaca kode yang menggunakan itu, saya akan mengharapkan hasilnya menjadi 2, tetapi ternyata @mdlayher mengharapkannya menjadi 0x80000000. Di sisi lain, RotateLeft dan RotateRight adalah nama yang tidak ambigu, terlepas dari apakah mereka mengambil argumen yang ditandatangani atau tidak. (Saya tidak setuju dengan @minux bahwa ambigu apakah RotateRight oleh -2 sama dengan RotateLeft 2. Ini tampak jelas setara dengan saya dan saya tidak melihat bagaimana lagi Anda bisa menentukannya.)

@clements yang dapat diperbaiki dengan hanya memiliki satu fungsi yang disebut RotateLeft64 dan menggunakan nilai negatif untuk memutar ke kanan. Atau dengan dokumen. (FWIW, dalam contoh Anda, saya juga mengharapkan 2, bukan 0x800000000.)

@josharian , saya setuju, meskipun tampaknya agak aneh untuk memiliki RotateLeft tanpa juga memiliki RotateRight . Konsistensi memiliki rotasi yang ditandatangani tampaknya berpotensi berharga jika rotasi dihitung, tetapi untuk rotasi konstan saya lebih suka membaca kode yang mengatakan "putar ke kanan dua bit" daripada "putar ke kiri hanya dengan

Masalah dengan memperbaiki ini dengan dokumen adalah bahwa dokumen tidak membantu keterbacaan kode yang memanggil fungsi.

Orang yang menulis kode ingin memutar ke kiri atau ke kanan. Mereka tidak ingin memutar ke kiri atau ke kanan, tergantung. Jika kami hanya menyediakan rotate-left, maka siapa pun yang ingin memutar ke kanan harus menulis ekspresi untuk mengubah rotasi kanan mereka menjadi rotasi kiri. Ini adalah jenis ekspresi yang dapat dilakukan komputer secara sepele tetapi pemrogram akan membuat kesalahan. Mengapa membuat programmer menulisnya sendiri?

Saya yakin.

@clements @ianlancetaylor Poin diambil. (Yang mengatakan, implementasi RotateLeft/Right mungkin hanya akan memanggil satu implementasi rotasi.)

Ide nama adalah untuk menempatkan jenis dalam nama paket daripada nama tanda tangan. bits64.Ones daripada bits.Ones64 .

@btracey , saya muntah di mulut saya sedikit di sana. :) Kami tidak memiliki flag64.Int atau math64.Floatfrombits atau sort64.Floats atau atomic64.StoreInt .

@bradfitz golang.org/x/image/math/f64 dan golang.org/x/image/math/f32 ada

Saya tidak memikirkan atomic sebagai preseden (untungnya tidak dalam penggunaan Go saya yang normal). Contoh lain berbeda karena paket lebih besar dari satu set fungsi yang diulang untuk sejumlah tipe yang berbeda.

Dokumentasi lebih mudah dilihat (misalnya, di godoc), ketika Anda membuka bits64 dan melihat
Ones LeadingZeros TrailingZeros

Alih-alih pergi ke bits dan melihat
Ones8 Ones16 Ones32 Ones64 LeadingZeros8 ...

@iand , itu juga cukup menjijikkan. Saya kira 32 dan 64 tidak terlihat bagus untuk semua sufiks numerik yang ada untuk Aff, Mat, dan Vec. Tetap saja, saya akan mengatakan itu pengecualian daripada gaya Go yang normal.

Ada preseden yang cukup kuat di Go untuk menggunakan gaya penamaan pkg.foo64 daripada pkg64.foo .

API paket menjadi n kali lebih besar jika kita memiliki n tipe, tetapi kompleksitas API tidak. Pendekatan yang lebih baik untuk menyelesaikan ini mungkin melalui dokumentasi dan bagaimana API disajikan melalui alat seperti go doc. Misalnya, alih-alih:

// TrailingZeros16 returns the number of trailing zero bits in x.
// The result is 16 if x == 0.
func TrailingZeros16(x uint16) uint

// TrailingZeros32 returns the number of trailing zero bits in x.
// The result is 32 if x == 0.
func TrailingZeros32(x uint32) uint

// TrailingZeros64 returns the number of trailing zero bits in x.
// The result is 64 if x == 0.
func TrailingZeros64(x uint64) uint

yang dengan jelas menambahkan overhead mental saat melihat API, kami dapat menyajikannya sebagai:

// TrailingZerosN returns the number of trailing zero bits in a uintN value x for N = 16, 32, 64.
// The result is N if x == 0.
func TrailingZeros16(x uint16) uint
func TrailingZeros32(x uint32) uint
func TrailingZeros64(x uint64) uint

godoc bisa pintar tentang fungsi yang serupa dalam pengertian itu dan menyajikannya sebagai grup dengan string dokumen tunggal. Ini akan membantu dalam paket lain juga.

Untuk meringkas, saya pikir skema penamaan yang diusulkan tampaknya baik-baik saja dan dalam tradisi Go. Masalah presentasi adalah pertanyaan terpisah yang dapat didiskusikan di tempat lain.

+1 untuk menempatkan ukuran bit dalam nama paket.

bits64.Log2 membaca lebih baik daripada bits.Log264 (Saya merasa Log2 memang termasuk di sana - dan penamaan paket bukanlah alasan yang baik untuk menyimpannya)

Pada akhirnya, ini adalah API yang sama untuk setiap jenis "diparameterisasi" menurut jenis skalar, jadi jika fungsi memiliki nama yang sama di semua jenis, kode lebih mudah untuk difaktorkan ulang dengan paket terpisah - cukup ubah jalur impor (penggantian seluruh kata adalah sepele dengan gofmt -r tetapi transformasi sufiks khusus lebih canggung).

Saya setuju dengan @griesmeyer bahwa akhiran bitsize pada nama fungsi dapat menjadi idiomatis, tetapi saya merasa itu sepadan hanya jika ada kode non-sepele dalam paket yang tidak tergantung pada jenisnya.

Kami dapat mencuri permainan dari encoding/binary, dan membuat vars bernama Uint64, Uint32, ... yang akan memiliki metode yang menerima tipe standar terkait.

bits.Uint64.RightShift
bit.Uint8.Reverse
bit.Uintptr.Log2
...

@griesemer bagaimana cara mengelompokkannya? Satu string dokumen dengan nama fungsi yang diakhiri dengan N dalam dokumentasi alih-alih nama sebenarnya dan kemudian menemukan awalan umum di antara fungsi tanpa dokumen yang cocok dengan ketidaksesuaian? Bagaimana itu menggeneralisasi? Sepertinya kasus khusus yang rumit untuk melayani sangat sedikit paket.

@rogpeppe bisa berupa bit.Log64 dan dokumen mengatakan itu adalah basis 2 (apa lagi yang akan ada dalam paket bit?) Meskipun sama berantakannya dengan memiliki paket 8/16/32/64/ptr berada pada satu tingkat membuat mereka masing-masing bersih secara individual. (Juga sepertinya transmisi Anda terputus di tengah kalimat.)

@nerdatmath ini akan sedikit berbeda karena mereka akan memiliki antarmuka yang sama dalam arti sehari-hari tetapi tidak dalam pengertian Go, seperti halnya dalam pengkodean/biner (keduanya mengimplementasikan binary.ByteOrder), jadi variabelnya hanya untuk spasi nama dan godoc tidak akan mengambil metode apa pun (#7823) kecuali jenisnya diekspor, yang berantakan dengan cara yang berbeda.

Saya baik-baik saja dengan sufiks ukuran, tetapi, secara keseluruhan, saya lebih suka paket terpisah. Namun, tidak cukup untuk repot-repot mendorongnya melewati komentar ini.

@nerdatmath jika mereka vars, maka mereka bisa berubah (Anda bisa melakukan bits.Uint64 = bits.Uint8 ), yang akan mencegah kompiler memperlakukannya sebagai intrinsik, yang merupakan salah satu motivasi untuk (setidaknya sebagian) paket.

Variabel tidak benar-benar bisa berubah jika tipenya tidak diekspor dan tidak memiliki status (struktur kosong yang tidak diekspor). Tetapi tanpa antarmuka umum, godoc (hari ini) akan menjadi kotor. Diperbaiki meskipun jika itu jawabannya.

Namun, jika Anda akhirnya menggunakan banyak paket, jika ada pengulangan dan volume yang cukup untuk menjaminnya, setidaknya beri nama paket-paket tersebut seperti "X/bits/int64s", "X/bits/ints", "X/ bits/int32s" untuk mencocokkan "kesalahan", "string", "byte". Masih tampak seperti banyak ledakan paket.

Saya tidak berpikir kita harus pergi ke jalur ke beberapa paket khusus tipe, memiliki satu bit paket itu sederhana dan tidak menambah jumlah paket di perpustakaan Go.

Saya tidak berpikir bahwa Ones64 dan TrailingZeroes64 adalah nama yang bagus. Mereka tidak memberi tahu bahwa mereka mengembalikan hitungan. Menambahkan Count awalan membuat nama menjadi lebih panjang. Dalam program saya, fungsi-fungsi itu sering disematkan dalam ekspresi yang lebih besar, jadi nama fungsi yang pendek akan meningkatkan keterbacaan. Meskipun saya menggunakan nama-nama dari buku "Hacker's Delight" saya sarankan untuk mengikuti mnemonik assembler Intel: Popcnt64, Tzcnt64 dan Lzcnt64. Nama-namanya pendek, mengikuti pola yang konsisten, menginformasikan bahwa hitungan dikembalikan dan sudah ditetapkan.

Biasanya hitungan di Go dikembalikan sebagai int, meskipun hitungan tidak pernah bisa negatif. Contoh utama adalah fungsi bawaan len, tetapi Read, Write, Printf, dll. semua mengembalikan bilangan bulat juga. Saya menemukan penggunaan nilai uint untuk hitungan cukup mengejutkan dan menyarankan untuk mengembalikan nilai int.

Jika pilihannya adalah antara (menyalahgunakan notasi) math/bits/int64s.Ones dan math/bits.Ones64, maka saya pasti lebih memilih satu paket. Lebih penting memiliki bit dalam pengidentifikasi paket daripada mempartisi berdasarkan ukuran. Memiliki bit dalam pengidentifikasi paket membuat membaca kode lebih mudah, yang lebih penting daripada ketidaknyamanan kecil pengulangan dalam dokumentasi paket.

@ulikunitz Anda selalu dapat melakukan ctz := bits.TrailingZeroes64 , dan sejenisnya, dalam kode yang menggunakan bit secara ekstensif. Itu menyeimbangkan antara memiliki nama yang mendokumentasikan diri sendiri secara global dan nama yang ringkas secara lokal untuk kode yang kompleks. Transformasi sebaliknya, countTrailingZeroes := bits.Ctz64 , kurang berguna karena properti global yang bagus sudah hilang.

Saya sangat jarang mengacaukan hal-hal pada level bit. Saya harus melihat banyak hal ini setiap kali, hanya karena sudah bertahun-tahun sejak saya harus memikirkannya, jadi saya menemukan semua nama Hacker's Delight/asm-style sangat samar. Saya lebih suka itu hanya mengatakan apa yang dilakukannya sehingga saya dapat menemukan yang saya butuhkan dan kembali ke pemrograman.

Saya setuju dengan @ulikunitz nama panjangnya

init() instead of initialize(), 
func instead of function
os instead of operatingsystem
proc instead of process
chan instead of channel

Selain itu, saya akan menantang bahwa bits.TrailingZeroes64 mendokumentasikan diri sendiri. Apa artinya angka nol tertinggal? Properti dokumentasi diri ada dengan asumsi bahwa pengguna mengetahui sesuatu tentang semantik dokumentasi untuk memulai. Jika tidak menggunakan Hacker's Delight untuk konsistensi, mengapa tidak menyebutnya ZeroesRight64 dan ZeroesLeft64 untuk mencocokkan RotateRight64 dan RotateLeft64?

Untuk memperjelas, saya tidak bermaksud menyiratkan bahwa setiap kali Anda menggunakannya, hal pertama yang harus Anda lakukan adalah membuat alias pendek dan Anda tidak boleh menggunakan nama yang diberikan. Maksud saya jika Anda menggunakannya berulang kali, Anda bisa membuat alias, jika itu meningkatkan keterbacaan kode.

Misalnya, jika saya memanggil strings.HasSuffix Saya menggunakan nama yang diberikan sebagian besar waktu karena saya memanggilnya sekali atau dua kali, tetapi, sesekali, dalam skrip ETL satu kali atau sejenisnya saya akan akhirnya menyebutnya banyak jadi saya akan melakukan ends := strings.HasSuffix yang lebih pendek dan membuat kode lebih jelas. Tidak apa-apa karena definisi alias sudah dekat.

Nama yang disingkat baik-baik saja untuk hal-hal yang sangat umum. Banyak non-programmer tahu apa artinya OS. Siapa pun yang membaca kode, bahkan jika mereka tidak tahu Go, akan mendapatkan fungsi itu kependekan dari function. Saluran sangat penting untuk Go dan digunakan secara luas, jadi chan baik-baik saja. Fungsi bit tidak akan pernah menjadi sangat umum.

TrailingZeroes mungkin tidak dapat memberi tahu Anda dengan tepat apa yang terjadi jika Anda tidak terbiasa dengan konsepnya, tetapi ini memberi Anda ide yang jauh lebih baik tentang apa yang terjadi, setidaknya secara kasar, daripada Ctz.

@jimmyfrasche Mengenai https://github.com/golang/go/issues/18616#issuecomment -275828661: Akan sangat mudah bagi go/doc untuk mengenali urutan fungsi yang berdekatan dalam file yang sama yang memiliki nama yang semuanya dimulai dengan awalan yang sama dan memiliki akhiran yang hanya merupakan urutan angka dan/atau mungkin kata yang "pendek" relatif terhadap awalan. Saya akan menggabungkannya dengan fakta bahwa hanya yang pertama dari fungsi-fungsi ini yang memiliki string doc dan yang lainnya dengan awalan yang cocok tidak. Saya pikir itu bisa bekerja cukup baik dalam pengaturan yang lebih umum. Yang mengatakan, mari kita bahas ini di tempat lain untuk tidak membajak proposal ini.

FYI, dibuat #18858 untuk membahas perubahan go/doc dan memisahkan percakapan itu dari yang ini.

@mdlayher terima kasih telah melakukan itu.

@rogpeppe Menempatkan ukuran ke dalam nama paket terdengar menarik, tetapi dilihat dari komentar dan mengingat gaya Go yang ada, saya pikir preferensinya adalah menempatkan ukuran dengan nama fungsi. Sehubungan dengan Log2, saya akan mengatakan, mari kita tinggalkan keduanya. (Juga, harap ulangi jika ada hal lain yang ingin Anda tambahkan, komentar Anda tampaknya terpotong di tengah kalimat.)

@ulikunitz Saya biasanya salah satu yang pertama memilih nama pendek; terutama dalam konteks lokal (dan dalam konteks global untuk nama yang sangat sering digunakan). Tetapi di sini kami memiliki API paket, dan (setidaknya menurut pengalaman saya) fungsinya tidak akan muncul secara meluas di klien. Misalnya, matematika/besar membuat menggunakan LeadingZeros, Log2, dll tapi itu hanya satu atau dua panggilan. Saya pikir nama deskriptif yang lebih panjang tidak masalah, dan dilihat dari diskusi, sebagian besar komentar mendukung itu. Jika Anda sering memanggil suatu fungsi, membungkusnya di dalam fungsi dengan nama pendek adalah hal yang murah. Panggilan tambahan akan dihapus. FWIW, mnemonik Intel juga tidak bagus, penekanannya adalah pada "hitungan" (cnt) dan kemudian Anda memiliki 2 huruf yang perlu didekripsi.

Saya setuju bahwa 2 di Log2 tidak diperlukan. bits.Log menyiratkan basis 2.

bit.Log64 SGTM.

@griesemer Kalimat cut-off saya mungkin merupakan artefak pengeditan yang kikuk. Saya baru saja menghapusnya.

@griesemer Saya bertanya-tanya apakah layak untuk melanjutkan nama sepeda shedding. Saya membuatnya singkat: Saya memiliki dua argumen: singkat dan jelas tentang mengembalikan nomor. Paket besar menggunakan nlz, bukan LeadingZeros, secara internal. Saya setuju jumlah penggunaan untuk fungsi-fungsi ini kecil.

@ulikunitz Saya pikir sebagian besar umpan balik di sini mendukung nama fungsi yang jelas yang bukan pintasan.

@ulikunitz , tambahan:

Paket besar menggunakan nlz, bukan LeadingZeros, secara internal.

Nama internal pribadi yang tidak diekspor tidak berpengaruh di sini.

Yang penting adalah konsistensi dan nuansa standar dari API publik.

Bikeshedding mungkin menjengkelkan tetapi nama penting ketika kita terjebak dengan mereka selamanya.

CL https://golang.org/cl/36315 menyebutkan masalah ini.

Saya telah mengunggah https://go-review.googlesource.com/#/c/36315/ sebagai API awal (diuji sebagian) (dengan implementasi awal) untuk ditinjau (sebagai pengganti dokumen desain).

Kami masih memastikan API sudah benar, jadi tolong beri komentar hanya di API (bits.go) untuk saat ini. Untuk masalah kecil (salah ketik, dll) silahkan berkomentar di CL. Untuk masalah desain, silakan komentari masalah ini. Saya akan terus memperbarui CL sampai kami puas dengan antarmukanya.

Secara khusus, jangan khawatir tentang implementasinya. Ini dasar, dan hanya sebagian yang diuji. Setelah kami puas dengan API, akan mudah untuk memperluas implementasinya.

@griesemer Saya yakin Anda baik-baik saja, tetapi jika ini berguna, saya memiliki implementasi Majelis CLZ dengan tes https://github.com/ericlagergren/decimal/tree/ba42df4f517084ca27f8017acfaeb69629a090fb/internal/arith yang Anda bebas untuk mencuri / mengutak-atik / apa pun.

@ericlagergren Terima kasih atas tautannya. Setelah API diselesaikan dan kami memiliki pengujian di mana-mana, kami dapat mulai mengoptimalkan implementasi. Aku akan mengingat ini. Terima kasih.

@griesemer , sepertinya dokumentasi API yang Anda usulkan bergantung pada go/doc yang dapat mendokumentasikan fungsi secara memadai dengan awalan yang sama tetapi akhiran bilangan bulat.

Apakah rencananya akan mengerjakan itu sebelum 1.9 juga?

18858, yaitu!

@mdlayher Itu ideal. Tapi itu tidak akan menjadi showstopper karena itu mempengaruhi dokumentasi "hanya", bukan API (yang harus tetap kompatibel ke belakang).

@griesemer @bradfitz Saya meluangkan waktu untuk memikirkan kembali posisi saya mengenai nama fungsi. Tujuan penting memilih nama harus Keterbacaan kode menggunakan API.

Kode berikut memang mudah dipahami:

n := bits.LeadingZeros64(x)

Saya masih sedikit ragu tentang kejelasan Ones64(x), tetapi konsisten dengan LeadingZeros dan TrailingZeros. Jadi saya mengistirahatkan kasus saya dan mendukung proposal saat ini. Sebagai percobaan, saya menggunakan kode saya yang ada untuk implementasi paket Go murni eksperimental termasuk kasus uji.

Repositori: https://github.com/ulikunitz/bits
Dokumentasi: https://godoc.org/github.com/ulikunitz/bits

Kita mungkin juga memiliki seperangkat fungsi Swap [...] sebagian besar penggunaan SwapBytes disebabkan oleh kode yang sadar-endian padahal seharusnya tidak. Komentar?

Saya ingin menyimpan SwapBytes dari API karena alasan ini. Saya khawatir orang akan mulai menggunakannya dengan cara yang tidak portabel karena lebih sederhana (atau dianggap lebih cepat) daripada binary/encoding.BigEndian .

Saya ingin menjauhkan SwapBytes dari API karena alasan ini. Saya khawatir orang akan mulai menggunakannya dengan cara non-portabel karena lebih sederhana (atau dianggap lebih cepat) daripada binary/encoding.BigEndian.

@mundaym apakah rutinitas ini akan SwapBytes64 dikompilasi secara langsung karena BSWAP mungkin lebih besar daripada orang yang menggunakannya dengan tidak benar, imo.

Saya khawatir orang akan mulai menggunakannya dengan cara non-portabel karena lebih sederhana (atau dianggap lebih cepat) daripada biner/encoding.BigEndian

Saya percaya penggunaan ReverseBytes hanya non-portabel jika digunakan bersama dengan unsafe mana Anda mengakses data pada tingkat rendah dengan cara mesin meletakkannya di memori. Namun, penggunaan encoding.{Little,Big}Endian.X sama tidak portabelnya bila digunakan dengan cara itu. Saya menantikan ReverseBytes untuk digunakan dalam kompresi dan akan sedih jika tidak disertakan.

@ericlagergren

apakah rutinitas ini akan diintrinsifikasi?

Ya, fungsi dalam encoding/binary yang melakukan pembalikan byte menggunakan pola kode yang dikenali oleh kompiler dan (atau dapat) dioptimalkan untuk instruksi tunggal (misalnya BSWAP ) pada platform yang mendukung data yang tidak selaras mengakses (misalnya 386, amd64, s390x, ppc64le dan mungkin lainnya).

Membiarkan SwapBytes64 dikompilasi secara langsung karena BSWAP mungkin lebih banyak daripada orang yang menggunakannya dengan tidak benar, imo.

Saya cenderung tidak setuju. Mungkin ada penggunaan yang sah dari SwapBytes dalam kode endianness-unware, tetapi saya menduga itu akan lebih sering disalahgunakan daripada digunakan dengan benar.

Perhatikan bahwa runtime/internal/sys telah mengoptimalkan Go, Assembly, dan versi intrinsik compiler dari trailing zeros dan byte swap, sehingga kami dapat menggunakan kembali implementasi tersebut.

@dsnet Menarik, apakah Anda memiliki sesuatu yang spesifik dalam pikiran?

@clements Apakah Anda tahu di mana byte swap intrinsik digunakan dalam runtime? Saya belum menemukan kegunaan di luar tes.

@mundaym , AFAIK itu tidak digunakan dalam runtime. Kami tidak harus berhati-hati dengan API internal, jadi saya pikir kami hanya menambahkannya saat menambahkan ctz karena itu mudah. :) (Popcount akan menjadi pilihan yang lebih baik.)

Semua: Sekedar pengingat untuk berkonsentrasi pada API untuk saat ini. Implementasi di CL hanyalah implementasi sepele dan lambat yang memungkinkan kita untuk benar-benar menggunakan fungsi-fungsi ini dan mengujinya. Setelah kami puas dengan API, kami dapat menyesuaikan implementasinya.

Pada catatan itu: Kami mungkin harus menyertakan versi untuk uintptr karena tidak dijamin (meskipun kemungkinan besar) ukurannya sama dengan uint32 atau uint64 . (Perhatikan bahwa uint selalu berupa uint32 atau uint64 ). Pendapat? Meninggalkannya untuk nanti? Apa yang akan menjadi nama yang baik? ( LeadingZerosPtr ?).

Kita harus melakukan uintptr sekarang, jika tidak matematika/besar tidak dapat menggunakannya. Akhiran Ptr SGTM. Saya pikir kita juga harus melakukan uint juga, jika tidak, semua kode panggilan perlu menulis kode bersyarat di sekitar ukuran int untuk membuat panggilan bebas konversi. Tidak ada ide penamaan.

Ptr untuk uintptr, tidak ada akhiran untuk uint. Ones, Ones8, Ones16, Ones32, Ones64, OnesPtr, dll.

Saya mungkin minoritas di sini, tetapi saya menentang penambahan fungsi yang menggunakan uintptr.
math/big seharusnya menggunakan uint32/uint64 dari awal. (Bahkan, saya akan
cukup gunakan uint64 untuk semua arsitektur dan serahkan pengoptimalan ke
penyusun.)

Masalahnya adalah ini:
matematika/besar ingin menggunakan ukuran kata asli untuk kinerja yang optimal,
namun, saat ditutup, uintptr bukanlah pilihan yang tepat.
tidak ada jaminan bahwa ukuran pointer sama dengan ukuran
ukuran kata asli.
Contoh utamanya adalah amd64p32, dan kami mungkin juga menambahkan mips64p32 dan
mips64p32le kemudian, yang jauh lebih populer untuk host MIPS 64-bit.

Saya tentu tidak ingin mendorong lebih banyak penggunaan seperti itu. uintptr paling
untuk pointer, bukan untuk arsitektur bilangan bulat netral.

Namun, salah satu solusinya adalah memperkenalkan alias tipe di API (mungkin itu
harus tipe bermerek, ini untuk diskusi).
ketik Word = uint32 // atau uint64 pada arsitektur 64-bit
// kita mungkin juga perlu menyediakan beberapa konstanta ideal untuk Word seperti
jumlah bit, topeng, dll.

Dan kemudian perkenalkan fungsi tanpa awalan tipe apa pun untuk mengambil Word.

Sebenarnya, saya membayangkan bahwa jika math/bit memberikan dua hasil tambah, sub, mul,
div; matematika/besar dapat ditulis ulang tanpa perakitan khusus arsitektur.

matematika/ekspor besar type Word uintptr . Saya setuju bahwa itu mungkin kesalahan, tetapi saya percaya bahwa kompatibilitas mengharuskan itu tetap ada. Jadi jika kita ingin menggunakan math/bits untuk mengimplementasikan math/big, yang menurut saya bisa, kita membutuhkan uintptr API.

Berkeliaran sedikit di luar topik, tetapi bukankah ukuran kata asli yang tidak ditandatangani hanya uint? Dalam hal ini, tidak memiliki akhiran untuk uint tampaknya benar.

Saya tidak ingin satu jenis, Word, berbeda pada arsitektur yang berbeda. Itu sepertinya memperkenalkan banyak kerumitan untuk penelepon dan dokumen. Berpegang pada tipe yang ada berarti Anda dapat menggunakannya dengan mudah. Memiliki tipe yang bervariasi di seluruh arsitektur berarti mendesain semua kode Anda di sekitar tipe itu atau memiliki banyak adaptor dalam file yang dilindungi tag-build.

FWIW, implementasi math/big masih bisa menggunakan API bit berbasis uint32/64 (jika tidak ada versi fungsi uintptr).

@minux Saya tidak menentang 2-hasil add,sub,mul,div - tapi mari kita lakukan itu dalam langkah ke-2. Kami masih membutuhkan kode perakitan jika kami menginginkan kinerja yang layak. Tapi saya senang diyakinkan sebaliknya oleh kompiler ...

Saya telah menambahkan versi uint dan uintptr ke API. Lihat CL dan beri komentar. Saya tidak terlalu senang dengan proliferasi fungsi.

@josharian Uint asli mungkin nilai 32bit bahkan pada mesin 64bit. Tidak ada jaminan. Saya menyadari bahwa uintptr juga tidak menjamin ukuran kata mesin; tetapi pada saat itu tampaknya pilihan yang lebih masuk akal, jika salah dalam retrospeksi. Mungkin kita benar-benar membutuhkan tipe Word.

Jika satu-satunya kebutuhan sah untuk fungsi uintptr adalah untuk mendukung matematika/besar, mungkin implementasi matematika/bit bisa masuk dalam paket internal: hanya gunakan barang uintptr dalam matematika/besar dan ekspos sisanya.

@jimmyfrasche , @griesemer bagaimana pengaruhnya terhadap big.Int.Bits? yaitu apakah masih akan menjadi zero-alloc?

uint juga salah. itu 32-bit di amd64p32.
Sebenarnya, math/big bisa menggunakan uint alih-alih uintptr, tetapi di Go 1,
int/uint selalu 32-bit, yang menjadikan uintptr satu-satunya solusi yang mungkin
untuk matematika/big.Word.

Kami sedang merancang paket baru, jadi saya tidak percaya kompatibilitasnya terlalu banyak
perhatian. matematika/besar menggunakan tipe yang salah, tapi itu lebih bersifat historis
kecelakaan. Mari kita tidak mengambil kesalahan lebih jauh.

Saya tidak mengerti mengapa menggunakan tipe terpadu "Kata" yang selalu paling banyak
tipe integer efisien untuk arsitektur tertentu lebih rumit daripada
menggunakan uintptr. Untuk kode pengguna, Anda dapat memperlakukannya sebagai tipe ajaib yaitu
baik 32-bit atau 64-bit, tergantung pada arsitekturnya. Jika Anda bisa menulis
kode Anda menggunakan uintptr (yang lebarnya juga bergantung pada arsitektur) di an
arsitektur cara independen, maka saya yakin Anda dapat melakukan hal yang sama dengan Word.
Dan Word benar pada semua arsitektur.

Untuk proliferasi API, saya sarankan kita meninggalkan fungsi untuk 8
dan tipe 16-bit pada lintasan pertama. Mereka jarang digunakan dan kebanyakan
arsitektur hanya akan memberikan instruksi 32-bit dan 64-bit.

matematika/besar mendefinisikan dan mengekspor Word, tetapi itu a) tidak secara langsung kompatibel dengan uintptr (ini adalah tipe yang berbeda), dan b) kode yang menggunakan Word dengan benar dan tidak membuat asumsi tentang implementasinya akan dapat dengan segala jenis implementasi Word . Kita bisa mengubahnya. Saya tidak mengerti mengapa itu harus memengaruhi jaminan kompatibilitas API (belum dicoba). Bagaimanapun, mari kita kesampingkan ini. Kita bisa menanganinya secara terpisah.

Bisakah kita melakukan semua tipe uint berukuran eksplisit? Jika kita mengetahui ukuran uint/uintptr sebagai konstanta, kita dapat dengan mudah menulis pernyataan if yang memanggil fungsi berukuran tepat. Pernyataan if akan dilipat secara konstan, dan fungsi pembungkus masing-masing hanya memanggil fungsi berukuran yang akan digariskan.

Akhirnya, apa solusi yang tepat mengenai jenis Word (terlepas dari matematika/besar)? Tentu saja kita dapat mendefinisikannya dalam matematika/bit tetapi apakah itu tempat yang tepat? Ini adalah tipe khusus platform. Haruskah itu menjadi tipe 'word' yang telah dideklarasikan sebelumnya? Dan kenapa tidak?

Memiliki tanda tangan fungsi (atau nama) di sini yang menyebutkan uintptr secara langsung sepertinya merupakan kesalahan. Orang-orang tidak seharusnya melakukan hal seperti ini pada pointer Go.

Jika harus ada fungsi untuk tipe kata mesin alami, saya pikir itu bisa merujuk ke int/uint sekarang. Kami tidak menggunakan uint dalam matematika/besar karena itu 32 bit pada sistem 64-bit, tetapi sejak itu kami telah memperbaikinya. Dan sementara matematika/besar adalah dunia yang koheren tersendiri, di mana masuk akal untuk memiliki jenisnya sendiri big.Word, paket ini lebih merupakan kumpulan rutinitas utilitas pick-and-choose. Mendefinisikan tipe baru dalam konteks ini kurang menarik.

Saya tidak tahu apakah kita membutuhkan varian int/uint sama sekali. Jika biasanya dibutuhkan, mendefinisikannya dalam paket ini lebih masuk akal daripada memaksa semua pemanggil untuk menulis pernyataan if. Tapi saya tidak tahu apakah mereka akan sering dibutuhkan.

Untuk mengatasi potensi ketidakcocokan dengan matematika/besar, setidaknya ada dua solusi yang tidak melibatkan penyebutan uintptr di API di sini.

  1. Tentukan file word32.go dan word64.go dalam math/big dengan tag build dan wrapper penerima uintptr yang mengarahkan ulang dengan tepat (dan pastikan inlining kompiler melakukan hal yang benar).

  2. Ubah definisi big.Word menjadi uint. Definisi yang tepat adalah detail implementasi internal, meskipun diekspos di API. Mengubahnya tidak dapat merusak kode apa pun kecuali pada amd64p32, dan bahkan di sana tampaknya sangat tidak penting di luar matematika/besar.

@rsc : "Kami tidak menggunakan uint dalam matematika/besar karena itu 32 bit pada sistem 64-bit, tetapi kami telah memperbaikinya." Ah ya, saya benar-benar lupa tentang alasan pemilihan uintptr. Inti dari tipe Go uint/int adalah memiliki tipe integer yang mencerminkan ukuran register alami mesin. Saya akan mencoba mengubah big.Word menjadi uint dan melihat apa yang terjadi.

Semua: https://go-review.googlesource.com/#/c/36315/ Diperbarui untuk mengecualikan versi fungsi uintptr per diskusi di atas.

Saya sementara memperbarui math/big untuk menggunakan math/bits untuk melihat efeknya (https://go-review.googlesource.com/36328).

Beberapa komentar:
1) Saya condong ke arah membuat hasil dari fungsi Leading / TrailingZeros uint daripada int . Hasil ini cenderung digunakan untuk menggeser nilai yang sesuai; dan math/big membuktikan hal ini. Saya juga mendukung membuat Ones mengembalikan uint , untuk konsistensi. Argumen kontra?

2) Saya bukan penggemar nama One , namun konsisten dengan Leading / TrailingZeros . Bagaimana dengan Population ?

3) Beberapa orang mengeluh bahwa Log tidak sesuai dengan paket ini. Log kebetulan setara dengan indeks msb (dengan -1 untuk x == 0). Jadi kita bisa menyebutnya MsbIndex (meskipun Log tampaknya lebih bagus). Atau, kita dapat memiliki fungsi Len yang merupakan panjang x dalam bit; yaitu, `Log(x) == Len(x)-1).

Komentar?

Saya bukan penggemar nama One, namun konsisten dengan Leading/TrailingZeros. Bagaimana dengan Populasi?

Mengapa tidak Popcount tradisional?

Atau, kita dapat memiliki fungsi Len yang merupakan panjang dari x dalam bit; yaitu, `Log(x) == Len(x)-1).

Len atau Length terdengar seperti nama yang bagus dan ide yang bagus.

1.

Saya bukan penggemar nama One, namun konsisten dengan Leading/
TrailingZeros. Bagaimana dengan Populasi?

bit. Hitung?

@clements Hitung apa?

Populasi mungkin merupakan nama yang lebih baik untuk alasan historis tetapi tidak benar-benar mengatakan lebih dari Satu jika Anda tidak terbiasa dengan istilah tersebut dan memiliki masalah yang sama hanya Hitung: Populasi dari apa?

Ini agak unidiomatik, bahkan di dalam paket, tapi mungkin CountOnes untuk memberikannya nama yang jelas dan jelas.

@clements Hitung apa?

Dalam paket yang disebut "bit", saya tidak yakin apa lagi yang bisa Anda hitung kecuali set bit, tetapi CountOnes juga baik-baik saja dan jelas lebih eksplisit. Menambahkan "Satu" juga paralel dengan "Nol" di LeadingZeros / TrailingZeros .

Itu interpretasi yang paling jelas tapi masih ada ambiguitas. Itu bisa menghitung bit yang tidak disetel atau bit total (interpretasi terakhir akan sangat tidak mungkin, tetapi masih merupakan jebakan potensial bagi seseorang yang membaca kode menggunakan bit yang tidak terbiasa dengan konsep yang terlibat dan mungkin berpikir Hitungan bebas sufiks seperti tidak aman.SizeOf)

Mungkin sesuatu seperti AllOnes atau TotalOnes untuk mencerminkan Trailing/LeadingZeroes tetapi tentukan bahwa, tidak seperti itu, posisi tidak diperhitungkan.

AllOnes terdengar seperti mengembalikan semua yang (dalam bitmask mungkin?), Atau mungkin sebuah kata yang semuanya.

CountOnes dan TotalOnes tampaknya hampir sama, tetapi karena nama operasi ini yang paling umum dikenal adalah "jumlah populasi", CountOnes sepertinya lebih disukai.

Saya telah mengunggah versi baru (https://go-review.googlesource.com/#/c/36315/) dengan beberapa perubahan:

1) Saya mengganti nama Ones menjadi PopCount : Kebanyakan orang tidak terlalu senang dengan nama yang konsisten tetapi agak menjemukan Ones . Semua orang yang akan menggunakan paket ini akan tahu persis apa yang dilakukan PopCount : itu adalah nama yang umum digunakan untuk fungsi ini. Ini sedikit tidak konsisten dengan yang lain tetapi artinya menjadi jauh lebih jelas. Saya akan memilih Ralph Waldo Emerson untuk yang satu ini ("Konsistensi yang bodoh adalah hobgoblin dari pikiran-pikiran kecil...").

2) Saya mengganti nama Log menjadi Len seperti pada bits.Len . Panjang bit dari bilangan x adalah jumlah bit yang diperlukan untuk merepresentasikan x dalam representasi biner (https://en.wikipedia.org/wiki/Bit-length). Tampaknya pas, dan menghilangkan kebutuhan untuk memiliki Log sini yang memiliki kualitas yang tidak "sedikit-sedikit". Saya percaya ini juga merupakan kemenangan karena Len(x) == Log(x) + 1 mengingat bagaimana kami mendefinisikan Log . Selanjutnya memiliki keuntungan bahwa hasilnya sekarang selalu >= 0, dan menghilangkan beberapa koreksi +/-1 dalam implementasi (sepele).

Secara keseluruhan saya cukup senang dengan API ini pada saat ini (kami mungkin ingin menambahkan lebih banyak fungsi nanti). Satu-satunya hal lain yang saya pikir mungkin ingin kita pertimbangkan secara serius adalah apakah semua hasil harus tidak ditandatangani. Seperti yang telah saya tunjukkan sebelumnya, hasil fungsi Trailing/Leading Zero cenderung menjadi input untuk operasi shift yang harus tidak ditandatangani. Itu hanya menyisakan Len dan PopCount yang bisa dibilang bisa mengembalikan nilai yang tidak ditandatangani juga.

Komentar?

Pengalaman saya dengan matematika/besar adalah frustrasi karena dipaksa ke mode uint oleh fungsi ketika saya tidak bergeser. Di math/big/prime.go, saya menulis

for i := int(s.bitLen()); i >= 0; i-- {

meskipun s.bitLen() mengembalikan int bukan uint, karena saya tidak yakin tanpa melihat, dan saya juga tidak yakin bahwa beberapa CL masa depan mungkin tidak mengubahnya untuk mengembalikan uint, sehingga mengubahnya untuk loop menjadi infinite loop. Perlu bersikap defensif ini menunjukkan ada masalah.

Uints jauh lebih rawan kesalahan daripada int, itulah sebabnya kami tidak menyarankannya di sebagian besar API. Saya pikir akan jauh lebih baik jika setiap fungsi dalam matematika/bit mengembalikan int dan membiarkan konversi ke uint dilakukan dalam ekspresi shift, seperti yang diperlukan di sebagian besar ekspresi shift.

(Saya tidak mengusulkan perubahan, tetapi saya pikir pergeseran yang membutuhkan uint mungkin merupakan kesalahan dalam retrospeksi. Mungkin kita dapat memperbaikinya di beberapa titik. Akan lebih baik jika itu tidak merusak API kita yang lain.)

Saya mendukung pengembalian int setelah mengambil kode saya untuk panggilan dari nol tambahan dan fungsi popcount. Mayoritas panggilan dalam deklarasi variabel pendek dan perbandingan tipe int. Panggilan dalam shift tentu saja membutuhkan tipe uint, tetapi sangat jarang.

Tweak kecil yang diunggah. Per +1 dan komentar mari kita tinggalkan hasil hitungan sebagai int .

https://go-review.googlesource.com/36315

Saya membiarkan input menghitung RotateLeft/Right sebagai uint jika tidak, kita perlu menentukan apa yang terjadi ketika nilainya negatif atau melarangnya.

Akhirnya, kita bahkan mungkin meninggalkan Len karena LenN(x) == N - LeadingZerosN(x) . Pendapat?

Jika tidak ada umpan balik yang signifikan lagi pada saat ini, saya sarankan agar kita melanjutkan dengan API ini dan melakukan implementasi awal setelah peninjauan. Setelah itu kita bisa mulai mengutak-atik implementasinya.

Saya langkah selanjutnya yang mungkin ingin kita diskusikan jika dan fungsi lain mana yang mungkin ingin kita sertakan, khususnya Add / Sub / dll. yang menggunakan 2 argumen dan carry, dan menghasilkan hasil dan carry .

@gri memikirkan fungsi dasar 10 Len ? Itu hanya ((N - clz(x) + 1) * 1233) >> 12

Ini kurang "sedikit hacky" dari basis 2 tetapi masih berguna.
Pada Jumat, Feb 10, 2017 at 05:03 Robert Griesemer [email protected]
menulis:

Tweak kecil yang diunggah. Per +1 dan komentar mari kita tinggalkan hasil
dihitung sebagai int.

https://go-review.googlesource.com/36315

Saya meninggalkan jumlah input untuk RotateLeft/Right sebagai uint jika tidak, kami akan melakukannya
perlu menentukan apa yang terjadi ketika nilainya negatif atau melarangnya.

Akhirnya, kita bahkan mungkin meninggalkan Len karena LenN(x) == N -
LeadingZerosN(x). Pendapat?

Jika tidak ada umpan balik yang signifikan lagi pada saat ini, saya sarankan kita
maju dengan API ini dan lakukan implementasi awal setelah
tinjauan. Setelah itu kita bisa mulai mengutak-atik implementasinya.

Saya langkah selanjutnya yang mungkin ingin kita diskusikan jika dan fungsi lain mana yang mungkin kita lakukan
ingin menyertakan, khususnya Tambah/Sub/ dll. yang menggunakan 2 argumen dan
membawa, dan menghasilkan hasil dan membawa.


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/golang/go/issues/18616#issuecomment-279107013 , atau bisukan
benang
https://github.com/notifications/unsubscribe-auth/AFnwZ_QMhMtBZ_mzQAb7XZDucXrpliSYks5rbQjCgaJpZM4Lg5zU
.

Juga. Maafkan saya jika saya keluar dari ruang lingkup masalah ini, tetapi saya akan mendukung aritmatika yang diperiksa. Misal AddN(x, y T) (sum T, overflow bool)

Pada Jumat, Feb 10, 2017 at 08:16, Eric Lagergren [email protected]
menulis:

Juga. Maafkan saya jika saya keluar dari ruang lingkup masalah ini, tetapi saya akan masuk
mendukung aritmatika diperiksa. Misal AddN(x, y T) (jumlah T, overflow bool)

Apakah Anda berbicara tentang overflow yang ditandatangani? atau luapan yang tidak ditandatangani (bawa/pinjam)?

Juga, saya lebih suka mengembalikan overflow/carry/borrow sebagai tipe T, untuk menyederhanakan
aritmatika multi-presisi.

@ericlagergren Fungsi (basis 2) Len , sementara hampir log2, pada dasarnya masih merupakan fungsi penghitungan bit. Fungsi dasar 10 Len sebenarnya adalah fungsi log. Tidak dapat disangkal bahwa itu berguna, tetapi tampaknya kurang cocok untuk paket ini.

Ya, saya pikir akan menyenangkan untuk memasukkan aritmatika checked . Saya hanya ingin menutup API saat ini terlebih dahulu sehingga kami dapat membuat kemajuan daripada bolak-balik. Tampaknya sebagian besar orang yang berkomentar sejauh ini tampak senang dengannya.

Mengenai fungsi Add, Sub: Saya setuju dengan @minux bahwa carry harus bertipe sama dengan argumen. Juga, saya tidak yakin bahwa kita memerlukan apa pun selain argumen uint untuk fungsi-fungsi ini: Intinya adalah bahwa (dalam banyak kasus) uint memiliki ukuran register alami platform, dan itulah tingkat di mana operasi ini paling masuk akal.

Paket matematika/terperiksa bisa menjadi rumah yang lebih baik bagi mereka. checked.Add lebih jelas dari bits.Add .

@minux saya berpikir masuk diperiksa aritmatika, jadi meluap.

@griesemer re: base 10 Len : masuk akal!

Jika Anda mau, saya dapat mengirimkan CL untuk aritmatika yang diperiksa. Saya suka ide @jimmyfrasche untuk membuatnya di bawah nama paket yang terpisah.

Add/sub/mul mungkin atau mungkin tidak termasuk dalam bits , tetapi matematika yang diperiksa bukan satu-satunya yang digunakan untuk operasi ini. Secara lebih umum, saya akan mengatakan ini adalah operasi aritmatika "lebar". Untuk add/sub ada sedikit perbedaan antara satu bit hasil carry/overflow dan indikator boolean overflow, tetapi kami mungkin juga ingin menyediakan add-with-carry dan subtract-with-borrow untuk membuat ini dapat dirantai. Dan untuk wide mul ada lebih banyak informasi di hasil tambahan daripada overflow.

Merupakan ide yang baik untuk mengingat operasi aritmatika yang diperiksa/lebar, tetapi mari kita biarkan untuk putaran kedua.

"Semua orang yang akan menggunakan paket ini akan tahu persis apa yang dilakukan PopCount"

Saya telah menggunakan fungsionalitas itu sebelumnya dan entah bagaimana saya tidak terbiasa dengan nama PopCount (walaupun saya seharusnya memilikinya karena saya yakin saya mencubit implementasi dari Hacker's Delight, yang menggunakan "pop").

Saya tahu saya ke pesta, tetapi "OnesCount" tampaknya jauh lebih jelas bagi saya, dan jika kata "PopCount" disebutkan dalam komentar dokumen, orang yang mencarinya akan tetap menemukannya.

Terkait untuk aritmatika diperiksa/lebar: #6815. Tapi ya, mari kita ronde satu!

@griesemer menulis:

Fungsi Len (basis 2), meskipun hampir log2, pada dasarnya masih merupakan fungsi penghitungan bit. Fungsi basis 10 Len sebenarnya adalah fungsi log. Tidak dapat disangkal bahwa itu berguna, tetapi tampaknya kurang cocok untuk paket ini.

Saya menulis tolok ukur untuk membandingkan beberapa pendekatan terhadap masalah "panjang digit desimal" Oktober lalu, yang saya posting di Gist .

Diterima sebagai proposal; mungkin akan ada tweak kecil yang bergerak maju, dan itu tidak masalah.

@rogpeppe : Mengubah PopCount menjadi OnesCount karena juga menerima 4 jempol (seperti saran saya untuk menggunakan PopCount ). Disebut "jumlah populasi" dalam string dokumen.

Per @rsc , tinggalkan operasi aritmatika yang dicentang/lebar untuk saat ini.

Juga per @rsc , semua fungsi penghitungan mengembalikan nilai int , dan untuk kemudahan penggunaan (dan dengan memperhatikan #19113), gunakan nilai int untuk penghitungan rotasi.

Meninggalkan LenN fungsi meskipun hanya N - LeadingZerosN . Tetapi ada simetri serupa untuk RotateLeft / Right dan kami memiliki keduanya.

Menambahkan implementasi yang sedikit lebih cepat untuk TrailingZeroes dan menyelesaikan tes.

Pada titik ini saya percaya kami memiliki implementasi pertama yang dapat digunakan. Harap tinjau kode di https://go-review.googlesource.com/36315 , terutama API. Saya suka mengirimkan ini jika kita semua senang.

Langkah selanjutnya:

  • implementasi lebih cepat (utama)
  • menambahkan fungsionalitas tambahan (sekunder)

Kami sedang merancang paket baru

@minux Maksud Anda matematika baru/besar? Apakah mungkin untuk mengikuti proses di suatu tempat?

@TuomLarsen : @minux merujuk ke matematika/bit dengan "paket baru". Dia menyebutkan matematika/besar sebagai kasus di mana matematika/bit akan digunakan. (Di masa depan, harap lebih spesifik dengan komentar Anda sehingga kami tidak perlu mencari dan menebak apa yang Anda maksud - terima kasih).

CL https://golang.org/cl/37140 menyebutkan masalah ini.

Apakah akan ada intrinsifikasi berbantuan kompiler yang terjadi dalam matematika/bit untuk Go 1.9?

@cespare Tergantung pada apakah kita mendapatkannya (@khr?). Terlepas dari itu, kami ingin memiliki implementasi platform-independen yang layak. (Salah satu alasan kami tidak ingin memindahkan matematika/besar sepenuhnya ke menggunakan matematika/bit adalah karena saat ini kami memiliki beberapa perakitan khusus platform dalam matematika/besar yang lebih cepat.)

Di piringku, setidaknya untuk lengkungan kita sudah melakukan intrinsik untuk
(386,amd64,lengan,lengan64,s390x,mips, mungkin ppc64).

Pada Jumat, 17 Februari 2017 pukul 12:54, Robert Griesemer < [email protected]

menulis:

@cespare https://github.com/cespare Tergantung pada apakah kita mendapatkannya (
@khr https://github.com/khr ?). Terlepas dari itu, kami ingin memiliki
implementasi platform-independen yang layak. (Salah satu alasan kami tidak
ingin memindahkan matematika/besar sepenuhnya ke menggunakan matematika/bit adalah saat ini kami
memiliki beberapa perakitan khusus platform dalam matematika/besar yang lebih cepat.)


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/golang/go/issues/18616#issuecomment-280763679 , atau bisukan
benang
https://github.com/notifications/unsubscribe-auth/AGkgIIb8v1X5Cr-ljDgf8tQtT4Dg2MGiks5rdgkegaJpZM4Lg5zU
.

Artikel tentang cara tercepat untuk menerapkan penghitungan populasi pada x86-64 ini mungkin berguna: Perakitan kode tangan mengalahkan intrinsik dalam kecepatan dan kesederhanaan – Dan Luu, Okt 2014

CL https://golang.org/cl/38155 menyebutkan masalah ini.

CL https://golang.org/cl/38166 menyebutkan masalah ini.

CL https://golang.org/cl/38311 menyebutkan masalah ini.

CL https://golang.org/cl/38320 menyebutkan masalah ini.

CL https://golang.org/cl/38323 menyebutkan masalah ini.

Beberapa diskusi lagi:

Aku:

math/bits.RotateLeft saat ini didefinisikan panik jika argumennya kurang dari nol.
Saya ingin mengubahnya untuk mendefinisikan RotateLeft untuk melakukan rotasi kanan jika arg-nya kurang dari nol.

Memiliki rutinitas dasar seperti kepanikan yang satu ini tampaknya tidak perlu keras. Saya berpendapat bahwa rotasi dengan jumlah negatif lebih analog dengan pergeseran lebih besar dari ukuran Word (yang tidak panik) alih-alih membagi dengan nol (yang membuat panik). Bagi-oleh-nol benar-benar harus panik, karena tidak ada hasil yang masuk akal Anda akan kembali sebagai gantinya. Rotasi dengan jumlah negatif memiliki hasil yang terdefinisi dengan baik yang dapat kita kembalikan.

Saya pikir kita harus menjaga RotateLeft dan RotateRight sebagai fungsi yang terpisah, meskipun yang satu sekarang dapat diimplementasikan dengan yang lain. Penggunaan standar akan tetap dengan argumen non-negatif.

Jika kita akan melakukan sesuatu di sini, kita harus melakukannya dengan membekukan. Setelah go 1.9 keluar, kami tidak dapat mengubah pikiran kami.

Rampok:

Jika Anda benar-benar menginginkan sesuatu seperti ini, saya hanya memiliki satu fungsi, Putar, yang mengambil positif untuk kiri dan negatif untuk kanan.

Aku:

Masalahnya adalah
bit.Putar(x, -5)

Tidak jelas ketika membaca kode ini apakah kita akhirnya berputar ke kiri atau ke kanan.
bit.PutarKanan(5)
jauh lebih jelas, bahkan jika itu berarti ada dua kali lebih banyak fungsi Rotate* dalam matematika/bit.

Michael Jones:

Putar yang ditandatangani berarti melompat dalam kode, ya? Sepertinya kasihan.

Aku:

Tidak, implementasinya sebenarnya lebih sederhana dengan semantik yang diusulkan. Tutupi 6 bit rendah (untuk putaran 64-bit) dan itu hanya berfungsi.

Saya lebih suka Rotate tunggal dengan argumen yang ditandatangani karena itu berarti setengah jumlah fungsi dan dapat dilakukan dengan sangat efisien dalam semua kasus tanpa panik atau bahkan cabang bersyarat.

Rotate adalah fungsi spesialis, jadi orang yang menggunakannya pasti akan merasa nyaman ketika diminta untuk mengingat bahwa argumen positif bergeser ke kiri dan argumen negatif bergeser ke kanan.

Anda selalu dapat membagi perbedaan dan hanya menyediakan RotateLeft dengan argumen yang ditandatangani. Itu memberikan mnemonik yang berguna untuk arah tetapi menghindari duplikasi fungsi.

@bcmils @robpike lihat juga diskusi sebelumnya tentang topik yang tepat ini mulai dari https://github.com/golang/go/issues/18616#issuecomment -275598092 dan lanjutkan untuk beberapa komentar

@josharian Saya telah melihat komentar dan masih lebih suka versi saya. Ini dapat di-bikeshed selamanya tetapi saya mencoba untuk menerapkannya dengan sederhana, sederhana untuk didefinisikan, sederhana untuk dipahami, dan sederhana untuk didokumentasikan. Saya percaya satu fungsi Rotate dengan argumen yang ditandatangani memenuhi semua itu kecuali untuk kebutuhan untuk mendefinisikan tanda, tetapi kiri itu positif harus intuitif bagi siapa saja yang mampu menggunakan instruksi rotasi.

tetapi kiri itu positif harus intuitif bagi siapa saja yang mampu menggunakan instruksi putar.

Saya suka menganggap diri saya mampu menggunakan instruksi putar dan intuisi saya adalah "Ya ampun, mengapa ini tidak mengatakan arahnya? Mungkin tertinggal, tetapi saya harus melihat dokumentasi untuk memastikannya ." Saya setuju itu intuitif bahwa jika Anda akan memilih arah positif itu akan menjadi rotasi kiri, tetapi ada ambang batas yang jauh lebih tinggi untuk sesuatu yang begitu jelas merupakan jawaban yang benar sehingga jelas di setiap situs panggilan ke arah mana Anda berputar tanpa mengatakan dia.

Sejauh keterbacaan, bagaimana dengan sesuatu di sepanjang baris time.Duration API:

const RotateRight = -1

bits.Rotate(x, 5 * RotateRight)

Mungkin konstanta yang ditentukan oleh bit atau mungkin latihan untuk pembaca (panggilan situs)?

@clements Dan Anda berakhir dengan dua (tipe N kali) fungsi dengan kemampuan identik yang satu-satunya perbedaan adalah tanda dalam argumen. Sekarang kami mentolerirnya untuk Add dan Sub tapi itu satu-satunya contoh yang bisa saya pikirkan.

Pada sumbu angka, angka positif bertambah ke kanan, jadi saya mengharapkan rotasi/pergeseran yang ditentukan oleh tanda arah untuk memindahkan bit ke kanan untuk angka positif.

Saya tidak punya masalah jika itu akan menjadi [terdokumentasi] sebaliknya, tapi saya tidak akan menyebutnya intuitif.

@cznic bit ditulis dari kanan ke kiri

Saya juga mendukung hanya Rotate (https://github.com/golang/go/issues/18616#issuecomment-275016583) jika kami membuatnya berfungsi di kedua arah.

Sebagai kontra-argumen untuk @clements kekhawatiran tentang arah: Memberikan RotateLeft yang berfungsi juga saat memutar ke kanan juga dapat memberikan rasa aman yang salah: "Dikatakan RotateLeft jadi pasti itu tidak berputar Baik!". Dengan kata lain, jika dikatakan RotateLeft lebih baik tidak melakukan hal lain.

Juga, penggunaan bits.Rotate benar-benar hanya dalam kode spesialis. Ini bukan fungsi yang digunakan oleh sejumlah besar programmer. Pengguna yang benar-benar membutuhkannya akan memahami simetri rotasi.

@nathany

bit ditulis dari kanan ke kiri

Bit hanyalah digit biner. Digit angka dalam basis apa pun ditulis dari kiri ke kanan - bahkan di sebagian besar, jika tidak semua, sistem penulisan kanan-ke-kiri. 123 adalah seratus dua puluh tiga, bukan tiga ratus dua puluh satu.

Bahwa kekuatan perkalian untuk digit berkurang ke kanan adalah hal yang berbeda.

Sekali lagi: Saya tidak peduli dengan arahnya, hanya saja yang intuitif adalah masalah imajinasi pribadi.

Saya suka Rotasi. Sedikit yang paling tidak signifikan secara intuitif cukup 0 dalam pandangan saya.

Harap pertahankan RotateLeft dan RotateRight alih-alih melakukan sesuatu yang setengah dari pengembang akan salah ingat. Tampaknya baik-baik saja untuk menangani angka negatif.

99% pengembang tidak akan pernah memprogram instruksi rotasi, jadi kebutuhan akan arah yang tidak ambigu paling lemah. Satu panggilan sudah cukup.

Masalah yang membangkitkan kembali diskusi ini adalah bahwa memiliki keduanya memerlukan perdebatan tentang apakah nilai-nilai negatif itu boleh, dan jika tidak, apa yang harus dilakukan terhadap nilai-nilai itu. Dengan hanya memiliki satu, seluruh argumen itu hilang. Ini desain yang lebih bersih.

Saya agak bersimpati dengan argumen tentang desain yang bersih tetapi tampaknya aneh bahwa Anda harus menghapus "Kanan" dari "RotateRight", sambil mempertahankan implementasi yang sama, untuk mencapainya. Secara praktis, satu-satunya cara tampaknya untuk menjawab pertanyaan adalah dengan memaksa orang yang melihatnya untuk membaca dokumentasi, melalui pertanyaan yang dimunculkan namanya.
Pada akhirnya ini adalah masalah arah yang jelas vs perilaku yang tidak ambigu untuk nilai-nilai negatif. Nilai negatif mungkin tidak terlalu menjadi perhatian dalam kasus umum.

Apa yang saya katakan adalah bahwa Rotate mengajukan satu pertanyaan untuk semua orang, menjawabnya secara tidak langsung melalui dokumentasi.
RotateRight mengajukan satu pertanyaan untuk sangat sedikit orang yang dapat (dan harus) membaca dokumentasi jika mereka peduli.

Di sisi lain Rotate mungkin akan mencegah orang menulis if n < 0 { RotateLeft(...) } else { RotateRight(...) } .

@golang/proposal-review membahas ini dan akhirnya hanya memiliki satu fungsi, tetapi menamakannya RotateLeft , bukan hanya Rotate , agar lebih jelas di situs panggilan. Angka negatif berputar ke kanan, dan dokumentasi akan memperjelas hal ini.

CL https://golang.org/cl/40394 menyebutkan masalah ini.

CL https://golang.org/cl/41630 menyebutkan masalah ini.

Proposal asli ditambah beberapa fungsi tambahan telah dirancang dan diimplementasikan pada saat ini. Kami dapat menambahkan ke perpustakaan ini dari waktu ke waktu, tetapi tampaknya cukup "lengkap" untuk saat ini.

Terutama, kami belum memutuskan atau mengimplementasikan fungsionalitas untuk:

  • uji apakah add/mul/etc overflow
  • menyediakan fungsi untuk mengimplementasikan add/mul/etc yang menerima carry yang masuk dan menghasilkan hasil plus carry (atau kata yang lebih tinggi)

Secara pribadi saya tidak yakin itu termasuk dalam paket "bit" (mungkin tesnya). Fungsi untuk mengimplementasikan add/sub/mul multi-presisi akan memungkinkan implementasi Go murni dari beberapa matematika/kernel besar, tetapi saya tidak percaya perinciannya benar: Apa yang kami inginkan adalah kernel yang dioptimalkan yang bekerja pada vektor, dan maksimum kinerja untuk kernel tersebut. Saya tidak percaya kita dapat mencapainya dengan kode Go tergantung pada add/sub/mul "intrinsik" saja.

Jadi, untuk saat ini saya ingin menutup masalah ini sebagai "selesai" kecuali ada keberatan besar. Silakan berbicara selama minggu depan atau lebih jika Anda menentang penutupan ini.

Saya mendukung penambahan fungsi di sepanjang garis itu.

Saya sangat percaya bahwa mereka termasuk dalam paket mereka sendiri, jika tidak ada alasan lain selain memberinya nama yang lebih mencerminkan fungsionalitas kolektif mereka.

:+1: saat menutup masalah ini dan :heart: untuk pekerjaan yang dilakukan sejauh ini.

Penutupan karena tidak ada keberatan.

Ini adalah komentar untuk keputusan masa depan mengenai API, saya mengerti yang satu ini sudah diatur.

Rotate adalah fungsi spesialis; LTR atau RTL hanya relevan mengingat konteksnya. @clements memunculkan pertanyaan yang valid, bukan poin yang valid dan terus berkembang. Pertanyaannya bisa dijawab sebagai "itu RTL, sama seperti pertambahan bilangan bulat"; mudah, kan?

Tapi sebaliknya, kepintaran terjadi kemudian.

Apa yang dimaksud dengan "fungsi spesialis" adalah hal yang sangat sederhana, kemungkinan besar akan diberhentikan dengan cepat. Diberikan contoh kode, orang mungkin sudah memahami rotasi yang terjadi dan arahnya bahkan sebelum menemukan baris kode. Kode seperti itu biasanya sudah didahului oleh dokumentasi ascii ilustratif apa adanya.

Apa yang secara mental bergolak bukanlah bahwa Go bisa saja memilih RTL sebagai cara standar untuk menafsirkan bit dari perspektif API, melainkan, saya pertama-tama menarik perubahan 1.9 dan menemukan RotateLeft tanpa mitra dan dokumen memberikan contoh a langkah negatif. Ini adalah keputusan seperti komite yang mematikan pikiran yang sangat disayangkan mendarat di 1.9.

Saya hanya memohon untuk tetap berpegang pada konteks penggunaan untuk masa depan. Semua ini seharusnya sudah terbukti dengan sendirinya dengan pertanyaan seperti, "mengapa kita tidak menyediakan padanan untuk RotateLeft, mengapa kita panik pada langkah negatif atau memperdebatkan int vs uint untuk sebuah langkah"; pada akhirnya, karena saya pikir apa yang dimaksud dengan "fungsi spesialis" diabaikan begitu saja karena tidak pandai.

Mari kita hindari kepintaran dalam pembenaran API kita. Ini terlihat dalam pembaruan 1.9 ini.

Ubah https://golang.org/cl/90835 menyebutkan masalah ini: cmd/compile: arm64 intrinsics for math/bits.OnesCount

Apakah halaman ini membantu?
0 / 5 - 0 peringkat