fzyzcjy / flutter_rust_bridge

Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple.
https://fzyzcjy.github.io/flutter_rust_bridge/
MIT License
4.14k stars 285 forks source link

Floating precision rounding error when Rust API is called via Dart bindings #2241

Closed erdemyerebasmaz closed 1 month ago

erdemyerebasmaz commented 1 month ago

Describe the bug

We have encountered a floating precision rounding error on Rust layer when using Dart bindings.

One of our API's validate an amount against a response from a server. The amount returned from the server is a float, f64, and it needs to be multiplied to have the same unit we're validating it against and then it's cast to u64 for comparison.

Basically, an f64 field is multiplied by another float and then cast to u64.

The issue is not present when using Rust library directly, which may have something to do with the way Dart interacts with the Rust library via FFI.

We want to understand why this may be happening when this API is called via Dart bindings and not natively.

Steps to reproduce

// Assuming input_num is 59810
#[frb(sync)]
pub fn floating_precision_rounding_error(input_num: u64) -> bool {
    let float_num: f64 = 0.0005981;
    let multiplied_amount: u64 = (float_num * 100_000_000.0) as u64;
    (input_num == multiplied_amount)
} 

Of course, one approach would be to round the multiplied amount to nearest integer before casting it to u64

let multiplied_amount: u64 = (float_num * 100_000_000.0).round() as u64;

but we're trying to understand why this may be happening using Dart bindings in the first place as Rust & Dart follow the same IEEE 754 standard for double-precision floating-point format AFAIK.

Logs

N/A

Expected behavior

No response

Generated binding code

No response

OS

No response

Version of flutter_rust_bridge_codegen

2.2.0

Flutter info

Flutter (Channel stable, 3.22.3, on macOS 14.5 23F79 darwin-arm64, locale en-TR)
    • Flutter version 3.22.3 on channel stable at /Users/erdem/.fenv/versions/3.22.3
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision b0850beeb2 (4 weeks ago), 2024-07-16 21:43:41 -0700
    • Engine revision 235db911ba
    • Dart version 3.4.4
    • DevTools version 2.34.3

Version of clang++

Homebrew clang version 18.1.5

Additional context

No response

fzyzcjy commented 1 month ago

Hi, could you please check

If I understand correctly,

Then that's super weird. This is a standard normal rust function, and frb does not touch it (it merely calls it).

If checking things above does not help, maybe try to decompile and see the assembly. That's one of the common ways to see what is going on iirc.

erdemyerebasmaz commented 1 month ago
  • which platform are you using? (web? native?)

Native platforms. Haven't tested on web.

If I understand correctly,

  • the error happens when it is inside a Rust #[frb(sync)] fn

No, sync attribute is unrelated. The issue is seen on both sync & async fn's.

  • the error does not happen when it is inside anoher Rust fn

We are able to reproduce the issue on Rust layer, I had made an error on my initial tests.

If checking things above does not help, maybe try to decompile and see the assembly. That's one of the common ways to see what is going on iirc.

Thanks for the suggestion. I have no experience decompiling Rust. Any resources/tools you'd recommend to help with that process? Is Compiler Explorer a good option?

Closing the issue as this falls beyond the plugin's scope.

fzyzcjy commented 1 month ago

Any resources/tools you'd recommend to help with that process? Is Compiler Explorer a good option?

If you can isolate problem such that it only contain a dozen pure rust code then yes that's super convenient

github-actions[bot] commented 3 weeks ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new issue.