Skip to content

added support for an arbitrary number of fraction bits#44

Merged
timholy merged 2 commits intoJuliaMath:masterfrom
bjarthur:arbitrarynbits
Aug 24, 2016
Merged

added support for an arbitrary number of fraction bits#44
timholy merged 2 commits intoJuliaMath:masterfrom
bjarthur:arbitrarynbits

Conversation

@bjarthur
Copy link
Copy Markdown
Collaborator

@bjarthur bjarthur commented Aug 12, 2016

i need to add four Image{Gray{UFixed16}} together without overflowing. could convert to Float32, but thought a UFixed{UInt32,16} would be more graceful. so before realizing that the snazzy new @generated was taboo, i refactored ufixed.jl to support arbitrary fractional bit depths. anything goes, like UFixed{UInt64,3}, as an additional example.

all of the tests pass in julia 0.5-rc2.

so why are generated functions to be avoided?

@vchuravy
Copy link
Copy Markdown
Collaborator

A lot of the generated functions are unnecessary and I think we could rework most of the eval-for loops by using methods like @pure mask{T, f}(::Type{UFixed{T,f}}) = convert(T, 1<<(f-1)). LLVM constant-folds this calculation and we won't need to resort to the inlining trick.

Will put up an PR for that momentarily. Thank you for your help.

@bjarthur bjarthur force-pushed the arbitrarynbits branch 2 times, most recently from ddff03b to f9218ff Compare August 13, 2016 14:44
@bjarthur
Copy link
Copy Markdown
Collaborator Author

doh! it should've occurred to me that generated functions whose body only contains the returned expression could be rewritten as normal functions. thanks!

i've added more tests, updated the docs, and included a commit, which could be a separate PR if preferred, which fixes the type returned by round and ceil.

any ideas for benchmarks?

src/ufixed.jl Outdated
one(::Type{$T}) = $T($(2^f-1),0)
end
end
one{T<:UFixed}(::Type{T}) = T((2^nbitsfrac(T)-1),0)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be costly on v0.4. On v0.5 we can constant fold this, but only if we outline the 2^nbitsfrac(T) into a pure function Base.@pure one_pattern(f)=(2^f-1), but this won't work on v0.4.

One solution would be for now to use the current way on v0.4 with your method as a fallback, and on v0.5 and higher use pure functions on the type-parameter to get the same effect.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. thanks. it was 4x slower. fixed for 0.4 and 0.5 with a generated function. that seems a simpler solution to me than having to switch on the version.

@vchuravy
Copy link
Copy Markdown
Collaborator

Thank you for tackling this. The added generality will be valuable, but we have to make sure that this comes at no extra cost, because FixedPointNumbers is used in performance sensitive places.

Would you mind also adding a few benchmarks with BenchmarkTools?

@bjarthur
Copy link
Copy Markdown
Collaborator Author

thanks for pointing out BenchmarkTools to me. i used it to fix a few things you pointed out. is it customary to commit benchmarks? if so, where?

round{T<:Integer}(::Type{T}, x::UFixed) = round(T, reinterpret(x)/rawone(x))
floor{T<:Integer}(::Type{T}, x::UFixed) = trunc(T, x)
ceil{T<:Integer}(::Type{T}, x::UFixed) = ceil(T, reinterpret(x)/rawone(x))
trunc(x::UFixed) = trunc(Int, x)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for these to be removed?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is part of the second commit. removing them fixes the bug that round(UFixed) returns an Int, not a UFixed.

@timholy
Copy link
Copy Markdown
Member

timholy commented Aug 19, 2016

This looks quite good to me. I do not personally have a problem with the generated functions. Some could become @pure on Julia 0.5, of course.

@bjarthur
Copy link
Copy Markdown
Collaborator Author

show now omits FixedPointNumbers for brevity, as requested.

anything else?

convert(Tdual, b/one(T)), reinterpret(rawtype(T), x)

# printing
@generated function show{T,f}(io::IO, x::FixedPoint{T,f})
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a @generated function? I would think it is unnecessary here ;)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, this should not be @generated, it's not performance-critical and in any case being @generated won't help here.

@vchuravy
Copy link
Copy Markdown
Collaborator

Looks good to me.

@bjarthur
Copy link
Copy Markdown
Collaborator Author

is this what you had in mind instead of a generated function?

README.md Outdated
`0xffff`).

To construct such a number, use `convert(UFixed12, 1.3)`, `ufixed12(1.3)` (a
convenience function), `UFixed{UInt16,12}`, or the literal syntax `0x14ccuf12`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UFixed{UInt16,12} is a type, not a value.

@timholy
Copy link
Copy Markdown
Member

timholy commented Aug 24, 2016

Sorry to keep pestering you with review comments. I was about to hit merge and thought I should give it another once-over. I must be less tired this time.

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

Successfully merging this pull request may close these issues.

3 participants