Phát triển hợp đồng thông minh Rust: Khắc phục vấn đề độ chính xác trong tính toán số

Vấn đề độ chính xác trong tính toán số học trong phát triển hợp đồng thông minh Rust

1. Vấn đề độ chính xác trong phép toán số thực

Ngôn ngữ Rust hỗ trợ tính toán số thực bản địa, nhưng tính toán số thực có vấn đề về độ chính xác không thể tránh khỏi. Khi viết hợp đồng thông minh, không nên sử dụng tính toán số thực, đặc biệt là khi xử lý tỷ lệ hoặc lãi suất trong các quyết định kinh tế/tài chính quan trọng.

Loại số thực độ chính xác gấp đôi f64 trong ngôn ngữ Rust tuân theo tiêu chuẩn IEEE 754, sử dụng biểu diễn khoa học với cơ số là 2. Một số số thập phân không thể được biểu diễn chính xác bằng số thực có độ dài hữu hạn, dẫn đến hiện tượng "làm tròn".

Ví dụ, khi phân phối 0.7 NEAR token cho 10 người dùng trên chuỗi công khai NEAR:

gỉ #[test] fn precision_test_float() { let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
println!("Giá trị của số lượng: {:.20}", amount); assert_eq!(result_0, 0.07, ""); }

Kết quả đầu ra cho thấy giá trị của amount là 0.69999999999999995559, không phải là 0.7 chính xác. Kết quả phép chia cũng trở thành 0.06999999999999999 không chính xác, thay vì 0.07 như mong đợi.

Để giải quyết vấn đề này, có thể xem xét sử dụng số cố định. Trong NEAR Protocol, thường sử dụng 10^24 yoctoNEAR để biểu thị 1 mã thông báo NEAR. Mã kiểm tra đã được sửa đổi:

gỉ #[test] fn precision_test_integer() { let N: u128 = 1_000_000_000_000_000_000_000_000;
let amount: u128 = 700_000_000_000_000_000_000_000; let divisor: u128 = 10;
let result_0 = amount / divisor; assert_eq!(result_0, 70_000_000_000_000_000_000_000, ""); }

Cách này có thể đạt được kết quả tính toán chính xác: 0.7 NEAR / 10 = 0.07 NEAR.

2. Vấn đề độ chính xác trong tính toán số nguyên Rust

Việc sử dụng phép toán số nguyên có thể giải quyết vấn đề mất độ chính xác trong phép toán số thực ở một số trường hợp, nhưng kết quả của phép toán số nguyên cũng không hoàn toàn chính xác và đáng tin cậy.

2.1 Thứ tự toán tử

Thứ tự của phép nhân và phép chia có cùng độ ưu tiên số học có thể ảnh hưởng trực tiếp đến kết quả tính toán, dẫn đến vấn đề độ chính xác của phép tính số nguyên. Ví dụ:

gỉ #[test] fn precision_test_div_before_mul() { let a: u128 = 1_0000; let b: u128 = 10_0000; let c: u128 = 20;

let result_0 = a.checked_mul(c).expect("ERR_MUL").checked_div(b).expect("ERR_DIV");
let result_1 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");

assert_eq!(result_0,result_1,"");

}

Kết quả thực thi cho thấy result_0 và result_1 không bằng nhau. Nguyên nhân là phép chia số nguyên sẽ loại bỏ độ chính xác nhỏ hơn mẫu số. Khi tính toán result_1, (a / b) trước tiên mất độ chính xác và trở thành 0; trong khi khi tính toán result_0, trước tiên tính a * c để tránh mất độ chính xác.

2.2 quy mô quá nhỏ

Khi liên quan đến tính toán số thập phân, phép toán số nguyên có thể dẫn đến mất độ chính xác:

rỉ sét #[test] fn precision_test_decimals() { let a: u128 = 10; let b: u128 = 3; let c: u128 = 4; let decimal: u128 = 100_0000;

let result_0 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");
let result_1 = a.checked_mul(decimal).expect("ERR_MUL").checked_div(b).expect("ERR_DIV")
    .checked_mul(c).expect("ERR_MUL").checked_div(decimal).expect("ERR_DIV");

println!("{}:{}", result_0, result_1);
assert_eq!(result_0, result_1, "");

}

Kết quả cho thấy result_0=12, result_1=13, trong khi giá trị dự kiến thực tế nên là 13.3333....

3. Làm thế nào để viết hợp đồng thông minh Rust cho việc định giá số

Để nâng cao độ chính xác, có thể áp dụng các biện pháp bảo vệ sau:

3.1 Điều chỉnh thứ tự thực hiện phép toán

Hãy ưu tiên phép nhân số nguyên hơn phép chia số nguyên.

3.2 tăng bậc số nguyên

Sử dụng bậc lớn hơn, tạo ra phân số lớn hơn. Ví dụ, biểu thị 5.123 NEAR có thể sử dụng 5.123 * 10^10 = 51_230_000_000 để tham gia vào các phép toán tiếp theo.

3.3 Tổn thất độ chính xác của phép toán tích lũy

Đối với các vấn đề độ chính xác không thể tránh khỏi, có thể ghi lại tổn thất độ chính xác tích lũy. Ví dụ:

gỉ const USER_NUM: u128 = 3;

u128 { let token_to_distribute = offset + amount; let per_user_share = token_to_distribute / USER_NUM; println!("per_user_share {}", per_user_share); let recorded_offset = token_to_distribute - per_user_share * USER_NUM; recorded_offset }

#( fn record_offset_test)[test] { let mut offset: u128 = 0; cho i trong 1..7 { println!("Round {}", i); offset = distribute(to_yocto)"10"(, offset(; println!)"Offset {}\n", offset); } }

Phương pháp này có thể tích lũy số token còn lại từ mỗi lần phân phối, và phát cùng nhau trong lần phân phối tiếp theo, cuối cùng đạt được mục tiêu phát đủ.

( 3.4 Sử dụng thư viện Rust Crate rust-decimal

Thư viện này phù hợp cho các phép toán tài chính với số thập phân cần tính toán chính xác mà không có sai số do làm tròn.

) 3.5 Xem xét cơ chế làm tròn

Trong thiết kế hợp đồng thông minh, vấn đề làm tròn thường áp dụng nguyên tắc "Tôi muốn lợi ích, người khác không được lợi dụng tôi". Tùy thuộc vào tình huống mà chọn làm tròn xuống hoặc làm tròn lên, rất ít khi sử dụng làm tròn thông thường.

![]###https://img-cdn.gateio.im/webp-social/moments-6e8b4081214a69423fc7ae022d05c728.webp###

Xem bản gốc
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
  • Phần thưởng
  • 6
  • Chia sẻ
Bình luận
0/400
consensus_failurevip
· 11giờ trước
Sử dụng độ chính xác cố định an toàn hơn
Xem bản gốcTrả lời0
Ser_Liquidatedvip
· 07-12 19:41
Nếu lại gặp vấn đề về độ chính xác sẽ bị thanh lý
Xem bản gốcTrả lời0
DecentralizeMevip
· 07-11 16:13
Hãy thay thế bằng số cố định.
Xem bản gốcTrả lời0
BoredWatchervip
· 07-11 15:58
Mã hơi rối một chút.
Xem bản gốcTrả lời0
BrokenDAOvip
· 07-11 15:53
Khả năng tính toán tổng dư thừa thì rắc rối
Xem bản gốcTrả lời0
MEVSandwichMakervip
· 07-11 15:51
Là một cái hố cũ, nên khuyên tránh xa.
Xem bản gốcTrả lời0
  • Ghim
Giao dịch tiền điện tử mọi lúc mọi nơi
qrCode
Quét để tải xuống ứng dụng Gate
Cộng đồng
Tiếng Việt
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)