Desarrollo de contratos inteligentes en Rust: Técnicas de cálculo numérico y control de precisión

Diario de desarrollo de contratos inteligentes en Rust (7): cálculo numérico

1. Problemas de precisión en cálculos de punto flotante

El lenguaje Rust admite de forma nativa operaciones con números de punto flotante, pero estas operaciones presentan problemas de precisión de cálculo que son inevitables. Al escribir contratos inteligentes, no se recomienda utilizar operaciones con números de punto flotante, especialmente al tratar con tasas o intereses que implican decisiones económicas/financieras importantes.

El tipo de punto flotante de doble precisión f64 en el lenguaje Rust sigue el estándar IEEE 754 y utiliza la notación científica con una base de 2. Algunos decimales como 0.7 no se pueden representar con precisión utilizando números de punto flotante de longitud finita, lo que da lugar a un fenómeno de "redondeo".

En la prueba de distribución de 0.7 tokens NEAR a diez usuarios en la cadena pública NEAR, el resultado de los cálculos en punto flotante no es preciso:

óxido let amount: f64 = 0.7;
let divisor: f64 = 10.0; let result_0 = amount / divisor;

El valor de amount es 0.69999999999999995559, el valor de result_0 es 0.06999999999999999, en lugar del esperado 0.07.

Para resolver este problema, se pueden utilizar números de punto fijo. En el Protocolo NEAR, generalmente se expresa como 1 NEAR = 10^24 yoctoNEAR:

óxido 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;

De esta manera se puede obtener un resultado de cálculo preciso: 0.7 NEAR / 10 = 0.07 NEAR.

2. Problemas de precisión en cálculos enteros de Rust

2.1 Orden de operaciones

En las operaciones de multiplicación y división con la misma prioridad aritmética, el cambio en el orden de las operaciones puede afectar directamente el resultado del cálculo. Por ejemplo:

óxido let a: u128 = 1_0000; let b: u128 = 10_0000; let c: u128 = 20;

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

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

el resultado de result_0 y result_1 es diferente, porque en la división entera, la precisión menor que el divisor se descartará.

2.2 orden de magnitud demasiado pequeño

Cuando se trata de valores pequeños, las operaciones enteras pueden provocar una pérdida de precisión:

óxido let a: u128 = 10; let b: u128 = 3; let c: u128 = 4; let decimal: u128 = 100_0000;

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

// result_1 = (a * decimal / b) * c / decimal; 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");

el resultado de result_0 y result_1 son diferentes, result_1 se acerca más al valor esperado real.

3. Cómo escribir contratos inteligentes de cálculo actuarial numérico en Rust

3.1 Ajustar el orden de las operaciones

Hacer que la multiplicación de enteros tenga prioridad sobre la división de enteros.

3.2 aumentar el orden de magnitud de los enteros

Usar un orden de magnitud mayor para crear moléculas más grandes. Por ejemplo, representar 5.123 NEAR como 51_230_000_000 yoctoNEAR.

3.3 Pérdida de precisión en cálculos acumulativos

Registrar la pérdida acumulada de precisión en los cálculos y compensarla en cálculos posteriores. Por ejemplo:

óxido u128 { let token_to_distribute = offset + amount; let per_user_share = token_to_distribute / USER_NUM; let recorded_offset = token_to_distribute - per_user_share * USER_NUM; recorded_offset }

( 3.4 Uso de la biblioteca Rust Crate rust-decimal

Esta biblioteca es adecuada para cálculos financieros decimales que requieren una precisión efectiva y no tienen errores de redondeo.

) 3.5 Considerar el mecanismo de redondeo

En el diseño de contratos inteligentes, el problema del redondeo generalmente se aborda con el principio "quiero aprovecharme, los demás no deben aprovecharse de mí". Según la situación, se elige redondear hacia abajo, hacia arriba o redondear al entero más cercano.

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

TOKEN1.24%
NUM0.48%
Ver originales
Esta página puede contener contenido de terceros, que se proporciona únicamente con fines informativos (sin garantías ni declaraciones) y no debe considerarse como un respaldo por parte de Gate a las opiniones expresadas ni como asesoramiento financiero o profesional. Consulte el Descargo de responsabilidad para obtener más detalles.
  • Recompensa
  • 3
  • Compartir
Comentar
0/400
BearMarketBuildervip
· 08-05 07:58
El pozo de los números de punto flotante es simplemente profundo como el mar.
Ver originalesResponder0
SelfSovereignStevevip
· 08-05 07:53
Los números de punto flotante son muy problemáticos, los contratos inteligentes deben fallar, no me atrevo a usarlos en absoluto.
Ver originalesResponder0
DegenGamblervip
· 08-05 07:49
¡Atención, hermanos que juegan a Rust! Esta trampa de precisión no es pequeña.
Ver originalesResponder0
Opere con criptomonedas en cualquier momento y lugar
qrCode
Escanee para descargar la aplicación Gate
Comunidad
Español
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)