ستتناول هذه المقالة مشكلات الحساب العددي في برمجة العقود الذكية بلغة Rust، والتي تشمل بشكل رئيسي مشكلات دقة العمليات العائمة، ومشكلات دقة الحسابات الصحيحة، بالإضافة إلى كيفية كتابة العقود الذكية بلغة Rust الخاصة بالحساب العددي.
1. مشكلة دقة العمليات العشرية
تدعم لغة Rust العمليات الحسابية للأعداد العشرية بشكل أصلي، ولكن توجد مشاكل لا مفر منها في دقة الحسابات. عند كتابة العقود الذكية، لا يُنصح باستخدام العمليات الحسابية للأعداد العشرية، خاصة عند التعامل مع النسب أو أسعار الفائدة التي تتعلق بقرارات اقتصادية/مالية هامة.
تتبع نوع الفاصلة العائمة مزدوجة الدقة f64 في لغة Rust معيار IEEE 754، وتستخدم صيغة العد العلمي بأساس 2 للتعبير. ومع ذلك، فإن بعض الأعداد العشرية مثل ( و 0.7) لا يمكن تمثيلها بدقة باستخدام أعداد الفاصلة العائمة ذات الطول المحدود، مما يؤدي إلى "ظاهرة التقريب".
كمثال على توزيع 0.7 من رموز NEAR على عشرة مستخدمين على سلسلة NEAR العامة، قد تظهر نتائج الحساب الفعلية حالات عدم دقة:
تظهر نتائج التنفيذ أن قيمة المبلغ ليست بالضبط 0.7، بل هي قيمة قريبة للغاية تبلغ 0.69999999999999995559. كما أن نتيجة عملية القسمة الإضافية أصبحت غير دقيقة أيضاً، حيث بلغت 0.06999999999999999، بدلاً من 0.07 المتوقعة.
لحل هذه المشكلة، يمكن النظر في استخدام الأعداد العشرية الثابتة. في بروتوكول NEAR، يتم استخدام 10^24 ككسر، أي أن 10^24 من yoctoNEAR تعادل 1 من عملة NEAR.
بهذه الطريقة يمكن الحصول على نتيجة حسابية دقيقة: 0.7 NEAR / 10 = 0.07 NEAR.
!
2. مشكلة دقة حسابات الأعداد الصحيحة في Rust
على الرغم من أن استخدام العمليات الحسابية الصحيحة يمكن أن يحل بعض مشاكل فقدان دقة الأعداد العشرية في بعض السيناريوهات، إلا أن نتائج العمليات الحسابية الصحيحة ليست دائماً دقيقة وموثوقة تماماً. تشمل بعض الأسباب التي تؤثر على دقة العمليات الحسابية الصحيحة:
2.1 ترتيب العمليات
قد يؤثر تغيير ترتيب العمليات بين الضرب والقسمة ذات الأولوية الحسابية نفسها مباشرة على نتيجة الحساب. على سبيل المثال:
نتائج الاختبار تظهر أن نتائج الحساب لـ result_0 و result_1 مختلفة. وذلك لأن دقة الأعداد تكون مهملة عندما تكون أقل من المقام في قسمة الأعداد الصحيحة. عند حساب result_1، ستفقد (a / b) دقة الحساب أولاً، مما يؤدي إلى أن تصبح 0؛ في حين أنه عند حساب result_0، فإن حساب a * c أولاً يمكن أن يتجنب فقدان الدقة.
2.2 حجم صغير للغاية
عندما يتعلق الأمر بالحسابات ذات الأحجام الصغيرة، قد تحدث مشكلات دقة أيضًا:
#[test]
الجبهة الوطنية record_offset_test() {
دع إزاحة MUT: U128 = 0 ؛
من أجل i في 1..7 {
println!("Round {}", i);
الإزاحة = distribute(to_yocto( "10" ) ، offset) ؛
println!("إزاحة {}\n", offset);
}
}
تسمح هذه الطريقة بتجميع وإعادة توزيع الرموز التي لم يتم توزيعها بسبب فقدان الدقة.
3.4 استخدام مكتبة Rust Crate rust-decimal
هذه المكتبة مناسبة للحسابات المالية العشرية التي تتطلب دقة فعالة ولا تحتوي على أخطاء تقريب.
3.5 النظر في آلية التقريب
عند تصميم العقود الذكية، غالبًا ما تتبع مسألة التقريب مبدأ "أريد الاستفادة، ولا ينبغي للآخرين انتزاع الصوف مني". وفقًا لهذا المبدأ، إذا كان التقريب للأسفل مفيدًا للعقد، يتم التقريب للأسفل؛ وإذا كان التقريب للأعلى مفيدًا للعقد، يتم التقريب للأعلى؛ نظرًا لأنه لا يمكن تحديد من له المصلحة، نادرًا ما يتم استخدام التقريب لأقرب عدد.
من خلال استخدام هذه الطرق، يمكن تحقيق حسابات عددية أكثر دقة في العقود الذكية بلغة Rust، مما يعزز موثوقية العقد وعدالته.
!
شاهد النسخة الأصلية
قد تحتوي هذه الصفحة على محتوى من جهات خارجية، يتم تقديمه لأغراض إعلامية فقط (وليس كإقرارات/ضمانات)، ولا ينبغي اعتباره موافقة على آرائه من قبل Gate، ولا بمثابة نصيحة مالية أو مهنية. انظر إلى إخلاء المسؤولية للحصول على التفاصيل.
تسجيلات الإعجاب 14
أعجبني
14
8
مشاركة
تعليق
0/400
ZeroRushCaptain
· 07-17 09:17
آه، بدأت العبث بهذا الشيء مرة أخرى. المرة الماضية كانت مشكلة دقة أدت إلى قفل المركز بالعقد العاجل، خسرت حتى أكلت التراب.
شاهد النسخة الأصليةرد0
BlockchainFries
· 07-16 10:52
هذه الأشياء العائمة مزعجة للغاية، من يستخدمها سيكون سيئ الحظ.
شاهد النسخة الأصليةرد0
MoonBoi42
· 07-15 08:48
ما هو دقة الأعداد العشرية مقارنة بالأعداد الثابتة~
شاهد النسخة الأصليةرد0
OnchainDetective
· 07-14 09:54
من الواضح أن خطأ الدقة هو بالضبط الثغرة التي استغلها بعض الهاكرز في الجسور عبر السلسلة، مما يدعو للفزع.
شاهد النسخة الأصليةرد0
HashRateHermit
· 07-14 09:54
مسألة الدقة حقًا أوقعتني في المشكلة.
شاهد النسخة الأصليةرد0
GateUser-e87b21ee
· 07-14 09:47
مرة أخرى، لدي مشكلة مع الأرقام العشرية، الأمر مزعج.
شاهد النسخة الأصليةرد0
BearMarketSurvivor
· 07-14 09:45
الدقة هذه الحفرة لا يستطيع أحد الهروب منها، هذا الشخص يفهم.
شاهد النسخة الأصليةرد0
AirdropLicker
· 07-14 09:35
تقريب الأعداد العشرية هذه حفرة عميقة جداً لقد وقعت فيها من قبل
تقنيات الدقة العددية والملاحظات في العقود الذكية بلغة Rust
Rust العقود الذكية养成日记(7):数值精算
ستتناول هذه المقالة مشكلات الحساب العددي في برمجة العقود الذكية بلغة Rust، والتي تشمل بشكل رئيسي مشكلات دقة العمليات العائمة، ومشكلات دقة الحسابات الصحيحة، بالإضافة إلى كيفية كتابة العقود الذكية بلغة Rust الخاصة بالحساب العددي.
1. مشكلة دقة العمليات العشرية
تدعم لغة Rust العمليات الحسابية للأعداد العشرية بشكل أصلي، ولكن توجد مشاكل لا مفر منها في دقة الحسابات. عند كتابة العقود الذكية، لا يُنصح باستخدام العمليات الحسابية للأعداد العشرية، خاصة عند التعامل مع النسب أو أسعار الفائدة التي تتعلق بقرارات اقتصادية/مالية هامة.
تتبع نوع الفاصلة العائمة مزدوجة الدقة f64 في لغة Rust معيار IEEE 754، وتستخدم صيغة العد العلمي بأساس 2 للتعبير. ومع ذلك، فإن بعض الأعداد العشرية مثل ( و 0.7) لا يمكن تمثيلها بدقة باستخدام أعداد الفاصلة العائمة ذات الطول المحدود، مما يؤدي إلى "ظاهرة التقريب".
كمثال على توزيع 0.7 من رموز NEAR على عشرة مستخدمين على سلسلة NEAR العامة، قد تظهر نتائج الحساب الفعلية حالات عدم دقة:
صدأ #[test] الجبهة precision_test_float() { دع المبلغ: F64 = 0.7 ؛
دع المقسوم عليه: F64 = 10.0 ؛
دع result_0 = الكمية / القاسم ؛
println!("قيمة المبلغ: {:.20}", amount); assert_eq!(result_0 ، 0.07 ، "") ؛ }
تظهر نتائج التنفيذ أن قيمة المبلغ ليست بالضبط 0.7، بل هي قيمة قريبة للغاية تبلغ 0.69999999999999995559. كما أن نتيجة عملية القسمة الإضافية أصبحت غير دقيقة أيضاً، حيث بلغت 0.06999999999999999، بدلاً من 0.07 المتوقعة.
لحل هذه المشكلة، يمكن النظر في استخدام الأعداد العشرية الثابتة. في بروتوكول NEAR، يتم استخدام 10^24 ككسر، أي أن 10^24 من yoctoNEAR تعادل 1 من عملة NEAR.
الكود التجريبي المعدل كما يلي:
صدأ #[test] الجبهة الوطنية precision_test_integer() { دع N: u128 = 1_000_000_000_000_000_000_000_000_000 ؛
المبلغ اليدخ: U128 = 700_000_000_000_000_000_000_000 ؛ دع المقسوم: U128 = 10 ؛
دع result_0 = الكمية / القاسم ؛ assert_eq!(result_0, 70_000_000_000_000_000_000_000_000, ""); }
بهذه الطريقة يمكن الحصول على نتيجة حسابية دقيقة: 0.7 NEAR / 10 = 0.07 NEAR.
!
2. مشكلة دقة حسابات الأعداد الصحيحة في Rust
على الرغم من أن استخدام العمليات الحسابية الصحيحة يمكن أن يحل بعض مشاكل فقدان دقة الأعداد العشرية في بعض السيناريوهات، إلا أن نتائج العمليات الحسابية الصحيحة ليست دائماً دقيقة وموثوقة تماماً. تشمل بعض الأسباب التي تؤثر على دقة العمليات الحسابية الصحيحة:
2.1 ترتيب العمليات
قد يؤثر تغيير ترتيب العمليات بين الضرب والقسمة ذات الأولوية الحسابية نفسها مباشرة على نتيجة الحساب. على سبيل المثال:
صدأ #[test] الجبهة precision_test_div_before_mul() { دع أ: U128 = 1_0000 ؛ دع ب: U128 = 10_0000 ؛ دع C: U128 = 20 ؛
}
نتائج الاختبار تظهر أن نتائج الحساب لـ result_0 و result_1 مختلفة. وذلك لأن دقة الأعداد تكون مهملة عندما تكون أقل من المقام في قسمة الأعداد الصحيحة. عند حساب result_1، ستفقد (a / b) دقة الحساب أولاً، مما يؤدي إلى أن تصبح 0؛ في حين أنه عند حساب result_0، فإن حساب a * c أولاً يمكن أن يتجنب فقدان الدقة.
2.2 حجم صغير للغاية
عندما يتعلق الأمر بالحسابات ذات الأحجام الصغيرة، قد تحدث مشكلات دقة أيضًا:
صدأ #[test] الجبهة precision_test_decimals() { دع أ: u128 = 10 ؛ دع ب: u128 = 3 ؛ دع C: U128 = 4 ؛ دع الرقم العشري: U128 = 100_0000 ؛
}
أظهرت نتائج الاختبار أن نتيجة result_0 و result_1 مختلفة، وأن result_1 = 13 أقرب إلى القيمة المتوقعة الفعلية للحساب 13.3333....
!
3. كيفية كتابة العقود الذكية Rust لتقييم القيم
لزيادة الدقة، يمكن اتخاذ التدابير الوقائية التالية:
3.1 تعديل ترتيب العمليات الحسابية
اجعل ضرب الأعداد الصحيحة له أولوية على قسمة الأعداد الصحيحة.
3.2 زيادة عدد الأعداد الصحيحة
استخدام أعداد أكبر، لإنشاء جزيئات أكبر. على سبيل المثال، يمكن تمثيل 5.123 NEAR على أنها 5.123 * 10^10 = 51_230_000_000.
3.3 فقدان دقة العمليات التراكمية
بالنسبة لمشكلة دقة حساب الأعداد الصحيحة التي لا يمكن تجنبها، يمكن النظر في تسجيل الخسائر المتراكمة في دقة العمليات. على سبيل المثال:
صدأ كونست USER_NUM: U128 = 3 ؛
الجبهة distribute(amount: U128 ، الإزاحة: u128) -> U128 { دع token_to_distribute = الإزاحة + المبلغ ؛ دع per_user_share = token_to_distribute / USER_NUM ؛ println!("per_user_share {}", per_user_share); دع recorded_offset = token_to_distribute - per_user_share * USER_NUM ؛ recorded_offset }
#[test] الجبهة الوطنية record_offset_test() { دع إزاحة MUT: U128 = 0 ؛ من أجل i في 1..7 { println!("Round {}", i); الإزاحة = distribute(to_yocto( "10" ) ، offset) ؛ println!("إزاحة {}\n", offset); } }
تسمح هذه الطريقة بتجميع وإعادة توزيع الرموز التي لم يتم توزيعها بسبب فقدان الدقة.
3.4 استخدام مكتبة Rust Crate rust-decimal
هذه المكتبة مناسبة للحسابات المالية العشرية التي تتطلب دقة فعالة ولا تحتوي على أخطاء تقريب.
3.5 النظر في آلية التقريب
عند تصميم العقود الذكية، غالبًا ما تتبع مسألة التقريب مبدأ "أريد الاستفادة، ولا ينبغي للآخرين انتزاع الصوف مني". وفقًا لهذا المبدأ، إذا كان التقريب للأسفل مفيدًا للعقد، يتم التقريب للأسفل؛ وإذا كان التقريب للأعلى مفيدًا للعقد، يتم التقريب للأعلى؛ نظرًا لأنه لا يمكن تحديد من له المصلحة، نادرًا ما يتم استخدام التقريب لأقرب عدد.
من خلال استخدام هذه الطرق، يمكن تحقيق حسابات عددية أكثر دقة في العقود الذكية بلغة Rust، مما يعزز موثوقية العقد وعدالته.
!