# Questions about fixed point numbers

Should conversions between different fixed point representations work (example below) ?

Also I’d like to use the library for some DSP algorithm implementation, so doing things like automatic promotion of multiplies to more bits would be really nice.

Thinking about it, I decided that FixedPointNumbers should not do that, I like the fact that it maintains consistency in the results.

So what I need to do is -

• create a value of 15 bits of precision
• extend to 31 bits
• perform a multiplication
• truncate back to 15 bits

However it looks like the only way to perform that sequence to do intermediate conversions to float and then back.

am I missing something ?

``````julia> using FixedPointNumbers

julia> t1=Fixed{Int32,15}
FixedPointNumbers.Fixed{Int32,15}

julia> t2=Fixed{Int16,15}
FixedPointNumbers.Fixed{Int16,15}

julia> a=t1(0.25)
0.25Q16f15

julia> b=convert(t2, a)
ERROR: MethodError: Cannot `convert` an object of type FixedPointNumbers.Fixed{Int32,15} to an object of type FixedPointNumbers.Fixed{Int16,15}
This may have arisen from a call to the constructor FixedPointNumbers.Fixed{Int16,15}(...),
since type constructors fall back to convert methods.

julia>
``````

In practice, the `Normed` numbers have gotten a lot more practical testing (they are used by the Colors/Images suite), and so we seem to have the following:

``````julia> using FixedPointNumbers

julia> x = rand(N2f6)     # Normed numbers example
1.1N2f6

julia> convert(N6f10, x)
1.0948N6f10

julia> x = rand(Q2f5)    # Fixed numbers example
1.66Q2f5

julia> convert(Q6f9, x)
ERROR: MethodError: Cannot `convert` an object of type FixedPointNumbers.Fixed{Int8,5} to an object of type FixedPointNumbers.Fixed{Int16,9}
This may have arisen from a call to the constructor FixedPointNumbers.Fixed{Int16,9}(...),
since type constructors fall back to convert methods.
``````

Any chance you could tweak the implementation for `Normed` to build one for `Fixed`? And then contribute it?

yes that is something i could do. i’ve only done a PR once, so it will take me a bit to get things figured out again. I’ve already looked at the code and it seems to be straightforward.

However in thinking about this what I really want to be able to do, and this is a generic Julia question is something like

a= Int8(127)
b= Int8(127)

a*b => automatic promotion to Int16

Is there a way through macro-fu or some other method for me to set up a system where I can automatically do that ?
I’m thinking that it simply requires me to generate an operator/method that would capture the types and do so.

``````function op1(a::Int8, b::Int8) :: Int16
a1 = Int16(a)
b1 = Int16(b)
return a1*b1
end
``````

Should be that easy, right ? well I know it is, I tried it. The problem is that if I try to use the standard multiplication operator, i.e. ‘*’, then I figure it will almost certainly clash with the built in assignment which is to maintain the same type. Interestingly that would not be a problem if the method was actually matched using the return type- which I don’t think is true at this time.

Thanks

One problem with making this the default strategy: `Int8^2``Int16`, `Int16^2``Int32`, and `Int32^2``Int64`. It becomes almost impossible to predict the output type from a computation: go from 2 to 3 multiplies and suddenly the output type changes. Of course sometimes you can compute the same thing in two different ways (e.g., `x^4` can be computed in either 2 multiplies or 3), and it would be crazy if the output type depended on how you chose to implement the computation. A lesson is that If you’re going to widen, you need to widen “all the way” immediately.

We used to widen, e.g., `UInt8``UInt`, and interestingly it was not very popular. I think the lesson is that if you aren’t using one of the “default” types (`Int`, `UInt`, and `Float64`), you probably have a reason and therefore want some manual control. Consequently the dominant behavior (with a few exceptions) is that any widening has to be implemented manually.

2 Likes

I agree. I didn’t mean to imply it should be default behavior . I was just describing what I was trying to do and figuring out a way to make it “look nice”.

I like the fact that the type is precisely conserved and that any modification must be done with an explicit operation.