Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_nearest_representable_edf_time_value isn't quite right #76

Open
ericphanson opened this issue Oct 19, 2023 · 0 comments
Open

_nearest_representable_edf_time_value isn't quite right #76

ericphanson opened this issue Oct 19, 2023 · 0 comments

Comments

@ericphanson
Copy link
Member

ericphanson commented Oct 19, 2023

EDF.jl/src/types.jl

Lines 117 to 121 in 2eef49f

_nearest_representable_edf_time_value(::Nothing) = nothing
function _nearest_representable_edf_time_value(x)
return round(x; digits=(8 - (ndigits(floor(Int, x)) + signbit(x) + isinteger(x))))
end

First- I don't think we need this for onsets and annotations, xref #75, #72). But I think it is useful to have, at least for folks doing the encoding (which are EDF.jl's users but not EDF.jl itself). However, it should be:

function _nearest_representable_edf_time_value(x, rm::RoundingMode=RoundNearest)
    return round(x, rm; digits=(8 - (ndigits(floor(Int, x)) + signbit(x) + !isinteger(x))))
end

where I've added an optional rounding mode. The difference here is !isinteger - we lose a digit when we have to write the decimal.

Running

using Printf
function edf_roundtrip(x::Real)
    result = missing
    if isinteger(x)
        str = string(trunc(Int, x))
        if length(str) <= 8
            result = str
        end
    else
        fpart, ipart = modf(x)
        ipart_str = string('-'^signbit(x), Int(abs(ipart))) # handles `-0.0` case
        fpart_str = @sprintf "%.7f" abs(fpart)
        fpart_str = fpart_str[3:end] # remove leading `0.`
        if length(ipart_str) < 7
            result = ipart_str * '.' * fpart_str[1:(7-length(ipart_str))]
        elseif length(ipart_str) <= 8
            result = ipart_str
        end
    end
    if !ismissing(result)
        return parse(Float64, result)
    end
    error("failed to fit header field into EDF's 8 ASCII character limit. Got: $x")
    return nothing
end

edf_roundtrip_error(x) = abs(x - edf_roundtrip(x))

function _nearest_representable_edf_time_value(x, rm::RoundingMode=RoundNearest)
    return round(x, rm; digits=(8 - (ndigits(floor(Int, x)) + signbit(x) + !isinteger(x))))
end

f = x -> edf_roundtrip_error(_nearest_representable_edf_time_value(x))
lines(xs, f.(xs))

which modifies the _edf_repr code for use here, I get
!isinteger
whereas if I remove the ! to match the current code, I get
isinteger

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant