Go: الرياضيات / بت: مكتبة تلاعب عدد صحيح بت

تم إنشاؤها على ١١ يناير ٢٠١٧  ·  168تعليقات  ·  مصدر: golang/go

المناقشات السابقة على https://github.com/golang/go/issues/17373 و https://github.com/golang/go/issues/10757.

الملخص

يقدم هذا الاقتراح مجموعة من واجهة برمجة التطبيقات (API) لملفات عدد صحيح من البتات.

خلفية

يقدم هذا الاقتراح مجموعة من واجهة برمجة التطبيقات (API) لملفات عدد صحيح من البتات. لهذا الاقتراح نحن مهتمون بالوظائف التالية:

  • ctz - عد الأصفار الزائدة.
  • clz - عد الأصفار البادئة ؛ تسجيل_2.
  • popcnt - تعداد السكان ؛ مسافة المطرقة تكافؤ عدد صحيح.
  • bswap - يعكس ترتيب البايت.

تم اختيار هذه الوظائف من خلال المسح:

لقد قصرنا أنفسنا على هذه الوظائف الأربع لأننا نلعب دورًا آخر
الحيل سهلة التنفيذ باستخدام المكتبة المقترحة ،
أو بنيات Go المتاحة بالفعل.

وجدنا تطبيقات لمجموعة فرعية من وظائف التلاعب المختارة
في العديد من الحزم بما في ذلك وقت التشغيل والمترجم والأدوات:

| الحزمة | clz | كتز | بوبكنت | bswap |
| --- | --- | --- | --- | --- |
| رياضيات / كبيرة | X | X | | |
| وقت التشغيل / داخلي / sys | X | X | | X |
| أدوات / حاوية / intsets | X | | X | |
| cmd / تجميع / داخلي / 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 | |
| عمارات دول مجلس التعاون الخليجي | X | X | X | X |

تطبق العديد من الحزم الأخرى مجموعة فرعية من هذه الوظائف:

وبالمثل ، أدرك مقدمو الأجهزة أهمية ذلك
من هذه الوظائف وشمل دعم مستوى الجهاز.
بدون دعم الأجهزة ، تكون هذه العمليات باهظة الثمن.

| قوس | clz | كتز | بوبكنت | bswap |
| --- | --- | --- | --- | --- |
| AMD64 | X | X | X | X |
| الذراع | X | X | ؟ | X |
| ARM64 | X | X | ؟ | X |
| S390X | X | X | ؟ | X |

يتم تنفيذ جميع وظائف bit twiddling ، باستثناء popcnt ، عن طريق runtime / internal / sys وتتلقى دعمًا خاصًا من المترجم من أجل "المساعدة في الحصول على أفضل أداء". ومع ذلك ، فإن دعم المترجم يقتصر على حزمة وقت التشغيل ويتعين على مستخدمي Golang الآخرين إعادة تنفيذ البديل الأبطأ لهذه الوظائف.

عرض

نقدم مكتبة std جديدة math/bits مع واجهة برمجة التطبيقات الخارجية التالية ، لتوفير تطبيقات مُحسَّنة للمترجم / الأجهزة لوظائف clz و ctz و popcnt و 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

المنطق

بدائل هذا الاقتراح هي:

  • يتم تنفيذ وظائف twiddling في مكتبة خارجية لا يدعمها المترجم. هذا النهج يعمل وهو الوضع الحالي للأمور. يستخدم Runtime الطرق المدعومة من المترجم ، بينما يستمر مستخدمو Golang في استخدام تطبيقات أبطأ.
  • المكتبة الخارجية مدعومة من قبل المترجم. بالنظر إلى أننا نتوقع أن تحل هذه المكتبة محل وقت التشغيل / Internal / sys ، فهذا يعني أن هذه المكتبة يجب أن تكون مقفلة مع المترجم وتعيش في المكتبة القياسية.

التوافق

هذا الاقتراح لا يغير أو يكسر أي stdlib API موجود ويتوافق مع المبادئ التوجيهية المتوافقة.

تطبيق

تم بالفعل تنفيذ SwapBytes و TrailingZeros و LeadingZeros. الوظيفة الوحيدة المفقودة هي الوظائف التي يمكن تنفيذها بشكل مشابه للوظائف الأخرى. إذا تم قبول هذا الاقتراح ، فيمكن تنفيذه في الوقت المناسب لـ Go1.9.

القضايا المفتوحة (إن وجدت)

الأسماء صعبة ، سقيفة الدراجات في التعليقات.

يرجى اقتراح وظائف إضافية لتضمينها في التعليقات. من الناحية المثالية ، يرجى تضمين مكان استخدام هذه الوظيفة في stdlib (مثل الرياضيات / الكبيرة) أو الأدوات أو الحزم الشائعة.

تم اقتراح الوظائف التالية حتى الآن وهي قيد الدراسة:

  • استدارة لليسار / استدارة لليمين

    • الإيجابيات: & 63 لم تعد بحاجة إلى تجميع استدارة مع وسيطة غير ثابتة لتعليمة واحدة على x86 و x86-64 ..

    • السلبيات: قصير جدًا / سهل التنفيذ ومضمّن.

    • مستخدم: التشفير / يستخدم التدوير الثابت الذي يتم التعامل معه بشكل صحيح من قبل المترجم.

  • ReverseBits

    • الايجابيات:؟

    • سلبيات: ؟

    • مستخدم: ؟

  • إضافة / فرعية مع ترحيل إرجاع

    • الإيجابيات: باهظ الثمن بخلاف ذلك

    • سلبيات: ؟

    • مستخدم: رياضيات / كبير

تاريخ

14- يناير: أوضح ناتج TrailingZeros و LeadingZeros عندما تكون الوسيطة 0.
14. يناير: الطرق المعاد تسميتها: CountTrailingZeros -> TrailingZeros ، CountLeadingZeros -> LeadingZeros ، CountOnes -> Ones.
13. Jan: اسم العمارة الثابتة.
11. يناير: فتح الاقتراح الأولي للجمهور.

FrozenDueToAge Proposal-Accepted

التعليق الأكثر فائدة

يريد الأشخاص الذين يكتبون رمز الاستدارة لليسار أو لليمين. لا يريدون الاستدارة لليسار أو لليمين ، اعتمادًا على ذلك. إذا قمنا بتوفير التدوير لليسار فقط ، فإن أي شخص يريد التدوير لليمين يجب أن يكتب تعبيرًا لتحويل دورانه الأيمن إلى دوران لليسار. هذا هو نوع التعبير الذي يمكن لأجهزة الكمبيوتر القيام به بشكل تافه ولكن المبرمجين سيرتكبون الأخطاء. لماذا تجعل المبرمجين يكتبونها بأنفسهم؟

ال 168 كومينتر

brtzsnr ربما يجب عليك إرسال هذا المستند إلى الريبو المقترح كما هو موضح في خطوات عملية الاقتراح ؟

نظرًا لأنه تم بالفعل تخفيض السعر باتباع النموذج ، فمن السهل نسخه ولصقه في CL لإنشاء تصميم ملف / 18616-bit-twiddling.md (أو أيًا كان).

cespare من https://github.com/golang/proposal "إذا أراد المؤلف كتابة مستند تصميم ، فيمكنه كتابة مستند". لقد بدأت كمستند تصميم ، إذا كان هناك شعور قوي بضرورة إرسال هذا ، فأنا بخير تمامًا.

سأكون على ما يرام مع هذا ، فمن الشائع استخدام وظائف كافية في العديد من المكتبات الخوارزمية والرياضيات / البتات تبدو وكأنها مكان مناسب.

(على سبيل المثال ، الرياضيات / كبيرة تنفذ أيضًا nlz (== clz).)

من المحتمل أن يكون هناك بعض إراقة الدراجات حول الأسماء. أنا شخصياً أفضل أن تقول الوظائف ما يعودون بدلاً من ما يفعلونه ؛ مما قد يؤدي بدوره إلى أسماء أقصر. على سبيل المثال:

bits.TrailingZeros64(x) بدلاً من bits.CountTrailingZeros64(x)

وهكذا دواليك.

يبدو الاقتراح واضحًا جدًا ومحدودًا - يبدو مستند التصميم مبالغًا فيه. أعتقد أن CL سيكون أكثر ملاءمة في هذه المرحلة.

(هذا هو CL مع API والتنفيذ الأساسي - لغرض المناقشة بدلاً من مستند التصميم. ما زلنا بحاجة إلى تحديد ما إذا كان ينبغي قبول هذا الاقتراح أم لا.)

لقد كتب brtzsnr مستند التصميم بالفعل: إنه موجود في وصف المشكلة ويتبع النموذج . افترضت أن هناك بعض القيمة في وجود كل هذه المستندات في مكان واحد.

آخر قوس مدرج في جدول دعم الأجهزة هو "BSWAP" - هل هو خطأ مطبعي؟

شكرا لكتابة هذا الأمر.

يجب أن تحدد سلسلة doc لـ ctz و clz النتيجة عند تمرير 0.

أنا أيضا أفضل (على سبيل المثال) TrailingZeros32 إلى CountTrailingZeros32. سأكون سعيدًا أيضًا باستخدام Ctz32. إنه موجز ، ومألوف لمعظم الناس ، ويسهل الوصول إليه من خلال googlable للباقي.

شكرا على الاقتراح.
أريد فقط أن أضيف أننا ربما نريد أيضًا التركيز على الاستخدام ، بدلاً من التركيز فقط على التعليمات. على سبيل المثال ، وجد @ dr2chase مرة واحدة أن هناك عدة وظائف log2 في المترجم / المجمّع. إنه قريب من CLZ ولكن ليس هو نفسه. من المحتمل أيضًا أن تكون وظائف مثل هذه في حزمة twiddling. وربما تتضمن أيضًا وظائف مفيدة لا تتعلق بهذه التعليمات.

ماذا عن تقديم حزمة لجميع الأعداد الأولية التي تم تحديدها بواسطة
فرحة الهاكر؟

عند تصميم الحزمة ، لا نحتاج إلى التفكير فيما إذا كانت الوظيفة
يمكن أن تكون جوهرية أم لا. يمكن أن يحدث التحسين لاحقًا. هذا هو،
لا تدع مستوى التنفيذ المنخفض يتحكم في حزمة المستوى العلوي
واجهه المستخدم. نريد واجهة حزمة جيدة ، حتى لو كان بعضها لا يستطيع ذلك
يمكن تعيينها لتعليمات واحدة.

minux ، لحسن الحظ ، كل وظيفة تحتاج إليها حتى الآن هي بالضبط تلك الموجودة في هذا الاقتراح.

تتمتع متابعة Hacker's Delight بميزة أننا لسنا بحاجة إلى إضاعة الوقت في الجدال حول الأسماء.

أود إضافة ما يلي:

ReverseBits (لـ uint32 و uint64)
RotateLeft / Right (يمكن توسيعه بالتوازي مع نوبتين ، لكن المترجم
لا يمكن دائمًا إجراء التحويل بسبب مشكلات نطاق التحول)

ربما أيضا نوعين من نتائج الجمع والطرح؟ على سبيل المثال

func AddUint32 (x ، y ، محمول uint32) (ترحيل ، مجموع uint32) // يجب أن
يكون 0 أو 1.
وبالمثل لـ uint64.

و SqrtInt.

لا يمكن تنفيذ العديد من اقتراحاتي في تعليمات واحدة ، ولكن
هذه هي النقطة: نريد حزمة غمضة جيدة ، وليس مجرد
حزمة intrisics. لا تدع الأجهزة تحد من حزمة المستوى العالي
واجهه المستخدم.

ذات الصلة ، وظائف للتحقق مما إذا كانت إضافة / مضاعفة ستتجاوز.

نقطة بيانات ذات صلة: هناك العديد من المشكلات التي تم تقديمها من أجل cgo بشكل أسرع. في أحد الأمثلة (الاقتراح رقم 16051) ، حقيقة أن التنفيذ السريع لـ bsr / ctz / etc. قد يحدث تم ذكره على أنه من المأمول تقطيعه بعيدًا في مجموعة حالات الاستخدام حيث يميل الأشخاص الذين يكتبون go إلى استخدام cgo.

aclements علق في 1 يوليو 2016:

eloff ، كانت هناك بعض المناقشات (على الرغم من عدم وجود مقترحات محددة على حد علمي) لإضافة وظائف لأشياء مثل popcount و bsr التي سيتم تجميعها على أنها عناصر جوهرية حيث يتم دعمها (مثل الرياضيات. qrt اليوم). مع 1.7 ، نحاول ذلك في وقت التشغيل ، والذي أصبح متوفرًا الآن ctz جوهريًا على amd64 SSA. من الواضح أن هذا لا يحل المشكلة الإجمالية ، لكنه سيقضي على سبب آخر لاستخدام cgo في سياق منخفض النفقات.

ينجذب الكثير من الأشخاص (بمن فيهم أنا) للذهاب بسبب الأداء ، لذا فإن أشياء مثل هذا الاقتراح الحالي للعبث قليلاً ستساعد. (ونعم ، أصبح cgo الآن أسرع في 1.8 ، وهو أمر جيد أيضًا).

RotateLeft / Right (يمكن توسيعه بالتوازي مع نوبتين ، لكن المترجم
لا يمكن دائمًا إجراء التحويل بسبب مشكلات نطاق التحول)

minux هل يمكنك توضيح ما هي المشكلة؟

brtzsnr : أعتقد أن ما يشير إليه Minux هو أنه عندما تكتب (x << k) | (x >> (64-k)) ، فأنت تعلم أنك تستخدم 0 <= k < 64 ، لكن المترجم لا يمكنه قراءة أفكارك ، وهذا ليس واضحًا مشتق من الكود. إذا كانت لدينا الوظيفة

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

ثم يمكننا التأكد (عبر & 63) من أن المترجم يعرف أن نطاق k محدود.
لذلك إذا لم يتمكن المترجم من إثبات أن الإدخال مقيد ، فنحن بحاجة إلى AND إضافية. هذا أفضل من عدم توليد التجميع الدوار على الإطلاق.

يوم الجمعة ، 13 كانون الثاني (يناير) 2017 الساعة 10:37 مساءً ، Keith Randall [email protected]
كتب:

brtzsnr https://github.com/brtzsnr : أعتقد أن ما يشير إليه Minux
هو ذلك عندما تكتب (س << ك) | (x >> (64-k)) ، أنت تعلم أنك تستخدم 0
<= k <64 ، لكن المترجم لا يمكنه قراءة أفكارك ، وهذا ليس واضحًا
مشتق من الكود. إذا كانت لدينا الوظيفة

func leftRot (x uint64، k uint) uint64 {
ك & = 63
العودة (س << ك) | (س >> (64 ك))
}

ثم يمكننا التأكد (عبر & 63) من أن المترجم يعرف أن النطاق
من k يحدها.
لذلك إذا لم يتمكن المترجم من إثبات أن الإدخال مقيد ، فنحن بحاجة إلى قيمة إضافية
و. هذا أفضل من عدم توليد التجميع الدوار على الإطلاق.

حق. إذا حددنا وظائف RotateLeft و RotateRight ، فيمكننا رسميًا
حدد وظيفة استدارة لليسار / لليمين k بت (بغض النظر عن ماهية k). هذا هو
على غرار كيفية تعريف عمليات التحول لدينا. وهذا التعريف ايضا
خرائط لتدوير التعليمات الفعلية بشكل جيد (على عكس التحولات ، حيث يكون لدينا المزيد
يتطلب التعريف الحدسي مقارنة مع بنى معينة).

ماذا عن وظائف خلط البايت والبت (والتفكيك ) التي تستخدمها مكتبة ضغط الشرائح (يبدأ الخلط من الشريحة 17). يمكن تسريع هذه الوظائف SSE2 / AVX2.

في الجمعة ، 13 كانون الثاني (يناير) 2017 الساعة 11:24 مساءً ، كتب opennota [email protected] :

ماذا عن وظائف خلط البايت والبت التي يستخدمها blosc
https://github.com/Blosc/c-blosc مكتبة الضغط؟ الشرائح
http://www.slideshare.net/PyData/blosc-py-data-2014 (الخلط
يبدأ من الشريحة 17). يمكن تسريع هذه الوظائف SSE2 / AVX2.

SIMD مشكلة أكبر وهي خارج نطاق هذه الحزمة. إنه

17373.

الوظائف المقترحة الحالية لها تطبيق Go أصلي أكبر بكثير وأكثر تكلفة بشكل غير متناسب من الأمثل. من ناحية أخرى ، من السهل كتابة التدوير بطريقة مضمنة بطريقة يمكن للمجمع أن يتعرف عليها.

minux وأيضًا أي شخص آخر: هل تعرف مكان استخدام التدوير لليسار / لليمين مع عدد غير ثابت من البتات المستديرة؟ يستخدم crypto / sha256 التدوير على سبيل المثال ، ولكن مع عدد ثابت من البتات.

rotate سهل للكتابة بشكل مضمّن بطريقة يمكن للمترجم أن يتعرف عليها.

إنه سهل لمن هم على دراية بالأجزاء الداخلية للمترجم. يسهل وضعها في حزمة الرياضيات / البتات على الجميع.

هل تعلم أين يتم استخدام التدوير لليسار / لليمين مع عدد غير ثابت من البتات المستديرة؟

هذا مثال من # 9337:

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

في كل استدعاء ، يكون عدد البتات الذي تم تدويره ثابتًا في كل مرة ، ولكن الوظيفة نفسها ليست مضمنة حاليًا ، لذلك يتم تجميعها بدون أي تعليمات تدوير. من المؤكد أن وظيفة مكتبة الرياضيات / البتات ستساعد هنا.

يوم السبت 14 كانون الثاني (يناير) 2017 الساعة 5:05 صباحًا ، ألكساندرو Moșoi [email protected]
كتب:

الوظائف المقترحة الحالية لها تنفيذ أصلي لـ Go أكبر بكثير
وأغلى بشكل غير متناسب من الأمثل. من ناحية أخرى تناوب
من السهل أن تكتب بطريقة مضمنة بطريقة يمكن للمترجم أن يتعرف عليها.

كما شددت مرات عديدة في هذا الموضوع ، هذه ليست الطريقة الصحيحة
تصميم حزمة Go. يرتبط كثيرًا بالأجهزة الأساسية. ما كنا
want عبارة عن حزمة غمضة جيدة تكون مفيدة بشكل عام. سواء
وظائف يمكن توسيعها إلى تعليمات واحدة غير ذات صلة طالما
لأن واجهة API معروفة ومفيدة بشكل عام.

minux https://github.com/minux وأيضًا أي شخص آخر: هل تعلم
أين يتم استخدام التدوير لليسار / لليمين مع عدد غير ثابت من البتات المستديرة؟
يستخدم crypto / sha256 التدوير على سبيل المثال ، ولكن مع عدد ثابت من البتات.

حتى لو كان عدد بتات التدوير في المشكلة الفعلية ثابتًا ، فإن
المترجم قد لا يكون قادرا على رؤية ذلك. على سبيل المثال عندما يتم تخزين عدد التحول
في مصفوفة ، أو الاختباء في عداد الحلقة أو حتى المتصل غير المضمّن
وظيفة.

أحد الأمثلة البسيطة على استخدام عدد متغير من التدوير هو مثير للاهتمام
تنفيذ 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 يبدو المثال قرارًا داخليًا سيئًا إذا لم يكن العفن مضمّنًا. هل حاولت كتابة الدالة كـ func rot(x, n) بدلاً من rot = func(x, n) ؟

minux : أتفق معك. لا أحاول ربط API بمجموعة تعليمات معينة ؛ دعم الأجهزة مكافأة لطيفة. ينصب تركيزي الأساسي على العثور على الاستخدامات في الكود الحقيقي (وليس رمز اللعبة) لفهم السياق ، وما هو أفضل توقيع ومدى أهمية توفير الوظيفة المفضلة للجميع. وعد التوافق سوف يعضنا لاحقًا إذا لم نفعل ذلك بشكل صحيح الآن.

على سبيل المثال: ماذا يجب أن يكون توقيع الإضافة مع الإرجاع بالحمل؟ Add(x, y uint64) (c, s uint64) ؟ بالنظر إلى math/big ربما نحتاج إلى Add(x, y uintptr) (c, s uintptr) أيضًا.

يبدو المثال قرارًا داخليًا سيئًا إذا لم يكن التعفن مضمّنًا.

نعم فعلا. إنه جزء من خطأ يشكو من التضمين. :)

هل حاولت كتابة الدالة كـ func rot (x، n) بدلاً من rot = func (x، n)؟

إنه ليس الكود الخاص بي - وهذا جزء من النقطة. وعلى أي حال ، إنه رمز معقول.

سيكون من الجيد أن نضمن (في وثائق الحزمة؟) أن وظائف التدوير ومبادلة البايت هي عمليات ذات وقت ثابت بحيث يمكن استخدامها بأمان في خوارزميات التشفير. ربما شيء للتفكير فيه لوظائف أخرى أيضا.

يوم الخميس ، 19 كانون الثاني (يناير) 2017 الساعة 11:50 صباحًا ، مايكل مونداي [email protected]
كتب:

سيكون من الجيد أن نضمن (في وثائق الحزمة؟) أن ملف
وظائف التدوير ومبادلة البايت هي عمليات ذات وقت ثابت بحيث تكون
يمكن استخدامها بأمان في خوارزميات التشفير. ربما شيء للتفكير فيه
للوظائف الأخرى أيضًا.

التنفيذ البسيط لمقايضة البايت هو وقت ثابت ، ولكن إذا كان الأساس
لا توفر الهندسة المعمارية تعليمات تغيير متغيرة ، سيكون الأمر صعبًا
لضمان تنفيذ تناوب الوقت المستمر. ربما لن يركض Go أبدًا
على تلك الأبنية بالرغم من ذلك.

بعد قولي هذا ، هناك أيضًا فرصة لا يستهان بها أن الأساس
تستخدم الهندسة المعمارية الدقيقة ناقل حركة متعدد الدورات ، ولا يمكننا ضمان ذلك
وقت ثابت بالتناوب على تلك التطبيقات.

إذا كان الوقت الثابت الصارم مطلوبًا ، فربما تكون الطريقة الوحيدة هي كتابة التجميع
(وحتى في هذه الحالة ، فإنه يضع افتراضات قوية أن جميع ملفات
التعليمات هي نفسها وقت ثابت ، والذي يعتمد ضمنيًا على
العمارة الدقيقة.)

بينما أفهم الحاجة إلى مثل هذه الضمانات ، إلا أنها في الواقع أبعد من ذلك
سيطرتنا.

أنا أميل إلى الاتفاق معminux. إذا كنت تريد أساسيات تشفير في الوقت الثابت ، فيجب أن تعيش في تشفير / خفية. يمكن أن يُعيد التشفير / الدقيق التوجيه بسهولة إلى الرياضيات / وحدات البت على الأنظمة الأساسية حيث تم التحقق من هذه التطبيقات. يمكنهم فعل شيء آخر إذا تطلب الأمر تنفيذًا أبطأ ولكن في وقت ثابت.

يبدو أن هذا يستحق القيام به. ترك لـ griesemer و @ randall77 للطبيب البيطري. تبدو الخطوة التالية كمستند تصميم تم تسجيله في المكان المعتاد (أرى الرسم أعلاه).

الآن وبعد أن تمضي قدمًا في هذا الاقتراح ، يجب أن نتفق على تفاصيل واجهة برمجة التطبيقات. الأسئلة التي أراها في الوقت الحالي:

  • ما الوظائف التي يجب تضمينها؟
  • الأنواع التي يجب التعامل معها ( uint64 ، uint32 فقط ، أو uint64 ، uint32 ، uint16 ، uint8 ، أو uintptr
  • تفاصيل التوقيع (على سبيل المثال ، TrailingZeroesxx(x uintxx) uint ، مع xx = 64 ، 32 ، وما إلى ذلك ، مقابل TrailingZeroes(x uint64, size uint) uint حيث الحجم هو واحد من 64 ، 32 ، وما إلى ذلك - قد يؤدي الأخير إلى واجهة برمجة تطبيقات أصغر وقد لا يزال سريعًا بدرجة كافية عند التنفيذ)
  • بعض أسماء التخلص من الدراجات (أحب مصطلحات "Hacker's Delight" ولكن قد يكون تهجئتها أكثر ملاءمة)
  • هل هناك مكان أفضل من الرياضيات / بت لهذه الحزمة.

brtzsnr هل ترغب في الاستمرار في قيادة هذا الجهد؟ أنا بخير إذا كنت تريد أن تأخذ التصميم الأولي الخاص بك وتكرره في هذه المشكلة أو إذا كنت تفضل إعداد مستند تصميم مخصص. بدلاً من ذلك ، يمكنني اختيار هذا ودفعه إلى الأمام. أحب أن أرى هذا يدخل خلال مرحلة 1.9.

أفضل أسماء xx المكتوبة ، شخصيًا: bits. يعتبر TrailingZeroes (uint64 (x) ، 32) أكثر تعقيدًا وأقل قابلية للقراءة من البتات. uintptr أكثر سهولة (xx = Ptr؟).

قد يكون الأمر أكثر وضوحًا أيضًا إذا لم تقم ، على سبيل المثال ، بتضمين uint8 في الإصدار الأول ولكنك قمت بإضافته لاحقًا - فجأة سيكون هناك الكثير من وظائف xx = 8 الجديدة بدلاً من مجموعة من تعليقات المستندات المحدثة التي تضيف 8 إلى قائمة الأحجام الصالحة مع ملاحظة في مستندات الإصدار يسهل تفويتها.

إذا تم استخدام الأسماء المكتوبة ، أعتقد أنه يجب تضمين مصطلحات فرحة القراصنة في الأوصاف على أنها "تُعرف أيضًا باسم" حتى تتمكن عمليات البحث (في الصفحة أو عبر محرك البحث) من العثور على الاسم المتعارف عليه بسهولة إذا كنت تبحث عن تهجئة خاطئة .

أعتقد أن الرياضيات / البتات مكان جيد - إنها رياضيات تحتوي على وحدات بت.

يجب أن أشير إلى أن SwapBytes{16,32,64} أكثر اتساقًا مع الوظائف في sync/atomic من SwapBytes(..., bitSize uint) .

على الرغم من أن strconv حزمة يفعل استخدام ParseInt(..., bitSize int) نمط، وهناك المزيد العلاقة بين bits و atomic ، من هناك مع strconv .

ثلاثة أسباب لا أحب SwapBytes (uint64 ، الحجم uint):

  1. قد يستخدمه الأشخاص في الحالات التي لا يكون فيها الحجم ثابتًا وقت التجميع (عند
    الأقل إلى المترجم الحالي) ،
  2. يستلزم الكثير من نوع التحويلات. أول من قام بتحويل uint32 إلى
    uint64 ، ثم تحويله مرة أخرى.
  3. يجب أن نحتفظ بالاسم العام SwapBytes للحصول على اسم عام مستقبلي
    نسخة من الوظيفة (عندما تحصل Go على دعم الأدوية).

griesemer روبرت ، من فضلك تولي الاقتراح. سيكون لدي الوقت لدفع هذا الاقتراح إلى الأمام في غضون شهر واحد ، ولكن التقدم لا ينبغي أن يتوقف حتى ذلك الحين.

يبدو أن هناك تفضيلًا واضحًا لتوقيعات النموذج:

func fffNN(x uintNN) uint

الذي يترك مفتوحًا أي NN لدعمه. دعنا نركز على NN = 64 لغرض المناقشة المستمرة. سيكون من السهل جدًا إضافة الأنواع المتبقية حسب الحاجة (بما في ذلك uintptr).

وهو ما يقودنا مباشرة إلى الاقتراح الأصلي من قبل brtzsnr والوظائف التالية (والاختلافات الخاصة بكل منها لأنواع مختلفة) ، بالإضافة إلى ما اقترحه الناس في هذه الأثناء:

// 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

قد يكون لدينا مجموعة من وظائف المبادلة أيضًا. أنا شخصياً متشكك في ما يلي: 1) لم أحتاج إلى SwapBits مطلقًا ، ومعظم استخدامات SwapBytes ترجع إلى رمز يدركه endian عندما لا يكون كذلك. تعليقات؟

// 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

ثم قد يكون هناك مجموعة من العمليات الصحيحة. ستكون موجودة فقط في هذه الحزمة لأن بعضها (مثل Log2) قد يكون قريبًا من وظائف أخرى في هذه الحزمة. يمكن أن تكون هذه الوظائف في مكان آخر. ربما يحتاج اسم الحزمة bits إلى التعديل. تعليقات؟

// 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

أخيرًا ، اقترحت minux عمليات مثل AddUint32 وما إلى ذلك. سأتركها بالخارج الآن لأنني أعتقد أنها أكثر صعوبة في تحديدها بشكل صحيح (وهناك المزيد من التنوع). يمكننا العودة إليهم لاحقًا. دعنا نصل إلى بعض الإجماع على ما ورد أعلاه.

أسئلة:

  • أي آراء حول أسماء الوظائف؟
  • أي آراء حول العمليات الصحيحة؟
  • أي آراء حول اسم الحزمة / الموقع؟

أفضل أسماء الوظائف الطويلة. يتجنب Go الاختصار في أسماء الوظائف. يمكن للتعليقات أن تقول ألقابها ("nlz" ، "ntz" ، إلخ) للأشخاص الذين يبحثون في الحزمة بهذه الطريقة.

griesemer ، يبدو أن رسالتك تحتوي على أخطاء إملائية. التعليقات لا تتطابق مع تواقيع الوظيفة.

أستخدم SwapBits في تطبيقات الضغط. ومع ذلك ، هل توفر الأبنية الرئيسية أي قدرة على عمل انعكاس البت بكفاءة؟ كنت أخطط لعمل الكود الخاص بي فقط:

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 : تواقيع محدثة (أخطاء مطبعية ثابتة). تم أيضًا تحديث الأسئلة (يفضل الأشخاص أسماء الاختصارات الصريحة).

ما لم يكن هناك دعم أصلي لمبادلة البت ، سأصوت لإهمال SwapBits . يمكن أن يكون غامضًا بعض الشيء بالاسم وحده سواء تم تبديل البتات فقط داخل كل بايت ، أو عبر uint64 بأكمله.

لماذا تستبعد شيئًا ما بناءً على توفر التعليمات فقط؟ بت عكسي
له استخدامات ملحوظة في FFT.

للإجابة على سؤالك حول توفر تعليمات البت العكسي: يوجد arm
تعليمات RBIT.

griesemer بقدر ما نوع تواقيع وظائف مثل

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

هل يأخذ RotateLeftN إلخ نقاطًا لأن هذا ضروري لسهولة التطفل (عندما يكون ذلك ممكنًا) أو لمجرد أن هذا هو المجال؟ إذا لم تكن هناك حاجة تقنية قوية ، فهناك سابقة أقوى لأخذ النوايا ، حتى لو كانت القيم السلبية غير منطقية. إذا كانت هناك حاجة فنية قوية ، فهل يجب أن يكونوا متفقين مع N المناسب من أجل الانتظام؟

بغض النظر عن OnesN وأمثالها يجب أن ترجع ints إلا إذا كان الأمر كذلك يمكن أن تتكون هذه العمليات من عمليات بت أخرى وفي هذه الحالة يجب عليهم إرجاع uintN لـ N.

jimmyfrasche لأنه المجال. وحدة المعالجة المركزية لا تهتم. ما إذا كان هناك شيء ما هو int أو uint غير ذي صلة لمعظم العمليات باستثناء المقارنات. ومع ذلك ، إذا جعلناها قيمة int ، فعلينا أن نشرح أنها ليست سلبية (نتيجة) ، أو أنه يجب ألا تكون سلبية (وسيطة) ، أو تحديد ما يفترض أن تفعله عندما تكون سلبية (حجة التناوب). قد نتمكن من الحصول على تدوير واحد فقط في هذه الحالة والذي سيكون أمرًا رائعًا.

لست مقتنعًا بأن استخدام int يجعل الأمور أسهل. إذا تم تصميمها بشكل صحيح ، فسوف تتدفق uints إلى uints (هذا هو الحال في الرياضيات / الكبيرة) ولا يلزم إجراء أي تحويلات. ولكن حتى إذا كان التحويل مطلوبًا ، فسيكون مجانيًا من حيث تكلفة وحدة المعالجة المركزية (ولكن ليس من حيث سهولة القراءة).

لكنني سعيد لسماع / رؤية الحجج المقنعة بخلاف ذلك.

يجب أن يكون عدد بتات التدوير uint (بدون حجم محدد) لمطابقة
عامل التحول للغة.

سبب عدم استخدام int هو أنه سيكون هناك غموض سواء
RotateRight - 2 بت يساوي RotateLeft 2 بت.

minux لا يوجد غموض عندما يتم تحديد Rotate(x, n) لتدوير x بمقدار n mod 64 بت: التدوير لليسار بمقدار 10 بت هو نفسه التدوير لليمين بمقدار 64-10 = 54 بت ، أو (إذا سمحنا بالوسيطات int) بمقدار -10 بت (بافتراض أن القيمة الموجبة تعني التدوير إلى اليسار). -10 mod 64 = 54. على الأرجح نحصل على التأثير مجانًا حتى مع تعليمات وحدة المعالجة المركزية. على سبيل المثال ، تنظر تعليمات 32 بت x86 ROL / ROR بالفعل إلى 5 بتات السفلية من سجل CL ، مما يؤدي بفعالية إلى تعديل 32 لدورات 32 بت.

الحجة الحقيقية الوحيدة هي الانتظام مع بقية stdlib. هناك العديد من الأماكن التي تكون فيها uints منطقية جدًا ولكن يتم استخدام ints بدلاً من ذلك.

نظرًا لأن الرياضيات / الكبيرة هي استثناء ملحوظ ، فليس لدي مشكلة في أن تكون هذه مشكلة أخرى ، لكنها شيء يجب مراعاته.

أفترض أن minux تعني الغموض بالنسبة لشخص ما يقرأ /

هل يجب أن يتم تسمية وحدات البت. ماذا عن البتات.

فكرة أخرى هي bits.SwapN (v uint64، n int) بدلاً من bits.SwapBytes حيث يمثل n عدد البتات التي سيتم تجميعها من أجل المقايضة. عندما n = 1 يتم عكس البتات ، وعندما n = 8 ، يتم تبديل البايت. إحدى الفوائد هي أن bits.SwapBytes لم يعد من الضروري وجودها ، على الرغم من أنني لم أر أبدًا ضرورة لأي قيمة أخرى لـ n ، فربما يختلف الآخرون.

كما هو محدد أعلاه ، LeadingZeros64 ، TrailingZeros64 ، Ones64 كل LGTM.

يعد Rotate64 واحدًا

ليس لدي رأي قوي حول خلط البايت / البايت / تبديل / عكس. لعكس البتات ، يبدو أن bits.Reverse64 هو اسم أفضل. وربما bits.ReverseBytes64 ؟ أجد Swap64 قليلاً غير واضح. أرى جاذبية امتلاك Swap64 لحجم المجموعة ، لكن ما هو السلوك عندما لا يقسم حجم المجموعة 64 بالتساوي؟ إذا كانت أحجام المجموعة الوحيدة المهمة هي 1 و 8 ، فسيكون من الأسهل منحهم وظائف منفصلة. أتساءل أيضًا عما إذا كان نوعًا من التلاعب العام بمجال البت قد يكون أفضل ، ربما بالنظر إلى تعليمات arm64 و amd64 BMI2 للإلهام.

لست مقتنعًا بأن وظائف الرياضيات الصحيحة تنتمي إلى هذه الحزمة. يبدو أنهم ينتمون إلى حزمة الرياضيات ، حيث يمكنهم استخدام وظائف البتات في تنفيذها. ذات صلة ، لماذا لا func Sqrt(x uint64) uint32 (بدلاً من إرجاع uint64

على الرغم من أن AddUint32 والأصدقاء معقدون ، آمل أن نعيد زيارتهم في النهاية. إلى جانب أشياء أخرى ، سيوفر MulUint64 الوصول إلى HMUL ، والذي يوفره حتى RISC-V ISA كإرشادات. لكن نعم ، دعنا نحصل على شيء ما أولاً ؛ يمكننا دائمًا التوسع لاحقًا.

bits يشبه اسم الحزمة الصحيح. إنني أميل إلى القول إن مسار الاستيراد يجب أن يكون فقط bits ، وليس math/bits ، لكنني لا أشعر بقوة.

يبدو أن البتات تشبه اسم الحزمة الصحيح. إنني أميل إلى القول إن مسار الاستيراد يجب أن يكون مجرد أجزاء ، وليس رياضيات / بتات ، لكنني لا أشعر بقوة.

IMO ، إذا كانت bits ، (بدون قراءة مستندات الحزمة) كنت أتوقع أن تكون مشابهة إلى حد ما للحزمة bytes . هذا ، بالإضافة إلى الوظائف التي تعمل على وحدات البت ، أتوقع العثور على Reader و Writer لقراءة البتات وكتابتها إلى / من تدفق بايت. جعلها math/bits تجعلها أكثر وضوحا أنها مجرد مجموعة من الوظائف عديمة الحالة.

(أنا لا أقترح أن نضيف قارئ / كاتب لتدفقات البت)

يعتبر Rotate64 واحدًا مع مبلغ تدوير موقع أمرًا جذابًا. ستكون معظم التدويرات بكمية ثابتة أيضًا ، لذلك (إذا / عندما يصبح هذا أمرًا جوهريًا) فلن تكون هناك تكلفة وقت تشغيل لعدم وجود وظائف منفصلة يمين / يسار.

أستطيع أن أرى كيف يمكن أن يكون من الملائم أن يكون لديك حزمة API أصغر قليلاً من خلال الجمع بين التدوير لليسار / لليمين في Rotate ، ولكن هناك أيضًا مسألة التوثيق الفعال للمعامل n أجل تشير إلى أن:

  • نتائج سلبية n في تدوير لليسار
  • صفر n النتائج بدون تغيير
  • نتائج موجبة n في تدوير اليمين

بالنسبة لي ، لا يبدو أن النفقات العقلية والوثائق الإضافية تبرر الجمع بين الاثنين في Rotate . الحصول على RotateLeft و RotateRight حيث n هو uint يبدو أكثر سهولة بالنسبة لي.

mdlayher ضع في اعتبارك أنه بالنسبة لكلمة n-bit يتم تدويرها بمقدار k بت إلى اليسار هو نفس تدوير nk bits إلى اليمين. حتى إذا قمت بفصل هذا في وظيفتين ما زلت بحاجة إلى فهم أن التدوير بمقدار k بت إلى اليسار يعني دائمًا الدوران بواسطة (k mod n) بت (إذا قمت بالتدوير بأكثر من n بت ، فستبدأ من جديد). بمجرد القيام بذلك ، يمكنك فقط أن تقول أن وظيفة التدوير تدور دائمًا بمقدار k mod n bits ، وقد انتهيت. لا داعي لشرح القيمة السالبة أو دالة ثانية. انها فقط تعمل. إنه في الواقع أبسط.

علاوة على ذلك ، فإن الأجهزة (على سبيل المثال في x86) تقوم بذلك تلقائيًا ، حتى بالنسبة لـ k غير الثابت.

griesemer ، الجانب السلبي لـ Rotate هو أنه لا يشير إلى الاتجاه الإيجابي. هل Rotate32(1, 1) يساوي 2 أم 0x80000000؟ على سبيل المثال ، إذا كنت أقرأ الكود الذي استخدم ذلك ، فأنا أتوقع أن تكون النتيجة 2 ، ولكن يبدو أن mdlayher يتوقع أن تكون 0x80000000. من ناحية أخرى ، RotateLeft و RotateRight اسمان لا لبس فيهما ، بغض النظر عما إذا كانا يأخذان وسيطة موقعة أو غير موقعة. (لا أتفق مع minux في أنه من الغموض ما إذا كان RotateRight by -2 يساوي RotateLeft 2. يبدو أنهما مكافئ لي بوضوح ولا أرى كيف يمكنك تحديدهما بخلاف ذلك.)

@ المكملات التي يمكن إصلاحها من خلال وجود دالة واحدة فقط تسمى RotateLeft64 واستخدام القيم السالبة للتدوير إلى اليمين. أو مع المستندات. (FWIW ، في مثالك ، أتوقع أيضًا 2 ، وليس 0x800000000.)

josharian ، أوافق ، على الرغم من أنه يبدو غريبًا بعض الشيء أن يكون لديك RotateLeft دون أن يكون لديك أيضًا RotateRight . يبدو التناسق في وجود دوران موقَّع ذا قيمة محتملة إذا تم حساب التدوير ، ولكن بالنسبة للدوران المستمر ، أفضل قراءة الكود الذي يقول "استدارة لليمين بتتين" بدلاً من "استدارة لليسار بمجرد مزاح سالب بتتين".

تكمن مشكلة إصلاح هذا الأمر في المستندات في أن المستندات لا تساعد في قراءة الكود الذي يستدعي الوظيفة.

يريد الأشخاص الذين يكتبون رمز الاستدارة لليسار أو لليمين. لا يريدون الاستدارة لليسار أو لليمين ، اعتمادًا على ذلك. إذا قمنا بتوفير التدوير لليسار فقط ، فإن أي شخص يريد التدوير لليمين يجب أن يكتب تعبيرًا لتحويل دورانه الأيمن إلى دوران لليسار. هذا هو نوع التعبير الذي يمكن لأجهزة الكمبيوتر القيام به بشكل تافه ولكن المبرمجين سيرتكبون الأخطاء. لماذا تجعل المبرمجين يكتبونها بأنفسهم؟

انا مقتنع.

aclementsianlancetaylor اتخاذها نقطة. (ومع ذلك ، من المحتمل أن يؤدي تطبيق RotateLeft / Right إلى استدعاء تنفيذ واحد لـ rotate.)

فكرة الاسم هي وضع الكتابة في اسم الحزمة بدلاً من اسم التوقيع. bits64.Ones بدلاً من bits.Ones64 .

btracey ، flag64.Int أو math64.Floatfrombits أو sort64.Floats أو atomic64.StoreInt .

على الرغم من وجود

لم أفكر في atomic كسابقة (ليس في استخدام Go العادي ، لحسن الحظ). الأمثلة الأخرى مختلفة لأن الحزم أكبر من مجموعة وظائف متكررة لعدد من الأنواع المختلفة.

من السهل الاطلاع على الوثائق (على سبيل المثال ، على godoc) ، عندما تذهب إلى bits64 وترى
Ones LeadingZeros TrailingZeros

بدلاً من الذهاب إلى bits والمشاهدة
Ones8 Ones16 Ones32 Ones64 LeadingZeros8 ...

iand ، هذا أيضًا إجمالي جدًا. أعتقد أن 32 و 64 لا يبدوان جيدًا لجميع اللواحق الرقمية الحالية لـ Aff و Mat و Vec. ومع ذلك ، أود أن أقول إن هذا استثناء وليس أسلوب Go العادي.

هناك سابقة قوية جدًا في Go لاستخدام أسلوب التسمية pkg.foo64 بدلاً من pkg64.foo.

تصبح حزمة API أكبر بمقدار n مرة إذا كان لدينا أنواع n ، لكن تعقيد واجهة برمجة التطبيقات لا يزداد. قد يكون النهج الأفضل لحل هذه المشكلة من خلال التوثيق وكيفية تقديم واجهة برمجة التطبيقات عبر أداة مثل go doc. على سبيل المثال ، بدلاً من:

// 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

التي تضيف بوضوح النفقات العقلية عند النظر إلى واجهة برمجة التطبيقات ، يمكننا تقديمها على النحو التالي:

// 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 ذكيًا فيما يتعلق بالوظائف المتشابهة بهذا المعنى ويقدمها كمجموعة بسلسلة مستند واحدة. سيكون هذا مفيدًا في الحزم الأخرى أيضًا.

للتلخيص ، أعتقد أن مخطط التسمية المقترح يبدو جيدًا وفي تقليد Go. مشكلة العرض هي سؤال منفصل يمكن مناقشته في مكان آخر.

+1 وضع حجم البت في اسم الحزمة.

bits64.Log2 يقرأ أفضل من bits.Log264 (أشعر أن Log2 ينتمي إليها - وتسمية الحزمة ليست سببًا جيدًا لإبقائها بالخارج)

في النهاية ، إنها نفس واجهة برمجة التطبيقات لكل نوع "معلمة" حسب النوع القياسي ، لذلك إذا كان للوظائف نفس الاسم عبر الأنواع ، فمن الأسهل إعادة بناء الشفرة باستخدام حزم منفصلة - فقط قم بتغيير مسار الاستيراد (بدائل الكلمة بأكملها هي تافهة مع gofmt -r لكن تحويلات اللاحقة المخصصة أكثر صعوبة).

أتفق مع griesmeyer على أن اللاحقة bitsize في اسم الوظيفة يمكن أن تكون اصطلاحية ، لكنني أشعر أن هذا يستحق ذلك فقط إذا كان هناك رمز غير تافه في الحزمة مستقل عن النوع.

يمكننا سرقة مسرحية من التشفير / الثنائي ، وإنشاء متغيرات باسم Uint64 ، Uint32 ، ... والتي سيكون لها طرق تقبل الأنواع المحددة مسبقًا المرتبطة.

بت. Uint64
بت وحدة 8. العكس
بت
...

griesemer كيف تعرف كيفية

rogpeppe ، يمكن أن تكون بتات. يقول Log64 والمستندات أنه كان الأساس 2 (ماذا سيكون أيضًا في حزمة بت؟) على الرغم من الفوضى مثل وجود حزم 8/16/32/64 / ptr على مستوى واحد ، فهو كذلك اجعل كل منهم منظف على حدة. (يبدو أيضًا أن ناقل الحركة الخاص بك قد تم قطعه عن مركز الصمت.)

nerdatmath سيكون هذا مختلفًا بعض الشيء نظرًا لأنه سيكون لديهم نفس الواجهة بالمعنى العامي ولكن ليس بمعنى Go ، كما هو الحال في التشفير / الثنائي (كلاهما ينفذ binary.ByteOrder) ، لذا فإن المتغيرات ستكون فقط لمسافات الأسماء ولن يلتقط godoc أيًا من الطرق (# 7823) ما لم يتم تصدير الأنواع ، وهو أمر فوضوي بطريقة مختلفة.

أنا بخير مع لواحق الحجم ، لكن بشكل عام ، أفضل الحزم المنفصلة. ومع ذلك ، لا يكفي عناء تجاوز هذا التعليق.

nerdatmath إذا كانت bits.Uint64 = bits.Uint8 ) ، مما سيمنع المترجم من معاملتها على أنها جوهرية ، والتي كانت أحد الدوافع (على الأقل جزء من) الحزمة.

لا يمكن تغيير المتغيرات حقًا إذا كانت من نوع غير مُستورد وليس لها حالة (بنية فارغة غير مُصدرة). ولكن بدون واجهة مشتركة ، فإن godoc (اليوم) سيكون إجماليًا. قابل للإصلاح على الرغم من أن هذا هو الجواب.

إذا انتهى بك الأمر باستخدام حزم متعددة ، على الرغم من ذلك ، إذا كان هناك عدد كافٍ من التكرار والحجم لضمان ذلك ، فربما عليك على الأقل تسمية الحزم مثل "X / bits / int64s" ، "X / bits / ints" ، "X / بت / int32s "لمطابقة" أخطاء "،" سلاسل "،" بايت ". لا يزال يبدو وكأنه الكثير من انفجار الحزمة.

لا أعتقد أننا يجب أن نسير في الطريق إلى حزم متعددة خاصة بالنوع ، فوجود حزمة واحدة بسيطة ولا يؤدي إلى تضخيم عدد الحزم في مكتبة Go.

لا أعتقد أن Ones64 و TrailingZeroes64 أسماء جيدة. لا يخبرون أنهم يعيدون عددًا. إضافة البادئة Count تجعل الأسماء أطول. غالبًا ما يتم تضمين هذه الوظائف في برامجي في تعبيرات أكبر ، لذا فإن أسماء الوظائف القصيرة ستزيد من قابلية القراءة. على الرغم من أنني استخدمت الأسماء من كتاب "Hacker's Delight" ، إلا أنني أقترح اتباع فن الإستذكار لمجمع Intel: Popcnt64 و Tzcnt64 و Lzcnt64. الأسماء مختصرة ، تتبع نمطًا ثابتًا ، تبلغ عن إرجاع العدد وأنه تم إنشاؤه بالفعل.

عادةً ما يتم إرجاع الأعداد في Go على أنها ints ، حتى عندما لا يكون العد سالبًا أبدًا. المثال الرئيسي هو الدالة المضمنة len ، ولكن قراءة وكتابة و Printf وما إلى ذلك ، تُرجع جميع الأعداد الصحيحة أيضًا. أجد استخدام قيمة uint للعد أمرًا مفاجئًا للغاية وأقترح إعادة قيمة int.

إذا كان الاختيار بين (لإساءة التدوين) math / bits / int64s.Ones و math / bits.Ones64 ، فأنا بالتأكيد أفضل حزمة واحدة. من الأهمية بمكان أن يكون لديك بت في معرف الحزمة بدلاً من التقسيم حسب الحجم. إن وجود وحدات بت في معرّف الحزمة يجعل قراءة الكود أسهل ، وهو أكثر أهمية من الإزعاج الطفيف المتمثل في التكرار في وثائق الحزمة.

ulikunitz يمكنك دائمًا عمل ctz := bits.TrailingZeroes64 ، وما شابه ذلك ، في الكود الذي يستخدم وحدات البت على نطاق واسع. يحقق ذلك توازنًا بين وجود أسماء ذاتية التوثيق عالميًا وأسماء مضغوطة محليًا للتعليمات البرمجية المعقدة. التحول المعاكس ، countTrailingZeroes := bits.Ctz64 ، يكون أقل فائدة لأن الخصائص العامة اللطيفة قد ضاعت بالفعل.

أنا أعبث بالأشياء على مستوى البت نادرًا جدًا. لا بد لي من البحث عن الكثير من هذه الأشياء في كل مرة ، فقط لأنه مرت سنوات منذ أن كان علي التفكير في الأمر ، لذلك أجد جميع أسماء Hacker's Delight / asm غامضة بشكل مثير للغضب. أفضل أن أقول فقط ما فعلته حتى أتمكن من تحديد الشخص الذي أحتاجه والعودة إلى البرمجة.

أتفق مع ulikunitz على أن الأسماء الطويلة تؤلم العين. في المرة الأولى التي ترى فيها بت ، TrailingZeroes64 ، قد يكون توثيقًا ذاتيًا. في كل مرة لاحقة ، يكون الأمر مزعجًا. أستطيع أن أرى لماذا يفعل الناس ctz: = bits.TrailingZeroes64 ، لكنني أعتقد أن الاسم الذي يجب تخصيصه لاسم أقصر هو اسم سيء. هناك أماكن يختصر فيها Go ، على سبيل المثال ،

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

بالإضافة إلى ذلك ، أود أن أتحدى تلك البتات. ماذا يعني أن يتخلف الصفر؟ توجد خاصية التوثيق الذاتي بافتراض أن المستخدم يعرف شيئًا ما عن دلالات الوثائق لتبدأ بها. إذا لم تستخدم Hacker Delight لتحقيق التناسق ، فلماذا لا نسميها ZeroesRight64 و ZeroesLeft64 لمطابقة RotateRight64 و RotateLeft64؟

للتوضيح ، لم أقصد الإشارة إلى أنه في أي وقت تستخدمه ، فإن أول شيء يجب عليك فعله هو إنشاء اسم مستعار قصير ويجب ألا تستخدم الاسم المحدد مطلقًا. قصدت أنه إذا كنت تستخدمه بشكل متكرر ، فيمكنك تسميته ، إذا كان ذلك يحسن قابلية قراءة الكود.

على سبيل المثال ، إذا كنت أتصل بـ سلاسل. HasSuffix أستخدم الاسم المعطى معظم الوقت لأنني أسميه مرة أو مرتين ، ولكن بين الحين والآخر ، في نص ETL لمرة واحدة أو ما شابه انتهى بي الأمر إلى تسميته حفنة ، لذا سأفعل ends := strings.HasSuffix وهو أقصر ويجعل الكود أكثر وضوحًا. لا بأس لأن تعريف الاسم المستعار في متناول اليد.

الأسماء المختصرة جيدة للأشياء الشائعة للغاية. يعرف الكثير من غير المبرمجين معنى نظام التشغيل. أي شخص يقرأ الكود ، حتى لو لم يكن يعرف Go ، سيحصل على أن func قصيرة للوظيفة. القنوات أساسية للذهاب ومستخدمة على نطاق واسع ، لذا فإن القناة جيدة. لن تكون وظائف البتات شائعة للغاية.

قد لا تتمكن TrailingZeroes من إخبارك بالضبط بما يحدث إذا لم تكن على دراية بالمفهوم ولكنها تعطيك فكرة أفضل بكثير عما يحدث ، على الأقل تقريبًا ، من Ctz.

jimmyfrasche بخصوص https://github.com/golang/go/issues/18616#issuecomment -275828661: سيكون من السهل جدًا لـ go / doc التعرف على تسلسل متجاور من الوظائف في نفس الملف التي لها أسماء تبدأ جميعها بها نفس البادئة ولها لاحقة عبارة عن سلسلة من الأرقام و / أو ربما كلمة "قصيرة" بالنسبة للبادئة. أود أن أجمعها مع حقيقة أن أول هذه الوظائف فقط لها سلسلة doc والأخرى ذات البادئة المطابقة لا. أعتقد أن هذا يمكن أن يعمل بشكل جيد في الإعدادات العامة. بعد قولي هذا ، دعونا نناقش هذا في مكان آخر لعدم اختطاف هذا الاقتراح.

لمعلوماتك ، تم إنشاء # 18858 لمناقشة التغييرات go/doc والاحتفاظ بهذه المحادثة منفصلة عن هذه المحادثة.

mdlayher شكرا لفعل ذلك.

rogpeppe يبدو وضع الحجم في اسم الحزمة أمرًا مثيرًا للفضول ، ولكن بناءً على التعليقات ونمط Go الحالي ، أعتقد أن الأفضلية هي وضع الحجم مع اسم الوظيفة. فيما يتعلق بـ Log2 ، أود أن أقول ، دعنا نترك الرقم 2 بعيدًا. (أيضًا ، يرجى تكرار الأمر إذا كان هناك أي شيء آخر تريد إضافته ، فستظهر تعليقاتك مقطوعة في منتصف الجملة.)

ulikunitz عادة ما أكون من أوائل من يصوتون لأسماء قصيرة ؛ خاصة في السياق المحلي (وفي السياق العالمي للأسماء الأكثر استخدامًا). ولكن لدينا هنا حزمة API ، و (على الأقل من واقع خبرتي) لن تظهر الوظائف بكثرة في العملاء. على سبيل المثال ، تستخدم الرياضيات / الكبيرة LeadingZeros و Log2 وما إلى ذلك ، لكنها مجرد مكالمة واحدة أو مكالمتين. أعتقد أن الاسم الوصفي الأطول مقبول ، واستنادا إلى المناقشة ، فإن غالبية التعليقات تؤيد ذلك. إذا كنت تستدعي دالة بشكل متكرر ، فمن الرخيص تغليفها داخل دالة باسم قصير. سيتم تضمين المكالمة الإضافية بعيدًا. FWIW ، فن الإستذكار من إنتل ليس رائعًا أيضًا ، تركيزهم ينصب على "العد" (cnt) وبعد ذلك يتبقى لك حرفان يجب فك تشفيرهما.

أوافق على أن الرقم 2 في Log2 ليس ضروريًا. يشير bits.Log إلى أساس 2.

بت سجل 64 SGTM.

griesemer ربما كانت

griesemer أتساءل عما إذا كان الأمر يستحق الاستمرار في التخلص من اسم الدراجة. أبقيها مختصرة: كانت لدي حجتان: قصر ووضوح حول إعادة رقم. تستخدم الحزمة الكبيرة nlz ، وليس LeadingZeros ، داخليًا. أوافق على أن عدد الاستخدامات لهذه الوظائف صغير.

ulikunitz أعتقد أن غالبية التعليقات هنا تؤيد وجود أسماء وظيفية واضحة ليست اختصارات.

ulikunitz ، بالإضافة إلى ذلك:

تستخدم الحزمة الكبيرة nlz ، وليس LeadingZeros ، داخليًا.

الأسماء الداخلية الخاصة غير المُصدرة ليس لها تأثير هنا.

كل ما يهم هو الاتساق والشعور القياسي لواجهة برمجة التطبيقات العامة.

قد يكون التعرّف على الدرّاجات مزعجًا ولكن الأسماء مهمة عندما نكون عالقين معهم إلى الأبد.

يذكر CL https://golang.org/cl/36315 هذه المشكلة.

لقد قمت بتحميل https://go-review.googlesource.com/#/c/36315/ كواجهة برمجة تطبيقات أولية (تم اختبارها جزئيًا) (مع التنفيذ الأولي) للمراجعة (بدلاً من مستند التصميم).

ما زلنا نتأكد من صحة API ، لذا يرجى التعليق فقط على API (bits.go) في الوقت الحالي. بالنسبة للمشكلات البسيطة (الأخطاء المطبعية وما إلى ذلك) ، يرجى التعليق على CL. لقضايا التصميم ، يرجى التعليق على هذه المسألة. سأستمر في تحديث CL حتى نكون سعداء بالواجهة.

على وجه التحديد ، لا تقلق بشأن التنفيذ. إنه أساسي ، ويتم اختباره جزئيًا فقط. بمجرد أن نكون سعداء بواجهة برمجة التطبيقات ، سيكون من السهل التوسع في التنفيذ.

griesemer أنا متأكد من أنك بخير ، ولكن إذا كان ذلك مفيدًا ، فلدي تطبيق تجميع CLZ مع اختبارات https://github.com/ericlagergren/decimal/tree/ba42df4f517084ca27f8017acfaeb69629a090fb/internal/arith أنت حر في ذلك سرقة / عبث مع / أيا كان.

ericlagergren شكرا على الرابط. بمجرد استقرار واجهة برمجة التطبيقات وإجراء الاختبارات في كل مكان ، يمكننا البدء في تحسين التنفيذ. سأضع هذا في الاعتبار. شكرا.

griesemer ، يبدو أن وثائق API المقترحة تعتمد على قدرة go / doc على توثيق الوظائف بشكل مناسب بنفس البادئة ولكن لاحقة عدد صحيح.

هل ستكون الخطة العمل على ذلك قبل 1.9 أيضًا؟

18858 ، هذا هو!

mdlayher سيكون ذلك مثاليًا. لكنها لن تكون أداة عرض لأنها تؤثر على الوثائق "فقط" ، وليس واجهة برمجة التطبيقات (التي يجب أن تظل متوافقة مع الإصدارات السابقة من الآن فصاعدًا).

griesemerbradfitz أقضي بعض الوقت لإعادة النظر في موقفي بشأن أسماء وظيفة. يجب أن يكون أحد الأهداف المهمة لاختيار الأسماء قابلية قراءة الكود باستخدام واجهة برمجة التطبيقات.

الكود التالي سهل الفهم حقًا:

n := bits.LeadingZeros64(x)

ما زلت أشك قليلاً في وضوح Ones64 (x) ، لكنه يتوافق مع LeadingZeros و TrailingZeros. لذلك أرتاح قضيتي وأؤيد الاقتراح الحالي. كتجربة ، استخدمت الكود الخاص بي لتنفيذ Go التجريبي النقي للحزمة بما في ذلك حالات الاختبار.

المستودع: https://github.com/ulikunitz/bits
التوثيق: https://godoc.org/github.com/ulikunitz/bits

قد يكون لدينا مجموعة من وظائف Swap أيضًا [...] ترجع معظم استخدامات SwapBytes إلى رمز يدرك Endian عندما لا يكون كذلك. تعليقات؟

أود إبقاء SwapBytes خارج واجهة برمجة التطبيقات لهذا السبب. أخشى أن يبدأ الناس في استخدامه بطرق غير محمولة لأنه أبسط (أو يفترض أنه أسرع) من binary/encoding.BigEndian .

أرغب في إبقاء SwapBytes خارج واجهة برمجة التطبيقات لهذا السبب. أخشى أن يبدأ الناس في استخدامه بطرق غير محمولة لأنه أبسط (أو يفترض أنه أسرع) من الثنائي / الترميز.

mundaym هل سيتم SwapBytes64 مباشرة كـ BSWAP قد يفوق الأشخاص الذين يستخدمونه بشكل غير صحيح ، imo.

أخشى أن يبدأ الناس في استخدامه بطرق غير محمولة لأنه أبسط (أو يفترض أنه أسرع) من الثنائي / الترميز.

أعتقد أن استخدام ReverseBytes غير محمول فقط إذا تم استخدامه مع unsafe حيث يمكنك الوصول إلى البيانات على المستوى المنخفض بالطريقة التي يضعها الجهاز في الذاكرة. ومع ذلك ، فإن استخدام encoding.{Little,Big}Endian.X يعتبر غير قابل للنقل عند استخدامه بهذه الطريقة. إنني أتطلع إلى استخدام ReverseBytes في الضغط وسأكون حزينًا إذا لم يتم تضمينه.

تضمين التغريدة

هل هذه الإجراءات الروتينية ستصبح متأصلة في أي وقت؟

نعم ، الوظائف الموجودة في encoding/binary التي تقوم بعكس البايت تستخدم أنماط التعليمات البرمجية التي يتعرف عليها المترجم والتي (أو يمكن) تحسينها لتعليمات فردية (على سبيل المثال BSWAP ) على الأنظمة الأساسية التي تدعم البيانات غير المحاذية الوصول (على سبيل المثال 386 و amd64 و s390x و ppc64le وربما غيرها).

السماح لـ SwapBytes64 بالتجميع مباشرة لأن BSWAP قد يفوق الأشخاص الذين يستخدمونه بشكل غير صحيح ، imo.

أنا أميل إلى الاختلاف. قد تكون هناك استخدامات مشروعة لـ SwapBytes في كود endianness-unaware ، لكنني أظن أنه سيتم إساءة استخدامه أكثر من استخدامه بشكل صحيح.

لاحظ أن وقت التشغيل / داخليًا / sys قد قام بالفعل بتحسين إصدارات Go ، والتجميع ، والمترجم الداخلي من الأصفار الزائدة ومبادلة البايت ، حتى نتمكن من إعادة استخدام هذه التطبيقات.

dsnet مثير للاهتمام ، هل لديك شيء محدد في بالك؟

aclements هل تعلم أين يتم استخدام

mundaym ، AFAIK لم يتم استخدامه في وقت التشغيل. لا يتعين علينا توخي الحذر مع واجهات برمجة التطبيقات الداخلية ، لذلك أعتقد أننا أضفناها للتو عند إضافة ctz لأنه كان سهلاً. :) (كان من الممكن أن يكون Popcount خيارًا أفضل.)

الكل: مجرد تذكير برجاء التركيز على واجهة برمجة التطبيقات في الوقت الحالي. التنفيذ في CL هو ببساطة تنفيذ تافه وبطيء يسمح لنا بالفعل باستخدام هذه الوظائف واختبارها. بمجرد أن نكون سعداء بواجهة برمجة التطبيقات ، يمكننا ضبط التنفيذ.

في هذه الملاحظة: ربما يتعين علينا تضمين إصدارات uintptr نظرًا لأنه ليس مضمونًا (على الأرجح) أنه بنفس حجم uint32 أو uint64 . (لاحظ أن uint دائمًا إما uint32 أو uint64 ). آراء؟ اتركه لوقت لاحق؟ ما هي الأسماء الجيدة؟ ( LeadingZerosPtr ؟).

يجب أن نفعل uintptr الآن ، وإلا فإن الرياضيات / الكبيرة لا يمكنها استخدامها. لاحقة Ptr SGTM. أعتقد أنه يجب علينا أيضًا إجراء uint أيضًا ، وإلا فإن كل رمز الاتصال يحتاج إلى كتابة رمز شرطي حول حجم int لإجراء مكالمة خالية من التحويل. لا توجد أفكار تسمية.

Ptr لـ uintptr ، لا توجد لاحقة لـ uint. الآحاد ، 8 ، 16 ، 32 ، 64 ، OnesPtr ، إلخ.

قد يكون لدي أقلية هنا ، لكني ضد إضافة وظائف تأخذ uintptr.
يجب أن تستخدم الرياضيات / الكبيرة uint32 / uint64 من البداية. (في الواقع ، كنت سأفعل ذلك
فقط استخدم uint64 لجميع البنى واترك التحسين لـ
مترجم.)

المشكلة هي:
الرياضيات / كبيرة تريد استخدام حجم الكلمة الأصلي لتحقيق الأداء الأمثل ،
ومع ذلك ، أثناء الإغلاق ، لا يعد uintptr هو الخيار الصحيح.
ليس هناك ما يضمن أن حجم المؤشر هو نفس حجم
حجم الكلمة الأصلي.
المثال الرئيسي هو amd64p32 ، ويمكننا أيضًا إضافة mips64p32 و
mips64p32le لاحقًا ، وهي أكثر شيوعًا لمضيفي MIPS 64 بت.

أنا بالتأكيد لا أريد تشجيع المزيد من هذه الاستخدامات. uintptr هو الأكثر
للمؤشرات ، وليس لأعداد صحيحة معمارية محايدة.

ومع ذلك ، يتمثل أحد الحلول في تقديم اسم مستعار للنوع في واجهة برمجة التطبيقات (ربما يكون
يجب أن يكون من النوع ذي العلامة التجارية ، فهذا أمر مطروح للمناقشة).
اكتب Word = uint32 // أو uint64 على معماريات 64 بت
// ربما نحتاج أيضًا إلى توفير عدد قليل من الثوابت المثالية لـ Word like
عدد القطع والقناع وما إلى ذلك.

ثم قم بإدخال وظائف بدون أي نوع بادئة لأخذ Word.

في الواقع ، أتخيل أنه إذا كانت الرياضيات / البتة توفر النتيجتين ، قم بإضافة ، sub ، mul ،
شعبة. الرياضيات / كبيرة يمكن إعادة كتابتها بدون أي تجميع محدد للهندسة المعمارية.

الرياضيات / الكبيرة تصدر type Word uintptr . أوافق على أنه ربما كان خطأ ، لكنني أعتقد أن التوافق يتطلب ذلك. لذلك إذا أردنا استخدام الرياضيات / البتات لتطبيق الرياضيات / الكبيرة ، وهو ما أعتقد أننا نفعله ، فنحن بحاجة إلى واجهات برمجة تطبيقات uintptr.

تتجول قليلاً خارج الموضوع ، لكن أليس حجم الكلمات الأصلية غير الموقعة مجرد حرف واحد؟ في هذه الحالة ، يبدو عدم وجود لاحقة لـ uint أمرًا صحيحًا.

لا أريد أن يكون نوع واحد ، Word ، مختلفًا في البنى المختلفة. يبدو أن هذا يسبب الكثير من التعقيد للمتصل والمستندات. يعني التمسك بالأنواع الحالية أنه يمكنك ببساطة استخدامها. إن وجود نوع يختلف عبر البنى يعني تصميم كل التعليمات البرمجية الخاصة بك حول هذا النوع أو وجود مجموعة من المحولات في ملفات محمية بعلامات الإنشاء.

FWIW ، لا يزال من الممكن أن يستخدم تطبيق الرياضيات / كبيرة واجهة برمجة تطبيقات تستند إلى uint32 / 64 (إذا لم يكن هناك إصدار uintptr من الوظائف).

minux لست ضد إضافة 2-نتيجة ، sub ، mul ، div - لكن لنفعل ذلك في الخطوة الثانية. ما زلنا بحاجة إلى رمز التجميع إذا أردنا أداءً لائقًا. لكني سعيد لاقتناعي خلاف ذلك من قبل المترجم ...

لقد أضفت إصداري uint و uintptr إلى واجهة برمجة التطبيقات. الق نظرة على CL والتعليق. أنا لست سعيدًا جدًا بتكاثر الوظائف.

josharian قد تكون قيمة uint الأصلية 32 بت حتى على جهاز 64 بت. ليس هناك ما يضمن. أنا أدرك أن uintptr لا يضمن حجم كلمات الآلة أيضًا ؛ لكن في ذلك الوقت بدا أنه الخيار الأكثر منطقية ، إذا كان مخطئًا في الماضي. ربما نحتاج حقًا إلى نوع Word.

إذا كانت الحاجة المشروعة الوحيدة لوظائف uintptr هي دعم الرياضيات / الكبيرة ، فربما يتم تنفيذ الرياضيات / البتات في حزمة داخلية: استخدم فقط عناصر uintptr في الرياضيات / الكبيرة واكشف الباقي.

jimmyfrasche ، griesemer كيف سيؤثر ذلك على بتات كبيرة؟ أي هل سيظل تخصيصًا صفريًا؟

uint هو أيضا خطأ. إنه 32 بت على amd64p32.
في الواقع ، كان من الممكن استخدام الرياضيات / كبيرة uint بدلاً من uintptr ، ولكن في Go 1 ،
يكون int / uint دائمًا 32 بت ، مما يجعل uintptr الحل الوحيد الممكن
للرياضيات / كلمة كبيرة.

نحن نصمم حزمة جديدة ، لذلك لا أعتقد أن التوافق كبير
الاهتمام. تستخدم الرياضيات / الكبيرة نوعًا خاطئًا ، لكن هذا يعد تاريخيًا
حادثة. دعونا لا نأخذ الخطأ أبعد من ذلك.

لا أفهم سبب استخدام "Word" من النوع الموحد والذي يكون دائمًا هو الأكثر شيوعًا
نوع العدد الصحيح الفعال لهندسة معمارية معينة أكثر تعقيدًا من
باستخدام uintptr. بالنسبة لكود المستخدم ، يمكنك معاملته كنوع سحري
إما 32 بت أو 64 بت ، حسب البنية. إذا كنت تستطيع الكتابة
الكود الخاص بك باستخدام uintptr (الذي يعتمد عرضه أيضًا على الهندسة المعمارية) في ملف
بطريقة مستقلة للهندسة المعمارية ، فأعتقد أنه يمكنك فعل الشيء نفسه مع Word.
والكلمة صحيحة في كل البنى.

لتكاثر واجهة برمجة التطبيقات ، أقترح أن نتجاهل وظائف 8
وأنواع 16 بت في المرور الأول. نادرًا ما يتم استخدامها وأكثرها
ستوفر العمارة فقط إرشادات 32 بت و 64 بت على أي حال.

تحدد الرياضيات / الكبيرة Word وتصدره ، لكنها أ) غير متوافقة بشكل مباشر مع uintptr (إنها نوع مختلف) ، و ب) الكود الذي يستخدم Word بشكل صحيح ولا يضع افتراضات حول تطبيقاته سيكون قادرًا على أي نوع من تنفيذ Word . يمكننا تغييره. لا أفهم لماذا يجب أن يؤثر ذلك على ضمان توافق API (لم أجرب رغم ذلك). على أي حال ، دعنا نترك هذا جانبًا. يمكننا التعامل مع ذلك بشكل منفصل.

هل يمكننا ببساطة عمل جميع أنواع uint ذات الحجم الواضح؟ إذا عرفنا حجم uint / uintptr باعتباره ثابتًا ، فيمكننا بسهولة كتابة عبارة if التي تستدعي دالة الحجم المناسب. سيتم طي عبارة if بشكل ثابت بعيدًا ، وتستدعي وظيفة الغلاف المعنية ببساطة وظيفة الحجم التي ستكون مضمنة.

أخيرًا ، ما هو الحل الصحيح فيما يتعلق بنوع Word (بغض النظر عن الرياضيات / كبير)؟ بالطبع يمكننا تحديده في الرياضيات / بت ولكن هل هذا هو المكان المناسب؟ إنه نوع خاص بالمنصة. هل يجب أن تكون "كلمة" محددة مسبقًا؟ ولما لا؟

يبدو أن وجود أي تواقيع (أو أسماء) دالة هنا تذكر uintptr مباشرة خطأ. ليس من المفترض أن يقوم الأشخاص بهذا النوع من العبث في مؤشرات Go.

إذا كان يجب أن تكون هناك وظائف لنوع كلمة آلة طبيعي ، أعتقد أن هذه يمكن أن تشير إلى int / uint الآن. لم نستخدم uint في الرياضيات / الكبيرة لأنها كانت 32 بت على أنظمة 64 بت ، لكننا أصلحنا ذلك منذ ذلك الحين. وعلى الرغم من أن الرياضيات / الكبيرة هي عالم متماسك في حد ذاته ، حيث يكون من المنطقي أن يكون لها نوع خاص بها كبير. كلمة ، هذه الحزمة عبارة عن مجموعة من إجراءات الانتقاء والاختيار. تحديد نوع جديد في هذا السياق أقل إلحاحًا.

لا أعرف ما إذا كنا بحاجة إلى متغيرات int / uint على الإطلاق. إذا كانت هناك حاجة إليها بشكل عام ، فإن تعريفها في هذه الحزمة يكون أكثر منطقية من إجبار جميع المتصلين على كتابة عبارات if. لكني لا أعرف ما إذا كانت هناك حاجة عامة إليها.

لمعالجة عدم التوافق المحتمل مع الرياضيات / الكبير ، هناك حلان على الأقل لا يتضمنان ذكر uintptr في واجهة برمجة التطبيقات هنا.

  1. حدد ملفات word32.go و word64.go في الرياضيات / كبيرة باستخدام علامات الإنشاء وأغلفة قبول uintptr التي تعيد التوجيه بشكل مناسب (وتأكد من قيام المترجم الداخلي بالشيء الصحيح).

  2. تغيير تعريف big.Word to uint. التعريف الدقيق هو تفاصيل تنفيذ داخلية ، على الرغم من أنها مكشوفة في واجهة برمجة التطبيقات. تغييره لا يمكن أن يكسر أي كود باستثناء amd64p32 ، وحتى هناك يبدو أنه من غير المحتمل أن يكون مهمًا خارج الرياضيات / الكبيرة.

rsc : "لم نستخدم uint في الرياضيات / الكبيرة لأنها كانت 32 بت على أنظمة 64 بت ، لكننا أصلحنا ذلك منذ ذلك الحين." نعم ، لقد نسيت تمامًا سبب اختيار uintptr. كان الهدف الكامل لأنواع Go uint / int هو الحصول على أنواع أعداد صحيحة تعكس حجم التسجيل الطبيعي للآلة. سأحاول تغيير كبير. Word to uint ونرى ما سيحدث.

الكل: تم تحديث https://go-review.googlesource.com/#/c/36315/ لاستبعاد إصدارات وظيفة uintptr في المناقشة أعلاه.

لقد قمت بتحديث الرياضيات / الكبيرة مبدئيًا لاستخدام الرياضيات / وحدات البت لرؤية التأثير (https://go-review.googlesource.com/36328).

بعض التعليقات:
1) أميل إلى تحقيق نتائج وظائف Leading / TrailingZeros uint بدلاً من int . تميل هذه النتائج إلى استخدامها لتحويل القيمة وفقًا لذلك ؛ و math/big يثبت ذلك. أنا أيضًا أؤيد جعل عائد Ones uint ، من أجل الاتساق. الحجج المضادة؟

2) لست من المعجبين بالاسم One ، ولكن يتوافق مع الاسم Leading / TrailingZeros . ماذا عن Population ؟

3) اشتكى بعض الأشخاص من أن Log لا يتناسب مع هذه الحزمة. يحدث أن يكون Log مساويًا لمؤشر msb (مع -1 لـ x == 0). لذلك يمكننا تسميتها MsbIndex (على الرغم من أن السجل يبدو أجمل). بدلاً من ذلك ، يمكن أن يكون لدينا دالة Len وهي طول x بالبتات ؛ على سبيل المثال ، `Log (x) == Len (x) -1).

تعليقات؟

أنا لست من المعجبين بالاسم واحد ، ولكن بما يتفق مع Leading / TrailingZeros. ماذا عن السكان؟

لماذا لا يكون Popcount التقليدي؟

بدلاً من ذلك ، يمكن أن يكون لدينا دالة Len وهي طول x بالبتات ؛ على سبيل المثال ، `Log (x) == Len (x) -1).

Len أو Length اسمًا جيدًا وفكرة جيدة.

1.

أنا لست من المعجبين بالاسم One ، ولكن بما يتفق مع Leading /
الأصفار الزائدة. ماذا عن السكان؟

بت. العد؟

aclements عد ماذا؟

قد يكون السكان هو الاسم الأفضل لأسباب تاريخية ولكنه لا يقول أكثر من الأسماء إذا لم تكن على دراية بالمصطلح ولديك نفس المشكلة وهي مجرد الإحصاء: سكان ماذا؟

إنها غير ذاتية إلى حد ما ، حتى داخل الحزمة ، ولكن ربما تقوم CountOnes بإعطائها اسمًا واضحًا وواضحًا.

aclements عد ماذا؟

في حزمة تسمى "bits" ، لست متأكدًا مما يمكنك حسابه أيضًا باستثناء مجموعة البتات ، لكن CountOnes جيد أيضًا ومن الواضح أنه أكثر وضوحًا. إضافة "العناصر" يوازي أيضًا "الأصفار" في LeadingZeros / TrailingZeros .

هذا هو التفسير الأكثر وضوحًا ولكن لا يزال هناك غموض. يمكن أن يكون عد البتات غير المحددة أو البتات الإجمالية (التفسير الأخير سيكون بعيد الاحتمال للغاية ، لكنه لا يزال فخًا محتملاً لشخص يقرأ الكود باستخدام بتات غير معتادة على المفاهيم المعنية وقد يعتقد أن العدد الخالي من اللاحقة غير آمن.

ربما شيء مثل AllOnes أو TotalOnes لعكس Trailing / LeadingZeroes ولكن حدد أنه ، على عكس هؤلاء ، لا يتم أخذ المركز في الاعتبار.

يبدو AllOnes وكأنه يعيد كل الآحاد (ربما في قناع bitmask؟) ، أو ربما كلمة واحدة.

يبدو CountOnes و TotalOnes متشابهين تقريبًا ، ولكن نظرًا لأن الاسم الأكثر شيوعًا لهذه العملية هو "عدد السكان" ، يبدو أن CountOnes سيكون مفضلاً.

لقد قمت بتحميل إصدار جديد (https://go-review.googlesource.com/#/c/36315/) مع إجراء بعض التغييرات:

1) لقد أعدت تسمية Ones إلى PopCount : لم يكن معظم الناس متحمسين جدًا للاسم المتسق ولكنه باهت إلى حد ما Ones . كل شخص سيستخدم هذه الحزمة سيعرف بالضبط ما تفعله PopCount : إنه الاسم الذي تُعرف به هذه الوظيفة بشكل عام. إنه يتعارض قليلاً مع الباقي ولكن معناه أصبح أكثر وضوحًا. سأذهب مع رالف والدو إيمرسون في هذا الموضوع ("الاتساق الأحمق هو هجولة العقول الصغيرة ...").

2) لقد قمت بإعادة تسمية Log إلى Len كما في bits.Len . طول البت للرقم x هو عدد البتات اللازمة لتمثيل x في التمثيل الثنائي (https://en.wikipedia.org/wiki/Bit-length). يبدو مناسبًا ، ويزيل الحاجة إلى الحصول على Log هنا والذي يتميز بجودة غير "bit-fiddly". أعتقد أن هذا يعد أيضًا فوزًا لأن Len(x) == Log(x) + 1 نظرًا لكيفية تحديد Log . علاوة على ذلك ، تتمتع بميزة أن النتيجة الآن دائمًا> = 0 ، وتزيل بعض التصحيحات +/- 1 في التنفيذ (التافه).

بشكل عام ، أنا سعيد جدًا بواجهة برمجة التطبيقات هذه في هذه المرحلة (قد نرغب في إضافة المزيد من الوظائف لاحقًا). الشيء الآخر الوحيد الذي أعتقد أننا قد نرغب في التفكير فيه بجدية هو ما إذا كان يجب أن تكون جميع النتائج غير موقعة. كما أشرت من قبل ، تميل نتائج وظيفة Trailing / Leading Zero إلى أن تكون مدخلات لتحويل العمليات التي يجب أن تكون غير موقعة. هذا يترك فقط Len و PopCount اللذان يمكن القول أنهما يمكنهما إرجاع القيم غير الموقعة أيضًا.

تعليقات؟

كانت تجربتي مع الرياضيات / كبيرة محبطة بسبب إجباري على الدخول في وضع uint بواسطة الوظائف عندما لا أتحول. كتبت في الرياضيات / كبيرة / prime.go

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

على الرغم من أن s.bitLen () لا يعود غير مستخدم ، لأنني لم أكن متأكدًا من عدم النظر ، ولم أكن متأكدًا أيضًا من أن بعض CL في المستقبل قد لا يغيرها لإرجاعها ، وبالتالي تحويل حلقة for إلى حلقة لا نهائية. الحاجة إلى أن تكون دفاعيًا يشير إلى وجود مشكلة.

Uints أكثر عرضة للخطأ من ints ، وهذا هو السبب في أننا لا نشجعهم في معظم واجهات برمجة التطبيقات. أعتقد أنه سيكون من الأجمل بكثير إذا عادت كل وظيفة في الرياضيات / بت إلى int وتركت التحويل إلى uint ليتم إجراؤه في تعبير التحول ، كما هو ضروري في معظم تعبيرات التحول على أي حال.

(أنا لا أقترح تغييرًا ، لكنني أعتقد أن التغيير الذي يتطلب تغييرًا ربما كان خطأً في الماضي. ربما يمكننا إصلاحه في وقت ما. سيكون من الجيد إذا لم يؤذي واجهات برمجة التطبيقات الأخرى لدينا.)

أنا أؤيد إعادة int بعد التقاط الكود الخاص بي لاستدعاءات الأصفار الزائدة ووظائف popcount. غالبية المكالمات في تصريحات متغيرة قصيرة ومقارنات من النوع int. تتطلب المكالمات في ورديات بالطبع النوع العادي ، لكنها نادرة بشكل مدهش.

تم تحميل القرص الطفيف. لكل +1 والتعليقات ، فلنترك نتائج الأعداد int .

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

تركت حسابات الإدخال لـ RotateLeft/Right كـ uint وإلا سنحتاج إلى تحديد ما يحدث عندما تكون القيمة سالبة أو غير مسموح بها.

أخيرًا ، قد نترك بعيدًا Len بعد كل شيء منذ LenN(x) == N - LeadingZerosN(x) . آراء؟

إذا لم تعد هناك تعليقات مهمة في هذه المرحلة ، أقترح أن نمضي قدمًا في استخدام واجهة برمجة التطبيقات هذه والالتزام بالتنفيذ الأولي بعد المراجعة. بعد ذلك يمكننا البدء في التغيير والتبديل في التنفيذ.

في الخطوة التالية ، قد نرغب في مناقشة ما إذا كانت الوظائف الأخرى التي قد نرغب في تضمينها وأي وظائف أخرى ، على وجه التحديد Add / Sub / إلخ. التي تستهلك وسيطتين وتحمل ، وتنتج نتيجة وتحمل .

أفكار gri على Len ؟ سيكون فقط ((N - clz(x) + 1) * 1233) >> 12

إنها أقل "اختراقًا بعض الشيء" من القاعدة 2 ولكنها لا تزال مفيدة.
يوم الجمعة 10 فبراير 2017 الساعة 5:03 مساءً Robert Griesemer [email protected]
كتب:

تم تحميل القرص الطفيف. لكل +1 والتعليقات دعونا نترك نتائج
تحسب على أنها كثافة العمليات.

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

لقد تركت حسابات الإدخال لـ RotateLeft / Right as uint وإلا سنفعل
تحتاج إلى تحديد ما يحدث عندما تكون القيمة سالبة أو تمنعها.

أخيرًا ، قد نتخلى عن Len بعد كل شيء منذ LenN (x) == N -
LeadingZerosN (x). آراء؟

إذا لم تعد هناك تعليقات مهمة في هذه المرحلة ، فإنني أقترح ذلك
المضي قدمًا في واجهة برمجة التطبيقات هذه والالتزام بالتنفيذ الأولي بعد ذلك
إعادة النظر. بعد ذلك يمكننا البدء في التغيير والتبديل في التنفيذ.

أنا الخطوة التالية قد نرغب في مناقشة ما إذا كانت وأي وظائف أخرى قد نقوم بها
تريد تضمين ، على وجه التحديد إضافة / فرعي / إلخ التي تستهلك وسيطتين و
تحمل ، وتنتج نتيجة وتحمل.

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/golang/go/issues/18616#issuecomment-279107013 ، أو كتم الصوت
الخيط
https://github.com/notifications/unsubscribe-auth/AFnwZ_QMhMtBZ_mzQAb7XZDucXrpliSYks5rbQjCgaJpZM4Lg5zU
.

أيضا. اعذرني إذا خرجت عن نطاق هذه المشكلة ولكني سأؤيد التحقق من الحساب. على سبيل المثال ، AddN(x, y T) (sum T, overflow bool)

الجمعة، 10 فبراير 2017 في 08:16، اريك Lagergren [email protected]
كتب:

أيضا. عفوا إذا خرجت من نطاق هذه المشكلة لكنني سأشارك فيها
صالح التحقق من الحساب. على سبيل المثال AddN (x ، y T) (مجموع T ، منطقي الفائض)

هل تتحدث عن تجاوز التوقيع؟ أو تجاوز بدون توقيع (حمل / استعارة)؟

أيضًا ، أفضل إرجاع الفائض / الترحيل / الاقتراض كنوع T ، للتبسيط
متعدد الدقة الحسابية.

ericlagergren الدالة (الأساسية 2) Len ، بينما تقريبًا log2 ، لا تزال في جوهرها دالة عد بت. الوظيفة الأساسية 10 Len هي بالفعل وظيفة تسجيل. ليس هناك من ينكر أنها مفيدة ، لكنها تبدو أقل ملاءمة لهذه الحزمة.

نعم ، أعتقد أنه سيكون من الجيد الحصول على حساب checked في. أردت فقط إنهاء واجهة برمجة التطبيقات الحالية أولاً حتى نتمكن من إحراز تقدم بدلاً من الانتقال ذهابًا وإيابًا. يبدو أن معظم الأشخاص الذين علقوا حتى الآن يبدون سعداء به.

فيما يتعلق بوظائف الإضافة والفرعية: أتفق مع minux على أن الحمل يجب أن يكون من نفس نوع الوسيطة. أيضًا ، لست مقتنعًا بأننا بحاجة إلى أي شيء آخر إلى جانب الحجج الموحدة لهذه الوظائف: النقطة المهمة هي أن uint (في معظم الحالات) يحتوي على حجم السجل الطبيعي للمنصة ، وهذا هو المستوى الذي تكون فيه هذه العمليات منطقية.

يمكن أن تكون الحزمة الرياضية / المحددة مكانًا أفضل لهؤلاء. checked.Add أوضح من bits.Add .

minux كنت أفكر حسابيًا موقّعًا ، لذا تجاوز السعة.

griesemer re: قاعدة 10 Len : منطقي!

إذا كنت تريد ، يمكنني إرسال CL لإجراء العمليات الحسابية المحددة. تعجبني فكرة

إضافة / sub / mul قد تنتمي أو لا تنتمي إلى bits ، لكن الرياضيات المحددة ليست هي الاستخدام الوحيد لهذه العمليات. بشكل عام ، أود أن أقول إن هذه عمليات حسابية "واسعة". بالنسبة إلى الإضافة / الفرعية ، هناك اختلاف بسيط بين نتيجة الحمل / الفائض بت واحد ومؤشر منطقي للتدفق الزائد ، لكننا ربما نرغب أيضًا في توفير إضافة مع حمل وطرح مع استعارة لجعل هذه قابلة للتسلسل. وللحصول الواسع ، توجد معلومات في النتيجة الإضافية أكثر بكثير من الفائض.

من الجيد تذكر العمليات الحسابية المحددة / الواسعة ، لكن دعنا نتركها للجولة الثانية.

"كل من سيستخدم هذه الحزمة سيعرف بالضبط ما يفعله PopCount"

لقد استخدمت هذه الوظيفة من قبل وبطريقة ما لم أكن على دراية باسم PopCount (على الرغم من أنني يجب أن أعرف ذلك لأنني متأكد من أنني قمت بإيقاف التنفيذ عن Hacker's Delight ، والذي يستخدم "pop").

أعلم أنني منضم إلى الحفلة ، لكن "OnesCount" تبدو أكثر وضوحًا بالنسبة لي ، وإذا تم ذكر كلمة "PopCount" في تعليق المستند ، فسيجدها الأشخاص الذين يبحثون عنها على أي حال.

ذات صلة بحساب محدد / واسع: # 6815. لكن نعم ، دعنا ندخل في الجولة الأولى!

كتب griesemer :

دالة Len (الأساس 2) ، بينما تقريبًا log2 ، لا تزال في جوهرها دالة عد بت. دالة Len الأساسية 10 هي بالفعل دالة لوغاريتمية. ليس هناك من ينكر أنها مفيدة ، لكنها تبدو أقل ملاءمة لهذه الحزمة.

لقد كتبت مقياسًا معياريًا لمقارنة بعض الأساليب مع مشكلة "طول الرقم العشري" في تشرين الأول (أكتوبر) الماضي ، والتي نشرتها في الخلاصة .

تم قبوله كاقتراح ؛ من المحتمل أن يكون هناك تعديلات طفيفة للمضي قدمًا ، ولا بأس بذلك.

rogpeppe : تم تغيير PopCount إلى OnesCount لأنه تلقى أيضًا 4 إبهام لأعلى (مثل اقتراحي باستخدام PopCount ). يُشار إلى "عدد السكان" في سلسلة المستند.

لكل rsc ، ترك العمليات الحسابية المحددة / الواسعة بالخارج في الوقت الحالي.

وفقًا لـ rsc أيضًا ، int ، ولتسهيل الاستخدام (مع التركيز على # 19113) ، استخدم قيم int لحساب التدوير.

وظائف Left LenN على الرغم من أنها ببساطة N - LeadingZerosN . ولكن يوجد تماثل مماثل لـ RotateLeft / Right ولدينا كلاهما.

تمت إضافة تنفيذ أسرع قليلاً مقابل TrailingZeroes والاختبارات المكتملة.

في هذه المرحلة ، أعتقد أن لدينا أول تطبيق قابل للاستخدام. يرجى مراجعة الكود على https://go-review.googlesource.com/36315 ، وخاصة واجهة برمجة التطبيقات. أود الحصول على هذا إذا كنا جميعًا سعداء.

الخطوات التالية:

  • تنفيذ أسرع (أساسي)
  • إضافة وظائف إضافية (ثانوية)

نحن نصمم حزمة جديدة

minux تقصد الرياضيات الجديدة / الكبيرة؟ هل من الممكن متابعة العملية في مكان ما؟

TuomLarsen : minux يشار إلى الرياضيات / بت بـ "حزمة جديدة". ذكر الرياضيات / كبيرة كحالة حيث سيتم استخدام الرياضيات / بت. (في المستقبل ، يرجى أن تكون أكثر تحديدًا في تعليقاتك حتى لا نضطر إلى البحث وتخمين ما تشير إليه - شكرًا).

يذكر CL https://golang.org/cl/37140 هذه المشكلة.

هل سيكون هناك أي إدخال بمساعدة المترجم يحدث في الرياضيات / بت لـ Go 1.9؟

cespare يعتمد على ما إذا كنا سنصل إليها (khr؟). بصرف النظر عن ذلك ، نريد تطبيقًا لائقًا ومستقلًا عن النظام الأساسي. (أحد الأسباب التي تجعلنا لا نريد نقل الرياضيات / الكبيرة كليًا لاستخدام الرياضيات / البتات هو أن لدينا حاليًا بعض التجميعات الخاصة بالمنصة في الرياضيات / الكبيرة والتي تكون أسرع.)

على لوحي ، على الأقل بالنسبة للأقواس التي قمنا بالفعل بعمل عناصر جوهرية لها
(386 ، amd64 ، arm ، arm64 ، s390x ، mips ، ربما ppc64).

يوم الجمعة ، 17 شباط (فبراير) 2017 الساعة 12:54 مساءً ، روبرت جريسيمر < [email protected]

كتب:

cespare https://github.com/cespare يعتمد على ما إذا كنا سنصل إليه (
khr https://github.com/khr ؟). بغض النظر عن ذلك ، نريد أن يكون لدينا ملف
تطبيق مستقل عن النظام الأساسي اللائق. (أحد أسباب عدم قيامنا بذلك
تريد نقل الرياضيات / الكبيرة تمامًا لاستخدام الرياضيات / البتات ، هذا ما نقوم به حاليًا
لديك بعض التجميعات الخاصة بالمنصة في الرياضيات / الكبيرة وهي أسرع.)

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/golang/go/issues/18616#issuecomment-280763679 ، أو كتم الصوت
الخيط
https://github.com/notifications/unsubscribe-auth/AGkgIIb8v1X5Cr-ljDgf8tQtT4Dg2MGiks5rdgkegaJpZM4Lg5zU
.

قد تكون هذه المقالة حول أسرع طريقة لتنفيذ عدد السكان على x86-64 مفيدة: التجميع المشفر يدويًا يتفوق على الجوهر في السرعة والبساطة - دان لو ، أكتوبر 2014

يذكر CL https://golang.org/cl/38155 هذه المشكلة.

يذكر CL https://golang.org/cl/38166 هذه المشكلة.

يذكر CL https://golang.org/cl/38311 هذه المشكلة.

يذكر CL https://golang.org/cl/38320 هذه المشكلة.

يذكر CL https://golang.org/cl/38323 هذه المشكلة.

بعض المزيد من المناقشة:

أنا:

الرياضيات / بت .RotateLeft محدد حاليًا للذعر إذا كانت حجته أقل من الصفر.
أود تغيير ذلك لتعريف RotateLeft للقيام بتدوير لليمين إذا كانت حججه أقل من الصفر.

إن اتباع روتين أساسي مثل هذا الذعر يبدو قاسيًا بلا داعٍ. أود أن أزعم أن التدوير بمقدار سالب أكثر تشابهًا مع التحول بمقدار أكبر من حجم الكلمة (الذي لا ينزعج) بدلاً من القسمة على الصفر (وهو ما يسبب الذعر). القسمة على صفر يجب أن تثير الذعر حقًا ، حيث لا توجد نتيجة معقولة يمكنك إرجاعها بدلاً من ذلك. التدوير بالمبالغ السالبة له نتيجة محددة جيدًا يمكننا إرجاعها.

أعتقد أنه يجب علينا الاحتفاظ بـ RotateLeft و RotateRight كوظائف منفصلة ، على الرغم من أنه يمكن الآن تنفيذ أحدهما مع الآخر. سيظل الاستخدام القياسي مع وسيطات غير سلبية.

إذا كنا سنفعل شيئًا هنا ، فيجب أن نفعل ذلك بالتجميد. بمجرد خروج 1.9 ، لا يمكننا تغيير رأينا.

روب:

إذا كنت تريد شيئًا كهذا حقًا ، فسأكون لدي وظيفة واحدة فقط ، وهي التدوير ، تأخذ قيمة موجبة لليسار وسالب لليمين.

أنا:

المشكلة هي
بتات تدوير (س ، -5)

ليس من الواضح عند قراءة هذا الرمز ما إذا كنا سننتهي بالتناوب إلى اليسار أو اليمين.
بت. تدوير لليمين (5)
أكثر وضوحًا ، حتى لو كان ذلك يعني وجود ضعف عدد وظائف التدوير * في الرياضيات / وحدات البت.

مايكل جونز:

تناوب موقع يعني قفزات في الكود ، نعم؟ يبدو من المؤسف.

أنا:

لا ، التطبيق في الواقع أبسط مع الدلالات المقترحة. قم بإخفاء 6 بت المنخفضة (لتدوير 64 بت) وهي تعمل فقط.

أفضل التدوير الفردي باستخدام وسيطة موقعة لأنها تعني نصف عدد الوظائف ويمكن إجراؤها بكفاءة عالية في جميع الحالات دون ذعر أو حتى فرع شرطي.

التدوير هو وظيفة متخصصة على أي حال ، لذا فإن الأشخاص الذين يستخدمونها سيكونون بالتأكيد مرتاحين لأن يُطلب منهم تذكر أن الحجة الإيجابية تتحول إلى اليسار وتتحول الحجة السلبية إلى اليمين.

يمكنك دائمًا تقسيم الفرق وتقديم RotateLeft باستخدام وسيطة موقعة. هذا يعطي ذاكري مفيد للاتجاه ولكنه يتجنب تكرار الوظائف.

bcmillsrobpike انظر المناقشة أيضا سابقة لهذا الموضوع المحدد ابتداء من الساعة https://github.com/golang/go/issues/18616#issuecomment -275598092 وتستمر لمدة بضعة تعليقات

josharian لقد رأيت التعليقات وما زلت أفضّل روايتي. يمكن أن يكون هذا جزءًا لا يتجزأ من الدراجة إلى الأبد ، لكنني أحاول الوصول إلى تطبيق بسيط ، وسهل التحديد ، وسهل الفهم ، وسهل التوثيق. أعتقد أن وظيفة تدوير واحدة مع وسيطة موقعة تفي بكل ذلك باستثناء الحاجة إلى تحديد الإشارة ، ولكن هذا اليسار إيجابي يجب أن يكون بديهيًا لأي شخص قادر على استخدام تعليمات التدوير.

لكن هذا اليسار إيجابي يجب أن يكون بديهيًا لأي شخص قادر على استخدام تعليمات التدوير.

أحب أن أعتبر نفسي قادرًا على استخدام تعليمات دوارة وحدسي هو "جيز ، لماذا لا يقول هذا ما هو الاتجاه؟ من المحتمل أنه للتأكد ." أوافق على أنه من البديهي أنه إذا كنت ستختار اتجاهًا إيجابيًا فسيكون ذلك بمثابة دوران لليسار ، ولكن هناك حدًا أعلى بكثير لشيء ما ليكون من الواضح جدًا الإجابة الصحيحة بحيث يكون واضحًا في كل موقع اتصال ما هو الاتجاه الذي تدور فيه دون أن تقول هو - هي.

فيما يتعلق بقابلية القراءة ، ماذا عن شيء على غرار time.Duration API:

const RotateRight = -1

bits.Rotate(x, 5 * RotateRight)

ربما ثابت محدد بالبتات أو ربما تمرين للقارئ (موقع الاتصال)؟

aclements وهكذا ينتهي بك الأمر

على محور الأرقام ، تزداد الأرقام الإيجابية إلى اليمين ، لذلك أتوقع تدوير / إزاحة محددة الاتجاه بواسطة إشارة لتحريك البتات إلى اليمين للأرقام الموجبة.

ليس لدي أي مشكلة إذا كان سيكون العكس [الموثق] ، لكنني لا أسمي ذلك بديهيًا.

cznic بت مكتوبة من اليمين إلى اليسار بالرغم من ذلك

أنا أيضًا أؤيد فقط Rotate (https://github.com/golang/go/issues/18616#issuecomment-275016583) إذا جعلناها تعمل في كلا الاتجاهين.

كحجة مضادة للقلق بشأن RotateLeft والذي يعمل أيضًا عند تدوير اليمين يمكن أن يوفر أيضًا إحساسًا زائفًا بالأمان: "تقول RotateLeft لذا فمن المؤكد أنها لا تدور حق!". بمعنى آخر ، إذا كانت تقول RotateLeft فمن الأفضل ألا تفعل أي شيء آخر.

أيضًا ، استخدام bits.Rotate هو حقًا في كود متخصص فقط. هذه ليست وظيفة يستخدمها عدد كبير من المبرمجين. المستخدمون الذين يحتاجون إليه حقًا سيفهمون تناسق التدويرات.

تضمين التغريدة

تتم كتابة البتات من اليمين إلى اليسار بالرغم من ذلك

البتات هي مجرد أرقام ثنائية. تتم كتابة الأرقام في أي قاعدة من اليسار إلى اليمين - حتى في معظم ، إن لم يكن كل ، أنظمة الكتابة من اليمين إلى اليسار. 123 هي مائة وثلاثة وعشرون ، وليس ثلاثمائة وواحد وعشرون.

إن تناقص قوة المضاعف الخاص بالرقم جهة اليمين أمر مختلف.

مرة أخرى: أنا لا أهتم بالاتجاه ، الأمر يتعلق فقط بالحدس الذي يتعلق بالخيال الشخصي.

أنا أحب التدوير. أقل جزء مهم هو بشكل حدسي 0 بما يكفي من وجهة نظري.

يرجى الاحتفاظ بكل من RotateLeft و RotateRight بدلاً من فعل شيء لن يتذكره نصف المطورين. يبدو أنه من الجيد التعامل مع الأرقام السالبة.

لن يقوم 99٪ من المطورين أبدًا ببرمجة تعليمات متناوبة ، لذا فإن الحاجة إلى توجيه لا لبس فيه تكون ضعيفة في أحسن الأحوال. مكالمة واحدة تكفي.

المشكلة التي أعادت إيقاظ هذه المناقشة هي أن وجود كلاهما يتطلب الجدل حول ما إذا كانت القيم السلبية على ما يرام ، وإذا لم يكن الأمر كذلك ، فماذا تفعل حيالها. من خلال وجود واحدة فقط ، فإن هذه الحجة بأكملها تسقط. تصميم أنظف.

أتعاطف إلى حد ما مع الجدل الدائر حول التصميم النظيف ، لكن يبدو من الغريب أنه يتعين عليك إزالة كلمة "Right" من "RotateRight" ، مع الاحتفاظ بنفس التنفيذ ، من أجل تحقيق ذلك. من الناحية العملية ، فإن الطريقة الوحيدة للإجابة على الأسئلة هي إجبار الأشخاص الذين يرونها على قراءة الوثائق ، عن طريق الأسئلة التي يثيرها الاسم.
في النهاية ، إنها مسألة اتجاه لا لبس فيه مقابل سلوك لا لبس فيه للقيم السلبية. من المحتمل أن تكون القيم السلبية أقل أهمية في الحالة العامة.

ما أقوله هو أن برنامج Rotate يطرح سؤالاً واحدًا لجميع الأشخاص ، ويجيب عليه بشكل غير مباشر من خلال التوثيق.
يطرح RotateRight سؤالاً واحدًا لعدد قليل جدًا من الأشخاص الذين يمكنهم (ويجب عليهم) قراءة الوثائق إذا كانوا مهتمين بها.

من ناحية أخرى ، من المحتمل أن يمنع التدوير الأشخاص من كتابة if n < 0 { RotateLeft(...) } else { RotateRight(...) } .

ناقش @ golang / review-review هذا الأمر وانتهى به الأمر في الحصول على وظيفة واحدة فقط ، ولكن أطلق عليها اسم RotateLeft ، وليس فقط Rotate ، لتكون أكثر وضوحًا في مواقع الاتصال. يتم تدوير الأرقام السالبة لليمين ، وستوضح الوثائق ذلك.

يذكر CL https://golang.org/cl/40394 هذه المشكلة.

يذكر CL https://golang.org/cl/41630 هذه المشكلة.

تم تصميم وتنفيذ الاقتراح الأصلي بالإضافة إلى بعض الوظائف الإضافية في هذه المرحلة. قد نضيف إلى هذه المكتبة بمرور الوقت ، لكنها تبدو "كاملة" بشكل معقول في الوقت الحالي.

وعلى وجه الخصوص ، لم نقرر أو ننفذ وظيفة من أجل:

  • اختبار ما إذا كان تجاوز إضافة / مول / الخ
  • توفير وظائف لتنفيذ add / mul / etc التي تقبل حمل وارد وتنتج نتيجة بالإضافة إلى حمل (أو كلمة أعلى)

أنا شخصياً لست مقتنعًا بأن هؤلاء ينتمون إلى حزمة "بت" (ربما تفعل الاختبارات). ستسمح وظائف تنفيذ إضافة / فرعية / مول متعددة الدقة بتنفيذ Go نقي لبعض الرياضيات / النواة الكبيرة ، لكنني لا أعتقد أن الدقة صحيحة: ما نريده هو أن تكون حبات محسّنة تعمل على المتجهات ، والحد الأقصى أداء لتلك الحبات. لا أعتقد أنه يمكننا تحقيق ذلك باستخدام كود Go اعتمادًا على "الجوهر" add / sub / mul وحده.

وبالتالي ، أود في الوقت الحالي إغلاق هذه القضية على أنها "تم" ما لم تكن هناك اعتراضات كبيرة. يرجى التحدث خلال الأسبوع المقبل أو نحو ذلك إذا كنت تعارض إغلاق هذا.

أنا أؤيد إضافة وظائف على طول هذه الخطوط.

أعتقد بشدة أنهم ينتمون إلى الحزمة الخاصة بهم ، إن لم يكن لسبب آخر سوى إعطائها اسمًا يعكس وظائفهم الجماعية بشكل أفضل.

: +1: بشأن إغلاق هذا العدد و: القلب: للعمل المنجز حتى الآن.

تم الإغلاق حيث لم تكن هناك اعتراضات.

هذا تعليق للقرارات المستقبلية المتعلقة بواجهة برمجة التطبيقات ، وأنا أفهم أن هذا القرار بالتحديد قد تم تعيينه.

Rotate هي وظيفة متخصصة ؛ LTR أو RTL مناسبان فقط في ضوء السياق. aclements طرح سؤالًا صالحًا ، وليس نقطة صالحة

لكن بدلاً من ذلك ، يستتبع الذكاء.

ما تعنيه "وظيفة متخصصة" هو شيء بسيط ، من المحتمل أن يتم رفضه بسرعة. بالنظر إلى عينة رمز ، من المحتمل أن يفهم المرء بالفعل حدوث الدوران والاتجاه حتى قبل مواجهة سطر التعليمات البرمجية. عادة ما يكون هذا الرمز مسبوقًا بالفعل بوثائق ASCII التوضيحية كما هي.

الأمر المضطرب عقليًا ليس أن Go كان بإمكانه اختيار RTL ببساطة كطريقة معيارية لتفسير البتات من منظور API ، ولكن بدلاً من ذلك ، قمت أولاً بسحب التغييرات 1.9 ووجدت RotateLeft بدون نظير وقدم المستند مثالاً على خطوة سلبية. هذا قرار شبيه بلجنة الذهن ومن المؤسف جدًا أن يصل إلى 1.9.

أنا أدافع فقط عن التمسك بسياق الاستخدام في المستقبل. كل هذا كان يجب أن يكون بديهيًا مع أسئلة مثل ، "لماذا لا نقدم نظيرًا لـ RotateLeft ، لماذا نشعر بالذعر من الخطوات السلبية أو نناقش int vs uint من أجل خطوة" ؛ في النهاية ، لأنني أعتقد أن ما تعنيه "وظيفة متخصصة" قد تم استبعاده بسهولة لأنه ليس ذكيًا.

دعونا من فضلك تجنب البراعة في تبريرنا لواجهات برمجة التطبيقات. يظهر في هذا التحديث 1.9.

تغيير https://golang.org/cl/90835 يذكر هذه المشكلة: cmd/compile: arm64 intrinsics for math/bits.OnesCount

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات