4

I noticed a funny behaviour with Matlab-FI numbers. It occurs only with 1-bit, signed numbers (a datatype that does not make a lot of sense in practice). I'm aware that multiplying a double with a fi is not a good practice and the behaviour may even depend on the Matlab version, but I would expect the behaviour to be the same independent of the number of bits. This seems to be consistent in versions 2011b, 2013a and 2013b and I would like to understand why it happens that way.

Example 1: -1 can be representet as 1-bit, signed. However the result has a fraction-part of -2 which would allow only numbers [-8, -4, 0, 4]

>> a = fi(-1,1,1,0)
a = -1
      s1,0

>> 1*a
ans = 0
      s2,-2

Example 2: A 1-bit, unsigned behaves as expected, the fraction-part is unchanged

>> b = fi(1,0,1,0)
b = 1
      u1,0

>> 1*b
ans = 1
      u2,0

Example 3: A 2-bit, signed behaves as expected, the fraction-part is unchanged, the integer-part is extended

>> c = fi(-2,1,2,0)
c = -2
      s2,0

>> 1*c
ans = -2
      s4,0

Example 4: Another 1-bit, signed showing a similar behaviour as in example 1.

>> d = fi(-0.5,1,1,1)
d = -0.5000
      s1,1

>> 1*d
ans = 0
      s2,-1
mbschenkel
  • 1,865
  • 1
  • 18
  • 40
  • Since that question didn't get any attention, I have crossposted to [Matlab Central](http://www.mathworks.com/matlabcentral/answers/113278-behaviour-of-matlab-fixed-point-numbers-with-1-bit). I'll update here if I get any answers there. – mbschenkel Jan 22 '14 at 12:07
  • Stepping though this operation we get into `mtimes.m` which in this case calls the `fimtimes(a,b)` function. I cannot step into this function to examine the code. Therefore to get an answer we will need someone from Mathworks to chime in. Otherwise, the best I can give is: this is a bug in `fimtimes` (and `fitimes`). – nguthrie Mar 03 '14 at 01:32
  • 1
    Also, I observe similar odd behavior with division. With `a` defined as you have it in your first example I see `1/a = 0` and `a/1 = -1` but this second result gives a divide by zero warning! – nguthrie Mar 03 '14 at 01:36
  • Thanks @nguthrie for confirming the issue! I have also sent this question to Mathworks support directly. – mbschenkel Mar 03 '14 at 08:04
  • Not sure if I understand what is going on, but my guess would be that you have insufficient word length leading to something like rounding errors? – Dennis Jaheruddin Mar 04 '14 at 09:58
  • @DennisJaheruddin: Well given the output type of e.g. Ex. 1, there is rounding involved and the result is "correctly rounded". However I don't understand why the output type is correctly expanded to represent the result in all cases except for 1-bit, signed arguments where rounding would not introduce an error. – mbschenkel Mar 04 '14 at 14:10
  • Can't try myself, but does it matter whether you cast the 1 to `fi` before multiplication? – Dennis Jaheruddin Mar 05 '14 at 15:38
  • Yes it does matter. `fi(-1,1,1,0)*fi(1,0,1,0)`, `fi(-1,1,1,0)*fi(1,1,2,0)` and `fi(-1,1,1,0)*fi(-1,1,1,0)` all return correct values with correct sizes. – mbschenkel Mar 05 '14 at 16:53

2 Answers2

3

When matlab is multiplying numbers with different format, it is changing the first of all modifying the formats. If you convert the 1 to the same format as your value, sometimes the number one in this format is 0, so it makes sense that the product is zero, and everything is as expected.

Example 1

a = fi(-1,1,1,0); a_one = fi(1,1,1,0); disp([a, a_one, a*a_one])
    -1     0     0

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 1
        FractionLength: 0

Example 2

b = fi(1,0,1,0); b_one = fi(1,0,1,0); disp([b, b_one, b*b_one])
     1     1     1

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Unsigned
            WordLength: 1
        FractionLength: 0

Example 3

c = fi(-2,1,2,0); c_one = fi(1,1,2,0); disp([c, c_one, c*c_one])
    -2     1    -2

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 2
        FractionLength: 0

Example 4

d = fi(-0.5,1,1,1); d_one = fi(1,1,1,1); disp([d, d_one, d*d_one])
  -0.500000000000000                   0                   0

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 1
        FractionLength: 1
sebas
  • 869
  • 7
  • 16
  • You are right that this may depend on the exact type that the double is converted to in the first place. I found also some more strange cases which are not 1-bit numbers, like `fi(2,0,2,0)*10` returning `24`... It would be interesting to find a way to know this intermediary type - can the debugger be used somehow to investigate that? However, what I don't like in your answer is that you output 3 variables of different types as a vector: Because a vector always has a single datatype and our problem is specifically about types, it would be better to print `d`, `d_one` and `d*d_one` separately. – mbschenkel Mar 07 '14 at 08:00
  • +50 Since casting the double to the type of the other operand is really the key. Thanks. – mbschenkel Mar 08 '14 at 13:22
1

Disclaimer: The following is the (slightly edited) answer from MathWorks support which I'm adding for completeness. In brief it turns out that this is not limited to 1-bit datatypes, but (as pointed out by sebas) to the double constant being cast to the other operand and saturating there, notably without warning, but according to spec.


It turns out that the double constant value (e.g., 1) is cast to a FI type prior to the math operation (e.g. *), using the signedness and wordlength of the other operand. However, the new FI type uses a "best precision" fraction length instead of the fraction length of the other operand.

Here is some equivalent MATLAB code with the explicit fi() constructor illustrating this:

Example 1.

>> a = fi(-1,1,1,0)
a =
    -1
    s1,0

>> fi(1,a.SignednessBool,a.WordLength) * a
ans =
    0
    s2,-2

>> 1*a
ans =
    0
    s2,-2

Example 2.

>> b = fi(1,0,1,0)
b =
    1
    u1,0

>> fi(1,b.SignednessBool,b.WordLength) * b
ans =
    1
    u2,0

>> 1 * b
ans =
    1
    u2,0

Example 3.

>> c = fi(-2,1,2,0)
c =
    -2
    s2,0

>> fi(1,c.SignednessBool,c.WordLength) * c
ans =
    -2
    s4,0

>> 1 * c
ans =
    -2
    s4,0

Example 4.

>> d = fi(-0.5,1,1,1)
d =
    -0.5000
    s1,1

>> fi(1,d.SignednessBool,d.WordLength) * d
ans =
    0
    s2,-1

>> 1*d
ans =
    0
    s2,-1

I hope these examples help clarify the issue with the implicit type casting of a double constant value (e.g., 1).

mbschenkel
  • 1,865
  • 1
  • 18
  • 40