Stream: bugs

Topic: F64 rounding errors in Roc and Decimal to F64 conversion


view this post on Zulip Brian Teague (Nov 27 2024 at 05:37):

I am trying to solve this exercise in a unique way: https://exercism.org/tracks/roc/exercises/darts
Using this quadratic equation: https://www.desmos.com/calculator/q7f0iozldx
x coordinate is the dart unit distance from (0,0) and y coordinate is used to determine the points based on the when clause below.

I have passed almost all tests, but 1 fails due to a precision rounding error in F64 data type:
Attempts to round y2 by multiplying 100000.0, using Num.round and then dividing by 100000.0 don't work.

y2 = (-1.0 / 180.0) * x2 * x2 + (17.0 / 60.0) * x2 - 23.0 / 18.0
vs
y2 = (Num.toFrac (Num.round ((Num.toF64 1000000.0) * (-1.0 / 180.0) * x2 * x2 + (17.0 / 60.0) * x2 - 23.0 / 18.0))) / 1000000.0

thread 'main' panicked at crates/compiler/gen_llvm/src/llvm/lowlevel.rs:1198:21:
not yet implemented: Support converting Dec values to floats

Any other ideas on how to eliminate the rounding error on this example?

1 failed and 12 passed.

[/mnt/exercism-iteration/Darts.roc:7] y2 = -0.9999999999999999
[/mnt/exercism-iteration/Darts.roc:9] c = 0

28│>  # On the inner circle
29│>  expect
30│>      result = score 0.0f64 -1.0f64
31│>      result == 10

result : U64
result = 5
score : F64, F64 -> U64
score = \x, y ->
    x2 = Num.sqrt (x * x + y * y)
    y2 = (-1.0 / 180.0) * x2 * x2 + (17.0 / 60.0) * x2 - 23.0 / 18.0
    dbg y2
    c = Num.ceiling y2
    dbg c
    when c is
        -1 -> 10
        0 -> 5
        1 -> 1
        _ -> 0

view this post on Zulip Brendan Hansknecht (Nov 27 2024 at 06:21):

Not that it fixes the test results, but to get the code to compile, you can do this:

y2 = (Num.toF64 (Num.round (1000000.0 * (-1.0 / 180.0) * x2 * x2 + (17.0 / 60.0) * x2 - 23.0 / 18.0))) / 1000000.0

view this post on Zulip Brendan Hansknecht (Nov 27 2024 at 06:25):

Oh, I think you need to multiply everything by the 1000000.0 for it to be correct

view this post on Zulip Brendan Hansknecht (Nov 27 2024 at 06:26):

Cause the above only multiplies the first term by 1000000.0

view this post on Zulip Brendan Hansknecht (Nov 27 2024 at 06:26):

Something like this?

y2 = (Num.toF64 (Num.round (1000000.0 * ((-1.0 / 180.0) * x2 * x2 + (17.0 / 60.0) * x2 - 23.0 / 18.0)))) / 1000000.0

view this post on Zulip Brendan Hansknecht (Nov 27 2024 at 06:27):

Anyway, I don't think there are any rounding errors here (past expected float inaccuracies), but maybe I am missing something?

We definitely are missing the function to convert from dec to f64 and should add that.

view this post on Zulip Brian Teague (Nov 27 2024 at 14:39):

Worked like a charm. Thanks!

score : F64, F64 -> U64
score = \x, y ->
    distance = x * x + y * y
        |> Num.sqrt
    rawScore = (-1.0 / 180.0) * distance * distance + (17.0 / 60.0) * distance - 23.0 / 18.0
    # Need rounded score to remove precision errors with F64 data type
    roundedScore = rawScore * 1000000.0
        |> Num.round
        |> Num.toF64
        |> \n -> n / 1000000.0
    when Num.ceiling roundedScore is
        -1 -> 10
        0 -> 5
        1 -> 1
        _ -> 0

Last updated: Jul 06 2025 at 12:14 UTC